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