123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /* footnote.c -- footnotes for Texinfo.
- $Id: footnote.c,v 1.12 2007-12-03 01:38:43 karl Exp $
- Copyright (C) 1998, 1999, 2002, 2007 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "system.h"
- #include "footnote.h"
- #include "macro.h"
- #include "makeinfo.h"
- #include "node.h"
- #include "xml.h"
- #include "xref.h"
- /* Nonzero means that the footnote style for this document was set on
- the command line, which overrides any other settings. */
- int footnote_style_preset = 0;
- /* The current footnote number in this node. Each time a new node is
- started this is reset to 1. */
- int current_footnote_number = 1;
- /* Nonzero means we automatically number footnotes with no specified marker. */
- int number_footnotes = 1;
- /* Nonzero means we are currently outputting footnotes. */
- int already_outputting_pending_notes = 0;
- /* Footnotes can be handled in one of two ways:
- separate_node:
- Make them look like followed references, with the reference
- destinations in a makeinfo manufactured node or,
- end_node:
- Make them appear at the bottom of the node that they originally
- appeared in. */
- #define separate_node 0
- #define end_node 1
- int footnote_style = end_node;
- int first_footnote_this_node = 1;
- int footnote_count = 0;
- /* Set the footnote style based on the style identifier in STRING. */
- int
- set_footnote_style (char *string)
- {
- if (mbscasecmp (string, "separate") == 0)
- footnote_style = separate_node;
- else if (mbscasecmp (string, "end") == 0)
- footnote_style = end_node;
- else
- return -1;
- return 0;
- }
- void
- cm_footnotestyle (void)
- {
- char *arg;
- get_rest_of_line (1, &arg);
- /* If set on command line, do not change the footnote style. */
- if (!footnote_style_preset && set_footnote_style (arg) != 0)
- line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
- free (arg);
- }
- typedef struct fn
- {
- struct fn *next;
- char *marker;
- char *note;
- int number;
- } FN;
- FN *pending_notes = NULL;
- /* A method for remembering footnotes. Note that this list gets output
- at the end of the current node. */
- static void
- remember_note (char *marker, char *note)
- {
- FN *temp = xmalloc (sizeof (FN));
- temp->marker = xstrdup (marker);
- temp->note = xstrdup (note);
- temp->next = pending_notes;
- temp->number = current_footnote_number;
- pending_notes = temp;
- footnote_count++;
- }
- /* How to get rid of existing footnotes. */
- static void
- free_pending_notes (void)
- {
- FN *temp;
- while ((temp = pending_notes))
- {
- free (temp->marker);
- free (temp->note);
- pending_notes = pending_notes->next;
- free (temp);
- }
- first_footnote_this_node = 1;
- footnote_count = 0;
- current_footnote_number = 1; /* for html */
- }
- /* What to do when you see a @footnote construct. */
- /* Handle a "footnote".
- footnote *{this is a footnote}
- where "*" is the (optional) marker character for this note. */
- void
- cm_footnote (void)
- {
- char *marker;
- char *note;
- get_until ("{", &marker);
- canon_white (marker);
- if (macro_expansion_output_stream && !executing_string)
- append_to_expansion_output (input_text_offset + 1); /* include the { */
- /* Read the argument in braces. */
- if (curchar () != '{')
- {
- line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
- COMMAND_PREFIX, command, marker);
- free (marker);
- return;
- }
- else
- {
- int len;
- int braces = 1;
- int loc = ++input_text_offset;
- while (braces)
- {
- if (loc == input_text_length)
- {
- line_error (_("No closing brace for footnote `%s'"), marker);
- return;
- }
- if (input_text[loc] == '{')
- braces++;
- else if (input_text[loc] == '}')
- braces--;
- else if (input_text[loc] == '\n')
- line_number++;
- loc++;
- }
- len = (loc - input_text_offset) - 1;
- note = xmalloc (len + 1);
- memcpy (note, &input_text[input_text_offset], len);
- note[len] = 0;
- input_text_offset = loc;
- }
- /* Must write the macro-expanded argument to the macro expansion
- output stream. This is like the case in index_add_arg. */
- if (macro_expansion_output_stream && !executing_string)
- {
- /* Calling me_execute_string on a lone } provokes an error, since
- as far as the reader knows there is no matching {. We wrote
- the { above in the call to append_to_expansion_output. */
- me_execute_string_keep_state (note, "}");
- }
- if (!current_node || !*current_node)
- {
- line_error (_("Footnote defined without parent node"));
- free (marker);
- free (note);
- return;
- }
- /* output_pending_notes is non-reentrant (it uses a global data
- structure pending_notes, which it frees before it returns), and
- TeX doesn't grok footnotes inside footnotes anyway. Disallow
- that. */
- if (already_outputting_pending_notes)
- {
- line_error (_("Footnotes inside footnotes are not allowed"));
- free (marker);
- free (note);
- return;
- }
- if (!*marker)
- {
- free (marker);
- if (number_footnotes)
- {
- marker = xmalloc (10);
- sprintf (marker, "%d", current_footnote_number);
- }
- else
- marker = xstrdup ("*");
- }
- if (xml)
- xml_insert_footnote (note);
- else
- {
- remember_note (marker, note);
- /* fixme: html: footnote processing needs work; we currently ignore
- the style requested; we could clash with a node name of the form
- `fn-<n>', though that's unlikely. */
- if (html)
- {
- /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote
- definition.) */
- add_html_elt ("<a rel=\"footnote\" href=");
- add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>",
- current_footnote_number, current_footnote_number,
- marker);
- }
- else
- /* Your method should at least insert MARKER. */
- switch (footnote_style)
- {
- case separate_node:
- add_word_args ("(%s)", marker);
- execute_string (" (*note %s-Footnote-%d::)",
- current_node, current_footnote_number);
- if (first_footnote_this_node)
- {
- char *temp_string, *expanded_ref;
- temp_string = xmalloc (strlen (current_node)
- + strlen ("-Footnotes") + 1);
- strcpy (temp_string, current_node);
- strcat (temp_string, "-Footnotes");
- expanded_ref = expansion (temp_string, 0);
- remember_node_reference (expanded_ref, line_number,
- followed_reference);
- free (temp_string);
- free (expanded_ref);
- first_footnote_this_node = 0;
- }
- break;
- case end_node:
- add_word_args ("(%s)", marker);
- break;
- default:
- break;
- }
- current_footnote_number++;
- }
- free (marker);
- free (note);
- }
- /* Output the footnotes. We are at the end of the current node. */
- void
- output_pending_notes (void)
- {
- FN *footnote = pending_notes;
- if (!pending_notes)
- return;
- if (html)
- {
- add_html_block_elt ("<div class=\"footnote\">\n<hr>\n");
- /* We add an anchor here so @printindex can refer to this point
- (as the node name) for entries defined in footnotes. */
- if (!splitting)
- add_word ("<a name=\"texinfo-footnotes-in-document\"></a>");
- add_word_args ("<h4>%s</h4>", (char *) _("Footnotes"));
- }
- else
- switch (footnote_style)
- {
- case separate_node:
- {
- char *old_current_node = current_node;
- char *old_command = xstrdup (command);
- already_outputting_pending_notes++;
- execute_string ("%cnode %s-Footnotes,,,%s\n",
- COMMAND_PREFIX, current_node, current_node);
- already_outputting_pending_notes--;
- current_node = old_current_node;
- free (command);
- command = old_command;
- }
- break;
- case end_node:
- close_paragraph ();
- in_fixed_width_font++;
- /* This string should be translated according to the
- @documentlanguage, not the current LANG. We can't do that
- yet, so leave it in English. */
- execute_string ("---------- Footnotes ----------\n\n");
- in_fixed_width_font--;
- break;
- }
- /* Handle the footnotes in reverse order. */
- {
- int save_in_fixed_width_font = in_fixed_width_font;
- FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
- array[footnote_count] = NULL;
- while (--footnote_count > -1)
- {
- array[footnote_count] = footnote;
- footnote = footnote->next;
- }
- filling_enabled = 1;
- indented_fill = 1;
- in_fixed_width_font = 0;
- while ((footnote = array[++footnote_count]))
- {
- if (html)
- {
- /* Make the text of every footnote begin a separate paragraph. */
- add_html_block_elt ("<p class=\"footnote\"><small>");
- /* Make footnote number a link to its definition. */
- add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]",
- footnote->number, footnote->number, footnote->number);
- add_word ("</small> ");
- already_outputting_pending_notes++;
- execute_string ("%s", footnote->note);
- already_outputting_pending_notes--;
- add_word ("</p>\n");
- }
- else
- {
- char *old_current_node = current_node;
- char *old_command = xstrdup (command);
- already_outputting_pending_notes++;
- execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
- COMMAND_PREFIX, current_node, footnote->number,
- footnote->marker, footnote->note);
- already_outputting_pending_notes--;
- current_node = old_current_node;
- free (command);
- command = old_command;
- }
- close_paragraph ();
- }
- if (html)
- add_html_block_elt ("<hr></div>");
- close_paragraph ();
- free (array);
- in_fixed_width_font = save_in_fixed_width_font;
- }
- free_pending_notes ();
- }
|