/* makeinfo -- convert Texinfo source into other formats.
$Id: makeinfo.c,v 1.74 2004/12/19 17:15:42 karl Exp $
Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001, 2002, 2003, 2004 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.
Original author of makeinfo: 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 "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;
#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;
/* Nonzero means we are inserting a block level HTML element that must not be
enclosed in a
, such as
, and . */
int in_html_block_level_elt = 0;
/* True when expanding a macro definition. */
static int executing_macro = 0;
/* True when we are inside a - block of a menu. */
static int in_menu_item = 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 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\
--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 ("");
/* 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 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 ("");
puts (_("\
Options for HTML:\n\
--css-include=FILE include FILE in HTML