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