No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / texinfo / makeinfo / footnote.c
blob35ffcd59683862a0332c7552972c915a909eda3a
1 /* $NetBSD$ */
3 /* footnote.c -- footnotes for Texinfo.
4 Id: footnote.c,v 1.7 2004/04/11 17:56:47 karl Exp
6 Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
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.
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.
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 Foundation,
20 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 #include "system.h"
23 #include "footnote.h"
24 #include "macro.h"
25 #include "makeinfo.h"
26 #include "node.h"
27 #include "xml.h"
28 #include "xref.h"
30 /* Nonzero means that the footnote style for this document was set on
31 the command line, which overrides any other settings. */
32 int footnote_style_preset = 0;
34 /* The current footnote number in this node. Each time a new node is
35 started this is reset to 1. */
36 int current_footnote_number = 1;
38 /* Nonzero means we automatically number footnotes with no specified marker. */
39 int number_footnotes = 1;
41 /* Nonzero means we are currently outputting footnotes. */
42 int already_outputting_pending_notes = 0;
45 /* Footnotes can be handled in one of two ways:
47 separate_node:
48 Make them look like followed references, with the reference
49 destinations in a makeinfo manufactured node or,
50 end_node:
51 Make them appear at the bottom of the node that they originally
52 appeared in. */
54 #define separate_node 0
55 #define end_node 1
57 int footnote_style = end_node;
58 int first_footnote_this_node = 1;
59 int footnote_count = 0;
61 /* Set the footnote style based on the style identifier in STRING. */
62 int
63 set_footnote_style (char *string)
65 if (strcasecmp (string, "separate") == 0)
66 footnote_style = separate_node;
67 else if (strcasecmp (string, "end") == 0)
68 footnote_style = end_node;
69 else
70 return -1;
72 return 0;
75 void
76 cm_footnotestyle (void)
78 char *arg;
80 get_rest_of_line (1, &arg);
82 /* If set on command line, do not change the footnote style. */
83 if (!footnote_style_preset && set_footnote_style (arg) != 0)
84 line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
86 free (arg);
89 typedef struct fn
91 struct fn *next;
92 char *marker;
93 char *note;
94 int number;
95 } FN;
97 FN *pending_notes = NULL;
99 /* A method for remembering footnotes. Note that this list gets output
100 at the end of the current node. */
101 static void
102 remember_note (char *marker, char *note)
104 FN *temp = xmalloc (sizeof (FN));
106 temp->marker = xstrdup (marker);
107 temp->note = xstrdup (note);
108 temp->next = pending_notes;
109 temp->number = current_footnote_number;
110 pending_notes = temp;
111 footnote_count++;
114 /* How to get rid of existing footnotes. */
115 static void
116 free_pending_notes (void)
118 FN *temp;
120 while ((temp = pending_notes))
122 free (temp->marker);
123 free (temp->note);
124 pending_notes = pending_notes->next;
125 free (temp);
127 first_footnote_this_node = 1;
128 footnote_count = 0;
129 current_footnote_number = 1; /* for html */
132 /* What to do when you see a @footnote construct. */
134 /* Handle a "footnote".
135 footnote *{this is a footnote}
136 where "*" is the (optional) marker character for this note. */
137 void
138 cm_footnote (void)
140 char *marker;
141 char *note;
143 get_until ("{", &marker);
144 canon_white (marker);
146 if (macro_expansion_output_stream && !executing_string)
147 append_to_expansion_output (input_text_offset + 1); /* include the { */
149 /* Read the argument in braces. */
150 if (curchar () != '{')
152 line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
153 COMMAND_PREFIX, command, marker);
154 free (marker);
155 return;
157 else
159 int len;
160 int braces = 1;
161 int loc = ++input_text_offset;
163 while (braces)
165 if (loc == input_text_length)
167 line_error (_("No closing brace for footnote `%s'"), marker);
168 return;
171 if (input_text[loc] == '{')
172 braces++;
173 else if (input_text[loc] == '}')
174 braces--;
175 else if (input_text[loc] == '\n')
176 line_number++;
178 loc++;
181 len = (loc - input_text_offset) - 1;
182 note = xmalloc (len + 1);
183 memcpy (note, &input_text[input_text_offset], len);
184 note[len] = 0;
185 input_text_offset = loc;
188 /* Must write the macro-expanded argument to the macro expansion
189 output stream. This is like the case in index_add_arg. */
190 if (macro_expansion_output_stream && !executing_string)
192 /* Calling me_execute_string on a lone } provokes an error, since
193 as far as the reader knows there is no matching {. We wrote
194 the { above in the call to append_to_expansion_output. */
195 me_execute_string_keep_state (note, "}");
198 if (!current_node || !*current_node)
200 line_error (_("Footnote defined without parent node"));
201 free (marker);
202 free (note);
203 return;
206 /* output_pending_notes is non-reentrant (it uses a global data
207 structure pending_notes, which it frees before it returns), and
208 TeX doesn't grok footnotes inside footnotes anyway. Disallow
209 that. */
210 if (already_outputting_pending_notes)
212 line_error (_("Footnotes inside footnotes are not allowed"));
213 free (marker);
214 free (note);
215 return;
218 if (!*marker)
220 free (marker);
222 if (number_footnotes)
224 marker = xmalloc (10);
225 sprintf (marker, "%d", current_footnote_number);
227 else
228 marker = xstrdup ("*");
231 if (xml)
232 xml_insert_footnote (note);
233 else
235 remember_note (marker, note);
237 /* fixme: html: footnote processing needs work; we currently ignore
238 the style requested; we could clash with a node name of the form
239 `fn-<n>', though that's unlikely. */
240 if (html)
242 /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
243 definition.) */
244 add_html_elt ("<a rel=\"footnote\" href=");
245 add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
246 current_footnote_number, current_footnote_number,
247 marker);
249 else
250 /* Your method should at least insert MARKER. */
251 switch (footnote_style)
253 case separate_node:
254 add_word_args ("(%s)", marker);
255 execute_string (" (*note %s-Footnote-%d::)",
256 current_node, current_footnote_number);
257 if (first_footnote_this_node)
259 char *temp_string, *expanded_ref;
261 temp_string = xmalloc (strlen (current_node)
262 + strlen ("-Footnotes") + 1);
264 strcpy (temp_string, current_node);
265 strcat (temp_string, "-Footnotes");
266 expanded_ref = expansion (temp_string, 0);
267 remember_node_reference (expanded_ref, line_number,
268 followed_reference);
269 free (temp_string);
270 free (expanded_ref);
271 first_footnote_this_node = 0;
273 break;
275 case end_node:
276 add_word_args ("(%s)", marker);
277 break;
279 default:
280 break;
282 current_footnote_number++;
284 free (marker);
285 free (note);
288 /* Output the footnotes. We are at the end of the current node. */
289 void
290 output_pending_notes (void)
292 FN *footnote = pending_notes;
294 if (!pending_notes)
295 return;
297 if (html)
299 add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
300 /* We add an anchor here so @printindex can refer to this point
301 (as the node name) for entries defined in footnotes. */
302 if (!splitting)
303 add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
304 add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
306 else
307 switch (footnote_style)
309 case separate_node:
311 char *old_current_node = current_node;
312 char *old_command = xstrdup (command);
314 already_outputting_pending_notes++;
315 execute_string ("%cnode %s-Footnotes,,,%s\n",
316 COMMAND_PREFIX, current_node, current_node);
317 already_outputting_pending_notes--;
318 current_node = old_current_node;
319 free (command);
320 command = old_command;
322 break;
324 case end_node:
325 close_paragraph ();
326 in_fixed_width_font++;
327 /* This string should be translated according to the
328 @documentlanguage, not the current LANG. We can't do that
329 yet, so leave it in English. */
330 execute_string ("---------- Footnotes ----------\n\n");
331 in_fixed_width_font--;
332 break;
335 /* Handle the footnotes in reverse order. */
337 int save_in_fixed_width_font = in_fixed_width_font;
338 FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
339 array[footnote_count] = NULL;
341 while (--footnote_count > -1)
343 array[footnote_count] = footnote;
344 footnote = footnote->next;
347 filling_enabled = 1;
348 indented_fill = 1;
349 in_fixed_width_font = 0;
351 while ((footnote = array[++footnote_count]))
353 if (html)
355 /* Make the text of every footnote begin a separate paragraph. */
356 add_html_block_elt ("<p class=\"footnote\"><small>");
357 /* Make footnote number a link to its definition. */
358 add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
359 footnote->number, footnote->number, footnote->number);
360 add_word ("</small> ");
361 already_outputting_pending_notes++;
362 execute_string ("%s", footnote->note);
363 already_outputting_pending_notes--;
364 add_word ("</p>\n");
366 else
368 char *old_current_node = current_node;
369 char *old_command = xstrdup (command);
371 already_outputting_pending_notes++;
372 execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
373 COMMAND_PREFIX, current_node, footnote->number,
374 footnote->marker, footnote->note);
375 already_outputting_pending_notes--;
376 current_node = old_current_node;
377 free (command);
378 command = old_command;
381 close_paragraph ();
384 if (html)
385 add_word ("<hr></div>");
386 close_paragraph ();
387 free (array);
389 in_fixed_width_font = save_in_fixed_width_font;
392 free_pending_notes ();