1 /* footnotes.c -- Some functions for manipulating footnotes.
2 $Id: footnotes.c,v 1.4 2004/04/11 17:56:45 karl Exp $
4 Copyright (C) 1993, 1997, 1998, 1999, 2002, 2004 Free Software
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 Originally written by Brian Fox (bfox@ai.mit.edu). */
25 /* Nonzero means attempt to show footnotes when displaying a new window. */
26 int auto_footnotes_p
= 0;
28 static char *footnote_nodename
= "*Footnotes*";
30 NODE
* make_footnotes_node (NODE
*node
);
32 #define FOOTNOTE_HEADER_FORMAT \
33 "*** Footnotes appearing in the node `%s' ***\n"
35 /* Find the window currently showing footnotes. */
37 find_footnotes_window (void)
41 /* Try to find an existing window first. */
42 for (win
= windows
; win
; win
= win
->next
)
43 if (internal_info_node_p (win
->node
) &&
44 (strcmp (win
->node
->nodename
, footnote_nodename
) == 0))
50 /* Manufacture a node containing the footnotes of this node, and
51 return the manufactured node. If NODE has no footnotes, return a
54 make_footnotes_node (NODE
*node
)
56 NODE
*fn_node
, *result
= (NODE
*)NULL
;
59 /* Make the initial assumption that the footnotes appear as simple
60 text within this windows node. */
63 /* See if this node contains the magic footnote label. */
65 info_search_in_node (FOOTNOTE_LABEL
, node
, 0, (WINDOW
*)NULL
, 1, 0);
67 /* If it doesn't, check to see if it has an associated footnotes node. */
72 refs
= info_xrefs_of_node (node
);
78 int reflen
= strlen ("-Footnotes") + strlen (node
->nodename
);
80 refname
= (char *)xmalloc (reflen
+ 1);
82 strcpy (refname
, node
->nodename
);
83 strcat (refname
, "-Footnotes");
85 for (i
= 0; refs
[i
]; i
++)
86 if ((refs
[i
]->nodename
!= (char *)NULL
) &&
87 /* Support both the older "foo-Footnotes" and the new
88 style "foo-Footnote-NN" references. */
89 (strcmp (refs
[i
]->nodename
, refname
) == 0 ||
90 (strncmp (refs
[i
]->nodename
, refname
, reflen
- 1) == 0 &&
91 refs
[i
]->nodename
[reflen
- 1] == '-' &&
92 isdigit (refs
[i
]->nodename
[reflen
]))))
96 filename
= node
->parent
;
98 filename
= node
->filename
;
100 fn_node
= info_get_node (filename
, refname
);
109 info_free_references (refs
);
113 /* If we never found the start of a footnotes area, quit now. */
115 return ((NODE
*)NULL
);
117 /* Make the new node. */
118 result
= (NODE
*)xmalloc (sizeof (NODE
));
120 result
->display_pos
= 0;
122 /* Get the size of the footnotes appearing within this node. */
125 long text_start
= fn_start
;
127 header
= (char *)xmalloc
128 (1 + strlen (node
->nodename
) + strlen (FOOTNOTE_HEADER_FORMAT
));
129 sprintf (header
, FOOTNOTE_HEADER_FORMAT
, node
->nodename
);
131 /* Move the start of the displayed text to right after the first line.
132 This effectively skips either "---- footno...", or "File: foo...". */
133 while (text_start
< fn_node
->nodelen
)
134 if (fn_node
->contents
[text_start
++] == '\n')
137 result
->nodelen
= strlen (header
) + fn_node
->nodelen
- text_start
;
139 /* Set the contents of this node. */
140 result
->contents
= (char *)xmalloc (1 + result
->nodelen
);
141 sprintf (result
->contents
, "%s", header
);
142 memcpy (result
->contents
+ strlen (header
),
143 fn_node
->contents
+ text_start
, fn_node
->nodelen
- text_start
);
145 name_internal_node (result
, footnote_nodename
);
150 /* If the footnotes were gleaned from the node that we were called with,
151 shorten the calling node's display length. */
153 narrow_node (node
, 0, fn_start
);
159 /* Create or delete the footnotes window depending on whether footnotes
160 exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
161 and displayed. Returns FN_UNFOUND if there were no footnotes found
162 in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
163 window to show them couldn't be made. */
165 info_get_or_remove_footnotes (WINDOW
*window
)
170 fn_win
= find_footnotes_window ();
172 /* If we are in the footnotes window, change nothing. */
173 if (fn_win
== window
)
176 /* Try to find footnotes for this window's node. */
177 new_footnotes
= make_footnotes_node (window
->node
);
179 /* If there was a window showing footnotes, and there are no footnotes
180 for the current window, delete the old footnote window. */
181 if (fn_win
&& !new_footnotes
)
184 info_delete_window_internal (fn_win
);
187 /* If there are footnotes for this window's node, but no window around
188 showing footnotes, try to make a new window. */
189 if (new_footnotes
&& !fn_win
)
194 /* Always make this window be the last one appearing in the list. Find
195 the last window in the chain. */
196 for (win
= windows
, last
= windows
; win
; last
= win
, win
= win
->next
);
198 /* Try to split this window, and make the split window the one to
199 contain the footnotes. */
200 old_active
= active_window
;
201 active_window
= last
;
202 fn_win
= window_make_window (new_footnotes
);
203 active_window
= old_active
;
207 free (new_footnotes
->contents
);
208 free (new_footnotes
);
210 /* If we are hacking automatic footnotes, and there are footnotes
211 but we couldn't display them, print a message to that effect. */
212 if (auto_footnotes_p
)
213 inform_in_echo_area ((char *) _("Footnotes could not be displayed"));
218 /* If there are footnotes, and there is a window to display them,
219 make that window be the number of lines appearing in the footnotes. */
220 if (new_footnotes
&& fn_win
)
222 window_set_node_of_window (fn_win
, new_footnotes
);
224 window_change_window_height
225 (fn_win
, fn_win
->line_count
- fn_win
->height
);
227 remember_window_and_node (fn_win
, new_footnotes
);
228 add_gcable_pointer (new_footnotes
->contents
);
237 /* Show the footnotes associated with this node in another window. */
238 DECLARE_INFO_COMMAND (info_show_footnotes
,
239 _("Show the footnotes associated with this node in another window"))
241 /* A negative argument means just make the window go away. */
244 WINDOW
*fn_win
= find_footnotes_window ();
246 /* If there is an old footnotes window, and it isn't the only window
247 on the screen, delete it. */
248 if (fn_win
&& windows
->next
)
249 info_delete_window_internal (fn_win
);
255 result
= info_get_or_remove_footnotes (window
);
260 info_error ((char *) msg_no_foot_node
, NULL
, NULL
);
264 info_error ((char *) msg_win_too_small
, NULL
, NULL
);