1*dc174305Schristos /* $NetBSD: footnote.c,v 1.1.1.1 2016/01/14 00:11:29 christos Exp $ */
2*dc174305Schristos
3*dc174305Schristos /* footnote.c -- footnotes for Texinfo.
4*dc174305Schristos Id: footnote.c,v 1.7 2004/04/11 17:56:47 karl Exp
5*dc174305Schristos
6*dc174305Schristos Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
7*dc174305Schristos
8*dc174305Schristos This program is free software; you can redistribute it and/or modify
9*dc174305Schristos it under the terms of the GNU General Public License as published by
10*dc174305Schristos the Free Software Foundation; either version 2, or (at your option)
11*dc174305Schristos any later version.
12*dc174305Schristos
13*dc174305Schristos This program is distributed in the hope that it will be useful,
14*dc174305Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
15*dc174305Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*dc174305Schristos GNU General Public License for more details.
17*dc174305Schristos
18*dc174305Schristos You should have received a copy of the GNU General Public License
19*dc174305Schristos along with this program; if not, write to the Free Software Foundation,
20*dc174305Schristos Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21*dc174305Schristos
22*dc174305Schristos #include "system.h"
23*dc174305Schristos #include "footnote.h"
24*dc174305Schristos #include "macro.h"
25*dc174305Schristos #include "makeinfo.h"
26*dc174305Schristos #include "node.h"
27*dc174305Schristos #include "xml.h"
28*dc174305Schristos #include "xref.h"
29*dc174305Schristos
30*dc174305Schristos /* Nonzero means that the footnote style for this document was set on
31*dc174305Schristos the command line, which overrides any other settings. */
32*dc174305Schristos int footnote_style_preset = 0;
33*dc174305Schristos
34*dc174305Schristos /* The current footnote number in this node. Each time a new node is
35*dc174305Schristos started this is reset to 1. */
36*dc174305Schristos int current_footnote_number = 1;
37*dc174305Schristos
38*dc174305Schristos /* Nonzero means we automatically number footnotes with no specified marker. */
39*dc174305Schristos int number_footnotes = 1;
40*dc174305Schristos
41*dc174305Schristos /* Nonzero means we are currently outputting footnotes. */
42*dc174305Schristos int already_outputting_pending_notes = 0;
43*dc174305Schristos
44*dc174305Schristos
45*dc174305Schristos /* Footnotes can be handled in one of two ways:
46*dc174305Schristos
47*dc174305Schristos separate_node:
48*dc174305Schristos Make them look like followed references, with the reference
49*dc174305Schristos destinations in a makeinfo manufactured node or,
50*dc174305Schristos end_node:
51*dc174305Schristos Make them appear at the bottom of the node that they originally
52*dc174305Schristos appeared in. */
53*dc174305Schristos
54*dc174305Schristos #define separate_node 0
55*dc174305Schristos #define end_node 1
56*dc174305Schristos
57*dc174305Schristos int footnote_style = end_node;
58*dc174305Schristos int first_footnote_this_node = 1;
59*dc174305Schristos int footnote_count = 0;
60*dc174305Schristos
61*dc174305Schristos /* Set the footnote style based on the style identifier in STRING. */
62*dc174305Schristos int
set_footnote_style(char * string)63*dc174305Schristos set_footnote_style (char *string)
64*dc174305Schristos {
65*dc174305Schristos if (strcasecmp (string, "separate") == 0)
66*dc174305Schristos footnote_style = separate_node;
67*dc174305Schristos else if (strcasecmp (string, "end") == 0)
68*dc174305Schristos footnote_style = end_node;
69*dc174305Schristos else
70*dc174305Schristos return -1;
71*dc174305Schristos
72*dc174305Schristos return 0;
73*dc174305Schristos }
74*dc174305Schristos
75*dc174305Schristos void
cm_footnotestyle(void)76*dc174305Schristos cm_footnotestyle (void)
77*dc174305Schristos {
78*dc174305Schristos char *arg;
79*dc174305Schristos
80*dc174305Schristos get_rest_of_line (1, &arg);
81*dc174305Schristos
82*dc174305Schristos /* If set on command line, do not change the footnote style. */
83*dc174305Schristos if (!footnote_style_preset && set_footnote_style (arg) != 0)
84*dc174305Schristos line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
85*dc174305Schristos
86*dc174305Schristos free (arg);
87*dc174305Schristos }
88*dc174305Schristos
89*dc174305Schristos typedef struct fn
90*dc174305Schristos {
91*dc174305Schristos struct fn *next;
92*dc174305Schristos char *marker;
93*dc174305Schristos char *note;
94*dc174305Schristos int number;
95*dc174305Schristos } FN;
96*dc174305Schristos
97*dc174305Schristos FN *pending_notes = NULL;
98*dc174305Schristos
99*dc174305Schristos /* A method for remembering footnotes. Note that this list gets output
100*dc174305Schristos at the end of the current node. */
101*dc174305Schristos static void
remember_note(char * marker,char * note)102*dc174305Schristos remember_note (char *marker, char *note)
103*dc174305Schristos {
104*dc174305Schristos FN *temp = xmalloc (sizeof (FN));
105*dc174305Schristos
106*dc174305Schristos temp->marker = xstrdup (marker);
107*dc174305Schristos temp->note = xstrdup (note);
108*dc174305Schristos temp->next = pending_notes;
109*dc174305Schristos temp->number = current_footnote_number;
110*dc174305Schristos pending_notes = temp;
111*dc174305Schristos footnote_count++;
112*dc174305Schristos }
113*dc174305Schristos
114*dc174305Schristos /* How to get rid of existing footnotes. */
115*dc174305Schristos static void
free_pending_notes(void)116*dc174305Schristos free_pending_notes (void)
117*dc174305Schristos {
118*dc174305Schristos FN *temp;
119*dc174305Schristos
120*dc174305Schristos while ((temp = pending_notes))
121*dc174305Schristos {
122*dc174305Schristos free (temp->marker);
123*dc174305Schristos free (temp->note);
124*dc174305Schristos pending_notes = pending_notes->next;
125*dc174305Schristos free (temp);
126*dc174305Schristos }
127*dc174305Schristos first_footnote_this_node = 1;
128*dc174305Schristos footnote_count = 0;
129*dc174305Schristos current_footnote_number = 1; /* for html */
130*dc174305Schristos }
131*dc174305Schristos
132*dc174305Schristos /* What to do when you see a @footnote construct. */
133*dc174305Schristos
134*dc174305Schristos /* Handle a "footnote".
135*dc174305Schristos footnote *{this is a footnote}
136*dc174305Schristos where "*" is the (optional) marker character for this note. */
137*dc174305Schristos void
cm_footnote(void)138*dc174305Schristos cm_footnote (void)
139*dc174305Schristos {
140*dc174305Schristos char *marker;
141*dc174305Schristos char *note;
142*dc174305Schristos
143*dc174305Schristos get_until ("{", &marker);
144*dc174305Schristos canon_white (marker);
145*dc174305Schristos
146*dc174305Schristos if (macro_expansion_output_stream && !executing_string)
147*dc174305Schristos append_to_expansion_output (input_text_offset + 1); /* include the { */
148*dc174305Schristos
149*dc174305Schristos /* Read the argument in braces. */
150*dc174305Schristos if (curchar () != '{')
151*dc174305Schristos {
152*dc174305Schristos line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
153*dc174305Schristos COMMAND_PREFIX, command, marker);
154*dc174305Schristos free (marker);
155*dc174305Schristos return;
156*dc174305Schristos }
157*dc174305Schristos else
158*dc174305Schristos {
159*dc174305Schristos int len;
160*dc174305Schristos int braces = 1;
161*dc174305Schristos int loc = ++input_text_offset;
162*dc174305Schristos
163*dc174305Schristos while (braces)
164*dc174305Schristos {
165*dc174305Schristos if (loc == input_text_length)
166*dc174305Schristos {
167*dc174305Schristos line_error (_("No closing brace for footnote `%s'"), marker);
168*dc174305Schristos return;
169*dc174305Schristos }
170*dc174305Schristos
171*dc174305Schristos if (input_text[loc] == '{')
172*dc174305Schristos braces++;
173*dc174305Schristos else if (input_text[loc] == '}')
174*dc174305Schristos braces--;
175*dc174305Schristos else if (input_text[loc] == '\n')
176*dc174305Schristos line_number++;
177*dc174305Schristos
178*dc174305Schristos loc++;
179*dc174305Schristos }
180*dc174305Schristos
181*dc174305Schristos len = (loc - input_text_offset) - 1;
182*dc174305Schristos note = xmalloc (len + 1);
183*dc174305Schristos memcpy (note, &input_text[input_text_offset], len);
184*dc174305Schristos note[len] = 0;
185*dc174305Schristos input_text_offset = loc;
186*dc174305Schristos }
187*dc174305Schristos
188*dc174305Schristos /* Must write the macro-expanded argument to the macro expansion
189*dc174305Schristos output stream. This is like the case in index_add_arg. */
190*dc174305Schristos if (macro_expansion_output_stream && !executing_string)
191*dc174305Schristos {
192*dc174305Schristos /* Calling me_execute_string on a lone } provokes an error, since
193*dc174305Schristos as far as the reader knows there is no matching {. We wrote
194*dc174305Schristos the { above in the call to append_to_expansion_output. */
195*dc174305Schristos me_execute_string_keep_state (note, "}");
196*dc174305Schristos }
197*dc174305Schristos
198*dc174305Schristos if (!current_node || !*current_node)
199*dc174305Schristos {
200*dc174305Schristos line_error (_("Footnote defined without parent node"));
201*dc174305Schristos free (marker);
202*dc174305Schristos free (note);
203*dc174305Schristos return;
204*dc174305Schristos }
205*dc174305Schristos
206*dc174305Schristos /* output_pending_notes is non-reentrant (it uses a global data
207*dc174305Schristos structure pending_notes, which it frees before it returns), and
208*dc174305Schristos TeX doesn't grok footnotes inside footnotes anyway. Disallow
209*dc174305Schristos that. */
210*dc174305Schristos if (already_outputting_pending_notes)
211*dc174305Schristos {
212*dc174305Schristos line_error (_("Footnotes inside footnotes are not allowed"));
213*dc174305Schristos free (marker);
214*dc174305Schristos free (note);
215*dc174305Schristos return;
216*dc174305Schristos }
217*dc174305Schristos
218*dc174305Schristos if (!*marker)
219*dc174305Schristos {
220*dc174305Schristos free (marker);
221*dc174305Schristos
222*dc174305Schristos if (number_footnotes)
223*dc174305Schristos {
224*dc174305Schristos marker = xmalloc (10);
225*dc174305Schristos sprintf (marker, "%d", current_footnote_number);
226*dc174305Schristos }
227*dc174305Schristos else
228*dc174305Schristos marker = xstrdup ("*");
229*dc174305Schristos }
230*dc174305Schristos
231*dc174305Schristos if (xml)
232*dc174305Schristos xml_insert_footnote (note);
233*dc174305Schristos else
234*dc174305Schristos {
235*dc174305Schristos remember_note (marker, note);
236*dc174305Schristos
237*dc174305Schristos /* fixme: html: footnote processing needs work; we currently ignore
238*dc174305Schristos the style requested; we could clash with a node name of the form
239*dc174305Schristos `fn-<n>', though that's unlikely. */
240*dc174305Schristos if (html)
241*dc174305Schristos {
242*dc174305Schristos /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
243*dc174305Schristos definition.) */
244*dc174305Schristos add_html_elt ("<a rel=\"footnote\" href=");
245*dc174305Schristos add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
246*dc174305Schristos current_footnote_number, current_footnote_number,
247*dc174305Schristos marker);
248*dc174305Schristos }
249*dc174305Schristos else
250*dc174305Schristos /* Your method should at least insert MARKER. */
251*dc174305Schristos switch (footnote_style)
252*dc174305Schristos {
253*dc174305Schristos case separate_node:
254*dc174305Schristos add_word_args ("(%s)", marker);
255*dc174305Schristos execute_string (" (*note %s-Footnote-%d::)",
256*dc174305Schristos current_node, current_footnote_number);
257*dc174305Schristos if (first_footnote_this_node)
258*dc174305Schristos {
259*dc174305Schristos char *temp_string, *expanded_ref;
260*dc174305Schristos
261*dc174305Schristos temp_string = xmalloc (strlen (current_node)
262*dc174305Schristos + strlen ("-Footnotes") + 1);
263*dc174305Schristos
264*dc174305Schristos strcpy (temp_string, current_node);
265*dc174305Schristos strcat (temp_string, "-Footnotes");
266*dc174305Schristos expanded_ref = expansion (temp_string, 0);
267*dc174305Schristos remember_node_reference (expanded_ref, line_number,
268*dc174305Schristos followed_reference);
269*dc174305Schristos free (temp_string);
270*dc174305Schristos free (expanded_ref);
271*dc174305Schristos first_footnote_this_node = 0;
272*dc174305Schristos }
273*dc174305Schristos break;
274*dc174305Schristos
275*dc174305Schristos case end_node:
276*dc174305Schristos add_word_args ("(%s)", marker);
277*dc174305Schristos break;
278*dc174305Schristos
279*dc174305Schristos default:
280*dc174305Schristos break;
281*dc174305Schristos }
282*dc174305Schristos current_footnote_number++;
283*dc174305Schristos }
284*dc174305Schristos free (marker);
285*dc174305Schristos free (note);
286*dc174305Schristos }
287*dc174305Schristos
288*dc174305Schristos /* Output the footnotes. We are at the end of the current node. */
289*dc174305Schristos void
output_pending_notes(void)290*dc174305Schristos output_pending_notes (void)
291*dc174305Schristos {
292*dc174305Schristos FN *footnote = pending_notes;
293*dc174305Schristos
294*dc174305Schristos if (!pending_notes)
295*dc174305Schristos return;
296*dc174305Schristos
297*dc174305Schristos if (html)
298*dc174305Schristos {
299*dc174305Schristos add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
300*dc174305Schristos /* We add an anchor here so @printindex can refer to this point
301*dc174305Schristos (as the node name) for entries defined in footnotes. */
302*dc174305Schristos if (!splitting)
303*dc174305Schristos add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
304*dc174305Schristos add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
305*dc174305Schristos }
306*dc174305Schristos else
307*dc174305Schristos switch (footnote_style)
308*dc174305Schristos {
309*dc174305Schristos case separate_node:
310*dc174305Schristos {
311*dc174305Schristos char *old_current_node = current_node;
312*dc174305Schristos char *old_command = xstrdup (command);
313*dc174305Schristos
314*dc174305Schristos already_outputting_pending_notes++;
315*dc174305Schristos execute_string ("%cnode %s-Footnotes,,,%s\n",
316*dc174305Schristos COMMAND_PREFIX, current_node, current_node);
317*dc174305Schristos already_outputting_pending_notes--;
318*dc174305Schristos current_node = old_current_node;
319*dc174305Schristos free (command);
320*dc174305Schristos command = old_command;
321*dc174305Schristos }
322*dc174305Schristos break;
323*dc174305Schristos
324*dc174305Schristos case end_node:
325*dc174305Schristos close_paragraph ();
326*dc174305Schristos in_fixed_width_font++;
327*dc174305Schristos /* This string should be translated according to the
328*dc174305Schristos @documentlanguage, not the current LANG. We can't do that
329*dc174305Schristos yet, so leave it in English. */
330*dc174305Schristos execute_string ("---------- Footnotes ----------\n\n");
331*dc174305Schristos in_fixed_width_font--;
332*dc174305Schristos break;
333*dc174305Schristos }
334*dc174305Schristos
335*dc174305Schristos /* Handle the footnotes in reverse order. */
336*dc174305Schristos {
337*dc174305Schristos int save_in_fixed_width_font = in_fixed_width_font;
338*dc174305Schristos FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
339*dc174305Schristos array[footnote_count] = NULL;
340*dc174305Schristos
341*dc174305Schristos while (--footnote_count > -1)
342*dc174305Schristos {
343*dc174305Schristos array[footnote_count] = footnote;
344*dc174305Schristos footnote = footnote->next;
345*dc174305Schristos }
346*dc174305Schristos
347*dc174305Schristos filling_enabled = 1;
348*dc174305Schristos indented_fill = 1;
349*dc174305Schristos in_fixed_width_font = 0;
350*dc174305Schristos
351*dc174305Schristos while ((footnote = array[++footnote_count]))
352*dc174305Schristos {
353*dc174305Schristos if (html)
354*dc174305Schristos {
355*dc174305Schristos /* Make the text of every footnote begin a separate paragraph. */
356*dc174305Schristos add_html_block_elt ("<p class=\"footnote\"><small>");
357*dc174305Schristos /* Make footnote number a link to its definition. */
358*dc174305Schristos add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
359*dc174305Schristos footnote->number, footnote->number, footnote->number);
360*dc174305Schristos add_word ("</small> ");
361*dc174305Schristos already_outputting_pending_notes++;
362*dc174305Schristos execute_string ("%s", footnote->note);
363*dc174305Schristos already_outputting_pending_notes--;
364*dc174305Schristos add_word ("</p>\n");
365*dc174305Schristos }
366*dc174305Schristos else
367*dc174305Schristos {
368*dc174305Schristos char *old_current_node = current_node;
369*dc174305Schristos char *old_command = xstrdup (command);
370*dc174305Schristos
371*dc174305Schristos already_outputting_pending_notes++;
372*dc174305Schristos execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
373*dc174305Schristos COMMAND_PREFIX, current_node, footnote->number,
374*dc174305Schristos footnote->marker, footnote->note);
375*dc174305Schristos already_outputting_pending_notes--;
376*dc174305Schristos current_node = old_current_node;
377*dc174305Schristos free (command);
378*dc174305Schristos command = old_command;
379*dc174305Schristos }
380*dc174305Schristos
381*dc174305Schristos close_paragraph ();
382*dc174305Schristos }
383*dc174305Schristos
384*dc174305Schristos if (html)
385*dc174305Schristos add_word ("<hr></div>");
386*dc174305Schristos close_paragraph ();
387*dc174305Schristos free (array);
388*dc174305Schristos
389*dc174305Schristos in_fixed_width_font = save_in_fixed_width_font;
390*dc174305Schristos }
391*dc174305Schristos
392*dc174305Schristos free_pending_notes ();
393*dc174305Schristos }
394