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