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@ai.mit.edu). */
24
25#include "info.h"
26
27/* Nonzero means attempt to show footnotes when displaying a new window. */
28int auto_footnotes_p = 0;
29
30static char *footnote_nodename = "*Footnotes*";
31
32NODE * 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. */
38static WINDOW *
39find_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. */
55NODE *
56make_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. */
166int
167info_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. */
240DECLARE_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