3 /* footnotes.c -- Some functions for manipulating footnotes.
4 Id: footnotes.c,v 1.4 2004/04/11 17:56:45 karl Exp
6 Copyright (C) 1993, 1997, 1998, 1999, 2002, 2004 Free Software
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)
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.
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.
23 Originally written by Brian Fox (bfox@ai.mit.edu). */
27 /* Nonzero means attempt to show footnotes when displaying a new window. */
28 int auto_footnotes_p
= 0;
30 static char *footnote_nodename
= "*Footnotes*";
32 NODE
* make_footnotes_node (NODE
*node
);
34 #define FOOTNOTE_HEADER_FORMAT \
35 "*** Footnotes appearing in the node `%s' ***\n"
37 /* Find the window currently showing footnotes. */
39 find_footnotes_window (void)
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))
52 /* Manufacture a node containing the footnotes of this node, and
53 return the manufactured node. If NODE has no footnotes, return a
56 make_footnotes_node (NODE
*node
)
58 NODE
*fn_node
, *result
= (NODE
*)NULL
;
61 /* Make the initial assumption that the footnotes appear as simple
62 text within this windows node. */
65 /* See if this node contains the magic footnote label. */
67 info_search_in_node (FOOTNOTE_LABEL
, node
, 0, (WINDOW
*)NULL
, 1, 0);
69 /* If it doesn't, check to see if it has an associated footnotes node. */
74 refs
= info_xrefs_of_node (node
);
80 int reflen
= strlen ("-Footnotes") + strlen (node
->nodename
);
82 refname
= (char *)xmalloc (reflen
+ 1);
84 strcpy (refname
, node
->nodename
);
85 strcat (refname
, "-Footnotes");
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
]))))
98 filename
= node
->parent
;
100 filename
= node
->filename
;
102 fn_node
= info_get_node (filename
, refname
);
111 info_free_references (refs
);
115 /* If we never found the start of a footnotes area, quit now. */
117 return ((NODE
*)NULL
);
119 /* Make the new node. */
120 result
= (NODE
*)xmalloc (sizeof (NODE
));
122 result
->display_pos
= 0;
124 /* Get the size of the footnotes appearing within this node. */
127 long text_start
= fn_start
;
129 header
= (char *)xmalloc
130 (1 + strlen (node
->nodename
) + strlen (FOOTNOTE_HEADER_FORMAT
));
131 sprintf (header
, FOOTNOTE_HEADER_FORMAT
, node
->nodename
);
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')
139 result
->nodelen
= strlen (header
) + fn_node
->nodelen
- text_start
;
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
);
147 name_internal_node (result
, footnote_nodename
);
152 /* If the footnotes were gleaned from the node that we were called with,
153 shorten the calling node's display length. */
155 narrow_node (node
, 0, fn_start
);
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. */
167 info_get_or_remove_footnotes (WINDOW
*window
)
172 fn_win
= find_footnotes_window ();
174 /* If we are in the footnotes window, change nothing. */
175 if (fn_win
== window
)
178 /* Try to find footnotes for this window's node. */
179 new_footnotes
= make_footnotes_node (window
->node
);
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
)
186 info_delete_window_internal (fn_win
);
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
)
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
);
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
;
209 free (new_footnotes
->contents
);
210 free (new_footnotes
);
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"));
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
)
224 window_set_node_of_window (fn_win
, new_footnotes
);
226 window_change_window_height
227 (fn_win
, fn_win
->line_count
- fn_win
->height
);
229 remember_window_and_node (fn_win
, new_footnotes
);
230 add_gcable_pointer (new_footnotes
->contents
);
239 /* Show the footnotes associated with this node in another window. */
240 DECLARE_INFO_COMMAND (info_show_footnotes
,
241 _("Show the footnotes associated with this node in another window"))
243 /* A negative argument means just make the window go away. */
246 WINDOW
*fn_win
= find_footnotes_window ();
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
);
257 result
= info_get_or_remove_footnotes (window
);
262 info_error ((char *) msg_no_foot_node
, NULL
, NULL
);
266 info_error ((char *) msg_win_too_small
, NULL
, NULL
);