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