/* makeinfo -- convert Texinfo source into other formats. $Id: makeinfo.c,v 1.34 2003/06/02 12:32:29 karl Exp $ Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 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 2, 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Makeinfo was authored by Brian Fox (bfox@ai.mit.edu). */ #include "system.h" #include "getopt.h" #define COMPILING_MAKEINFO #include "makeinfo.h" #include "cmds.h" #include "files.h" #include "footnote.h" #include "html.h" #include "index.h" #include "insertion.h" #include "lang.h" #include "macro.h" #include "node.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; /* Flags which control initial output string for xrefs. */ int px_ref_flag = 0; int ref_flag = 0; #define INITIAL_PARAGRAPH_SPACE 5000 int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE; /* 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; /* True when expanding a macro definition. */ static int executing_macro = 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; extern void do_multitable (), end_multitable (); void push_node_filename (), pop_node_filename (); void remember_error (); void convert_from_stream (), convert_from_file (), convert_from_loaded_file (); void init_internals (), init_paragraph (), init_brace_stack (); void init_insertion_stack (), init_indices (); void init_tag_table (), write_tag_table (), write_tag_table_internal (); void validate_file (), validate_other_references (), split_file (); void free_node_references (), handle_variable (); void handle_variable_internal (); void normalize_node_name (); void add_anchor_name (); void free_node_node_references (), remember_node_node_reference (); char **get_brace_args (); int array_len (); void free_array (); static int end_of_sentence_p (); void reader_loop (); void remember_brace (), remember_brace_1 (); void pop_and_call_brace (), discard_braces (); void add_word (), add_char (), insert (), flush_output (); void insert_string (); void close_paragraph (); void ignore_blank_line (); void do_flush_right_indentation (), discard_insertions (); void start_paragraph (), indent (); void inhibit_output_flushing (), uninhibit_output_flushing (); int set_paragraph_indent (); int self_delimiting (), search_forward (); int multitable_item (), number_of_node (); void me_execute_string_keep_state (); void maybe_update_execution_strings (); extern char *escape_string (); extern void insert_html_tag (); extern void sectioning_html (); #if defined (VA_FPRINTF) && __STDC__ /* Unfortunately we must use prototypes if we are to use . */ void add_word_args (const char *, ...); void execute_string (char *, ...); #else void add_word_args (); void execute_string (); #endif /* no prototypes */ /* Error handling. */ /* Number of errors encountered. */ int errors_printed = 0; /* Print the last error gotten from the file system. */ int fs_error (filename) 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"); } } /* Remember that an error has been printed. If more than max_error_level have been printed, then exit the program. */ void remember_error () { errors_printed++; if (max_error_level && (errors_printed > max_error_level)) { fprintf (stderr, _("Too many errors! Gave up.\n")); flush_file_stack (); cm_bye (); xexit (1); } } /* The other side of a malformed expression. */ void misplaced_brace () { line_error (_("Misplaced %c"), '}'); } /* Main. */ /* Display the version info of this invocation of Makeinfo. */ static void print_version_info () { 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 (exit_value) 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\ --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\ --reference-limit=NUM warn about at most NUM references (default %d).\n\ -v, --verbose explain what is being done.\n\ --version display version information and exit.\n"), max_error_level, reference_warning_limit); puts ("\n"); /* 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\ ")); 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 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 (directory if split HTML),\n\ ")); printf (_("\ Options for Info and plain text:\n\ --enable-encoding output accented and special characters in\n\ Info output based on @documentencoding.\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\n\ in which they are defined (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 ("\n"); puts (_("\ Options for HTML:\n\ --css-include=FILE include FILE in HTML