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