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