1 /* footnote.c -- footnotes for Texinfo.
2 $Id: footnote.c,v 1.7 2004/04/11 17:56:47 karl Exp $
4 Copyright (C) 1998, 1999, 2002 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 2, or (at your option)
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, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
28 /* Nonzero means that the footnote style for this document was set on
29 the command line, which overrides any other settings. */
30 int footnote_style_preset
= 0;
32 /* The current footnote number in this node. Each time a new node is
33 started this is reset to 1. */
34 int current_footnote_number
= 1;
36 /* Nonzero means we automatically number footnotes with no specified marker. */
37 int number_footnotes
= 1;
39 /* Nonzero means we are currently outputting footnotes. */
40 int already_outputting_pending_notes
= 0;
43 /* Footnotes can be handled in one of two ways:
46 Make them look like followed references, with the reference
47 destinations in a makeinfo manufactured node or,
49 Make them appear at the bottom of the node that they originally
52 #define separate_node 0
55 int footnote_style
= end_node
;
56 int first_footnote_this_node
= 1;
57 int footnote_count
= 0;
59 /* Set the footnote style based on the style identifier in STRING. */
61 set_footnote_style (char *string
)
63 if (strcasecmp (string
, "separate") == 0)
64 footnote_style
= separate_node
;
65 else if (strcasecmp (string
, "end") == 0)
66 footnote_style
= end_node
;
74 cm_footnotestyle (void)
78 get_rest_of_line (1, &arg
);
80 /* If set on command line, do not change the footnote style. */
81 if (!footnote_style_preset
&& set_footnote_style (arg
) != 0)
82 line_error (_("Bad argument to %c%s"), COMMAND_PREFIX
, command
);
95 FN
*pending_notes
= NULL
;
97 /* A method for remembering footnotes. Note that this list gets output
98 at the end of the current node. */
100 remember_note (char *marker
, char *note
)
102 FN
*temp
= xmalloc (sizeof (FN
));
104 temp
->marker
= xstrdup (marker
);
105 temp
->note
= xstrdup (note
);
106 temp
->next
= pending_notes
;
107 temp
->number
= current_footnote_number
;
108 pending_notes
= temp
;
112 /* How to get rid of existing footnotes. */
114 free_pending_notes (void)
118 while ((temp
= pending_notes
))
122 pending_notes
= pending_notes
->next
;
125 first_footnote_this_node
= 1;
127 current_footnote_number
= 1; /* for html */
130 /* What to do when you see a @footnote construct. */
132 /* Handle a "footnote".
133 footnote *{this is a footnote}
134 where "*" is the (optional) marker character for this note. */
141 get_until ("{", &marker
);
142 canon_white (marker
);
144 if (macro_expansion_output_stream
&& !executing_string
)
145 append_to_expansion_output (input_text_offset
+ 1); /* include the { */
147 /* Read the argument in braces. */
148 if (curchar () != '{')
150 line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
151 COMMAND_PREFIX
, command
, marker
);
159 int loc
= ++input_text_offset
;
163 if (loc
== input_text_length
)
165 line_error (_("No closing brace for footnote `%s'"), marker
);
169 if (input_text
[loc
] == '{')
171 else if (input_text
[loc
] == '}')
173 else if (input_text
[loc
] == '\n')
179 len
= (loc
- input_text_offset
) - 1;
180 note
= xmalloc (len
+ 1);
181 memcpy (note
, &input_text
[input_text_offset
], len
);
183 input_text_offset
= loc
;
186 /* Must write the macro-expanded argument to the macro expansion
187 output stream. This is like the case in index_add_arg. */
188 if (macro_expansion_output_stream
&& !executing_string
)
190 /* Calling me_execute_string on a lone } provokes an error, since
191 as far as the reader knows there is no matching {. We wrote
192 the { above in the call to append_to_expansion_output. */
193 me_execute_string_keep_state (note
, "}");
196 if (!current_node
|| !*current_node
)
198 line_error (_("Footnote defined without parent node"));
204 /* output_pending_notes is non-reentrant (it uses a global data
205 structure pending_notes, which it frees before it returns), and
206 TeX doesn't grok footnotes inside footnotes anyway. Disallow
208 if (already_outputting_pending_notes
)
210 line_error (_("Footnotes inside footnotes are not allowed"));
220 if (number_footnotes
)
222 marker
= xmalloc (10);
223 sprintf (marker
, "%d", current_footnote_number
);
226 marker
= xstrdup ("*");
230 xml_insert_footnote (note
);
233 remember_note (marker
, note
);
235 /* fixme: html: footnote processing needs work; we currently ignore
236 the style requested; we could clash with a node name of the form
237 `fn-<n>', though that's unlikely. */
240 /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
242 add_html_elt ("<a rel=\"footnote\" href=");
243 add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
244 current_footnote_number
, current_footnote_number
,
248 /* Your method should at least insert MARKER. */
249 switch (footnote_style
)
252 add_word_args ("(%s)", marker
);
253 execute_string (" (*note %s-Footnote-%d::)",
254 current_node
, current_footnote_number
);
255 if (first_footnote_this_node
)
257 char *temp_string
, *expanded_ref
;
259 temp_string
= xmalloc (strlen (current_node
)
260 + strlen ("-Footnotes") + 1);
262 strcpy (temp_string
, current_node
);
263 strcat (temp_string
, "-Footnotes");
264 expanded_ref
= expansion (temp_string
, 0);
265 remember_node_reference (expanded_ref
, line_number
,
269 first_footnote_this_node
= 0;
274 add_word_args ("(%s)", marker
);
280 current_footnote_number
++;
286 /* Output the footnotes. We are at the end of the current node. */
288 output_pending_notes (void)
290 FN
*footnote
= pending_notes
;
297 add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
298 /* We add an anchor here so @printindex can refer to this point
299 (as the node name) for entries defined in footnotes. */
301 add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
302 add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
305 switch (footnote_style
)
309 char *old_current_node
= current_node
;
310 char *old_command
= xstrdup (command
);
312 already_outputting_pending_notes
++;
313 execute_string ("%cnode %s-Footnotes,,,%s\n",
314 COMMAND_PREFIX
, current_node
, current_node
);
315 already_outputting_pending_notes
--;
316 current_node
= old_current_node
;
318 command
= old_command
;
324 in_fixed_width_font
++;
325 /* This string should be translated according to the
326 @documentlanguage, not the current LANG. We can't do that
327 yet, so leave it in English. */
328 execute_string ("---------- Footnotes ----------\n\n");
329 in_fixed_width_font
--;
333 /* Handle the footnotes in reverse order. */
335 int save_in_fixed_width_font
= in_fixed_width_font
;
336 FN
**array
= xmalloc ((footnote_count
+ 1) * sizeof (FN
*));
337 array
[footnote_count
] = NULL
;
339 while (--footnote_count
> -1)
341 array
[footnote_count
] = footnote
;
342 footnote
= footnote
->next
;
347 in_fixed_width_font
= 0;
349 while ((footnote
= array
[++footnote_count
]))
353 /* Make the text of every footnote begin a separate paragraph. */
354 add_html_block_elt ("<p class=\"footnote\"><small>");
355 /* Make footnote number a link to its definition. */
356 add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
357 footnote
->number
, footnote
->number
, footnote
->number
);
358 add_word ("</small> ");
359 already_outputting_pending_notes
++;
360 execute_string ("%s", footnote
->note
);
361 already_outputting_pending_notes
--;
366 char *old_current_node
= current_node
;
367 char *old_command
= xstrdup (command
);
369 already_outputting_pending_notes
++;
370 execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
371 COMMAND_PREFIX
, current_node
, footnote
->number
,
372 footnote
->marker
, footnote
->note
);
373 already_outputting_pending_notes
--;
374 current_node
= old_current_node
;
376 command
= old_command
;
383 add_word ("<hr></div>");
387 in_fixed_width_font
= save_in_fixed_width_font
;
390 free_pending_notes ();