Back to index

tetex-bin  3.0
footnotes.c
Go to the documentation of this file.
00001 /* footnotes.c -- Some functions for manipulating footnotes.
00002    $Id: footnotes.c,v 1.4 2004/04/11 17:56:45 karl Exp $
00003 
00004    Copyright (C) 1993, 1997, 1998, 1999, 2002, 2004 Free Software
00005    Foundation, Inc.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 
00021    Originally written by Brian Fox (bfox@ai.mit.edu). */
00022 
00023 #include "info.h"
00024 
00025 /* Nonzero means attempt to show footnotes when displaying a new window. */
00026 int auto_footnotes_p = 0;
00027 
00028 static char *footnote_nodename = "*Footnotes*";
00029 
00030 NODE * make_footnotes_node (NODE *node);
00031 
00032 #define FOOTNOTE_HEADER_FORMAT \
00033    "*** Footnotes appearing in the node `%s' ***\n"
00034 
00035 /* Find the window currently showing footnotes. */
00036 static WINDOW *
00037 find_footnotes_window (void)
00038 {
00039   WINDOW *win;
00040 
00041   /* Try to find an existing window first. */
00042   for (win = windows; win; win = win->next)
00043     if (internal_info_node_p (win->node) &&
00044         (strcmp (win->node->nodename, footnote_nodename) == 0))
00045       break;
00046 
00047   return (win);
00048 }
00049 
00050 /* Manufacture a node containing the footnotes of this node, and
00051    return the manufactured node.  If NODE has no footnotes, return a 
00052    NULL pointer. */
00053 NODE *
00054 make_footnotes_node (NODE *node)
00055 {
00056   NODE *fn_node, *result = (NODE *)NULL;
00057   long fn_start;
00058 
00059   /* Make the initial assumption that the footnotes appear as simple
00060      text within this windows node. */
00061   fn_node = node;
00062 
00063   /* See if this node contains the magic footnote label. */
00064   fn_start =
00065     info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1, 0);
00066 
00067   /* If it doesn't, check to see if it has an associated footnotes node. */
00068   if (fn_start == -1)
00069     {
00070       REFERENCE **refs;
00071 
00072       refs = info_xrefs_of_node (node);
00073 
00074       if (refs)
00075         {
00076           register int i;
00077           char *refname;
00078           int reflen = strlen ("-Footnotes") + strlen (node->nodename);
00079 
00080           refname = (char *)xmalloc (reflen + 1);
00081 
00082           strcpy (refname, node->nodename);
00083           strcat (refname, "-Footnotes");
00084 
00085           for (i = 0; refs[i]; i++)
00086             if ((refs[i]->nodename != (char *)NULL) &&
00087                 /* Support both the older "foo-Footnotes" and the new
00088                    style "foo-Footnote-NN" references.  */
00089                 (strcmp (refs[i]->nodename, refname) == 0 ||
00090                  (strncmp (refs[i]->nodename, refname, reflen - 1) == 0 &&
00091                   refs[i]->nodename[reflen - 1] == '-' &&
00092                   isdigit (refs[i]->nodename[reflen]))))
00093               {
00094                 char *filename;
00095 
00096                 filename = node->parent;
00097                 if (!filename)
00098                   filename = node->filename;
00099 
00100                 fn_node = info_get_node (filename, refname);
00101 
00102                 if (fn_node)
00103                   fn_start = 0;
00104 
00105                 break;
00106               }
00107 
00108           free (refname);
00109           info_free_references (refs);
00110         }
00111     }
00112 
00113   /* If we never found the start of a footnotes area, quit now. */
00114   if (fn_start == -1)
00115     return ((NODE *)NULL);
00116 
00117   /* Make the new node. */
00118   result = (NODE *)xmalloc (sizeof (NODE));
00119   result->flags = 0;
00120   result->display_pos = 0;
00121 
00122   /* Get the size of the footnotes appearing within this node. */
00123   {
00124     char *header;
00125     long text_start = fn_start;
00126 
00127     header = (char *)xmalloc
00128       (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
00129     sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
00130 
00131     /* Move the start of the displayed text to right after the first line.
00132        This effectively skips either "---- footno...", or "File: foo...". */
00133     while (text_start < fn_node->nodelen)
00134       if (fn_node->contents[text_start++] == '\n')
00135         break;
00136   
00137     result->nodelen = strlen (header) + fn_node->nodelen - text_start;
00138 
00139     /* Set the contents of this node. */
00140     result->contents = (char *)xmalloc (1 + result->nodelen);
00141     sprintf (result->contents, "%s", header);
00142     memcpy (result->contents + strlen (header),
00143             fn_node->contents + text_start, fn_node->nodelen - text_start);
00144 
00145     name_internal_node (result, footnote_nodename);
00146     free (header);
00147   }
00148 
00149 #if defined (NOTDEF)
00150   /* If the footnotes were gleaned from the node that we were called with,
00151      shorten the calling node's display length. */
00152   if (fn_node == node)
00153     narrow_node (node, 0, fn_start);
00154 #endif /* NOTDEF */
00155 
00156   return (result);
00157 }
00158 
00159 /* Create or delete the footnotes window depending on whether footnotes
00160    exist in WINDOW's node or not.  Returns FN_FOUND if footnotes were found
00161    and displayed.  Returns FN_UNFOUND if there were no footnotes found
00162    in WINDOW's node.  Returns FN_UNABLE if there were footnotes, but the
00163    window to show them couldn't be made. */
00164 int
00165 info_get_or_remove_footnotes (WINDOW *window)
00166 {
00167   WINDOW *fn_win;
00168   NODE *new_footnotes;
00169 
00170   fn_win = find_footnotes_window ();
00171 
00172   /* If we are in the footnotes window, change nothing. */
00173   if (fn_win == window)
00174     return (FN_FOUND);
00175 
00176   /* Try to find footnotes for this window's node. */
00177   new_footnotes = make_footnotes_node (window->node);
00178 
00179   /* If there was a window showing footnotes, and there are no footnotes
00180      for the current window, delete the old footnote window. */
00181   if (fn_win && !new_footnotes)
00182     {
00183       if (windows->next)
00184         info_delete_window_internal (fn_win);
00185     }
00186 
00187   /* If there are footnotes for this window's node, but no window around
00188      showing footnotes, try to make a new window. */
00189   if (new_footnotes && !fn_win)
00190     {
00191       WINDOW *old_active;
00192       WINDOW *last, *win;
00193 
00194       /* Always make this window be the last one appearing in the list.  Find
00195          the last window in the chain. */
00196       for (win = windows, last = windows; win; last = win, win = win->next);
00197 
00198       /* Try to split this window, and make the split window the one to
00199          contain the footnotes. */
00200       old_active = active_window;
00201       active_window = last;
00202       fn_win = window_make_window (new_footnotes);
00203       active_window = old_active;
00204 
00205       if (!fn_win)
00206         {
00207           free (new_footnotes->contents);
00208           free (new_footnotes);
00209 
00210           /* If we are hacking automatic footnotes, and there are footnotes
00211              but we couldn't display them, print a message to that effect. */
00212           if (auto_footnotes_p)
00213             inform_in_echo_area ((char *) _("Footnotes could not be displayed"));
00214           return (FN_UNABLE);
00215         }
00216     }
00217 
00218   /* If there are footnotes, and there is a window to display them,
00219      make that window be the number of lines appearing in the footnotes. */
00220   if (new_footnotes && fn_win)
00221     {
00222       window_set_node_of_window (fn_win, new_footnotes);
00223 
00224       window_change_window_height
00225         (fn_win, fn_win->line_count - fn_win->height);
00226 
00227       remember_window_and_node (fn_win, new_footnotes);
00228       add_gcable_pointer (new_footnotes->contents);
00229     }
00230 
00231   if (!new_footnotes)
00232     return (FN_UNFOUND);
00233   else
00234     return (FN_FOUND);
00235 }
00236 
00237 /* Show the footnotes associated with this node in another window. */
00238 DECLARE_INFO_COMMAND (info_show_footnotes,
00239    _("Show the footnotes associated with this node in another window"))
00240 {
00241   /* A negative argument means just make the window go away. */
00242   if (count < 0)
00243     {
00244       WINDOW *fn_win = find_footnotes_window ();
00245 
00246       /* If there is an old footnotes window, and it isn't the only window
00247          on the screen, delete it. */
00248       if (fn_win && windows->next)
00249         info_delete_window_internal (fn_win);
00250     }
00251   else
00252     {
00253       int result;
00254 
00255       result = info_get_or_remove_footnotes (window);
00256 
00257       switch (result)
00258         {
00259         case FN_UNFOUND:
00260           info_error ((char *) msg_no_foot_node, NULL, NULL);
00261           break;
00262 
00263         case FN_UNABLE:
00264           info_error ((char *) msg_win_too_small, NULL, NULL);
00265           break;
00266         }
00267     }
00268 }