1 /* footnote.c -- footnotes for Texinfo.
2 $Id: footnote.c,v 1.12 2007/12/03 01:38:43 karl Exp $
4 Copyright (C) 1998, 1999, 2002, 2007 Free Software Foundation, Inc.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 /* Nonzero means that the footnote style for this document was set on
28 the command line, which overrides any other settings. */
29 int footnote_style_preset = 0;
31 /* The current footnote number in this node. Each time a new node is
32 started this is reset to 1. */
33 int current_footnote_number = 1;
35 /* Nonzero means we automatically number footnotes with no specified marker. */
36 int number_footnotes = 1;
38 /* Nonzero means we are currently outputting footnotes. */
39 int already_outputting_pending_notes = 0;
42 /* Footnotes can be handled in one of two ways:
45 Make them look like followed references, with the reference
46 destinations in a makeinfo manufactured node or,
48 Make them appear at the bottom of the node that they originally
51 #define separate_node 0
54 int footnote_style = end_node;
55 int first_footnote_this_node = 1;
56 int footnote_count = 0;
58 /* Set the footnote style based on the style identifier in STRING. */
60 set_footnote_style (char *string)
62 if (mbscasecmp (string, "separate") == 0)
63 footnote_style = separate_node;
64 else if (mbscasecmp (string, "end") == 0)
65 footnote_style = end_node;
73 cm_footnotestyle (void)
77 get_rest_of_line (1, &arg);
79 /* If set on command line, do not change the footnote style. */
80 if (!footnote_style_preset && set_footnote_style (arg) != 0)
81 line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
94 FN *pending_notes = NULL;
96 /* A method for remembering footnotes. Note that this list gets output
97 at the end of the current node. */
99 remember_note (char *marker, char *note)
101 FN *temp = xmalloc (sizeof (FN));
103 temp->marker = xstrdup (marker);
104 temp->note = xstrdup (note);
105 temp->next = pending_notes;
106 temp->number = current_footnote_number;
107 pending_notes = temp;
111 /* How to get rid of existing footnotes. */
113 free_pending_notes (void)
117 while ((temp = pending_notes))
121 pending_notes = pending_notes->next;
124 first_footnote_this_node = 1;
126 current_footnote_number = 1; /* for html */
129 /* What to do when you see a @footnote construct. */
131 /* Handle a "footnote".
132 footnote *{this is a footnote}
133 where "*" is the (optional) marker character for this note. */
140 get_until ("{", &marker);
141 canon_white (marker);
143 if (macro_expansion_output_stream && !executing_string)
144 append_to_expansion_output (input_text_offset + 1); /* include the { */
146 /* Read the argument in braces. */
147 if (curchar () != '{')
149 line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
150 COMMAND_PREFIX, command, marker);
158 int loc = ++input_text_offset;
162 if (loc == input_text_length)
164 line_error (_("No closing brace for footnote `%s'"), marker);
168 if (input_text[loc] == '{')
170 else if (input_text[loc] == '}')
172 else if (input_text[loc] == '\n')
178 len = (loc - input_text_offset) - 1;
179 note = xmalloc (len + 1);
180 memcpy (note, &input_text[input_text_offset], len);
182 input_text_offset = loc;
185 /* Must write the macro-expanded argument to the macro expansion
186 output stream. This is like the case in index_add_arg. */
187 if (macro_expansion_output_stream && !executing_string)
189 /* Calling me_execute_string on a lone } provokes an error, since
190 as far as the reader knows there is no matching {. We wrote
191 the { above in the call to append_to_expansion_output. */
192 me_execute_string_keep_state (note, "}");
195 if (!current_node || !*current_node)
197 line_error (_("Footnote defined without parent node"));
203 /* output_pending_notes is non-reentrant (it uses a global data
204 structure pending_notes, which it frees before it returns), and
205 TeX doesn't grok footnotes inside footnotes anyway. Disallow
207 if (already_outputting_pending_notes)
209 line_error (_("Footnotes inside footnotes are not allowed"));
219 if (number_footnotes)
221 marker = xmalloc (10);
222 sprintf (marker, "%d", current_footnote_number);
225 marker = xstrdup ("*");
229 xml_insert_footnote (note);
232 remember_note (marker, note);
234 /* fixme: html: footnote processing needs work; we currently ignore
235 the style requested; we could clash with a node name of the form
236 `fn-<n>', though that's unlikely. */
239 /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
241 add_html_elt ("<a rel=\"footnote\" href=");
242 add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
243 current_footnote_number, current_footnote_number,
247 /* Your method should at least insert MARKER. */
248 switch (footnote_style)
251 add_word_args ("(%s)", marker);
252 execute_string (" (*note %s-Footnote-%d::)",
253 current_node, current_footnote_number);
254 if (first_footnote_this_node)
256 char *temp_string, *expanded_ref;
258 temp_string = xmalloc (strlen (current_node)
259 + strlen ("-Footnotes") + 1);
261 strcpy (temp_string, current_node);
262 strcat (temp_string, "-Footnotes");
263 expanded_ref = expansion (temp_string, 0);
264 remember_node_reference (expanded_ref, line_number,
268 first_footnote_this_node = 0;
273 add_word_args ("(%s)", marker);
279 current_footnote_number++;
285 /* Output the footnotes. We are at the end of the current node. */
287 output_pending_notes (void)
289 FN *footnote = pending_notes;
296 add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
297 /* We add an anchor here so @printindex can refer to this point
298 (as the node name) for entries defined in footnotes. */
300 add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
301 add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
304 switch (footnote_style)
308 char *old_current_node = current_node;
309 char *old_command = xstrdup (command);
311 already_outputting_pending_notes++;
312 execute_string ("%cnode %s-Footnotes,,,%s\n",
313 COMMAND_PREFIX, current_node, current_node);
314 already_outputting_pending_notes--;
315 current_node = old_current_node;
317 command = old_command;
323 in_fixed_width_font++;
324 /* This string should be translated according to the
325 @documentlanguage, not the current LANG. We can't do that
326 yet, so leave it in English. */
327 execute_string ("---------- Footnotes ----------\n\n");
328 in_fixed_width_font--;
332 /* Handle the footnotes in reverse order. */
334 int save_in_fixed_width_font = in_fixed_width_font;
335 FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
336 array[footnote_count] = NULL;
338 while (--footnote_count > -1)
340 array[footnote_count] = footnote;
341 footnote = footnote->next;
346 in_fixed_width_font = 0;
348 while ((footnote = array[++footnote_count]))
352 /* Make the text of every footnote begin a separate paragraph. */
353 add_html_block_elt ("<p class=\"footnote\"><small>");
354 /* Make footnote number a link to its definition. */
355 add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
356 footnote->number, footnote->number, footnote->number);
357 add_word ("</small> ");
358 already_outputting_pending_notes++;
359 execute_string ("%s", footnote->note);
360 already_outputting_pending_notes--;
365 char *old_current_node = current_node;
366 char *old_command = xstrdup (command);
368 already_outputting_pending_notes++;
369 execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
370 COMMAND_PREFIX, current_node, footnote->number,
371 footnote->marker, footnote->note);
372 already_outputting_pending_notes--;
373 current_node = old_current_node;
375 command = old_command;
382 add_html_block_elt ("<hr></div>");
386 in_fixed_width_font = save_in_fixed_width_font;
389 free_pending_notes ();