summaryrefslogtreecommitdiff
path: root/Build/source/utils/texinfo/makeinfo/makeinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/texinfo/makeinfo/makeinfo.c')
-rw-r--r--Build/source/utils/texinfo/makeinfo/makeinfo.c4350
1 files changed, 0 insertions, 4350 deletions
diff --git a/Build/source/utils/texinfo/makeinfo/makeinfo.c b/Build/source/utils/texinfo/makeinfo/makeinfo.c
deleted file mode 100644
index 36792c26692..00000000000
--- a/Build/source/utils/texinfo/makeinfo/makeinfo.c
+++ /dev/null
@@ -1,4350 +0,0 @@
-/* makeinfo -- convert Texinfo source into other formats.
- $Id: makeinfo.c,v 1.118 2008/03/26 23:57:11 karl Exp $
-
- Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- 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/>.
-
- Original author of makeinfo: Brian Fox (bfox@ai.mit.edu). */
-
-#include "system.h"
-#include "getopt.h"
-#include "mbswidth.h"
-
-#define COMPILING_MAKEINFO
-#include "makeinfo.h"
-#include "cmds.h"
-#include "files.h"
-#include "float.h"
-#include "footnote.h"
-#include "html.h"
-#include "index.h"
-#include "insertion.h"
-#include "lang.h"
-#include "macro.h"
-#include "node.h"
-#include "sectioning.h"
-#include "toc.h"
-#include "xml.h"
-
-/* You can change some of the behavior of Makeinfo by changing the
- following defines: */
-
-/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which
- appear within an @table, @ftable, or @itemize environment to have
- standard paragraph indentation. Without this, such paragraphs have
- no starting indentation. */
-/* #define INDENT_PARAGRAPHS_IN_TABLE */
-
-/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
- the first lines of paragraphs receive by default, where no other
- value has been specified. Users can change this value on the command
- line, with the --paragraph-indent option, or within the texinfo file,
- with the @paragraphindent command. */
-#define PARAGRAPH_START_INDENT 3
-
-/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you
- wish to appear between paragraphs. A value of 1 creates a single blank
- line between paragraphs. Paragraphs are defined by 2 or more consecutive
- newlines in the input file (i.e., one or more blank lines). */
-#define DEFAULT_PARAGRAPH_SPACING 1
-
-/* Global variables. */
-
-/* The output file name. */
-char *output_filename = NULL;
-
-/* Name of the output file that the user elected to pass on the command line.
- Such a name overrides any name found with the @setfilename command. */
-char *command_output_filename = NULL;
-static char *save_command_output_filename = NULL;
-
-/* The amount of indentation to add at the starts of paragraphs.
- 0 means don't change existing indentation at paragraph starts.
- > 0 is amount to indent new paragraphs by.
- < 0 means indent to column zero by removing indentation if necessary.
-
- This is normally zero, but some people prefer paragraph starts to be
- somewhat more indented than paragraph bodies. A pretty value for
- this is 3. */
-int paragraph_start_indent = PARAGRAPH_START_INDENT;
-
-/* Indentation that is pending insertion. We have this for hacking lines
- which look blank, but contain whitespace. We want to treat those as
- blank lines. */
-int pending_indent = 0;
-
-/* The index in our internal command table of the currently
- executing command. */
-int command_index;
-
-/* A search string which is used to find the first @setfilename. */
-char setfilename_search[] =
- { COMMAND_PREFIX,
- 's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 };
-
-/* Values for calling handle_variable_internal (). */
-#define SET 1
-#define CLEAR 2
-#define IFSET 3
-#define IFCLEAR 4
-
-/* Flags controlling the operation of the program. */
-
-/* Default is to remove output if there were errors. */
-int force = 0;
-
-/* Default is to notify users of bad choices. */
-int print_warnings = 1;
-
-/* Number of errors that we tolerate on a given fileset. */
-int max_error_level = 100;
-
-/* The actual last inserted character. Note that this may be something
- other than NEWLINE even if last_char_was_newline is 1. */
-int last_inserted_character = 0;
-
-/* Nonzero means that a newline character has already been
- inserted, so close_paragraph () should insert one less. */
-int line_already_broken = 0;
-
-/* When nonzero we have finished an insertion (see end_insertion ()) and we
- want to ignore false continued paragraph closings. */
-int insertion_paragraph_closed = 0;
-
-/* Nonzero means attempt to make all of the lines have fill_column width. */
-int do_justification = 0;
-
-/* Nonzero means don't replace whitespace with &nbsp; in HTML mode. */
-int in_html_elt = 0;
-
-/* Nonzero means we are inserting a block level HTML element that must not be
- enclosed in a <p>, such as <ul>, <ol> and <h?>. */
-int in_html_block_level_elt = 0;
-
-/* True when expanding a macro definition. */
-static int executing_macro = 0;
-
-/* True when we are inside a <li> block of a menu. */
-static int in_menu_item = 0;
-
-/* The column position of output_paragraph[0]. This is not saved and restored
- in the multitable code because flush_output () is only called in environment
- 0. */
-static int output_paragraph_start_column = 0;
-
-typedef struct brace_element
-{
- struct brace_element *next;
- COMMAND_FUNCTION *proc;
- char *command;
- int pos, line;
- int in_fixed_width_font;
-} BRACE_ELEMENT;
-
-BRACE_ELEMENT *brace_stack = NULL;
-
-static void convert_from_file (char *name);
-static void convert_from_loaded_file (char *name);
-static void convert_from_stream (FILE *stream, char *name);
-static void do_flush_right_indentation (void);
-static void handle_variable (int action);
-static void handle_variable_internal (int action, char *name);
-static void init_brace_stack (void);
-static void init_internals (void);
-static void pop_and_call_brace (void);
-static void remember_brace (COMMAND_FUNCTION (*proc));
-static void write_trailer (char *filename, char *trailer);
-static int end_of_sentence_p (void);
-
-void maybe_update_execution_strings (char **text, unsigned int new_len);
-
-/* Error handling. */
-
-/* Number of errors encountered. */
-int errors_printed = 0;
-
-/* Remember that an error has been printed. If more than
- max_error_level have been printed, then exit the program. */
-static void
-remember_error (void)
-{
- errors_printed++;
- if (max_error_level && (errors_printed > max_error_level))
- {
- fprintf (stderr, _("Too many errors! Gave up.\n"));
- flush_file_stack ();
- if (errors_printed - max_error_level < 2)
- cm_bye ();
- xexit (1);
- }
-}
-
-/* Print the last error gotten from the file system. */
-int
-fs_error (char *filename)
-{
- remember_error ();
- perror (filename);
- return 0;
-}
-
-/* Print an error message, and return false. */
-void
-#if defined (VA_FPRINTF) && __STDC__
-error (const char *format, ...)
-#else
-error (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- remember_error ();
-
- VA_START (ap, format);
-#ifdef VA_FPRINTF
- VA_FPRINTF (stderr, format, ap);
-#else
- fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_FPRINTF */
- va_end (ap);
-
- putc ('\n', stderr);
-}
-
-/* Just like error (), but print the input file and line number as well. */
-void
-#if defined (VA_FPRINTF) && __STDC__
-file_line_error (char *infile, int lno, const char *format, ...)
-#else
-file_line_error (infile, lno, format, va_alist)
- char *infile;
- int lno;
- const char *format;
- va_dcl
-#endif
-{
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- remember_error ();
- fprintf (stderr, "%s:%d: ", infile, lno);
-
- VA_START (ap, format);
-#ifdef VA_FPRINTF
- VA_FPRINTF (stderr, format, ap);
-#else
- fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_FPRINTF */
- va_end (ap);
-
- fprintf (stderr, ".\n");
-}
-
-/* Just like file_line_error (), but take the input file and the line
- number from global variables. */
-void
-#if defined (VA_FPRINTF) && __STDC__
-line_error (const char *format, ...)
-#else
-line_error (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- remember_error ();
- fprintf (stderr, "%s:%d: ", input_filename, line_number);
-
- VA_START (ap, format);
-#ifdef VA_FPRINTF
- VA_FPRINTF (stderr, format, ap);
-#else
- fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_FPRINTF */
- va_end (ap);
-
- fprintf (stderr, ".\n");
-}
-
-void
-#if defined (VA_FPRINTF) && __STDC__
-warning (const char *format, ...)
-#else
-warning (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- if (print_warnings)
- {
- fprintf (stderr, _("%s:%d: warning: "), input_filename, line_number);
-
- VA_START (ap, format);
-#ifdef VA_FPRINTF
- VA_FPRINTF (stderr, format, ap);
-#else
- fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_FPRINTF */
- va_end (ap);
-
- fprintf (stderr, ".\n");
- }
-}
-
-
-/* The other side of a malformed expression. */
-static void
-misplaced_brace (void)
-{
- line_error (_("Misplaced %c"), '}');
-}
-
-/* Main. */
-
-/* Display the version info of this invocation of Makeinfo. */
-static void
-print_version_info (void)
-{
- printf ("makeinfo (GNU %s) %s\n", PACKAGE, VERSION);
-}
-
-/* If EXIT_VALUE is zero, print the full usage message to stdout.
- Otherwise, just say to use --help for more info.
- Then exit with EXIT_VALUE. */
-static void
-usage (int exit_value)
-{
- if (exit_value != 0)
- fprintf (stderr, _("Try `%s --help' for more information.\n"), progname);
- else
- {
- printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n"), progname);
- puts ("");
-
- puts (_("\
-Translate Texinfo source documentation to various other formats, by default\n\
-Info files suitable for reading online with Emacs or standalone GNU Info.\n"));
-
- printf (_("\
-General options:\n\
- --error-limit=NUM quit after NUM errors (default %d).\n\
- --document-language=STR locale to use in translating Texinfo keywords\n\
- for the output document (default C).\n\
- --force preserve output even if errors.\n\
- --help display this help and exit.\n\
- --no-validate suppress node cross-reference validation.\n\
- --no-warn suppress warnings (but not errors).\n\
- -v, --verbose explain what is being done.\n\
- --version display version information and exit.\n"),
- max_error_level);
- puts ("");
-
- /* xgettext: no-wrap */
- puts (_("\
-Output format selection (default is to produce Info):\n\
- --docbook output Docbook XML rather than Info.\n\
- --html output HTML rather than Info.\n\
- --xml output Texinfo XML rather than Info.\n\
- --plaintext output plain text rather than Info.\n\
-"));
-
- puts (_("\
-General output options:\n\
- -E, --macro-expand=FILE output macro-expanded source to FILE,\n\
- ignoring any @setfilename.\n\
- --no-headers suppress node separators, Node: lines, and menus\n\
- from Info output (thus producing plain text)\n\
- or from HTML (thus producing shorter output);\n\
- also, write to standard output by default.\n\
- --no-split suppress the splitting of Info or HTML output,\n\
- generate only one output file.\n\
- --number-sections output chapter and sectioning numbers.\n\
- -o, --output=FILE output to FILE (or directory if split HTML).\n\
-"));
-
- printf (_("\
-Options for Info and plain text:\n\
- --disable-encoding do not output accented and special characters\n\
- in Info output based on @documentencoding.\n\
- --enable-encoding override --disable-encoding (default).\n\
- --fill-column=NUM break Info lines at NUM characters (default %d).\n\
- --footnote-style=STYLE output footnotes in Info according to STYLE:\n\
- `separate' to put them in their own node;\n\
- `end' to put them at the end of the node, in\n\
- which they are defined (this is the default).\n\
- --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).\n\
- If VAL is `none', do not indent; if VAL is\n\
- `asis', preserve existing indentation.\n\
- --split-size=NUM split Info files at size NUM (default %d).\n"),
- fill_column, paragraph_start_indent,
- DEFAULT_SPLIT_SIZE);
- puts ("");
-
- puts (_("\
-Options for HTML:\n\
- --css-include=FILE include FILE in HTML <style> output;\n\
- read stdin if FILE is -.\n\
- --css-ref=URL generate reference to a CSS file.\n\
- --transliterate-file-names\n\
- produce file names in ASCII transliteration.\n\
-"));
-
- printf (_("\
-Options for XML and Docbook:\n\
- --output-indent=VAL indent XML elements by VAL spaces (default %d).\n\
- If VAL is 0, ignorable whitespace is dropped.\n\
-"), xml_indentation_increment);
- puts ("");
-
- puts (_("\
-Input file options:\n\
- --commands-in-node-names allow @ commands in node names.\n\
- -D VAR define the variable VAR, as with @set.\n\
- -I DIR append DIR to the @include search path.\n\
- -P DIR prepend DIR to the @include search path.\n\
- -U VAR undefine the variable VAR, as with @clear.\n\
-"));
-
- puts (_("\
-Conditional processing in input:\n\
- --ifdocbook process @ifdocbook and @docbook even if\n\
- not generating Docbook.\n\
- --ifhtml process @ifhtml and @html even if not generating HTML.\n\
- --ifinfo process @ifinfo even if not generating Info.\n\
- --ifplaintext process @ifplaintext even if not generating plain text.\n\
- --iftex process @iftex and @tex; implies --no-split.\n\
- --ifxml process @ifxml and @xml.\n\
- --no-ifdocbook do not process @ifdocbook and @docbook text.\n\
- --no-ifhtml do not process @ifhtml and @html text.\n\
- --no-ifinfo do not process @ifinfo text.\n\
- --no-ifplaintext do not process @ifplaintext text.\n\
- --no-iftex do not process @iftex and @tex text.\n\
- --no-ifxml do not process @ifxml and @xml text.\n\
-\n\
- Also, for the --no-ifFORMAT options, do process @ifnotFORMAT text.\n\
-"));
-
- puts (_("\
- The defaults for the @if... conditionals depend on the output format:\n\
- if generating HTML, --ifhtml is on and the others are off;\n\
- if generating Info, --ifinfo is on and the others are off;\n\
- if generating plain text, --ifplaintext is on and the others are off;\n\
- if generating XML, --ifxml is on and the others are off.\n\
-"));
-
- fputs (_("\
-Examples:\n\
- makeinfo foo.texi write Info to foo's @setfilename\n\
- makeinfo --html foo.texi write HTML to @setfilename\n\
- makeinfo --xml foo.texi write Texinfo XML to @setfilename\n\
- makeinfo --docbook foo.texi write DocBook XML to @setfilename\n\
- makeinfo --no-headers foo.texi write plain text to standard output\n\
-\n\
- makeinfo --html --no-headers foo.texi write html without node lines, menus\n\
- makeinfo --number-sections foo.texi write Info with numbered sections\n\
- makeinfo --no-split foo.texi write one Info file however big\n\
-"), stdout);
-
- puts (_("\n\
-Email bug reports to bug-texinfo@gnu.org,\n\
-general questions and discussion to help-texinfo@gnu.org.\n\
-Texinfo home page: http://www.gnu.org/software/texinfo/"));
-
- } /* end of full help */
-
- xexit (exit_value);
-}
-
-#define OPT_CSSREF 256
-#define OPT_TRANSLITERATE_FILE_NAMES 257
-
-struct option long_options[] =
-{
- { "commands-in-node-names", 0, &expensive_validation, 1 },
- { "css-include", 1, 0, 'C' },
- { "css-ref", 1, 0, OPT_CSSREF },
- { "docbook", 0, 0, 'd' },
- { "disable-encoding", 0, &enable_encoding, 0 },
- { "enable-encoding", 0, &enable_encoding, 1 },
- { "document-language", 1, 0, 'l' },
- { "error-limit", 1, 0, 'e' },
- { "fill-column", 1, 0, 'f' },
- { "footnote-style", 1, 0, 's' },
- { "force", 0, &force, 1 },
- { "help", 0, 0, 'h' },
- { "html", 0, 0, 'w' },
- { "ifdocbook", 0, &process_docbook, 1 },
- { "ifhtml", 0, &process_html, 1 },
- { "ifinfo", 0, &process_info, 1 },
- { "ifplaintext", 0, &process_plaintext, 1 },
- { "iftex", 0, &process_tex, 1 },
- { "ifxml", 0, &process_xml, 1 },
- { "macro-expand", 1, 0, 'E' },
- { "no-headers", 0, &no_headers, 1 },
- { "no-ifdocbook", 0, &process_docbook, 0 },
- { "no-ifhtml", 0, &process_html, 0 },
- { "no-ifinfo", 0, &process_info, 0 },
- { "no-ifplaintext", 0, &process_plaintext, 0 },
- { "no-iftex", 0, &process_tex, 0 },
- { "no-ifxml", 0, &process_xml, 0 },
- { "no-number-footnotes", 0, &number_footnotes, 0 },
- { "no-number-sections", 0, &number_sections, 0 },
- { "no-pointer-validate", 0, &validating, 0 },
- { "no-split", 0, &splitting, 0 },
- { "no-validate", 0, &validating, 0 },
- { "no-warn", 0, &print_warnings, 0 },
- { "number-footnotes", 0, &number_footnotes, 1 },
- { "number-sections", 0, &number_sections, 1 },
- { "output", 1, 0, 'o' },
- { "output-indent", 1, 0, 'i' },
- { "paragraph-indent", 1, 0, 'p' },
- { "plaintext", 0, 0, 't' },
- { "reference-limit", 1, 0, 'r' },
- { "split-size", 1, 0, 'S'},
- { "transliterate-file-names", 0, &transliterate_file_names, 1 },
- { "verbose", 0, &verbose_mode, 1 },
- { "version", 0, 0, 'V' },
- { "xml", 0, 0, 'x' },
- {NULL, 0, NULL, 0}
-};
-
-/* We use handle_variable_internal for -D and -U, and it depends on
- execute_string, which depends on input_filename, which is not defined
- while we are handling options. :-\ So we save these defines in this
- struct, and handle them later. */
-typedef struct command_line_define
-{
- struct command_line_define *next;
- int action;
- char *define;
-} COMMAND_LINE_DEFINE;
-
-static COMMAND_LINE_DEFINE *command_line_defines = NULL;
-
-/* For each file mentioned in the command line, process it, turning
- Texinfo commands into wonderfully formatted output text. */
-int
-main (int argc, char *argv[])
-{
- int c, ind;
- int reading_from_stdin = 0;
-
-#ifdef HAVE_SETLOCALE
- /* Do not use LC_ALL, because LC_NUMERIC screws up the scanf parsing
- of the argument to @multicolumn. */
- setlocale (LC_TIME, "");
-#ifdef LC_MESSAGES /* ultrix, djgpp 2.04 */
- setlocale (LC_MESSAGES, "");
-#endif
- setlocale (LC_CTYPE, "");
- setlocale (LC_COLLATE, "");
-#endif
-
-#ifdef ENABLE_NLS
- /* Set the text message domain. */
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-#endif
-
- /* If TEXINFO_OUTPUT_FORMAT envvar is set, use it to set default output.
- Can be overridden with one of the output options. */
- if (getenv ("TEXINFO_OUTPUT_FORMAT") != NULL)
- {
- if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "docbook"))
- {
- splitting = 0;
- html = 0;
- docbook = 1;
- xml = 1;
- process_docbook = 1;
- }
- else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "html"))
- {
- html = 1;
- docbook = 0;
- xml = 0;
- process_html = 1;
- }
- else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "info"))
- {
- html = 0;
- docbook = 0;
- xml = 0;
- }
- else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "plaintext"))
- {
- splitting = 0;
- no_headers = 1;
- html = 0;
- docbook = 0;
- xml = 0;
- process_plaintext = 1;
- }
- else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "xml"))
- {
- splitting = 0;
- html = 0;
- docbook = 0;
- xml = 1;
- process_xml = 1;
- }
- else
- fprintf (stderr,
- _("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"),
- progname, getenv ("TEXINFO_OUTPUT_FORMAT"));
- }
-
- /* Parse argument flags from the input line. */
- while ((c = getopt_long (argc, argv, "D:de:E:f:hI:i:o:p:P:r:s:t:U:vV:wx",
- long_options, &ind)) != EOF)
- {
- if (c == 0 && long_options[ind].flag == 0)
- c = long_options[ind].val;
-
- switch (c)
- {
- case 'C': /* --css-include */
- css_include = xstrdup (optarg);
- break;
-
- case OPT_CSSREF:
- css_ref = xstrdup (optarg);
- break;
-
- case 'D':
- case 'U':
- /* User specified variable to set or clear. */
- if (xml && !docbook)
- {
- COMMAND_LINE_DEFINE *new = xmalloc (sizeof (COMMAND_LINE_DEFINE));
- new->action = (c == 'D') ? SET : CLEAR;
- new->define = xstrdup (optarg);
- new->next = command_line_defines;
- command_line_defines = new;
- }
- else
- handle_variable_internal ((c == 'D' ? SET : CLEAR), optarg);
- break;
-
- case 'd': /* --docbook */
- splitting = 0;
- xml = 1;
- docbook = 1;
- html = 0;
- process_docbook = 1;
- break;
-
- case 'e': /* --error-limit */
- if (sscanf (optarg, "%d", &max_error_level) != 1)
- {
- fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
- progname, "--error-limit", optarg);
- usage (1);
- }
- break;
-
- case 'E': /* --macro-expand */
- if (!macro_expansion_output_stream)
- {
- macro_expansion_filename = optarg;
- macro_expansion_output_stream
- = strcmp (optarg, "-") == 0 ? stdout : fopen (optarg, "w");
- if (!macro_expansion_output_stream)
- error (_("%s: could not open macro expansion output `%s'"),
- progname, optarg);
- }
- else
- fprintf (stderr,
- _("%s: ignoring second macro expansion output `%s'.\n"),
- progname, optarg);
- break;
-
- case 'f': /* --fill-column */
- if (sscanf (optarg, "%d", &fill_column) != 1)
- {
- fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
- progname, "--fill-column", optarg);
- usage (1);
- }
- break;
-
- case 'h': /* --help */
- usage (0);
- break;
-
- case 'I':
- /* Append user-specified dir to include file path. */
- append_to_include_path (optarg);
- break;
-
- case 'l':
- /* save the override language code */
- document_language = xstrdup (optarg);
- break;
-
- case 'i':
- if (sscanf (optarg, "%d", &xml_indentation_increment) != 1)
- {
- fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
- progname, "--output-indent", optarg);
- usage (1);
- }
- break;
-
- case 'o': /* --output */
- command_output_filename = xstrdup (optarg);
- save_command_output_filename = command_output_filename;
- break;
-
- case 'p': /* --paragraph-indent */
- if (set_paragraph_indent (optarg) < 0)
- {
- fprintf (stderr,
- _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"),
- progname, optarg);
- usage (1);
- }
- break;
-
- case 'P':
- /* Prepend user-specified include dir to include path. */
- prepend_to_include_path (optarg);
- break;
-
- case 'r': /* was --reference-limit; obsolete, ignore */
- break;
-
- case 's': /* --footnote-style */
- if (set_footnote_style (optarg) < 0)
- {
- fprintf (stderr,
- _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"),
- progname, optarg);
- usage (1);
- }
- footnote_style_preset = 1;
- break;
-
- case 'S': /* --split-size */
- if (sscanf (optarg, "%d", &split_size) != 1)
- {
- fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
- progname, "--split-size", optarg);
- usage (1);
- }
- break;
-
- case 't': /* --plaintext */
- splitting = 0;
- no_headers = 1;
- html = 0;
- docbook = 0;
- xml = 0;
- process_plaintext = 1;
- break;
-
- case 'v':
- verbose_mode++;
- break;
-
- case 'V': /* --version */
- print_version_info ();
- puts ("");
- printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
-License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
-This is free software: you are free to change and redistribute it.\n\
-There is NO WARRANTY, to the extent permitted by law.\n"),
- "2008");
- xexit (0);
- break;
-
- case 'w': /* --html */
- xml = 0;
- docbook = 0;
- html = 1;
- process_html = 1;
- break;
-
- case 'x': /* --xml */
- splitting = 0;
- html = 0;
- docbook = 0;
- xml = 1;
- process_xml = 1;
- break;
-
- case '?':
- usage (1);
- break;
- }
- }
-
- if (macro_expansion_output_stream)
- validating = 0;
-
- if (!validating)
- expensive_validation = 0;
-
- if (optind == argc)
- {
- /* Check to see if input is a file. If so, process that. */
- if (!isatty (fileno (stdin)))
- reading_from_stdin = 1;
- else
- {
- fprintf (stderr, _("%s: missing file argument.\n"), progname);
- usage (1);
- }
- }
-
- if (no_headers)
- {
- /* If the user did not specify an output file, use stdout. */
- if (!command_output_filename)
- command_output_filename = xstrdup ("-");
-
- if (html && splitting && !STREQ (command_output_filename, "-"))
- { /* --no-headers --no-split --html indicates confusion. */
- fprintf (stderr,
- "%s: can't split --html output to `%s' with --no-headers.\n",
- progname, command_output_filename);
- usage (1);
- }
-
- /* --no-headers implies --no-split. */
- splitting = 0;
- }
-
- if (process_info == -1)
- { /* no explicit --[no-]ifinfo option, so we'll do @ifinfo
- if we're generating info or (for compatibility) plain text. */
- process_info = !html && !xml;
- }
-
- if (process_plaintext == -1)
- { /* no explicit --[no-]ifplaintext option, so we'll do @ifplaintext
- if we're generating plain text. */
- process_plaintext = no_headers && !html && !xml;
- }
-
- if (verbose_mode)
- print_version_info ();
-
- /* Remaining arguments are file names of texinfo files.
- Convert them, one by one. */
- if (!reading_from_stdin)
- {
- while (optind != argc)
- convert_from_file (argv[optind++]);
- }
- else
- convert_from_stream (stdin, "stdin");
-
- xexit (errors_printed ? 2 : 0);
- return 0; /* Avoid bogus warnings. */
-}
-
-/* Hacking tokens and strings. */
-
-/* Return the next token as a string pointer. We cons the string. This
- `token' means simply a command name. */
-
-/* = is so @alias works. ^ and _ are so macros can be used in math mode
- without a space following. Possibly we should simply allow alpha, to
- be compatible with TeX. */
-#define COMMAND_CHAR(c) (!cr_or_whitespace(c) \
- && (c) != '{' \
- && (c) != '}' \
- && (c) != '=' \
- && (c) != '_' \
- && (c) != '^' \
- )
-
-static char *
-read_token (void)
-{
- int i, character;
- char *result;
-
- /* If the first character to be read is self-delimiting, then that
- is the command itself. */
- character = curchar ();
- if (self_delimiting (character))
- {
- input_text_offset++;
-
- if (character == '\n')
- line_number++;
-
- result = xstrdup (" ");
- *result = character;
- return result;
- }
-
- for (i = 0; ((input_text_offset != input_text_length)
- && (character = curchar ())
- && COMMAND_CHAR (character));
- i++, input_text_offset++);
- result = xmalloc (i + 1);
- memcpy (result, &input_text[input_text_offset - i], i);
- result[i] = 0;
- return result;
-}
-
-/* Return nonzero if CHARACTER is self-delimiting. */
-int
-self_delimiting (int character)
-{
- /* @; and @\ are not Texinfo commands, but they are listed here
- anyway. I don't know why. --karl, 10aug96. */
- return strchr ("~{|}`^\\@?=;:./-,*\'\" !\n\t", character) != NULL;
-}
-
-/* Clear whitespace from the front and end of string. */
-void
-canon_white (char *string)
-{
- char *p = string;
- unsigned len;
-
- if (!*p)
- return;
-
- do
- {
- if (!cr_or_whitespace (*p))
- break;
- ++p;
- }
- while (*p);
-
- len = strlen (p);
- while (len && cr_or_whitespace (p[len-1]))
- --len;
-
- if (p != string)
- memmove (string, p, len);
-
- string[len] = 0;
-}
-
-/* Bash STRING, replacing all whitespace with just one space. */
-void
-fix_whitespace (char *string)
-{
- char *temp = xmalloc (strlen (string) + 1);
- int string_index = 0;
- int temp_index = 0;
- int c;
-
- canon_white (string);
-
- while (string[string_index])
- {
- c = temp[temp_index++] = string[string_index++];
-
- if (c == ' ' || c == '\n' || c == '\t')
- {
- temp[temp_index - 1] = ' ';
- while ((c = string[string_index]) && (c == ' ' ||
- c == '\t' ||
- c == '\n'))
- string_index++;
- }
- }
- temp[temp_index] = 0;
- strcpy (string, temp);
- free (temp);
-}
-
-/* Discard text until the desired string is found. The string is
- included in the discarded text. */
-void
-discard_until (char *string)
-{
- int temp = search_forward (string, input_text_offset);
-
- int tt = (temp < 0) ? input_text_length : temp + strlen (string);
- int from = input_text_offset;
-
- /* Find out what line we are on. */
- while (from != tt)
- if (input_text[from++] == '\n')
- line_number++;
-
- if (temp < 0)
- {
- /* not found, move current position to end of string */
- input_text_offset = input_text_length;
- if (strcmp (string, "\n") != 0)
- { /* Give a more descriptive feedback, if we are looking for ``@end ''
- during macro execution. That means someone used a multiline
- command as an argument to, say, @section ... style commands. */
- char *end_block = xmalloc (8);
- sprintf (end_block, "\n%cend ", COMMAND_PREFIX);
- if (executing_string && strstr (string, end_block))
- line_error (_("Multiline command %c%s used improperly"),
- COMMAND_PREFIX, command);
- else
- line_error (_("Expected `%s'"), string);
- free (end_block);
- return;
- }
- }
- else
- /* found, move current position to after the found string */
- input_text_offset = temp + strlen (string);
-}
-
-/* Read characters from the file until we are at MATCH.
- Place the characters read into STRING.
- On exit input_text_offset is after the match string.
- Return the offset where the string starts. */
-int
-get_until (char *match, char **string)
-{
- int len, current_point, x, new_point, tem;
-
- current_point = x = input_text_offset;
- new_point = search_forward (match, input_text_offset);
-
- if (new_point < 0)
- new_point = input_text_length;
- len = new_point - current_point;
-
- /* Keep track of which line number we are at. */
- tem = new_point + (strlen (match) - 1);
- while (x != tem)
- if (input_text[x++] == '\n')
- line_number++;
-
- *string = xmalloc (len + 1);
-
- memcpy (*string, &input_text[current_point], len);
- (*string)[len] = 0;
-
- /* Now leave input_text_offset in a consistent state. */
- input_text_offset = tem;
-
- if (input_text_offset > input_text_length)
- input_text_offset = input_text_length;
-
- return new_point;
-}
-
-/* Replace input_text[FROM .. TO] with its expansion. */
-void
-replace_with_expansion (int from, int *to)
-{
- char *xp;
- unsigned xp_len, new_len;
- char *old_input = input_text;
- unsigned raw_len = *to - from;
- char *str;
-
- /* The rest of the code here moves large buffers, so let's
- not waste time if the input cannot possibly expand
- into anything. Unfortunately, we cannot avoid expansion
- when we see things like @code etc., even if they only
- asked for expansion of macros, since any Texinfo command
- can be potentially redefined with a macro. */
- if (only_macro_expansion &&
- memchr (input_text + from, COMMAND_PREFIX, raw_len) == 0)
- return;
-
- /* Get original string from input. */
- str = xmalloc (raw_len + 1);
- memcpy (str, input_text + from, raw_len);
- str[raw_len] = 0;
-
- /* We are going to relocate input_text, so we had better output
- pending portion of input_text now, before the pointer changes. */
- if (macro_expansion_output_stream && !executing_string
- && !me_inhibit_expansion)
- append_to_expansion_output (from);
-
- /* Expand it. */
- xp = expansion (str, 0);
- xp_len = strlen (xp);
- free (str);
-
- /* Plunk the expansion into the middle of `input_text' --
- which is terminated by a newline, not a null. Avoid
- expensive move of the rest of the input if the expansion
- has the same length as the original string. */
- if (xp_len != raw_len)
- {
- new_len = from + xp_len + input_text_length - *to + 1;
- if (executing_string)
- { /* If we are in execute_string, we might need to update
- the relevant element in the execution_strings[] array,
- since it could have to be relocated from under our
- feet. (input_text is reallocated here as well, if needed.) */
- maybe_update_execution_strings (&input_text, new_len);
- }
- else if (new_len > input_text_length + 1)
- /* Don't bother to realloc if we have enough space. */
- input_text = xrealloc (input_text, new_len);
-
- memmove (input_text + from + xp_len,
- input_text + *to, input_text_length - *to + 1);
-
- *to += xp_len - raw_len;
- /* Since we change input_text_length here, the comparison above
- isn't really valid, but it seems the worst that might happen is
- an extra xrealloc or two, so let's not worry. */
- input_text_length += xp_len - raw_len;
- }
- memcpy (input_text + from, xp, xp_len);
- free (xp);
-
- /* Synchronize the macro-expansion pointers with our new input_text. */
- if (input_text != old_input)
- forget_itext (old_input);
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, from);
-}
-
-/* Read characters from the file until we are at MATCH or end of line.
- Place the characters read into STRING. If EXPAND is nonzero,
- expand the text before looking for MATCH for those cases where
- MATCH might be produced by some macro. */
-void
-get_until_in_line (int expand, char *match, char **string)
-{
- int real_bottom = input_text_length;
- int limit = search_forward ("\n", input_text_offset);
- if (limit < 0)
- limit = input_text_length;
-
- /* Replace input_text[input_text_offset .. limit-1] with its expansion.
- This allows the node names and menu entries themselves to be
- constructed via a macro, as in:
- @macro foo{p, q}
- Together: \p\ & \q\.
- @end macro
-
- @node @foo{A,B}, next, prev, top
-
- Otherwise, the `,' separating the macro args A and B is taken as
- the node argument separator, so the node name is `@foo{A'. This
- expansion is only necessary on the first call, since we expand the
- whole line then. */
- if (expand)
- {
- replace_with_expansion (input_text_offset, &limit);
- }
-
- real_bottom = input_text_length;
- input_text_length = limit;
- get_until (match, string);
- input_text_length = real_bottom;
-}
-
-void
-get_rest_of_line (int expand, char **string)
-{
- xml_no_para ++;
- if (expand)
- {
- char *tem;
-
- /* Don't expand non-macros in input, since we want them
- intact in the macro-expanded output. */
- only_macro_expansion++;
- get_until_in_line (1, "\n", &tem);
- only_macro_expansion--;
- *string = expansion (tem, 0);
- free (tem);
- }
- else
- get_until_in_line (0, "\n", string);
-
- canon_white (*string);
-
- if (curchar () == '\n') /* as opposed to the end of the file... */
- {
- line_number++;
- input_text_offset++;
- }
- xml_no_para --;
-}
-
-/* Backup the input pointer to the previous character, keeping track
- of the current line number. */
-void
-backup_input_pointer (void)
-{
- if (input_text_offset)
- {
- input_text_offset--;
- if (curchar () == '\n')
- line_number--;
- }
-}
-
-/* Read characters from the file until we are at MATCH or closing brace.
- Place the characters read into STRING. */
-void
-get_until_in_braces (char *match, char **string)
-{
- char *temp;
- int i, brace = 0;
- int match_len = strlen (match);
-
- for (i = input_text_offset; i < input_text_length; i++)
- {
- if (i < input_text_length - 1 && input_text[i] == '@')
- {
- i++; /* skip commands like @, and @{ */
- continue;
- }
- else if (input_text[i] == '{')
- brace++;
- else if (input_text[i] == '}')
- {
- brace--;
- /* If looking for a brace, don't stop at the interior brace,
- like after "baz" in "@foo{something @bar{baz} more}". */
- if (brace == 0)
- continue;
- }
- else if (input_text[i] == '\n')
- line_number++;
-
- if (brace < 0 ||
- (brace == 0 && strncmp (input_text + i, match, match_len) == 0))
- break;
- }
-
- match_len = i - input_text_offset;
- temp = xmalloc (2 + match_len);
- memcpy (temp, input_text + input_text_offset, match_len);
- temp[match_len] = 0;
- input_text_offset = i;
- *string = temp;
-}
-
-
-
-/* Converting a file. */
-
-/* Convert the file named by NAME. The output is saved on the file
- named as the argument to the @setfilename command. */
-static char *suffixes[] = {
- /* ".txi" is checked first so that on 8+3 DOS filesystems, if they
- have "texinfo.txi" and "texinfo.tex" in the same directory, the
- former is used rather than the latter, due to file name truncation. */
- ".txi",
- ".texinfo",
- ".texi",
- ".txinfo",
- "",
- NULL
-};
-
-static void
-initialize_conversion (void)
-{
- init_tag_table ();
- init_indices ();
- init_internals ();
- init_paragraph ();
-
- /* This is used for splitting the output file and for doing section
- headings. It was previously initialized in `init_paragraph', but its
- use there loses with the `init_paragraph' calls done by the
- multitable code; the tag indices get reset to zero. */
- output_position = 0;
-}
-
-/* Reverse the chain of structures in LIST. Output the new head
- of the chain. You should always assign the output value of this
- function to something, or you will lose the chain. */
-GENERIC_LIST *
-reverse_list (GENERIC_LIST *list)
-{
- GENERIC_LIST *next;
- GENERIC_LIST *prev = NULL;
-
- while (list)
- {
- next = list->next;
- list->next = prev;
- prev = list;
- list = next;
- }
- return prev;
-}
-
-/* We read in multiples of 4k, simply because it is a typical pipe size
- on unix systems. */
-#define READ_BUFFER_GROWTH (4 * 4096)
-
-/* Convert the Texinfo file coming from the open stream STREAM. Assume the
- source of the stream is named NAME. */
-static void
-convert_from_stream (FILE *stream, char *name)
-{
- char *buffer = NULL;
- int buffer_offset = 0, buffer_size = 0;
-
- initialize_conversion ();
-
- /* Read until the end of the stream. This isn't strictly correct, since
- the texinfo input may end before the stream ends, but it is a quick
- working hueristic. */
- while (!feof (stream))
- {
- int count;
-
- if (buffer_offset + (READ_BUFFER_GROWTH + 1) >= buffer_size)
- buffer = (char *)
- xrealloc (buffer, (buffer_size += READ_BUFFER_GROWTH));
-
- count = fread (buffer + buffer_offset, 1, READ_BUFFER_GROWTH, stream);
-
- if (count < 0)
- {
- perror (name);
- xexit (1);
- }
-
- buffer_offset += count;
- if (count == 0)
- break;
- }
-
- /* Set the globals to the new file. */
- input_text = buffer;
- input_text_length = buffer_offset;
- input_filename = xstrdup (name);
- node_filename = xstrdup (name);
- input_text_offset = 0;
- line_number = 1;
-
- /* Not strictly necessary. This magic prevents read_token () from doing
- extra unnecessary work each time it is called (that is a lot of times).
- The INPUT_TEXT_LENGTH is one past the actual end of the text. */
- input_text[input_text_length] = '\n';
-
- convert_from_loaded_file (name);
-}
-
-static void
-convert_from_file (char *name)
-{
- int i;
- char *filename = xmalloc (strlen (name) + 50);
-
- /* Prepend NAME's directory to the search path, so relative links work. */
- prepend_to_include_path (pathname_part (name));
-
- initialize_conversion ();
-
- /* Try to load the file specified by NAME, concatenated with our
- various suffixes. Prefer files like `makeinfo.texi' to `makeinfo'. */
- for (i = 0; suffixes[i]; i++)
- {
- strcpy (filename, name);
- strcat (filename, suffixes[i]);
-
- if (find_and_load (filename, 1))
- break;
- }
-
- if (!suffixes[i])
- {
- fs_error (name);
- free (filename);
- return;
- }
-
- /* `find_and_load' (when successful) clobbers this global with new
- memory. We're about to reset it, so may as well free first. */
- free (input_filename);
-
- /* Set the current filename. */
- input_filename = filename;
-
- /* Do the main conversion. */
- convert_from_loaded_file (name);
-
- /* Pop the prepended path, so multiple filenames in the
- command line do not screw each others include paths. */
- pop_path_from_include_path ();
-}
-
-static int
-create_html_directory (char *dir, int can_remove_file)
-{
- struct stat st;
-
- /* Already exists. */
- if (stat (dir, &st) == 0)
- {
- /* And it's a directory, so silently reuse it. */
- if (S_ISDIR (st.st_mode))
- return 1;
- /* Not a directory, so move it out of the way if we are allowed. */
- else if (can_remove_file)
- {
- if (unlink (dir) != 0)
- return 0;
- }
- else
- return 0;
- }
-
- if (mkdir (dir, 0777) == 0)
- /* Success! */
- return 1;
- else
- return 0;
-}
-
-/* Given OUTPUT_FILENAME == ``/foo/bar/baz.html'', return
- "/foo/bar/baz/baz.html". This routine is called only if html && splitting.
-
- Split html output goes into the subdirectory of the toplevel
- filename, without extension. For example:
- @setfilename foo.info
- produces output in files foo/index.html, foo/second-node.html, ...
-
- But if the user said -o foo.whatever on the cmd line, then use
- foo.whatever unchanged. */
-
-static char *
-insert_toplevel_subdirectory (char *output_filename)
-{
- static const char index_name[] = "index.html";
- char *dir, *subdir, *base, *basename, *p;
- char buf[PATH_MAX];
- const int index_len = sizeof (index_name) - 1;
-
- strcpy (buf, output_filename);
- dir = pathname_part (buf); /* directory of output_filename */
- base = filename_part (buf); /* strips suffix, too */
- basename = xstrdup (base); /* remember real @setfilename name */
- p = dir + strlen (dir) - 1;
- if (p > dir && IS_SLASH (*p))
- *p = 0;
- p = strrchr (base, '.');
- if (p)
- *p = 0;
-
- /* Split html output goes into subdirectory of toplevel name. */
- if (save_command_output_filename
- && STREQ (output_filename, save_command_output_filename))
- subdir = basename; /* from user, use unchanged */
- else
- subdir = base; /* implicit, omit suffix */
-
- free (output_filename);
- output_filename = xmalloc (strlen (dir) + 1
- + strlen (basename) + 1
- + index_len
- + 1);
- strcpy (output_filename, dir);
- if (strlen (dir))
- strcat (output_filename, "/");
- strcat (output_filename, subdir);
-
- /* First try, do not remove existing file. */
- if (!create_html_directory (output_filename, 0))
- {
- /* That failed, try subdir name with .html.
- Remove it if it exists. */
- strcpy (output_filename, dir);
- if (strlen (dir))
- strcat (output_filename, "/");
- strcat (output_filename, basename);
-
- if (!create_html_directory (output_filename, 1))
- {
- /* Last try failed too :-\ */
- line_error (_("Can't create directory `%s': %s"),
- output_filename, strerror (errno));
- xexit (1);
- }
- }
-
- strcat (output_filename, "/");
- strcat (output_filename, index_name);
- return output_filename;
-}
-
-/* FIXME: this is way too hairy */
-static void
-convert_from_loaded_file (char *name)
-{
- char *real_output_filename = NULL;
-
- remember_itext (input_text, 0);
-
- input_text_offset = 0;
-
- /* Avoid the `\input texinfo' line in HTML output (assuming it starts
- the file). */
- if (looking_at ("\\input"))
- discard_until ("\n");
-
- /* Search this file looking for the special string which starts conversion.
- Once found, we may truly begin. */
- while (input_text_offset >= 0)
- {
- input_text_offset =
- search_forward (setfilename_search, input_text_offset);
-
- if (input_text_offset == 0
- || (input_text_offset > 0
- && input_text[input_text_offset -1] == '\n'))
- break;
- else if (input_text_offset > 0)
- input_text_offset++;
- }
-
- if (input_text_offset < 0)
- {
- if (!command_output_filename)
- {
-#if defined (REQUIRE_SETFILENAME)
- error (_("No `%s' found in `%s'"), setfilename_search, name);
- goto finished;
-#else
- command_output_filename = output_name_from_input_name (name);
-#endif /* !REQUIRE_SETFILENAME */
- }
-
- {
- int i, end_of_first_line;
-
- /* Find the end of the first line in the file. */
- for (i = 0; i < input_text_length - 1; i++)
- if (input_text[i] == '\n')
- break;
-
- end_of_first_line = i + 1;
-
- for (i = 0; i < end_of_first_line; i++)
- {
- if ((input_text[i] == '\\') &&
- (strncmp (input_text + i + 1, "input", 5) == 0))
- {
- input_text_offset = i;
- break;
- }
- }
- }
- }
- else
- input_text_offset += strlen (setfilename_search);
-
- if (!command_output_filename)
- {
- get_until ("\n", &output_filename); /* read rest of line */
- if (html || xml)
- { /* Change any extension to .html or .xml. */
- char *html_name, *directory_part, *basename_part, *temp;
-
- canon_white (output_filename);
- directory_part = pathname_part (output_filename);
-
- basename_part = filename_part (output_filename);
-
- /* Zap any existing extension. */
- temp = strrchr (basename_part, '.');
- if (temp)
- *temp = 0;
-
- /* Construct new filename. */
- html_name = xmalloc (strlen (directory_part)
- + strlen (basename_part) + 6);
- strcpy (html_name, directory_part);
- strcat (html_name, basename_part);
- strcat (html_name, html ? ".html" : ".xml");
-
- /* Replace name from @setfilename with the html name. */
- free (output_filename);
- output_filename = html_name;
- }
- }
- else
- {
- if (input_text_offset != -1)
- discard_until ("\n");
- else
- input_text_offset = 0;
-
- real_output_filename = output_filename = command_output_filename;
- command_output_filename = NULL; /* for included files or whatever */
- }
-
- canon_white (output_filename);
- toplevel_output_filename = xstrdup (output_filename);
-
- if (real_output_filename && strcmp (real_output_filename, "-") == 0)
- {
- if (macro_expansion_filename
- && strcmp (macro_expansion_filename, "-") == 0)
- {
- fprintf (stderr,
- _("%s: Skipping macro expansion to stdout as Info output is going there.\n"),
- progname);
- macro_expansion_output_stream = NULL;
- }
- real_output_filename = xstrdup (real_output_filename);
- output_stream = stdout;
- splitting = 0; /* Cannot split when writing to stdout. */
- }
- else
- {
- if (html && splitting)
- {
- if (FILENAME_CMP (output_filename, NULL_DEVICE) == 0
- || FILENAME_CMP (output_filename, ALSO_NULL_DEVICE) == 0)
- splitting = 0;
- else
- output_filename = insert_toplevel_subdirectory (output_filename);
- real_output_filename = xstrdup (output_filename);
- }
- else if (!real_output_filename)
- real_output_filename = expand_filename (output_filename, name);
- else
- real_output_filename = xstrdup (real_output_filename);
-
- output_stream = fopen (real_output_filename, "w");
- }
-
- set_current_output_filename (real_output_filename);
-
- if (verbose_mode)
- printf (_("Making %s file `%s' from `%s'.\n"),
- no_headers ? "text"
- : html ? "HTML"
- : xml ? "XML"
- : "info",
- output_filename, input_filename);
-
- if (output_stream == NULL)
- {
- fs_error (real_output_filename);
- goto finished;
- }
-
- if (xml)
- xml_begin_document (filename_part (output_filename));
-
- /* Make the displayable filename from output_filename. Only the base
- portion of the filename need be displayed. */
- flush_output (); /* in case there was no @bye */
- if (output_stream != stdout)
- pretty_output_filename = filename_part (output_filename);
- else
- pretty_output_filename = xstrdup ("stdout");
-
- /* For this file only, count the number of newlines from the top of
- the file to here. This way, we keep track of line numbers for
- error reporting. Line_number starts at 1, since the user isn't
- zero-based. */
- {
- int temp = 0;
- line_number = 1;
- while (temp != input_text_offset)
- if (input_text[temp++] == '\n')
- line_number++;
- }
-
- if (xml && !docbook)
- {
- /* Just before the real main loop, let's handle the defines. */
- COMMAND_LINE_DEFINE *temp;
-
- for (temp = command_line_defines; temp; temp = temp->next)
- {
- handle_variable_internal (temp->action, temp->define);
- free(temp->define);
- }
- }
-
- reader_loop ();
- if (xml)
- xml_end_document ();
-
-
-finished:
- discard_insertions (0);
- close_paragraph ();
- flush_file_stack ();
-
- if (macro_expansion_output_stream)
- {
- fclose (macro_expansion_output_stream);
- if (errors_printed && !force
- && strcmp (macro_expansion_filename, "-") != 0
- && FILENAME_CMP (macro_expansion_filename, NULL_DEVICE) != 0
- && FILENAME_CMP (macro_expansion_filename, ALSO_NULL_DEVICE) != 0)
- {
- fprintf (stderr,
-_("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
- progname, macro_expansion_filename);
- if (unlink (macro_expansion_filename) < 0)
- perror (macro_expansion_filename);
- }
- }
-
- if (output_stream)
- {
- output_pending_notes ();
-
- if (html)
- {
- no_indent = 1;
- start_paragraph ();
- add_word ("</body></html>\n");
- close_paragraph ();
- }
-
- /* Write stuff makeinfo generates after @bye, ie. info_trailer. */
- flush_output ();
-
- if (output_stream != stdout)
- if (fclose (output_stream) != 0)
- fs_error (real_output_filename);
-
- /* If validating, then validate the entire file right now. */
- if (validating)
- validate_file (tag_table);
-
- handle_delayed_writes ();
-
- if (tag_table)
- {
- tag_table = (TAG_ENTRY *) reverse_list ((GENERIC_LIST *) tag_table);
- if (!no_headers && !html && !STREQ (current_output_filename, "-"))
- write_tag_table (real_output_filename);
- }
-
- /* Maybe we want local variables in info output. Must be after
- tag table, since otherwise usually Emacs will not see it. */
- write_trailer (real_output_filename, info_trailer ());
-
- if (splitting && !html && (!errors_printed || force))
- {
- clean_old_split_files (real_output_filename);
- split_file (real_output_filename, split_size);
- }
- else if (errors_printed
- && !force
- && strcmp (real_output_filename, "-") != 0
- && FILENAME_CMP (real_output_filename, NULL_DEVICE) != 0
- && FILENAME_CMP (real_output_filename, ALSO_NULL_DEVICE) != 0)
- { /* If there were errors, and no --force, remove the output. */
- fprintf (stderr,
- _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
- progname, real_output_filename);
- if (unlink (real_output_filename) < 0)
- perror (real_output_filename);
- }
- }
- free (real_output_filename);
-}
-
-/* If enable_encoding is set and @documentencoding is used, return a
- Local Variables section (as a malloc-ed string) so that Emacs'
- locale features can work. Else return NULL. */
-char *
-info_trailer (void)
-{
- char *encoding;
-
- if (!enable_encoding)
- return NULL;
-
- encoding = current_document_encoding ();
-
- if (encoding && *encoding)
- {
-#define LV_FMT "\n\037\nLocal Variables:\ncoding: %s\nEnd:\n"
- char *lv = xmalloc (sizeof (LV_FMT) + strlen (encoding));
- sprintf (lv, LV_FMT, encoding);
- free (encoding);
- return lv;
- }
-
- free (encoding);
- return NULL;
-}
-
-/* Append TRAILER to FILENAME for Info and HTML output. Include HTML
- comments if needed. */
-static void
-write_trailer (char *filename, char *trailer)
-{
- if (!trailer || xml || docbook)
- return;
-
- if (output_stream != stdout)
- output_stream = fopen (filename, "a");
- if (!output_stream)
- {
- fs_error (filename);
- return;
- }
-
- if (html)
- fwrite ("<!--", 1, 4, output_stream);
-
- fwrite (trailer, 1, strlen (trailer), output_stream);
- free (trailer);
-
- if (html)
- fwrite ("\n-->\n", 1, 5, output_stream);
-
- if (output_stream != stdout)
- if (fclose (output_stream) != 0)
- fs_error (filename);
-}
-
-
-void
-free_and_clear (char **pointer)
-{
- if (*pointer)
- {
- free (*pointer);
- *pointer = NULL;
- }
-}
-
- /* Initialize some state. */
-static void
-init_internals (void)
-{
- free_and_clear (&output_filename);
- free_and_clear (&command);
- free_and_clear (&input_filename);
- free_node_references ();
- free_node_node_references ();
- toc_free ();
- init_insertion_stack ();
- init_brace_stack ();
- current_node = NULL; /* sometimes already freed */
- command_index = 0;
- in_menu = 0;
- in_detailmenu = 0;
- top_node_seen = 0;
- non_top_node_seen = 0;
- node_number = -1;
-}
-
-void
-init_paragraph (void)
-{
- if (output_paragraph)
- free (output_paragraph);
- output_paragraph = xmalloc (paragraph_buffer_len);
- output_paragraph[0] = 0;
- output_paragraph_offset = 0;
- output_paragraph_start_column = 0;
- paragraph_is_open = 0;
- current_indent = 0;
- meta_char_pos = 0;
-}
-
-/* This is called from `reader_loop' when we are at the * beginning a
- menu line. */
-
-static void
-handle_menu_entry (void)
-{
- char *tem;
-
- /* Ugh, glean_node_from_menu wants to read the * itself. */
- input_text_offset--;
-
- /* Find node name in menu entry and save it in references list for
- later validation. Use followed_reference type for detailmenu
- references since we don't want to use them for default node pointers. */
- tem = glean_node_from_menu (1, in_detailmenu
- ? followed_reference : menu_reference);
-
- if (html && tem)
- { /* Start a menu item with the cleaned-up line. Put an anchor
- around the start text (before `:' or the node name). */
- char *string;
-
- discard_until ("* ");
-
- /* The line number was already incremented in reader_loop when we
- saw the newline, and discard_until has now incremented again. */
- line_number--;
-
- if (had_menu_commentary)
- {
- add_html_block_elt ("<ul class=\"menu\">\n");
- had_menu_commentary = 0;
- in_paragraph = 0;
- }
-
- if (in_paragraph)
- {
- add_html_block_elt ("</p>\n");
- add_html_block_elt ("<ul class=\"menu\">\n");
- in_paragraph = 0;
- }
-
- in_menu_item = 1;
-
- add_html_block_elt ("<li><a");
- if (next_menu_item_number <= 9)
- {
- add_word(" accesskey=");
- add_word_args("\"%d\"", next_menu_item_number);
- next_menu_item_number++;
- }
- add_word (" href=\"");
- string = expansion (tem, 0);
- add_anchor_name (string, 1);
- add_word ("\">");
- free (string);
-
- /* The menu item may use macros, so expand them now. */
- only_macro_expansion++;
- get_until_in_line (1, ":", &string);
- only_macro_expansion--;
- execute_string ("%s", string); /* get escaping done */
- free (string);
-
- add_word ("</a>");
-
- if (looking_at ("::"))
- discard_until (":");
- else
- { /* discard the node name */
- get_until_in_line (0, ".", &string);
- free (string);
- }
- input_text_offset++; /* discard the second colon or the period */
-
- /* Insert a colon only if there is a description of this menu item. */
- {
- int save_input_text_offset = input_text_offset;
- int save_line_number = line_number;
- char *test_string;
- get_rest_of_line (0, &test_string);
- if (strlen (test_string) > 0)
- add_word (": ");
- input_text_offset = save_input_text_offset;
- line_number = save_line_number;
- }
- }
- else if (xml && tem)
- {
- xml_start_menu_entry (tem);
- }
- else if (tem)
- { /* For Info output, we can just use the input and the main case in
- reader_loop where we output what comes in. Just move off the *
- so the next time through reader_loop we don't end up back here. */
- add_char ('*');
- input_text_offset += 2; /* undo the pointer back-up above. */
- }
-
- if (tem)
- free (tem);
-}
-
-/* Find the command corresponding to STRING. If the command is found,
- return a pointer to the data structure. Otherwise return -1. */
-static COMMAND *
-get_command_entry (char *string)
-{
- int i;
-
- for (i = 0; command_table[i].name; i++)
- if (strcmp (command_table[i].name, string) == 0)
- return &command_table[i];
-
- /* This command is not in our predefined command table. Perhaps
- it is a user defined command. */
- for (i = 0; i < user_command_array_len; i++)
- if (user_command_array[i] &&
- (strcmp (user_command_array[i]->name, string) == 0))
- return user_command_array[i];
-
- /* We never heard of this command. */
- return (COMMAND *) -1;
-}
-
-
-/* input_text_offset is right at the command prefix character.
- Read the next token to determine what to do. Return zero
- if there's no known command or macro after the prefix character. */
-static int
-read_command (void)
-{
- COMMAND *entry;
- int old_text_offset = input_text_offset++;
-
- free_and_clear (&command);
- command = read_token ();
-
- /* Check to see if this command is a macro. If so, execute it here. */
- {
- MACRO_DEF *def;
-
- def = find_macro (command);
-
- if (def)
- {
- /* We disallow recursive use of a macro call. Inhibit the expansion
- of this macro during the life of its execution. */
- if (!(def->flags & ME_RECURSE))
- def->inhibited = 1;
-
- executing_macro++;
- execute_macro (def);
- executing_macro--;
-
- if (!(def->flags & ME_RECURSE))
- def->inhibited = 0;
-
- return 1;
- }
- }
-
- if (only_macro_expansion)
- {
- /* Back up to the place where we were called, so the
- caller will have a chance to process this non-macro. */
- input_text_offset = old_text_offset;
- return 0;
- }
-
- /* Perform alias expansion */
- command = alias_expand (command);
-
- if (enclosure_command (command))
- {
- remember_brace (enclosure_expand);
- enclosure_expand (START, output_paragraph_offset, 0);
- return 0;
- }
-
- entry = get_command_entry (command);
- if (entry == (COMMAND *)-1)
- {
- line_error (_("Unknown command `%s'"), command);
- return 0;
- }
-
- if (entry->argument_in_braces == BRACE_ARGS)
- remember_brace (entry->proc);
- else if (entry->argument_in_braces == MAYBE_BRACE_ARGS)
- {
- if (curchar () == '{')
- remember_brace (entry->proc);
- else
- { /* No braces, so arg is next char. */
- int ch;
- int saved_offset = output_paragraph_offset;
- (*(entry->proc)) (START, output_paragraph_offset, 0);
-
- /* Possibilities left for the next character: @ (error), }
- (error), whitespace (skip) anything else (normal char). */
- skip_whitespace ();
- ch = curchar ();
- if (ch == '@')
- {
- line_error (_("Use braces to give a command as an argument to @%s"),
- entry->name);
- return 0;
- }
- else if (ch == '}')
- {
- /* Our caller will give the error message, because this }
- won't match anything. */
- return 0;
- }
-
- add_char (ch);
- input_text_offset++;
- (*(entry->proc)) (END, saved_offset, output_paragraph_offset);
- return 1;
- }
- }
-
- /* Get here if we have BRACE_ARGS, NO_BRACE_ARGS, or MAYBE_BRACE_ARGS
- with braces. */
- (*(entry->proc)) (START, output_paragraph_offset, 0);
- return 1;
-}
-
-/* Okay, we are ready to start the conversion. Call the reader on
- some text, and fill the text as it is output. Handle commands by
- remembering things like open braces and the current file position on a
- stack, and when the corresponding close brace is found, you can call
- the function with the proper arguments. Although the filling isn't
- necessary for HTML, it should do no harm. */
-void
-reader_loop (void)
-{
- int character;
- int done = 0;
-
- while (!done)
- {
- if (input_text_offset >= input_text_length)
- break;
-
- character = curchar ();
-
- /* If only_macro_expansion, only handle macros and leave
- everything else intact. */
- if (!only_macro_expansion && !in_fixed_width_font
- && ((!html && !xml) || escape_html)
- && (character == '\'' || character == '`')
- && input_text[input_text_offset + 1] == character)
- {
- if (html)
- {
- input_text_offset += 2;
- add_word (character == '`' ? "&ldquo;" : "&rdquo;");
- continue;
- }
- else if (xml)
- {
- input_text_offset += 2;
- xml_insert_entity (character == '`' ? "ldquo" : "rdquo");
- continue;
- }
- else
- {
- input_text_offset++;
- character = '"';
- }
- }
-
- /* Convert --- to --. */
- if (!only_macro_expansion && character == '-' && !in_fixed_width_font
- && ((!html && !xml) || escape_html))
- {
- int dash_count = 0;
-
- /* Get the number of consequtive dashes. */
- while (input_text[input_text_offset] == '-')
- {
- dash_count++;
- input_text_offset++;
- }
-
- /* Eat one dash. */
- dash_count--;
-
- if (html || xml)
- {
- if (dash_count == 0)
- add_char ('-');
- else
- while (dash_count > 0)
- {
- if (dash_count >= 2)
- {
- if (html)
- add_word ("&mdash;");
- else
- xml_insert_entity ("mdash");
- dash_count -= 2;
- }
- else if (dash_count >= 1)
- {
- if (html)
- add_word ("&ndash;");
- else
- xml_insert_entity ("ndash");
- dash_count--;
- }
- }
- }
- else
- {
- add_char ('-');
- while (--dash_count > 0)
- add_char ('-');
- }
-
- continue;
- }
-
- /* If this is a whitespace character, then check to see if the line
- is blank. If so, advance to the carriage return. */
- if (!only_macro_expansion && whitespace (character))
- {
- int i = input_text_offset + 1;
-
- while (i < input_text_length && whitespace (input_text[i]))
- i++;
-
- if (i == input_text_length || input_text[i] == '\n')
- {
- if (i == input_text_length)
- i--;
-
- input_text_offset = i;
- character = curchar ();
- }
- }
-
- if (character == '\n')
- line_number++;
-
- switch (character)
- {
- case '*': /* perhaps we are at a menu */
- /* We used to check for this in the \n case but an @c in a
- menu swallows its newline, so check here instead. */
- if (!only_macro_expansion && in_menu
- && input_text_offset + 1 < input_text_length
- && input_text_offset > 0
- && input_text[input_text_offset-1] == '\n')
- handle_menu_entry ();
- else
- { /* Duplicate code from below, but not worth twisting the
- fallthroughs to get down there. */
- add_char (character);
- input_text_offset++;
- }
- break;
-
- /* Escapes for HTML unless we're outputting raw HTML. Do
- this always, even if SGML rules don't require it since
- that's easier and safer for non-conforming browsers. */
- case '&':
- if (html && escape_html)
- add_word ("&amp;");
- else
- add_char (character);
- input_text_offset++;
- break;
-
- case '<':
- if (html && escape_html)
- add_word ("&lt;");
- else if (xml && escape_html)
- xml_insert_entity ("lt");
- else
- add_char (character);
- input_text_offset++;
- break;
-
- case '>':
- if (html && escape_html)
- add_word ("&gt;");
- else if (xml && escape_html)
- xml_insert_entity ("gt");
- else
- add_char (character);
- input_text_offset++;
- break;
-
- case COMMAND_PREFIX: /* @ */
- if (read_command () || !only_macro_expansion)
- break;
-
- /* FALLTHROUGH (usually) */
- case '{':
- /* Special case. We're not supposed to see this character by itself.
- If we do, it means there is a syntax error in the input text.
- Report the error here, but remember this brace on the stack so
- we can ignore its partner. */
- if (!only_macro_expansion)
- {
- if (command && !STREQ (command, "math"))
- {
- line_error (_("Misplaced %c"), '{');
- remember_brace (misplaced_brace);
- }
- else
- /* We don't mind `extra' braces inside @math. */
- remember_brace (cm_no_op);
- /* remember_brace advances input_text_offset. */
- break;
- }
-
- /* FALLTHROUGH (usually) */
- case '}':
- if (!only_macro_expansion)
- {
- pop_and_call_brace ();
- input_text_offset++;
- break;
- }
-
- /* FALLTHROUGH (usually) */
- default:
- add_char (character);
- input_text_offset++;
- }
- }
- if (macro_expansion_output_stream && !only_macro_expansion)
- maybe_write_itext (input_text, input_text_offset);
-}
-
-static void
-init_brace_stack (void)
-{
- brace_stack = NULL;
-}
-
-/* Remember the current output position here. Save PROC
- along with it so you can call it later. */
-static void
-remember_brace_1 (COMMAND_FUNCTION (*proc), int position)
-{
- BRACE_ELEMENT *new = xmalloc (sizeof (BRACE_ELEMENT));
- new->next = brace_stack;
- new->proc = proc;
- new->command = command ? xstrdup (command) : "";
- new->pos = position;
- new->line = line_number;
- new->in_fixed_width_font = in_fixed_width_font;
- brace_stack = new;
-}
-
-static void
-remember_brace (COMMAND_FUNCTION (*proc))
-{
- if (curchar () != '{')
- line_error (_("%c%s expected braces"), COMMAND_PREFIX, command);
- else
- input_text_offset++;
- remember_brace_1 (proc, output_paragraph_offset);
-}
-
-/* Pop the top of the brace stack, and call the associated function
- with the args END and POS. */
-static void
-pop_and_call_brace (void)
-{
- if (brace_stack == NULL)
- {
- line_error (_("Unmatched }"));
- return;
- }
-
- {
- BRACE_ELEMENT *temp;
-
- int pos = brace_stack->pos;
- COMMAND_FUNCTION *proc = brace_stack->proc;
- in_fixed_width_font = brace_stack->in_fixed_width_font;
-
- /* Reset current command, so the proc can know who it is. This is
- used in cm_accent. */
- command = brace_stack->command;
-
- temp = brace_stack->next;
- free (brace_stack);
- brace_stack = temp;
-
- (*proc) (END, pos, output_paragraph_offset);
- }
-}
-
-/* Shift all of the markers in `brace_stack' by AMOUNT. */
-static void
-adjust_braces_following (int here, int amount)
-{
- BRACE_ELEMENT *stack = brace_stack;
-
- while (stack)
- {
- if (stack->pos >= here)
- stack->pos += amount;
- stack = stack->next;
- }
-}
-
-/* Return the string which invokes PROC; a pointer to a function.
- Always returns the first function in the command table if more than
- one matches PROC. */
-static const char *
-find_proc_name (COMMAND_FUNCTION (*proc))
-{
- int i;
-
- for (i = 0; command_table[i].name; i++)
- if (proc == command_table[i].proc)
- return command_table[i].name;
- return _("NO_NAME!");
-}
-
-/* You call discard_braces () when you shouldn't have any braces on the stack.
- I used to think that this happens for commands that don't take arguments
- in braces, but that was wrong because of things like @code{foo @@}. So now
- I only detect it at the beginning of nodes. */
-void
-discard_braces (void)
-{
- if (!brace_stack)
- return;
-
- while (brace_stack)
- {
- if (brace_stack->proc != misplaced_brace)
- {
- const char *proc_name;
-
- proc_name = find_proc_name (brace_stack->proc);
- file_line_error (input_filename, brace_stack->line,
- _("%c%s missing close brace"), COMMAND_PREFIX,
- proc_name);
- pop_and_call_brace ();
- }
- else
- {
- BRACE_ELEMENT *temp;
- temp = brace_stack->next;
- free (brace_stack);
- brace_stack = temp;
- }
- }
-}
-
-/* Return the 0-based number of the current output column */
-int
-current_output_column (void)
-{
- int i, column;
-
- for (i = output_paragraph_offset; i > 0 && output_paragraph[i - 1] != '\n';
- i--)
- ;
- if (i == 0)
- column = output_paragraph_start_column;
- else
- column = 0;
- while (i < output_paragraph_offset)
- {
- int j;
-
- /* Find a span of non-control characters */
- for (j = i; j < output_paragraph_offset; j++)
- {
- char c;
-
- c = output_paragraph[j];
- if ((0 <= c && c < ' ') || c == '\t' || c == NON_BREAKING_SPACE)
- break;
- }
- if (i < j)
- {
- column += mbsnwidth ((char *)(output_paragraph + i), j - i, 0);
- i = j;
- }
- if (i < output_paragraph_offset)
- {
- char c;
-
- /* Handle a control character */
- c = output_paragraph[i];
- if (c == '\t')
- {
- column = (column + 8) & ~0x7;
- if (column > fill_column)
- column = fill_column;
- }
- else if (c == NON_BREAKING_SPACE)
- column++;
- else
- {
- /* ASCII control characters appear as two characters in the
- output (e.g., ^A). */
- if (!(0 <= c && c < ' '))
- abort ();
- column += 2;
- }
- i++;
- }
- }
- return column;
-}
-
-void
-#if defined (VA_FPRINTF) && __STDC__
-add_word_args (const char *format, ...)
-#else
-add_word_args (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
- char buffer[2000]; /* xx no fixed limits */
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- VA_START (ap, format);
-#ifdef VA_SPRINTF
- VA_SPRINTF (buffer, format, ap);
-#else
- sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_SPRINTF */
- va_end (ap);
- add_word (buffer);
-}
-
-/* Add STRING to output_paragraph. */
-void
-add_word (char *string)
-{
- while (*string)
- add_char (*string++);
-}
-
-/* Like add_word, but inhibits conversion of whitespace into &nbsp;.
- Use this to output HTML directives with embedded blanks, to make
- them @w-safe. */
-void
-add_html_elt (char *string)
-{
- in_html_elt++;
- add_word (string);
- in_html_elt--;
-}
-
-/* These two functions below, add_html_block_elt and add_html_block_elt_args,
- are mixtures of add_html_elt and add_word_args. They inform makeinfo that
- the current HTML element being inserted should not be enclosed in a <p>
- element. */
-void
-add_html_block_elt (char *string)
-{
- in_html_block_level_elt++;
- add_word (string);
- in_html_block_level_elt--;
-}
-
-void
-#if defined (VA_FPRINTF) && __STDC__
-add_html_block_elt_args (const char *format, ...)
-#else
-add_html_block_elt_args (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
- char buffer[2000]; /* xx no fixed limits */
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
-
- VA_START (ap, format);
-#ifdef VA_SPRINTF
- VA_SPRINTF (buffer, format, ap);
-#else
- sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_SPRINTF */
- va_end (ap);
- add_html_block_elt (buffer);
-}
-
-/* Here is another awful kludge, used in add_char. Ordinarily, macro
- expansions take place in the body of the document, and therefore we
- should html_output_head when we see one. But there's an exception: a
- macro call might take place within @copying, and that does not start
- the real output, even though we fully expand the copying text.
-
- So we need to be able to check if we are defining the @copying text.
- We do this by looking back through the insertion stack. */
-static int
-defining_copying (void)
-{
- INSERTION_ELT *i;
- for (i = insertion_stack; i; i = i->next)
- {
- if (i->insertion == copying)
- return 1;
- }
- return 0;
-}
-
-/* Output the header for Info.
- html fixxme: should output this as trailer on first page (at least). */
-
-static void
-info_output_head (void)
-{
- add_word_args (gdt("This is %s, produced by makeinfo version %s from %s.\n"),
- output_filename, VERSION, input_filename);
-
- /* Start afresh with whatever real text we have. */
- close_paragraph ();
-
- /* We do not want indentation in what follows, which is usually going
- to be a node marker (CTRL-_). */
- if (inhibit_paragraph_indentation == 0)
- inhibit_paragraph_indentation = -1;
-}
-
-void
-output_head (void)
-{
- if (output_head_p) /* no-op if we're mistakenly called twice */
- return;
- output_head_p = 1;
-
- if (html)
- html_output_head ();
- else if (xml)
- ; /* handled differently, via xml_begin_document */
- else if (no_headers)
- ; /* no header for plain text */
- else
- info_output_head ();
-}
-
-
-/* Add the character to the current paragraph. If filling_enabled is
- nonzero, then do filling as well. */
-void
-add_char (int character)
-{
- if (xml)
- {
- xml_add_char (character);
- return;
- }
-
- /* If we are avoiding outputting headers, and we are currently
- in a menu, then simply return. But if we're only expanding macros,
- then we're being called from glean_node_from_menu to try to
- remember a menu reference, and we need that so we can do defaulting. */
- if (no_headers && !only_macro_expansion && (in_menu || in_detailmenu))
- return;
-
- /* If we are adding a character now, then we don't have to
- ignore close_paragraph () calls any more. */
- if (must_start_paragraph && character != '\n')
- {
- int column;
-
- must_start_paragraph = 0;
- line_already_broken = 0; /* The line is no longer broken. */
- column = current_output_column ();
- if (current_indent > column)
- indent (current_indent - column);
- }
-
- if (non_splitting_words
- && !(html && in_html_elt)
- && strchr (" \t\n", character))
- {
- if (html || docbook)
- { /* Seems cleaner to use &nbsp; than an 8-bit char. */
- int saved_escape_html = escape_html;
- escape_html = 0;
- add_word ("&nbsp");
- escape_html = saved_escape_html;
- character = ';';
- }
- else
- character = NON_BREAKING_SPACE; /* restored in flush_output */
- }
-
- insertion_paragraph_closed = 0;
-
- switch (character)
- {
- case '\n':
- if (!filling_enabled && !(html && (in_menu || in_detailmenu)))
- {
- insert ('\n');
-
- if (force_flush_right)
- {
- close_paragraph ();
- /* Hack to force single blank lines out in this mode. */
- flush_output ();
- }
-
- if (!no_indent && paragraph_is_open)
- indent (current_indent);
- break;
- }
- else if (end_of_sentence_p () && !french_spacing)
- /* CHARACTER is newline, filling is enabled, and we're at the
- end of a sentence. Insert an extra space, unless
- @frenchspacing is in effect. */
- {
- insert (' ');
- last_inserted_character = character;
- }
-
- if (last_char_was_newline)
- {
- if (html)
- last_char_was_newline++;
- close_paragraph ();
- pending_indent = 0;
- }
- else
- {
- last_char_was_newline = 1;
- if (html)
- insert ('\n');
- else
- insert (' ');
- }
- break;
-
- default: /* not at newline */
- {
- int column;
- int suppress_insert = 0;
-
- if ((character == ' ') && (last_char_was_newline))
- {
- if (!paragraph_is_open)
- {
- pending_indent++;
- return;
- }
- }
-
- /* This is a sad place to do this, but it seems highly desirable
- to not force any particular order on the front matter
- commands. This way, the document can do @settitle,
- @documentlanguage, etc, in any order and with any omissions,
- and we'll still output the header ("produced by makeinfo",
- HTML <head>, etc.) `just in time'. */
- if ((executing_macro || !executing_string)
- && !only_macro_expansion
- && !defining_copying ()
- && !output_head_p)
- {
- output_head ();
- }
-
- if (!paragraph_is_open)
- {
- start_paragraph ();
- /* If the paragraph is supposed to be indented a certain
- way, then discard all of the pending whitespace.
- Otherwise, we let the whitespace stay. */
- if (!paragraph_start_indent)
- indent (pending_indent);
- pending_indent = 0;
-
- /* This check for in_html_block_level_elt prevents <p> from being
- inserted when we already have html markup starting a paragraph,
- as with <ul> and <h1> and the like. */
- if (html && !in_html_block_level_elt)
- {
- if ((in_menu || in_detailmenu) && in_menu_item)
- {
- insert_string ("</li></ul>\n");
- in_menu_item = 0;
- }
- insert_string ("<p>");
- in_paragraph = 1;
- adjust_braces_following (0, 3); /* adjust for <p> */
- }
- }
-
- output_paragraph[output_paragraph_offset] = character;
- output_paragraph_offset++;
- column = current_output_column ();
- output_paragraph_offset--;
- if (column > fill_column)
- {
- if (filling_enabled && !html)
- {
- int temp = output_paragraph_offset;
- while (--temp > 0 && output_paragraph[temp] != '\n')
- {
- /* If we have found a space, we have the place to break
- the line. */
- if (output_paragraph[temp] == ' ')
- {
- /* Remove trailing whitespace from output. */
- while (temp && whitespace (output_paragraph[temp - 1]))
- temp--;
-
- /* If we went back all the way to the newline of the
- preceding line, it probably means that the word we
- are adding is itself wider than the space that the
- indentation and the fill_column let us use. In
- that case, do NOT insert another newline, since it
- won't help. Just indent to current_indent and
- leave it alone, since that's the most we can do. */
- if (temp && output_paragraph[temp - 1] != '\n')
- output_paragraph[temp++] = '\n';
-
- /* We have correctly broken the line where we want
- to. What we don't want is spaces following where
- we have decided to break the line. We get rid of
- them. */
- {
- int t1 = temp;
-
- for (;; t1++)
- {
- if (t1 == output_paragraph_offset)
- {
- if (whitespace (character))
- suppress_insert = 1;
- break;
- }
- if (!whitespace (output_paragraph[t1]))
- break;
- }
-
- if (t1 != temp)
- {
- adjust_braces_following (temp, (- (t1 - temp)));
- memmove (&output_paragraph[temp],
- &output_paragraph[t1],
- output_paragraph_offset - t1);
- output_paragraph_offset -= (t1 - temp);
- }
- }
-
- /* Filled, but now indent if that is right. */
- if (indented_fill && current_indent > 0)
- {
- int buffer_len = ((output_paragraph_offset - temp)
- + current_indent);
- char *temp_buffer = xmalloc (buffer_len);
- int indentation = 0;
-
- /* We have to shift any markers that are in
- front of the wrap point. */
- adjust_braces_following (temp, current_indent);
-
- while (current_indent > 0 &&
- indentation != current_indent)
- temp_buffer[indentation++] = ' ';
-
- memcpy ((char *) &temp_buffer[current_indent],
- (char *) &output_paragraph[temp],
- buffer_len - current_indent);
-
- if (output_paragraph_offset + buffer_len
- >= paragraph_buffer_len)
- {
- unsigned char *tt = xrealloc
- (output_paragraph,
- (paragraph_buffer_len += buffer_len));
- output_paragraph = tt;
- }
- memcpy ((char *) &output_paragraph[temp],
- temp_buffer, buffer_len);
- output_paragraph_offset += current_indent;
- free (temp_buffer);
- }
- break;
- }
- }
- }
- }
-
- if (!suppress_insert)
- {
- insert (character);
- last_inserted_character = character;
- }
- last_char_was_newline = 0;
- line_already_broken = 0;
- }
- }
-}
-
-/* Add a character and store its position in meta_char_pos. */
-void
-add_meta_char (int character)
-{
- meta_char_pos = output_paragraph_offset;
- add_char (character);
-}
-
-/* Insert CHARACTER into `output_paragraph'. */
-void
-insert (int character)
-{
- /* We don't want to strip trailing whitespace in multitables. Otherwise
- horizontal separators confuse the font locking in Info mode in Emacs,
- because it looks like a @subsection. Adding a trailing space to those
- lines fixes it. */
- if (character == '\n' && !html && !xml && !multitable_active)
- {
- while (output_paragraph_offset
- && whitespace (output_paragraph[output_paragraph_offset-1]))
- output_paragraph_offset--;
- }
-
- output_paragraph[output_paragraph_offset++] = character;
- if (output_paragraph_offset == paragraph_buffer_len)
- {
- output_paragraph =
- xrealloc (output_paragraph, (paragraph_buffer_len += 100));
- }
-}
-
-/* Insert the null-terminated string STRING into `output_paragraph'. */
-void
-insert_string (const char *string)
-{
- while (*string)
- insert (*string++);
-}
-
-
-/* Sentences might have these characters after the period (or whatever). */
-#define POST_SENTENCE(c) ((c) == ')' || (c) == '\'' || (c) == '"' \
- || (c) == ']')
-
-/* Return true if at an end-of-sentence character, possibly followed by
- post-sentence punctuation to ignore. */
-static int
-end_of_sentence_p (void)
-{
- int loc = output_paragraph_offset - 1;
-
- /* If nothing has been output, don't check output_paragraph[-1]. */
- if (loc < 0)
- return 0;
-
- /* A post-sentence character that is at meta_char_pos is not really
- a post-sentence character; it was produced by a markup such as
- @samp. We don't want the period inside @samp to be treated as a
- sentence ender. */
- while (loc > 0
- && loc != meta_char_pos && POST_SENTENCE (output_paragraph[loc]))
- loc--;
- return loc != meta_char_pos && sentence_ender (output_paragraph[loc]);
-}
-
-
-/* Remove upto COUNT characters of whitespace from the
- the current output line. If COUNT is less than zero,
- then remove until none left. */
-void
-kill_self_indent (int count)
-{
- /* Handle infinite case first. */
- if (count < 0)
- {
- while (output_paragraph_offset)
- {
- if (whitespace (output_paragraph[output_paragraph_offset - 1]))
- output_paragraph_offset--;
- else
- break;
- }
- }
- else
- {
- while (output_paragraph_offset && count--)
- if (whitespace (output_paragraph[output_paragraph_offset - 1]))
- output_paragraph_offset--;
- else
- break;
- }
-}
-
-/* Nonzero means do not honor calls to flush_output (). */
-static int flushing_ignored = 0;
-
-/* Prevent calls to flush_output () from having any effect. */
-void
-inhibit_output_flushing (void)
-{
- flushing_ignored++;
-}
-
-/* Allow calls to flush_output () to write the paragraph data. */
-void
-uninhibit_output_flushing (void)
-{
- flushing_ignored--;
-}
-
-void
-flush_output (void)
-{
- int i;
-
- if (!output_paragraph_offset || flushing_ignored)
- return;
-
- for (i = 0; i < output_paragraph_offset; i++)
- {
- if (output_paragraph[i] == '\n')
- {
- output_line_number++;
- node_line_number++;
- }
-
- /* If we turned on the 8th bit for a space inside @w, turn it back off
- for output. Don't do this for HTML, since the nbsp character is valid
- input and must be passed along to the browser. */
- if (!html && output_paragraph[i] == NON_BREAKING_SPACE)
- output_paragraph[i] = ' ';
- }
-
- fwrite (output_paragraph, 1, output_paragraph_offset, output_stream);
-
- output_position += output_paragraph_offset;
- output_paragraph_start_column = current_output_column ();
- output_paragraph_offset = 0;
- meta_char_pos = 0;
-}
-
-/* How to close a paragraph controlling the number of lines between
- this one and the last one. */
-
-/* Paragraph spacing is controlled by this variable. It is the number of
- blank lines that you wish to appear between paragraphs. A value of
- 1 creates a single blank line between paragraphs. */
-int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING;
-
-static void
-close_paragraph_with_lines (int lines)
-{
- int old_spacing = paragraph_spacing;
- paragraph_spacing = lines;
- close_paragraph ();
- paragraph_spacing = old_spacing;
-}
-
-/* Close the current paragraph, leaving no blank lines between them. */
-void
-close_single_paragraph (void)
-{
- close_paragraph_with_lines (0);
-}
-
-/* Close a paragraph after an insertion has ended. */
-void
-close_insertion_paragraph (void)
-{
- if (!insertion_paragraph_closed)
- {
- /* Close the current paragraph, breaking the line. */
- close_single_paragraph ();
-
- /* Start a new paragraph, with the correct indentation for the now
- current insertion level (one above the one that we are ending). */
- start_paragraph ();
-
- /* Tell `close_paragraph' that the previous line has already been
- broken, so it should insert one less newline. */
- line_already_broken = 1;
-
- /* Tell functions such as `add_char' we've already found a newline. */
- ignore_blank_line ();
- }
- else
- {
- int column;
-
- /* If the insertion paragraph is closed already, then we are seeing
- two `@end' commands in a row. Note that the first one we saw was
- handled in the first part of this if-then-else clause, and at that
- time `start_paragraph' was called, partially to handle the proper
- indentation of the current line. However, the indentation level
- may have just changed again, so we may have to outdent the current
- line to the new indentation level. */
- column = current_output_column ();
- if (current_indent < column)
- kill_self_indent (column - current_indent);
- }
-
- insertion_paragraph_closed = 1;
-}
-
-/* Close the currently open paragraph. */
-void
-close_paragraph (void)
-{
- int i;
-
- /* We don't need these newlines in XML and Docbook outputs for
- paragraph separation. We have the <para> element for that. */
- if (xml)
- return;
-
- /* The insertion paragraph is no longer closed. */
- insertion_paragraph_closed = 0;
-
- if (paragraph_is_open && !must_start_paragraph)
- {
- int tindex = output_paragraph_offset;
-
- /* Back up to last non-newline/space character, forcing all such
- subsequent characters to be newlines. This isn't strictly
- necessary, but a couple of functions use the presence of a newline
- to make decisions. */
- for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex)
- {
- int c = output_paragraph[tindex];
-
- if (c == ' '|| c == '\n')
- output_paragraph[tindex] = '\n';
- else
- break;
- }
-
- /* All trailing whitespace is ignored. */
- output_paragraph_offset = ++tindex;
-
- /* Break the line if that is appropriate. */
- if (paragraph_spacing >= 0)
- insert ('\n');
-
- /* Add as many blank lines as is specified in `paragraph_spacing'. */
- if (!force_flush_right)
- {
- for (i = 0; i < (paragraph_spacing - line_already_broken); i++)
- {
- insert ('\n');
- /* Don't need anything extra for HTML in usual case of no
- extra paragraph spacing. */
- if (html && i > 0)
- insert_string ("<br>");
- }
- }
-
- /* If we are doing flush right indentation, then do it now
- on the paragraph (really a single line). */
- if (force_flush_right)
- do_flush_right_indentation ();
-
- flush_output ();
- paragraph_is_open = 0;
- no_indent = 0;
- }
-
- ignore_blank_line ();
-}
-
-/* Make the last line just read look as if it were only a newline. */
-void
-ignore_blank_line (void)
-{
- last_inserted_character = '\n';
- last_char_was_newline = 1;
-}
-
-/* Align the end of the text in output_paragraph with fill_column. The last
- character in output_paragraph is '\n'. */
-static void
-do_flush_right_indentation (void)
-{
- char *temp;
-
- kill_self_indent (-1);
-
- if (output_paragraph[0] != '\n')
- {
- int width;
-
- width = mbsnwidth ((char *)output_paragraph, output_paragraph_offset - 1,
- 0) + 1;
- if (width < fill_column)
- {
- int i;
-
- if (output_paragraph_offset + (fill_column - width)
- >= paragraph_buffer_len)
- output_paragraph =
- xrealloc (output_paragraph,
- (paragraph_buffer_len += fill_column));
-
- temp = xmalloc (output_paragraph_offset);
- memcpy (temp, (char *)output_paragraph, output_paragraph_offset);
-
- for (i = 0; i < fill_column - width; i++)
- output_paragraph[i] = ' ';
-
- memcpy ((char *)output_paragraph + i, temp, output_paragraph_offset);
- free (temp);
- output_paragraph_offset += i;
- adjust_braces_following (0, i);
- }
- }
-}
-
-/* Begin a new paragraph. */
-void
-start_paragraph (void)
-{
- /* First close existing one. */
- if (paragraph_is_open)
- close_paragraph ();
-
- /* In either case, the insertion paragraph is no longer closed. */
- insertion_paragraph_closed = 0;
-
- /* However, the paragraph is open! */
- paragraph_is_open = 1;
-
- /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph ()
- had to be called before we would allow any other paragraph operations
- to have an effect. */
- if (!must_start_paragraph)
- {
- int amount_to_indent = 0;
-
- /* If doing indentation, then insert the appropriate amount. */
- if (!no_indent)
- {
- int column;
-
- if (inhibit_paragraph_indentation)
- {
- amount_to_indent = current_indent;
- if (inhibit_paragraph_indentation < 0)
- inhibit_paragraph_indentation++;
- }
- else if (paragraph_start_indent < 0)
- amount_to_indent = current_indent;
- else
- amount_to_indent = current_indent + paragraph_start_indent;
-
- column = current_output_column ();
- if (amount_to_indent >= column)
- indent (amount_to_indent - column);
- }
- }
- else
- must_start_paragraph = 0;
-}
-
-/* Insert the indentation specified by AMOUNT. */
-void
-indent (int amount)
-{
- /* For every START_POS saved within the brace stack which will be affected
- by this indentation, bump that start pos forward. */
- adjust_braces_following (output_paragraph_offset, amount);
-
- while (--amount >= 0)
- insert (' ');
-}
-
-/* Search forward for STRING in input_text.
- FROM says where to start. */
-int
-search_forward (const char *string, int from)
-{
- int len = strlen (string);
-
- while (from < input_text_length)
- {
- if (strncmp (input_text + from, string, len) == 0)
- return from;
- from++;
- }
- return -1;
-}
-
-/* search_forward until n characters. */
-int
-search_forward_until_pos (char *string, int from, int end_pos)
-{
- int save_input_text_length = input_text_length;
- input_text_length = end_pos;
-
- from = search_forward (string, from);
-
- input_text_length = save_input_text_length;
-
- return from;
-}
-
-/* Return next non-whitespace and non-cr character. */
-int
-next_nonwhitespace_character (void)
-{
- /* First check the current input_text. Start from the next char because
- we already have input_text[input_text_offset] in ``current''. */
- int pos = input_text_offset + 1;
-
- while (pos < input_text_length)
- {
- if (!cr_or_whitespace(input_text[pos]))
- return input_text[pos];
- pos++;
- }
-
- { /* Can't find a valid character, so go through filestack
- in case we are doing @include or expanding a macro. */
- FSTACK *tos = filestack;
-
- while (tos)
- {
- int tmp_input_text_length = filestack->size;
- int tmp_input_text_offset = filestack->offset;
- char *tmp_input_text = filestack->text;
-
- while (tmp_input_text_offset < tmp_input_text_length)
- {
- if (!cr_or_whitespace(tmp_input_text[tmp_input_text_offset]))
- return tmp_input_text[tmp_input_text_offset];
- tmp_input_text_offset++;
- }
-
- tos = tos->next;
- }
- }
-
- return -1;
-}
-
-
-
-/* Replace " with \" and \ with \\. Used for alt tag in Info output.
- Return a newly-malloced string in all cases. */
-
-static char *
-bs_escape_quote (const char *src)
-{
- int c;
- char *dest = xmalloc (2 * strlen (src) + 1); /* can't need more. */
- char *p = dest;
-
- for (; c = *src; src++)
- {
- if (c == '"' || c == '\\')
- *p++ = '\\';
-
- *p++ = c;
- }
- *p = 0;
-
- return dest;
-}
-
-
-
-/* An external image is a reference, kind of. The parsing is (not
- coincidentally) similar, anyway. */
-void
-cm_image (int arg)
-{
- char *name_arg, *w_arg, *h_arg, *alt_arg, *ext_arg;
-
- if (arg == END)
- return;
-
- name_arg = get_xref_token (1); /* expands all macros in image */
- w_arg = get_xref_token (0);
- h_arg = get_xref_token (0);
- alt_arg = get_xref_token (1); /* expands all macros in alt text */
- ext_arg = get_xref_token (0);
-
- if (*name_arg)
- {
- struct stat file_info;
- char *pathname = NULL;
- unsigned ext_len = (ext_arg && *ext_arg) ? strlen (ext_arg) : 0;
- char *fullname = xmalloc (strlen (name_arg) + MAX (ext_len, 4) + 1);
-
- if (ext_arg && *ext_arg)
- {
- sprintf (fullname, "%s%s", name_arg, ext_arg);
- if (access (fullname, R_OK) != 0)
- pathname = get_file_info_in_path (fullname, include_files_path,
- &file_info);
-
- if (pathname == NULL)
- {
- /* Backwards compatibility (4.6 <= version < 4.7):
- try prefixing @image's EXTENSION parameter with a period. */
- sprintf (fullname, "%s.%s", name_arg, ext_arg);
- if (access (fullname, R_OK) != 0)
- pathname = get_file_info_in_path (fullname, include_files_path,
- &file_info);
- }
- }
- else
- {
- sprintf (fullname, "%s.png", name_arg);
- if (access (fullname, R_OK) != 0) {
- pathname = get_file_info_in_path (fullname,
- include_files_path, &file_info);
- if (pathname == NULL) {
- sprintf (fullname, "%s.jpg", name_arg);
- if (access (fullname, R_OK) != 0) {
- pathname = get_file_info_in_path (fullname,
- include_files_path,
- &file_info);
- if (pathname == NULL) {
- sprintf (fullname, "%s.gif", name_arg);
- if (access (fullname, R_OK) != 0) {
- pathname = get_file_info_in_path (fullname,
- include_files_path,
- &file_info);
- }
- }
- }
- }
- }
- }
-
- if (html)
- {
- int image_in_div = 0;
-
- if (pathname == NULL && access (fullname, R_OK) != 0)
- {
- line_error(_("@image file `%s' (for HTML) not readable: %s"),
- fullname, strerror (errno));
- return;
- }
- if (pathname != NULL && access (pathname, R_OK) != 0)
- {
- line_error (_("No such file `%s'"),
- fullname);
- return;
- }
-
- if (!paragraph_is_open)
- {
- add_html_block_elt ("<div class=\"block-image\">");
- image_in_div = 1;
- }
-
- add_html_elt ("<img src=");
- add_word_args ("\"%s\"", fullname);
- add_html_elt (" alt=");
- add_word_args ("\"%s\">",
- escape_string (*alt_arg ? text_expansion (alt_arg) : fullname));
-
- if (image_in_div)
- add_html_block_elt ("</div>");
- }
- else if (xml && docbook)
- xml_insert_docbook_image (name_arg);
- else if (xml)
- {
- extern int xml_in_para;
- extern int xml_no_para;
- int elt = xml_in_para ? INLINEIMAGE : IMAGE;
-
- if (!xml_in_para)
- xml_no_para++;
-
- xml_insert_element_with_attribute (elt,
- START, "width=\"%s\" height=\"%s\" name=\"%s\" extension=\"%s\"",
- w_arg, h_arg, name_arg, ext_arg);
- xml_insert_element (IMAGEALTTEXT, START);
- execute_string ("%s", alt_arg);
- xml_insert_element (IMAGEALTTEXT, END);
- xml_insert_element (elt, END);
-
- if (!xml_in_para)
- xml_no_para--;
- }
- else
- { /* Prefer foo.txt for Info/ASCII. Seems wrong nowadays. */
- FILE *image_file;
- char *txtpath = NULL;
- char *txtname = xmalloc (strlen (name_arg) + 4 + 1);
- strcpy (txtname, name_arg);
- strcat (txtname, ".txt");
- image_file = fopen (txtname, "r");
- if (image_file == NULL)
- {
- txtpath = get_file_info_in_path (txtname,
- include_files_path, &file_info);
- if (txtpath != NULL)
- image_file = fopen (txtpath, "r");
- }
-
- if (image_file != NULL
- || access (fullname, R_OK) == 0
- || (pathname != NULL && access (pathname, R_OK) == 0))
- {
- int ch;
- int save_inhibit_indentation = inhibit_paragraph_indentation;
- int save_filling_enabled = filling_enabled;
- int image_in_brackets = paragraph_is_open;
-
- /* Write magic ^@^H[image ...^@^H] cookie in the info file, if
- there's an accompanying bitmap. Otherwise just include the
- text image. In the plaintext output, always include the text
- image without the magic cookie. */
- int use_magic_cookie = !no_headers
- && access (fullname, R_OK) == 0 && !STREQ (fullname, txtname);
-
- inhibit_paragraph_indentation = 1;
- filling_enabled = 0;
- last_char_was_newline = 0;
-
- if (use_magic_cookie)
- {
- add_char ('\0');
- add_word ("\010[image");
-
- if (access (fullname, R_OK) == 0
- || (pathname != NULL && access (pathname, R_OK) == 0))
- add_word_args (" src=\"%s\"", fullname);
-
- if (*alt_arg)
- {
- char *expanded = text_expansion (alt_arg);
- char *escaped = bs_escape_quote (expanded);
- add_word_args (" alt=\"%s\"", escaped);
- free (expanded);
- free (escaped);
- }
- }
-
- if (image_file != NULL)
- {
- if (use_magic_cookie)
- add_word (" text=\"");
-
- if (image_in_brackets)
- add_char ('[');
-
- /* Maybe we need to remove the final newline if the image
- file is only one line to allow in-line images. On the
- other hand, they could just make the file without a
- final newline. */
- while ((ch = getc (image_file)) != EOF)
- {
- if (use_magic_cookie && (ch == '"' || ch == '\\'))
- add_char ('\\');
- add_char (ch);
- }
-
- if (image_in_brackets)
- add_char (']');
-
- if (use_magic_cookie)
- add_char ('"');
-
- if (fclose (image_file) != 0)
- perror (txtname);
- }
-
- if (use_magic_cookie)
- {
- add_char ('\0');
- add_word ("\010]");
- }
-
- inhibit_paragraph_indentation = save_inhibit_indentation;
- filling_enabled = save_filling_enabled;
- }
- else
- warning (_("@image file `%s' (for text) unreadable: %s"),
- txtname, strerror (errno));
- }
-
- free (fullname);
- if (pathname)
- free (pathname);
- }
- else
- line_error (_("@image missing filename argument"));
-
- if (name_arg)
- free (name_arg);
- if (w_arg)
- free (w_arg);
- if (h_arg)
- free (h_arg);
- if (alt_arg)
- free (alt_arg);
- if (ext_arg)
- free (ext_arg);
-}
-
-/* Conditionals. */
-
-/* A structure which contains `defined' variables. */
-typedef struct defines {
- struct defines *next;
- char *name;
- char *value;
-} DEFINE;
-
-/* The linked list of `set' defines. */
-DEFINE *defines = NULL;
-
-/* Add NAME to the list of `set' defines. */
-static void
-set (char *name, char *value)
-{
- DEFINE *temp;
-
- for (temp = defines; temp; temp = temp->next)
- if (strcmp (name, temp->name) == 0)
- {
- free (temp->value);
- temp->value = xstrdup (value);
- return;
- }
-
- temp = xmalloc (sizeof (DEFINE));
- temp->next = defines;
- temp->name = xstrdup (name);
- temp->value = xstrdup (value);
- defines = temp;
-
- if (xml && !docbook)
- {
- xml_insert_element_with_attribute (SETVALUE, START, "name=\"%s\"", name);
- execute_string ("%s", value);
- xml_insert_element (SETVALUE, END);
- }
-}
-
-/* Remove NAME from the list of `set' defines. */
-static void
-clear (char *name)
-{
- DEFINE *temp, *last;
-
- last = NULL;
- temp = defines;
-
- while (temp)
- {
- if (strcmp (temp->name, name) == 0)
- {
- if (last)
- last->next = temp->next;
- else
- defines = temp->next;
-
- free (temp->name);
- free (temp->value);
- free (temp);
- break;
- }
- last = temp;
- temp = temp->next;
- }
-
- if (xml && !docbook)
- {
- xml_insert_element_with_attribute (CLEARVALUE, START, "name=\"%s\"", name);
- xml_insert_element (CLEARVALUE, END);
- }
-}
-
-/* Return the value of NAME. The return value is NULL if NAME is unset. */
-static char *
-set_p (char *name)
-{
- DEFINE *temp;
-
- for (temp = defines; temp; temp = temp->next)
- if (strcmp (temp->name, name) == 0)
- return temp->value;
-
- return NULL;
-}
-
-/* Create a variable whose name appears as the first word on this line. */
-void
-cm_set (void)
-{
- handle_variable (SET);
-}
-
-/* Remove a variable whose name appears as the first word on this line. */
-void
-cm_clear (void)
-{
- handle_variable (CLEAR);
-}
-
-void
-cm_ifset (void)
-{
- handle_variable (IFSET);
-}
-
-void
-cm_ifclear (void)
-{
- handle_variable (IFCLEAR);
-}
-
-/* This command takes braces, but we parse the contents specially, so we
- don't use the standard brace popping code.
-
- The syntax @ifeq{arg1, arg2, texinfo-commands} performs texinfo-commands
- if ARG1 and ARG2 caselessly string compare to the same string, otherwise,
- it produces no output. */
-void
-cm_ifeq (void)
-{
- char **arglist;
-
- arglist = get_brace_args (quote_none);
-
- if (arglist)
- {
- if (array_len (arglist) > 1)
- {
- if ((mbscasecmp (arglist[0], arglist[1]) == 0) &&
- (arglist[2]))
- execute_string ("%s\n", arglist[2]);
- }
-
- free_array (arglist);
- }
-}
-
-void
-cm_value (int arg, int start_pos, int end_pos)
-{
- static int value_level = 0, saved_meta_pos = -1;
-
- /* xml_add_char() skips any content inside menus when output format is
- Docbook, so @value{} is no use there. Also start_pos and end_pos does not
- get updated, causing name to be empty string. So just return. */
- if (docbook && in_menu)
- return;
-
- /* All the text after @value{ upto the matching } will eventually
- disappear from output_paragraph, when this function is called
- with ARG == END. If the text produced until then sets
- meta_char_pos, we will need to restore it to the value it had
- before @value was seen. So we need to save the previous value
- of meta_char_pos here. */
- if (arg == START)
- {
- /* If we are already inside some outer @value, don't overwrite
- the value saved in saved_meta_pos. */
- if (!value_level)
- saved_meta_pos = meta_char_pos;
- value_level++;
- /* While the argument of @value is processed, we need to inhibit
- textual transformations like "--" into "-", since @set didn't
- do that when it grabbed the name of the variable. */
- in_fixed_width_font++;
- }
- else
- {
- char *name = (char *) &output_paragraph[start_pos];
- char *value;
- output_paragraph[end_pos] = 0;
- name = xstrdup (name);
- value = set_p (name);
- output_paragraph_offset = start_pos;
-
- /* Restore the previous value of meta_char_pos if the stuff
- inside this @value{} moved it. */
- if (saved_meta_pos == -1) /* can't happen inside @value{} */
- abort ();
- if (value_level == 1
- && meta_char_pos >= start_pos && meta_char_pos < end_pos)
- {
- meta_char_pos = saved_meta_pos;
- saved_meta_pos = -1;
- }
- value_level--;
- /* No need to decrement in_fixed_width_font, since before
- we are called with arg == END, the reader loop already
- popped the brace stack, which restored in_fixed_width_font,
- among other things. */
-
- if (value)
- {
- /* We need to get past the closing brace since the value may
- expand to a context-sensitive macro (e.g. @xref) and produce
- spurious warnings */
- input_text_offset++;
- execute_string ("%s", value);
- input_text_offset--;
- }
- else
- {
- warning (_("undefined flag: %s"), name);
- add_word_args (_("{No value for `%s'}"), name);
- }
-
- free (name);
- }
-}
-
-/* Set, clear, or conditionalize based on ACTION. */
-static void
-handle_variable (int action)
-{
- char *name;
-
- get_rest_of_line (0, &name);
- /* If we hit the end of text in get_rest_of_line, backing up
- input pointer will cause the last character of the last line
- be pushed back onto the input, which is wrong. */
- if (input_text_offset < input_text_length)
- backup_input_pointer ();
- handle_variable_internal (action, name);
- free (name);
-}
-
-static void
-handle_variable_internal (int action, char *name)
-{
- char *temp;
- int delimiter, additional_text_present = 0;
-
- /* Only the first word of NAME is a valid tag. */
- temp = name;
- delimiter = 0;
- while (*temp && (delimiter || !whitespace (*temp)))
- {
-/* #if defined (SET_WITH_EQUAL) */
- if (*temp == '"' || *temp == '\'')
- {
- if (*temp == delimiter)
- delimiter = 0;
- else
- delimiter = *temp;
- }
-/* #endif SET_WITH_EQUAL */
- temp++;
- }
-
- if (*temp)
- additional_text_present++;
-
- *temp = 0;
-
- if (!*name)
- line_error (_("%c%s requires a name"), COMMAND_PREFIX, command);
- else
- {
- switch (action)
- {
- case SET:
- {
- char *value;
-
-#if defined (SET_WITH_EQUAL)
- /* Allow a value to be saved along with a variable. The value is
- the text following an `=' sign in NAME, if any is present. */
-
- for (value = name; *value && *value != '='; value++);
-
- if (*value)
- *value++ = 0;
-
- if (*value == '"' || *value == '\'')
- {
- value++;
- value[strlen (value) - 1] = 0;
- }
-
-#else /* !SET_WITH_EQUAL */
- /* The VALUE of NAME is the remainder of the line sans
- whitespace. */
- if (additional_text_present)
- {
- value = temp + 1;
- canon_white (value);
- }
- else
- value = "";
-#endif /* !SET_WITH_VALUE */
-
- set (name, value);
- }
- break;
-
- case CLEAR:
- clear (name);
- break;
-
- case IFSET:
- case IFCLEAR:
- /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set,
- read lines from the the file until we reach a matching
- "@end CONDITION". This means that we only take note of
- "@ifset/clear" and "@end" commands. */
- {
- char condition[8];
- int condition_len;
- int orig_line_number = line_number;
-
- if (action == IFSET)
- strcpy (condition, "ifset");
- else
- strcpy (condition, "ifclear");
-
- condition_len = strlen (condition);
-
- if ((action == IFSET && !set_p (name))
- || (action == IFCLEAR && set_p (name)))
- {
- int level = 0, done = 0;
-
- while (!done && input_text_offset < input_text_length)
- {
- char *freeable_line, *line;
-
- get_rest_of_line (0, &freeable_line);
-
- for (line = freeable_line; whitespace (*line); line++);
-
- if (*line == COMMAND_PREFIX &&
- (strncmp (line + 1, condition, condition_len) == 0))
- level++;
- else if (strncmp (line, "@end", 4) == 0)
- {
- char *cname = line + 4;
- char *temp;
-
- while (*cname && whitespace (*cname))
- cname++;
- temp = cname;
-
- while (*temp && !whitespace (*temp))
- temp++;
- *temp = 0;
-
- if (strcmp (cname, condition) == 0)
- {
- if (!level)
- {
- done = 1;
- }
- else
- level--;
- }
- }
- free (freeable_line);
- }
-
- if (!done)
- file_line_error (input_filename, orig_line_number,
- _("Reached eof before matching @end %s"),
- condition);
-
- /* We found the end of a false @ifset/ifclear. If we are
- in a menu, back up over the newline that ends the ifset,
- since that newline may also begin the next menu entry. */
- break;
- }
- else
- {
- if (action == IFSET)
- begin_insertion (ifset);
- else
- begin_insertion (ifclear);
- }
- }
- break;
- }
- }
-}
-
-/* Execution of random text not in file. */
-typedef struct {
- char *string; /* The string buffer. */
- int size; /* The size of the buffer. */
- int in_use; /* Nonzero means string currently in use. */
-} EXECUTION_STRING;
-
-static EXECUTION_STRING **execution_strings = NULL;
-static int execution_strings_index = 0;
-static int execution_strings_slots = 0;
-
-static EXECUTION_STRING *
-get_execution_string (int initial_size)
-{
- int i = 0;
- EXECUTION_STRING *es = NULL;
-
- if (execution_strings)
- {
- for (i = 0; i < execution_strings_index; i++)
- if (execution_strings[i] && (execution_strings[i]->in_use == 0))
- {
- es = execution_strings[i];
- break;
- }
- }
-
- if (!es)
- {
- if (execution_strings_index + 1 >= execution_strings_slots)
- {
- execution_strings = xrealloc
- (execution_strings,
- (execution_strings_slots += 3) * sizeof (EXECUTION_STRING *));
- for (; i < execution_strings_slots; i++)
- execution_strings[i] = NULL;
- }
-
- execution_strings[execution_strings_index] =
- xmalloc (sizeof (EXECUTION_STRING));
- es = execution_strings[execution_strings_index];
- execution_strings_index++;
-
- es->size = 0;
- es->string = NULL;
- es->in_use = 0;
- }
-
- if (initial_size > es->size)
- {
- es->string = xrealloc (es->string, initial_size);
- es->size = initial_size;
- }
- return es;
-}
-
-/* Given a pointer to TEXT and its desired length NEW_LEN, find TEXT's
- entry in the execution_strings[] array and change the .STRING and
- .SIZE members of that entry as appropriate. */
-void
-maybe_update_execution_strings (char **text, unsigned int new_len)
-{
- int i = 0;
-
- if (execution_strings)
- {
- for (i = 0; i < execution_strings_index; i++)
- if (execution_strings[i] && (execution_strings[i]->in_use == 1) &&
- execution_strings[i]->string == *text)
- {
- /* Don't ever shrink the string storage in execution_strings[]!
- execute_string assumes that it is always big enough to store
- every possible execution_string, and will break if that's
- not true. So we only enlarge the string storage if the
- current size isn't big enough. */
- if (execution_strings[i]->size < new_len)
- {
- execution_strings[i]->string =
- *text = xrealloc (*text, new_len + 1);
- execution_strings[i]->size = new_len + 1;
- }
- return;
- }
- }
- /* We should *never* end up here, since if we are inside
- execute_string, TEXT is always in execution_strings[]. */
- abort ();
-}
-
-/* FIXME: this is an arbitrary limit. */
-#define EXECUTE_STRING_MAX 16*1024
-
-/* Execute the string produced by formatting the ARGs with FORMAT. This
- is like submitting a new file with @include. */
-void
-#if defined (VA_FPRINTF) && __STDC__
-execute_string (char *format, ...)
-#else
-execute_string (format, va_alist)
- char *format;
- va_dcl
-#endif
-{
- EXECUTION_STRING *es;
- char *temp_string, *temp_input_filename;
-#ifdef VA_FPRINTF
- va_list ap;
-#endif
- int insertion_level_at_start = insertion_level;
-
- es = get_execution_string (EXECUTE_STRING_MAX);
- temp_string = es->string;
- es->in_use = 1;
-
- VA_START (ap, format);
-#ifdef VA_SPRINTF
- VA_SPRINTF (temp_string, format, ap);
-#else
- sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif /* not VA_SPRINTF */
- va_end (ap);
-
- pushfile ();
- input_text_offset = 0;
- input_text = temp_string;
- input_text_length = strlen (temp_string);
- input_filename = xstrdup (input_filename);
- temp_input_filename = input_filename;
-
- executing_string++;
- reader_loop ();
-
- /* If insertion stack level changes during execution, that means a multiline
- command is used inside braces or @section ... kind of commands. */
- if (insertion_level_at_start != insertion_level && !executing_macro)
- {
- line_error (_("Multiline command %c%s used improperly"),
- COMMAND_PREFIX,
- command);
- /* We also need to keep insertion_level intact to make sure warnings are
- issued for @end ... command. */
- while (insertion_level > insertion_level_at_start)
- pop_insertion ();
- }
-
- popfile ();
- executing_string--;
- es->in_use = 0;
- free (temp_input_filename);
-}
-
-
-/* Return what would be output for STR (in newly-malloced memory), i.e.,
- expand Texinfo commands according to the current output format. If
- IMPLICIT_CODE is set, expand @code{STR}. This is generally used for
- short texts; filling, indentation, and html escapes are disabled. */
-
-char *
-expansion (char *str, int implicit_code)
-{
- return maybe_escaped_expansion (str, implicit_code, 0);
-}
-
-
-/* Do HTML escapes according to DO_HTML_ESCAPE. Needed in
- cm_printindex, q.v. */
-
-char *
-maybe_escaped_expansion (char *str, int implicit_code, int do_html_escape)
-{
- char *result;
-
- /* Inhibit indentation and filling, so that extra newlines
- are not added to the expansion. (This is undesirable if
- we write the expanded text to macro_expansion_output_stream.) */
- int saved_filling_enabled = filling_enabled;
- int saved_indented_fill = indented_fill;
- int saved_no_indent = no_indent;
- int saved_escape_html = escape_html;
-
- filling_enabled = 0;
- indented_fill = 0;
- no_indent = 1;
- escape_html = do_html_escape;
- xml_no_para++;
-
- result = full_expansion (str, implicit_code);
-
- filling_enabled = saved_filling_enabled;
- indented_fill = saved_indented_fill;
- no_indent = saved_no_indent;
- escape_html = saved_escape_html;
- xml_no_para--;
-
- return result;
-}
-
-
-/* Expand STR (or @code{STR} if IMPLICIT_CODE is nonzero). No change to
- any formatting parameters -- filling, indentation, html escapes,
- etc., are not reset. Always returned in new memory. */
-
-char *
-full_expansion (char *str, int implicit_code)
-{
- int length;
- char *result;
-
- /* Inhibit any real output. */
- int start = output_paragraph_offset;
- int saved_paragraph_is_open = paragraph_is_open;
-
- /* More output state to save. */
- int saved_meta_pos = meta_char_pos;
- int saved_last_char = last_inserted_character;
- int saved_last_nl = last_char_was_newline;
-
- /* If we are called in the middle of processing a command, we need
- to dup and save the global variable `command' (which holds the
- name of this command), since the recursive reader loop will free
- it from under our feet if it finds any macros in STR. */
- char *saved_command = command ? xstrdup (command) : NULL;
-
- inhibit_output_flushing ();
- paragraph_is_open = 1;
- if (strlen (str) > (implicit_code
- ? EXECUTE_STRING_MAX - 1 - sizeof("@code{}")
- : EXECUTE_STRING_MAX - 1))
- line_error (_("`%.40s...' is too long for expansion; not expanded"), str);
- else
- execute_string (implicit_code ? "@code{%s}" : "%s", str);
- uninhibit_output_flushing ();
-
- /* Copy the expansion from the buffer. */
- length = output_paragraph_offset - start;
- result = xmalloc (1 + length);
- memcpy (result, (char *) (output_paragraph + start), length);
- result[length] = 0;
-
- /* Pretend it never happened. */
- free_and_clear (&command);
- command = saved_command;
-
- output_paragraph_offset = start;
- paragraph_is_open = saved_paragraph_is_open;
-
- meta_char_pos = saved_meta_pos;
- last_inserted_character = saved_last_char;
- last_char_was_newline = saved_last_nl;
-
- return result;
-}
-
-
-/* Return text (info) expansion of STR no matter what the current output
- format is. */
-
-char *
-text_expansion (char *str)
-{
- char *ret;
- int save_html = html;
- int save_xml = xml;
- int save_docbook = docbook;
-
- html = 0;
- xml = 0;
- docbook = 0;
- ret = expansion (str, 0);
- html = save_html;
- xml = save_xml;
- docbook = save_docbook;
-
- return ret;
-}
-
-
-/* Set the paragraph indentation variable to the value specified in STRING.
- Values can be:
- `asis': Don't change existing indentation.
- `none': Remove existing indentation.
- NUM: Indent NUM spaces at the starts of paragraphs.
- If NUM is zero, we assume `none'.
- Returns 0 if successful, or nonzero if STRING isn't one of the above. */
-int
-set_paragraph_indent (char *string)
-{
- if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
- paragraph_start_indent = 0;
- else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
- paragraph_start_indent = -1;
- else
- {
- if (sscanf (string, "%d", &paragraph_start_indent) != 1)
- return -1;
- else
- {
- if (paragraph_start_indent == 0)
- paragraph_start_indent = -1;
- }
- }
- return 0;
-}
-
-
-/* Translate MSGID according to the document language (@documentlanguage
- value or --document-language), rather than the current locale
- (LANGUAGE/LC_ALL/LANG). This code is from the get_title function in
- gettext. (xsetenv and unsetenv come from the gnulib xsetenv module.) */
-
-char *
-getdocumenttext (const char *msgid)
-{
- /* The original get_title also saves, sets, and restores
- OUTPUT_CHARSET, so that the translation will be given in
- the proper encoding (via canonical_locale_charset). But defining
- that function ends up pulling a whole lot of subsidiary functions.
- Not sure how to handle it; skip the whole thing for now. */
- const char *tmp;
- char *old_LC_ALL;
- char *old_LANGUAGE;
- const char *result;
-#ifdef HAVE_SETLOCALE
- char *old_locale;
-#endif
-
- /* Save LC_ALL, LANGUAGE environment variables. */
-
- tmp = getenv ("LC_ALL");
- old_LC_ALL = (tmp != NULL ? xstrdup (tmp) : NULL);
-
- tmp = getenv ("LANGUAGE");
- old_LANGUAGE = (tmp != NULL ? xstrdup (tmp) : NULL);
-
- xsetenv ("LC_ALL", document_language, 1);
- unsetenv ("LANGUAGE");
-
-#ifdef HAVE_SETLOCALE
- old_locale = xstrdup (setlocale (LC_ALL, NULL));
- if (setlocale (LC_ALL, "") == NULL)
- /* Nonexistent locale. Use the original. */
- result = msgid;
- else
-#endif
- {
- /* Fetch the translation. */
- result = gettext ((char *) msgid);
- }
-
- /* Restore LC_ALL, LANGUAGE environment variables. */
-
- if (old_LC_ALL != NULL)
- xsetenv ("LC_ALL", old_LC_ALL, 1), free (old_LC_ALL);
- else
- unsetenv ("LC_ALL");
-
- if (old_LANGUAGE != NULL)
- xsetenv ("LANGUAGE", old_LANGUAGE, 1), free (old_LANGUAGE);
- else
- unsetenv ("LANGUAGE");
-
-#ifdef HAVE_SETLOCALE
- setlocale (LC_ALL, old_locale);
- free (old_locale);
-#endif
-
- return (char *) result;
-}