home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / texinfo-3.7-src.tgz / tar.out / fsf / texinfo / info / footnotes.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  266 lines

  1. /* footnotes.c -- Some functions for manipulating footnotes. */
  2.  
  3. /* This file is part of GNU Info, a program for reading online documentation
  4.    stored in Info format.
  5.  
  6.    Copyright (C) 1993 Free Software Foundation, Inc.
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  
  22.    Written by Brian Fox (bfox@ai.mit.edu). */
  23.  
  24. #include "info.h"
  25.  
  26. /* Non-zero means attempt to show footnotes when displaying a new window. */
  27. int auto_footnotes_p = 1;
  28.  
  29. static char *footnote_nodename = "*Footnotes*";
  30.  
  31. #define FOOTNOTE_HEADER_FORMAT \
  32.    "*** Footnotes appearing in the node \"%s\" ***\n"
  33.  
  34. /* Find the window currently showing footnotes. */
  35. static WINDOW *
  36. find_footnotes_window ()
  37. {
  38.   WINDOW *win;
  39.  
  40.   /* Try to find an existing window first. */
  41.   for (win = windows; win; win = win->next)
  42.     if (internal_info_node_p (win->node) &&
  43.     (strcmp (win->node->nodename, footnote_nodename) == 0))
  44.       break;
  45.  
  46.   return (win);
  47. }
  48.  
  49. /* Manufacture a node containing the footnotes of this node, and
  50.    return the manufactured node.  If NODE has no footnotes, return a 
  51.    NULL pointer. */
  52. NODE *
  53. make_footnotes_node (node)
  54.      NODE *node;
  55. {
  56.   NODE *fn_node, *result = (NODE *)NULL;
  57.   long fn_start;
  58.  
  59.   /* Make the initial assumption that the footnotes appear as simple
  60.      text within this windows node. */
  61.   fn_node = node;
  62.  
  63.   /* See if this node contains the magic footnote label. */
  64.   fn_start =
  65.     info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1);
  66.  
  67.   /* If it doesn't, check to see if it has an associated footnotes node. */
  68.   if (fn_start == -1)
  69.     {
  70.       REFERENCE **refs;
  71.  
  72.       refs = info_xrefs_of_node (node);
  73.  
  74.       if (refs)
  75.     {
  76.       register int i;
  77.       char *refname;
  78.  
  79.       refname = (char *)xmalloc
  80.         (1 + strlen ("-Footnotes") + strlen (node->nodename));
  81.  
  82.       strcpy (refname, node->nodename);
  83.       strcat (refname, "-Footnotes");
  84.  
  85.       for (i = 0; refs[i]; i++)
  86.         if ((refs[i]->nodename != (char *)NULL) &&
  87.         (strcmp (refs[i]->nodename, refname) == 0))
  88.           {
  89.         char *filename;
  90.  
  91.         filename = node->parent;
  92.         if (!filename)
  93.           filename = node->filename;
  94.  
  95.         fn_node = info_get_node (filename, refname);
  96.  
  97.         if (fn_node)
  98.           fn_start = 0;
  99.  
  100.         break;
  101.           }
  102.  
  103.       free (refname);
  104.       info_free_references (refs);
  105.     }
  106.     }
  107.  
  108.   /* If we never found the start of a footnotes area, quit now. */
  109.   if (fn_start == -1)
  110.     return ((NODE *)NULL);
  111.  
  112.   /* Make the new node. */
  113.   result = (NODE *)xmalloc (sizeof (NODE));
  114.   result->flags = 0;
  115.  
  116.   /* Get the size of the footnotes appearing within this node. */
  117.   {
  118.     char *header;
  119.     long text_start = fn_start;
  120.  
  121.     header = (char *)xmalloc
  122.       (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
  123.     sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
  124.  
  125.     /* Move the start of the displayed text to right after the first line.
  126.        This effectively skips either "---- footno...", or "File: foo...". */
  127.     while (text_start < fn_node->nodelen)
  128.       if (fn_node->contents[text_start++] == '\n')
  129.     break;
  130.   
  131.     result->nodelen = strlen (header) + fn_node->nodelen - text_start;
  132.  
  133.     /* Set the contents of this node. */
  134.     result->contents = (char *)xmalloc (1 + result->nodelen);
  135.     sprintf (result->contents, "%s", header);
  136.     memcpy (result->contents + strlen (header),
  137.         fn_node->contents + text_start, fn_node->nodelen - text_start);
  138.  
  139.     name_internal_node (result, footnote_nodename);
  140.     free (header);
  141.   }
  142.  
  143. #if defined (NOTDEF)
  144.   /* If the footnotes were gleaned from the node that we were called with,
  145.      shorten the calling node's display length. */
  146.   if (fn_node == node)
  147.     narrow_node (node, 0, fn_start);
  148. #endif /* NOTDEF */
  149.  
  150.   return (result);
  151. }
  152.  
  153. /* Create or delete the footnotes window depending on whether footnotes
  154.    exist in WINDOW's node or not.  Returns FN_FOUND if footnotes were found
  155.    and displayed.  Returns FN_UNFOUND if there were no footnotes found
  156.    in WINDOW's node.  Returns FN_UNABLE if there were footnotes, but the
  157.    window to show them couldn't be made. */
  158. int
  159. info_get_or_remove_footnotes (window)
  160.      WINDOW *window;
  161. {
  162.   WINDOW *fn_win;
  163.   NODE *new_footnotes;
  164.  
  165.   fn_win = find_footnotes_window ();
  166.  
  167.   /* If we are in the footnotes window, change nothing. */
  168.   if (fn_win == window)
  169.     return (FN_FOUND);
  170.  
  171.   /* Try to find footnotes for this window's node. */
  172.   new_footnotes = make_footnotes_node (window->node);
  173.  
  174.   /* If there was a window showing footnotes, and there are no footnotes
  175.      for the current window, delete the old footnote window. */
  176.   if (fn_win && !new_footnotes)
  177.     {
  178.       if (windows->next)
  179.     info_delete_window_internal (fn_win);
  180.     }
  181.  
  182.   /* If there are footnotes for this window's node, but no window around
  183.      showing footnotes, try to make a new window. */
  184.   if (new_footnotes && !fn_win)
  185.     {
  186.       WINDOW *old_active;
  187.       WINDOW *last, *win;
  188.  
  189.       /* Always make this window be the last one appearing in the list.  Find
  190.      the last window in the chain. */
  191.       for (win = windows, last = windows; win; last = win, win = win->next);
  192.  
  193.       /* Try to split this window, and make the split window the one to
  194.      contain the footnotes. */
  195.       old_active = active_window;
  196.       active_window = last;
  197.       fn_win = window_make_window (new_footnotes);
  198.       active_window = old_active;
  199.  
  200.       if (!fn_win)
  201.     {
  202.       free (new_footnotes->contents);
  203.       free (new_footnotes);
  204.  
  205.       /* If we are hacking automatic footnotes, and there are footnotes
  206.          but we couldn't display them, print a message to that effect. */
  207.       if (auto_footnotes_p)
  208.         inform_in_echo_area ("Footnotes could not be displayed");
  209.       return (FN_UNABLE);
  210.     }
  211.     }
  212.  
  213.   /* If there are footnotes, and there is a window to display them,
  214.      make that window be the number of lines appearing in the footnotes. */
  215.   if (new_footnotes && fn_win)
  216.     {
  217.       window_set_node_of_window (fn_win, new_footnotes);
  218.  
  219.       window_change_window_height
  220.     (fn_win, fn_win->line_count - fn_win->height);
  221.  
  222.       remember_window_and_node (fn_win, new_footnotes);
  223.       add_gcable_pointer (new_footnotes->contents);
  224.     }
  225.  
  226.   if (!new_footnotes)
  227.     return (FN_UNFOUND);
  228.   else
  229.     return (FN_FOUND);
  230. }
  231.  
  232. /* Show the footnotes associated with this node in another window. */
  233. DECLARE_INFO_COMMAND (info_show_footnotes,
  234.    "Show the footnotes associated with this node in another window")
  235. {
  236.   int result;
  237.  
  238.   /* A negative argument means just make the window go away. */
  239.   if (count < 0)
  240.     {
  241.       WINDOW *fn_win = find_footnotes_window ();
  242.  
  243.       /* If there is an old footnotes window, and it isn't the only window
  244.      on the screen, delete it. */
  245.       if (fn_win && windows->next)
  246.     info_delete_window_internal (fn_win);
  247.     }
  248.   else
  249.     {
  250.       int result;
  251.  
  252.       result = info_get_or_remove_footnotes (window);
  253.  
  254.       switch (result)
  255.     {
  256.     case FN_UNFOUND:
  257.       info_error (NO_FOOT_NODE);
  258.       break;
  259.  
  260.     case FN_UNABLE:
  261.       info_error (WIN_TOO_SMALL);
  262.       break;
  263.     }
  264.     }
  265. }
  266.