diff options
Diffstat (limited to 'Build/source/utils/texinfo/makeinfo/makeinfo.c')
-rw-r--r-- | Build/source/utils/texinfo/makeinfo/makeinfo.c | 4350 |
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 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 == '`' ? "“" : "”"); - 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 ("—"); - else - xml_insert_entity ("mdash"); - dash_count -= 2; - } - else if (dash_count >= 1) - { - if (html) - add_word ("–"); - 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 ("&"); - else - add_char (character); - input_text_offset++; - break; - - case '<': - if (html && escape_html) - add_word ("<"); - else if (xml && escape_html) - xml_insert_entity ("lt"); - else - add_char (character); - input_text_offset++; - break; - - case '>': - if (html && escape_html) - add_word (">"); - 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 . - 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 than an 8-bit char. */ - int saved_escape_html = escape_html; - escape_html = 0; - add_word (" "); - 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", ¶graph_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; -} |