Back to index

tetex-bin  3.0
footnote.c
Go to the documentation of this file.
00001 /* footnote.c -- footnotes for Texinfo.
00002    $Id: footnote.c,v 1.7 2004/04/11 17:56:47 karl Exp $
00003 
00004    Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software Foundation,
00018    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00019 
00020 #include "system.h"
00021 #include "footnote.h"
00022 #include "macro.h"
00023 #include "makeinfo.h"
00024 #include "node.h"
00025 #include "xml.h"
00026 #include "xref.h"
00027 
00028 /* Nonzero means that the footnote style for this document was set on
00029    the command line, which overrides any other settings. */
00030 int footnote_style_preset = 0;
00031 
00032 /* The current footnote number in this node.  Each time a new node is
00033    started this is reset to 1. */
00034 int current_footnote_number = 1;
00035 
00036 /* Nonzero means we automatically number footnotes with no specified marker. */
00037 int number_footnotes = 1;
00038 
00039 /* Nonzero means we are currently outputting footnotes. */
00040 int already_outputting_pending_notes = 0;
00041 
00042 
00043 /* Footnotes can be handled in one of two ways:
00044 
00045    separate_node:
00046         Make them look like followed references, with the reference
00047         destinations in a makeinfo manufactured node or,
00048    end_node:
00049         Make them appear at the bottom of the node that they originally
00050         appeared in. */
00051 
00052 #define separate_node 0
00053 #define end_node 1
00054 
00055 int footnote_style = end_node;
00056 int first_footnote_this_node = 1;
00057 int footnote_count = 0;
00058 
00059 /* Set the footnote style based on the style identifier in STRING. */
00060 int
00061 set_footnote_style (char *string)
00062 {
00063   if (strcasecmp (string, "separate") == 0)
00064     footnote_style = separate_node;
00065   else if (strcasecmp (string, "end") == 0)
00066     footnote_style = end_node;
00067   else
00068     return -1;
00069 
00070  return 0;
00071 }
00072 
00073 void
00074 cm_footnotestyle (void)
00075 {
00076   char *arg;
00077 
00078   get_rest_of_line (1, &arg);
00079 
00080   /* If set on command line, do not change the footnote style.  */
00081   if (!footnote_style_preset && set_footnote_style (arg) != 0)
00082     line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
00083 
00084   free (arg);
00085 }
00086 
00087 typedef struct fn
00088 {
00089   struct fn *next;
00090   char *marker;
00091   char *note;
00092   int number;
00093 }  FN;
00094 
00095 FN *pending_notes = NULL;
00096 
00097 /* A method for remembering footnotes.  Note that this list gets output
00098    at the end of the current node. */
00099 static void
00100 remember_note (char *marker, char *note)
00101 {
00102   FN *temp = xmalloc (sizeof (FN));
00103 
00104   temp->marker = xstrdup (marker);
00105   temp->note = xstrdup (note);
00106   temp->next = pending_notes;
00107   temp->number = current_footnote_number;
00108   pending_notes = temp;
00109   footnote_count++;
00110 }
00111 
00112 /* How to get rid of existing footnotes. */
00113 static void
00114 free_pending_notes (void)
00115 {
00116   FN *temp;
00117 
00118   while ((temp = pending_notes))
00119     {
00120       free (temp->marker);
00121       free (temp->note);
00122       pending_notes = pending_notes->next;
00123       free (temp);
00124     }
00125   first_footnote_this_node = 1;
00126   footnote_count = 0;
00127   current_footnote_number = 1;     /* for html */
00128 }
00129 
00130 /* What to do when you see a @footnote construct. */
00131 
00132  /* Handle a "footnote".
00133     footnote *{this is a footnote}
00134     where "*" is the (optional) marker character for this note. */
00135 void
00136 cm_footnote (void)
00137 {
00138   char *marker;
00139   char *note;
00140 
00141   get_until ("{", &marker);
00142   canon_white (marker);
00143 
00144   if (macro_expansion_output_stream && !executing_string)
00145     append_to_expansion_output (input_text_offset + 1); /* include the { */
00146 
00147   /* Read the argument in braces. */
00148   if (curchar () != '{')
00149     {
00150       line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
00151                   COMMAND_PREFIX, command, marker);
00152       free (marker);
00153       return;
00154     }
00155   else
00156     {
00157       int len;
00158       int braces = 1;
00159       int loc = ++input_text_offset;
00160 
00161       while (braces)
00162         {
00163           if (loc == input_text_length)
00164             {
00165               line_error (_("No closing brace for footnote `%s'"), marker);
00166               return;
00167             }
00168 
00169           if (input_text[loc] == '{')
00170             braces++;
00171           else if (input_text[loc] == '}')
00172             braces--;
00173           else if (input_text[loc] == '\n')
00174             line_number++;
00175 
00176           loc++;
00177         }
00178 
00179       len = (loc - input_text_offset) - 1;
00180       note = xmalloc (len + 1);
00181       memcpy (note, &input_text[input_text_offset], len);
00182       note[len] = 0;
00183       input_text_offset = loc;
00184     }
00185 
00186   /* Must write the macro-expanded argument to the macro expansion
00187      output stream.  This is like the case in index_add_arg.  */
00188   if (macro_expansion_output_stream && !executing_string)
00189     {
00190       /* Calling me_execute_string on a lone } provokes an error, since
00191          as far as the reader knows there is no matching {.  We wrote
00192          the { above in the call to append_to_expansion_output. */
00193       me_execute_string_keep_state (note, "}");
00194     }
00195 
00196   if (!current_node || !*current_node)
00197     {
00198       line_error (_("Footnote defined without parent node"));
00199       free (marker);
00200       free (note);
00201       return;
00202     }
00203 
00204   /* output_pending_notes is non-reentrant (it uses a global data
00205      structure pending_notes, which it frees before it returns), and
00206      TeX doesn't grok footnotes inside footnotes anyway.  Disallow
00207      that.  */
00208   if (already_outputting_pending_notes)
00209     {
00210       line_error (_("Footnotes inside footnotes are not allowed"));
00211       free (marker);
00212       free (note);
00213       return;
00214     }
00215 
00216   if (!*marker)
00217     {
00218       free (marker);
00219 
00220       if (number_footnotes)
00221         {
00222           marker = xmalloc (10);
00223           sprintf (marker, "%d", current_footnote_number);
00224         }
00225       else
00226         marker = xstrdup ("*");
00227     }
00228 
00229   if (xml)
00230     xml_insert_footnote (note);
00231   else 
00232     {
00233   remember_note (marker, note);
00234 
00235   /* fixme: html: footnote processing needs work; we currently ignore
00236      the style requested; we could clash with a node name of the form
00237      `fn-<n>', though that's unlikely. */
00238   if (html)
00239     {
00240       /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
00241          definition.)  */
00242       add_html_elt ("<a rel=\"footnote\" href=");
00243       add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
00244                    current_footnote_number, current_footnote_number,
00245                      marker);
00246     }
00247   else
00248     /* Your method should at least insert MARKER. */
00249     switch (footnote_style)
00250       {
00251       case separate_node:
00252         add_word_args ("(%s)", marker);
00253         execute_string (" (*note %s-Footnote-%d::)",
00254                         current_node, current_footnote_number);
00255         if (first_footnote_this_node)
00256           {
00257             char *temp_string, *expanded_ref;
00258 
00259             temp_string = xmalloc (strlen (current_node)
00260                                    + strlen ("-Footnotes") + 1);
00261 
00262             strcpy (temp_string, current_node);
00263             strcat (temp_string, "-Footnotes");
00264             expanded_ref = expansion (temp_string, 0);
00265             remember_node_reference (expanded_ref, line_number,
00266                                      followed_reference);
00267             free (temp_string);
00268             free (expanded_ref);
00269             first_footnote_this_node = 0;
00270           }
00271         break;
00272 
00273       case end_node:
00274         add_word_args ("(%s)", marker);
00275         break;
00276 
00277       default:
00278         break;
00279       }
00280   current_footnote_number++;
00281     }
00282   free (marker);
00283   free (note);
00284 }
00285 
00286 /* Output the footnotes.  We are at the end of the current node. */
00287 void
00288 output_pending_notes (void)
00289 {
00290   FN *footnote = pending_notes;
00291 
00292   if (!pending_notes)
00293     return;
00294 
00295   if (html)
00296     {
00297       add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
00298       /* We add an anchor here so @printindex can refer to this point
00299          (as the node name) for entries defined in footnotes.  */
00300       if (!splitting)
00301         add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
00302       add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
00303     }
00304   else
00305     switch (footnote_style)
00306       {
00307       case separate_node:
00308         {
00309           char *old_current_node = current_node;
00310           char *old_command = xstrdup (command);
00311 
00312           already_outputting_pending_notes++;
00313           execute_string ("%cnode %s-Footnotes,,,%s\n",
00314                           COMMAND_PREFIX, current_node, current_node);
00315           already_outputting_pending_notes--;
00316           current_node = old_current_node;
00317           free (command);
00318           command = old_command;
00319         }
00320       break;
00321 
00322       case end_node:
00323         close_paragraph ();
00324         in_fixed_width_font++;
00325         /* This string should be translated according to the
00326            @documentlanguage, not the current LANG.  We can't do that
00327            yet, so leave it in English.  */
00328         execute_string ("---------- Footnotes ----------\n\n");
00329         in_fixed_width_font--;
00330         break;
00331       }
00332 
00333   /* Handle the footnotes in reverse order. */
00334   {
00335     int save_in_fixed_width_font = in_fixed_width_font;
00336     FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
00337     array[footnote_count] = NULL;
00338 
00339     while (--footnote_count > -1)
00340       {
00341         array[footnote_count] = footnote;
00342         footnote = footnote->next;
00343       }
00344 
00345     filling_enabled = 1;
00346     indented_fill = 1;
00347     in_fixed_width_font = 0;
00348 
00349     while ((footnote = array[++footnote_count]))
00350       {
00351         if (html)
00352           {
00353            /* Make the text of every footnote begin a separate paragraph.  */
00354             add_html_block_elt ("<p class=\"footnote\"><small>");
00355             /* Make footnote number a link to its definition.  */
00356             add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
00357                         footnote->number, footnote->number, footnote->number);
00358             add_word ("</small> ");
00359             already_outputting_pending_notes++;
00360             execute_string ("%s", footnote->note);
00361             already_outputting_pending_notes--;
00362             add_word ("</p>\n");
00363           }
00364         else
00365           {
00366             char *old_current_node = current_node;
00367             char *old_command = xstrdup (command);
00368 
00369             already_outputting_pending_notes++;
00370             execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
00371                             COMMAND_PREFIX, current_node, footnote->number,
00372                             footnote->marker, footnote->note);
00373             already_outputting_pending_notes--;
00374             current_node = old_current_node;
00375             free (command);
00376             command = old_command;
00377           }
00378 
00379         close_paragraph ();
00380       }
00381 
00382     if (html)
00383       add_word ("<hr></div>");
00384     close_paragraph ();
00385     free (array);
00386 
00387     in_fixed_width_font = save_in_fixed_width_font;
00388   }
00389 
00390   free_pending_notes ();
00391 }