1/* makeinfo -- convert Texinfo source into other formats.
2   $Id: makeinfo.c,v 1.74 2004/12/19 17:15:42 karl Exp $
3
4   Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
5   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21   Original author of makeinfo: Brian Fox (bfox@ai.mit.edu).  */
22
23#include "system.h"
24#include "getopt.h"
25
26#define COMPILING_MAKEINFO
27#include "makeinfo.h"
28#include "cmds.h"
29#include "files.h"
30#include "float.h"
31#include "footnote.h"
32#include "html.h"
33#include "index.h"
34#include "insertion.h"
35#include "lang.h"
36#include "macro.h"
37#include "node.h"
38#include "sectioning.h"
39#include "toc.h"
40#include "xml.h"
41
42/* You can change some of the behavior of Makeinfo by changing the
43   following defines: */
44
45/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which
46   appear within an @table, @ftable, or @itemize environment to have
47   standard paragraph indentation.  Without this, such paragraphs have
48   no starting indentation. */
49/* #define INDENT_PARAGRAPHS_IN_TABLE */
50
51/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
52   the first lines of paragraphs receive by default, where no other
53   value has been specified.  Users can change this value on the command
54   line, with the --paragraph-indent option, or within the texinfo file,
55   with the @paragraphindent command. */
56#define PARAGRAPH_START_INDENT 3
57
58/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you
59   wish to appear between paragraphs.  A value of 1 creates a single blank
60   line between paragraphs.  Paragraphs are defined by 2 or more consecutive
61   newlines in the input file (i.e., one or more blank lines). */
62#define DEFAULT_PARAGRAPH_SPACING 1
63
64/* Global variables.  */
65
66/* The output file name. */
67char *output_filename = NULL;
68
69/* Name of the output file that the user elected to pass on the command line.
70   Such a name overrides any name found with the @setfilename command. */
71char *command_output_filename = NULL;
72static char *save_command_output_filename = NULL;
73
74#define INITIAL_PARAGRAPH_SPACE 5000
75int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE;
76
77/* The amount of indentation to add at the starts of paragraphs.
78   0 means don't change existing indentation at paragraph starts.
79   > 0 is amount to indent new paragraphs by.
80   < 0 means indent to column zero by removing indentation if necessary.
81
82   This is normally zero, but some people prefer paragraph starts to be
83   somewhat more indented than paragraph bodies.  A pretty value for
84   this is 3. */
85int paragraph_start_indent = PARAGRAPH_START_INDENT;
86
87/* Indentation that is pending insertion.  We have this for hacking lines
88   which look blank, but contain whitespace.  We want to treat those as
89   blank lines. */
90int pending_indent = 0;
91
92/* The index in our internal command table of the currently
93   executing command. */
94int command_index;
95
96/* A search string which is used to find the first @setfilename. */
97char setfilename_search[] =
98  { COMMAND_PREFIX,
99      's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 };
100
101/* Values for calling handle_variable_internal (). */
102#define SET     1
103#define CLEAR   2
104#define IFSET   3
105#define IFCLEAR 4
106
107/* Flags controlling the operation of the program. */
108
109/* Default is to remove output if there were errors.  */
110int force = 0;
111
112/* Default is to notify users of bad choices. */
113int print_warnings = 1;
114
115/* Number of errors that we tolerate on a given fileset. */
116int max_error_level = 100;
117
118/* The actual last inserted character.  Note that this may be something
119   other than NEWLINE even if last_char_was_newline is 1. */
120int last_inserted_character = 0;
121
122/* Nonzero means that a newline character has already been
123   inserted, so close_paragraph () should insert one less. */
124int line_already_broken = 0;
125
126/* When nonzero we have finished an insertion (see end_insertion ()) and we
127   want to ignore false continued paragraph closings. */
128int insertion_paragraph_closed = 0;
129
130/* Nonzero means attempt to make all of the lines have fill_column width. */
131int do_justification = 0;
132
133/* Nonzero means don't replace whitespace with &nbsp; in HTML mode.  */
134int in_html_elt = 0;
135
136/* Nonzero means we are inserting a block level HTML element that must not be
137   enclosed in a <p>, such as <ul>, <ol> and <h?>.  */
138int in_html_block_level_elt = 0;
139
140/* True when expanding a macro definition.  */
141static int executing_macro = 0;
142
143/* True when we are inside a <li> block of a menu.  */
144static int in_menu_item = 0;
145
146typedef struct brace_element
147{
148  struct brace_element *next;
149  COMMAND_FUNCTION *proc;
150  char *command;
151  int pos, line;
152  int in_fixed_width_font;
153} BRACE_ELEMENT;
154
155BRACE_ELEMENT *brace_stack = NULL;
156
157static void convert_from_file (char *name);
158static void convert_from_loaded_file (char *name);
159static void convert_from_stream (FILE *stream, char *name);
160static void do_flush_right_indentation (void);
161static void handle_variable (int action);
162static void handle_variable_internal (int action, char *name);
163static void init_brace_stack (void);
164static void init_internals (void);
165static void pop_and_call_brace (void);
166static void remember_brace (COMMAND_FUNCTION (*proc));
167static int end_of_sentence_p (void);
168
169void maybe_update_execution_strings (char **text, unsigned int new_len);
170
171/* Error handling.  */
172
173/* Number of errors encountered. */
174int errors_printed = 0;
175
176/* Remember that an error has been printed.  If more than
177   max_error_level have been printed, then exit the program. */
178static void
179remember_error (void)
180{
181  errors_printed++;
182  if (max_error_level && (errors_printed > max_error_level))
183    {
184      fprintf (stderr, _("Too many errors!  Gave up.\n"));
185      flush_file_stack ();
186      if (errors_printed - max_error_level < 2)
187	cm_bye ();
188      xexit (1);
189    }
190}
191
192/* Print the last error gotten from the file system. */
193int
194fs_error (char *filename)
195{
196  remember_error ();
197  perror (filename);
198  return 0;
199}
200
201/* Print an error message, and return false. */
202void
203#if defined (VA_FPRINTF) && __STDC__
204error (const char *format, ...)
205#else
206error (format, va_alist)
207     const char *format;
208     va_dcl
209#endif
210{
211#ifdef VA_FPRINTF
212  va_list ap;
213#endif
214
215  remember_error ();
216
217  VA_START (ap, format);
218#ifdef VA_FPRINTF
219  VA_FPRINTF (stderr, format, ap);
220#else
221  fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
222#endif /* not VA_FPRINTF */
223  va_end (ap);
224
225  putc ('\n', stderr);
226}
227
228/* Just like error (), but print the input file and line number as well. */
229void
230#if defined (VA_FPRINTF) && __STDC__
231file_line_error (char *infile, int lno, const char *format, ...)
232#else
233file_line_error (infile, lno, format, va_alist)
234   char *infile;
235   int lno;
236   const char *format;
237   va_dcl
238#endif
239{
240#ifdef VA_FPRINTF
241  va_list ap;
242#endif
243
244  remember_error ();
245  fprintf (stderr, "%s:%d: ", infile, lno);
246
247  VA_START (ap, format);
248#ifdef VA_FPRINTF
249  VA_FPRINTF (stderr, format, ap);
250#else
251  fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
252#endif /* not VA_FPRINTF */
253  va_end (ap);
254
255  fprintf (stderr, ".\n");
256}
257
258/* Just like file_line_error (), but take the input file and the line
259   number from global variables. */
260void
261#if defined (VA_FPRINTF) && __STDC__
262line_error (const char *format, ...)
263#else
264line_error (format, va_alist)
265   const char *format;
266   va_dcl
267#endif
268{
269#ifdef VA_FPRINTF
270  va_list ap;
271#endif
272
273  remember_error ();
274  fprintf (stderr, "%s:%d: ", input_filename, line_number);
275
276  VA_START (ap, format);
277#ifdef VA_FPRINTF
278  VA_FPRINTF (stderr, format, ap);
279#else
280  fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
281#endif /* not VA_FPRINTF */
282  va_end (ap);
283
284  fprintf (stderr, ".\n");
285}
286
287void
288#if defined (VA_FPRINTF) && __STDC__
289warning (const char *format, ...)
290#else
291warning (format, va_alist)
292     const char *format;
293     va_dcl
294#endif
295{
296#ifdef VA_FPRINTF
297  va_list ap;
298#endif
299
300  if (print_warnings)
301    {
302      fprintf (stderr, _("%s:%d: warning: "), input_filename, line_number);
303
304      VA_START (ap, format);
305#ifdef VA_FPRINTF
306      VA_FPRINTF (stderr, format, ap);
307#else
308      fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
309#endif /* not VA_FPRINTF */
310      va_end (ap);
311
312      fprintf (stderr, ".\n");
313    }
314}
315
316
317/* The other side of a malformed expression. */
318static void
319misplaced_brace (void)
320{
321  line_error (_("Misplaced %c"), '}');
322}
323
324/* Main.  */
325
326/* Display the version info of this invocation of Makeinfo. */
327static void
328print_version_info (void)
329{
330  printf ("makeinfo (GNU %s) %s\n", PACKAGE, VERSION);
331}
332
333/* If EXIT_VALUE is zero, print the full usage message to stdout.
334   Otherwise, just say to use --help for more info.
335   Then exit with EXIT_VALUE. */
336static void
337usage (int exit_value)
338{
339  if (exit_value != 0)
340    fprintf (stderr, _("Try `%s --help' for more information.\n"), progname);
341  else
342  {
343    printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n"), progname);
344    puts ("");
345
346    puts (_("\
347Translate Texinfo source documentation to various other formats, by default\n\
348Info files suitable for reading online with Emacs or standalone GNU Info.\n"));
349
350    printf (_("\
351General options:\n\
352      --error-limit=NUM       quit after NUM errors (default %d).\n\
353      --force                 preserve output even if errors.\n\
354      --help                  display this help and exit.\n\
355      --no-validate           suppress node cross-reference validation.\n\
356      --no-warn               suppress warnings (but not errors).\n\
357      --reference-limit=NUM   warn about at most NUM references (default %d).\n\
358  -v, --verbose               explain what is being done.\n\
359      --version               display version information and exit.\n"),
360            max_error_level, reference_warning_limit);
361    puts ("");
362
363     /* xgettext: no-wrap */
364    puts (_("\
365Output format selection (default is to produce Info):\n\
366      --docbook             output Docbook XML rather than Info.\n\
367      --html                output HTML rather than Info.\n\
368      --xml                 output Texinfo XML rather than Info.\n\
369      --plaintext           output plain text rather than Info.\n\
370"));
371
372    puts (_("\
373General output options:\n\
374  -E, --macro-expand FILE   output macro-expanded source to FILE.\n\
375                            ignoring any @setfilename.\n\
376      --no-headers          suppress node separators, Node: lines, and menus\n\
377                              from Info output (thus producing plain text)\n\
378                              or from HTML (thus producing shorter output);\n\
379                              also, write to standard output by default.\n\
380      --no-split            suppress splitting of Info or HTML output,\n\
381                            generate only one output file.\n\
382      --number-sections     output chapter and sectioning numbers.\n\
383  -o, --output=FILE         output to FILE (directory if split HTML),\n\
384"));
385
386    printf (_("\
387Options for Info and plain text:\n\
388      --enable-encoding       output accented and special characters in\n\
389                                Info output based on @documentencoding.\n\
390      --fill-column=NUM       break Info lines at NUM characters (default %d).\n\
391      --footnote-style=STYLE  output footnotes in Info according to STYLE:\n\
392                                `separate' to put them in their own node;\n\
393                                `end' to put them at the end of the node\n\
394                                  in which they are defined (default).\n\
395      --paragraph-indent=VAL  indent Info paragraphs by VAL spaces (default %d).\n\
396                                If VAL is `none', do not indent; if VAL is\n\
397                                `asis', preserve existing indentation.\n\
398      --split-size=NUM        split Info files at size NUM (default %d).\n"),
399             fill_column, paragraph_start_indent,
400             DEFAULT_SPLIT_SIZE);
401    puts ("");
402
403    puts (_("\
404Options for HTML:\n\
405      --css-include=FILE        include FILE in HTML <style> output;\n\
406                                  read stdin if FILE is -.\n\
407"));
408
409    printf (_("\
410Options for XML and Docbook:\n\
411      --output-indent=VAL       indent XML elements by VAL spaces (default %d).\n\
412                                  If VAL is 0, ignorable whitespace is dropped.\n\
413"), xml_indentation_increment);
414    puts ("");
415
416    puts (_("\
417Input file options:\n\
418      --commands-in-node-names  allow @ commands in node names.\n\
419  -D VAR                        define the variable VAR, as with @set.\n\
420  -I DIR                        append DIR to the @include search path.\n\
421  -P DIR                        prepend DIR to the @include search path.\n\
422  -U VAR                        undefine the variable VAR, as with @clear.\n\
423"));
424
425    puts (_("\
426Conditional processing in input:\n\
427  --ifdocbook       process @ifdocbook and @docbook even if\n\
428                      not generating Docbook.\n\
429  --ifhtml          process @ifhtml and @html even if not generating HTML.\n\
430  --ifinfo          process @ifinfo even if not generating Info.\n\
431  --ifplaintext     process @ifplaintext even if not generating plain text.\n\
432  --iftex           process @iftex and @tex; implies --no-split.\n\
433  --ifxml           process @ifxml and @xml.\n\
434  --no-ifdocbook    do not process @ifdocbook and @docbook text.\n\
435  --no-ifhtml       do not process @ifhtml and @html text.\n\
436  --no-ifinfo       do not process @ifinfo text.\n\
437  --no-ifplaintext  do not process @ifplaintext text.\n\
438  --no-iftex        do not process @iftex and @tex text.\n\
439  --no-ifxml        do not process @ifxml and @xml text.\n\
440\n\
441  Also, for the --no-ifFORMAT options, do process @ifnotFORMAT text.\n\
442"));
443
444    puts (_("\
445  The defaults for the @if... conditionals depend on the output format:\n\
446  if generating HTML, --ifhtml is on and the others are off;\n\
447  if generating Info, --ifinfo is on and the others are off;\n\
448  if generating plain text, --ifplaintext is on and the others are off;\n\
449  if generating XML, --ifxml is on and the others are off.\n\
450"));
451
452    fputs (_("\
453Examples:\n\
454  makeinfo foo.texi                     write Info to foo's @setfilename\n\
455  makeinfo --html foo.texi              write HTML to @setfilename\n\
456  makeinfo --xml foo.texi               write Texinfo XML to @setfilename\n\
457  makeinfo --docbook foo.texi           write DocBook XML to @setfilename\n\
458  makeinfo --no-headers foo.texi        write plain text to standard output\n\
459\n\
460  makeinfo --html --no-headers foo.texi write html without node lines, menus\n\
461  makeinfo --number-sections foo.texi   write Info with numbered sections\n\
462  makeinfo --no-split foo.texi          write one Info file however big\n\
463"), stdout);
464
465    puts (_("\n\
466Email bug reports to bug-texinfo@gnu.org,\n\
467general questions and discussion to help-texinfo@gnu.org.\n\
468Texinfo home page: http://www.gnu.org/software/texinfo/"));
469
470  } /* end of full help */
471
472  xexit (exit_value);
473}
474
475struct option long_options[] =
476{
477  { "commands-in-node-names", 0, &expensive_validation, 1 },
478  { "css-include", 1, 0, 'C' },
479  { "docbook", 0, 0, 'd' },
480  { "enable-encoding", 0, &enable_encoding, 1 },
481  { "error-limit", 1, 0, 'e' },
482  { "fill-column", 1, 0, 'f' },
483  { "footnote-style", 1, 0, 's' },
484  { "force", 0, &force, 1 },
485  { "help", 0, 0, 'h' },
486  { "html", 0, 0, 'w' },
487  { "ifdocbook", 0, &process_docbook, 1 },
488  { "ifhtml", 0, &process_html, 1 },
489  { "ifinfo", 0, &process_info, 1 },
490  { "ifplaintext", 0, &process_plaintext, 1 },
491  { "iftex", 0, &process_tex, 1 },
492  { "ifxml", 0, &process_xml, 1 },
493  { "macro-expand", 1, 0, 'E' },
494  { "no-headers", 0, &no_headers, 1 },
495  { "no-ifdocbook", 0, &process_docbook, 0 },
496  { "no-ifhtml", 0, &process_html, 0 },
497  { "no-ifinfo", 0, &process_info, 0 },
498  { "no-ifplaintext", 0, &process_plaintext, 0 },
499  { "no-iftex", 0, &process_tex, 0 },
500  { "no-ifxml", 0, &process_xml, 0 },
501  { "no-number-footnotes", 0, &number_footnotes, 0 },
502  { "no-number-sections", 0, &number_sections, 0 },
503  { "no-pointer-validate", 0, &validating, 0 },
504  { "no-split", 0, &splitting, 0 },
505  { "no-validate", 0, &validating, 0 },
506  { "no-warn", 0, &print_warnings, 0 },
507  { "number-footnotes", 0, &number_footnotes, 1 },
508  { "number-sections", 0, &number_sections, 1 },
509  { "output", 1, 0, 'o' },
510  { "output-indent", 1, 0, 'i' },
511  { "paragraph-indent", 1, 0, 'p' },
512  { "plaintext", 0, 0, 't' },
513  { "reference-limit", 1, 0, 'r' },
514  { "split-size", 1, 0, 'S'},
515  { "verbose", 0, &verbose_mode, 1 },
516  { "version", 0, 0, 'V' },
517  { "xml", 0, 0, 'x' },
518  {NULL, 0, NULL, 0}
519};
520
521/* We use handle_variable_internal for -D and -U, and it depends on
522   execute_string, which depends on input_filename, which is not defined
523   while we are handling options. :-\  So we save these defines in this
524   struct, and handle them later.  */
525typedef struct command_line_define
526{
527  struct command_line_define *next;
528  int action;
529  char *define;
530} COMMAND_LINE_DEFINE;
531
532static COMMAND_LINE_DEFINE *command_line_defines = NULL;
533
534/* For each file mentioned in the command line, process it, turning
535   Texinfo commands into wonderfully formatted output text. */
536int
537main (int argc, char **argv)
538{
539  int c, ind;
540  int reading_from_stdin = 0;
541
542#ifdef HAVE_SETLOCALE
543  /* Do not use LC_ALL, because LC_NUMERIC screws up the scanf parsing
544     of the argument to @multicolumn.  */
545  setlocale (LC_TIME, "");
546#ifdef LC_MESSAGES /* ultrix */
547  setlocale (LC_MESSAGES, "");
548#endif
549  setlocale (LC_CTYPE, "");
550  setlocale (LC_COLLATE, "");
551#endif
552
553#ifdef ENABLE_NLS
554  /* Set the text message domain.  */
555  bindtextdomain (PACKAGE, LOCALEDIR);
556  textdomain (PACKAGE);
557#endif
558
559  /* If TEXINFO_OUTPUT_FORMAT envvar is set, use it to set default output.
560     Can be overridden with one of the output options.  */
561  if (getenv ("TEXINFO_OUTPUT_FORMAT") != NULL)
562    {
563      if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "docbook"))
564        {
565          splitting = 0;
566          html = 0;
567          docbook = 1;
568          xml = 1;
569          process_docbook = 1;
570        }
571      else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "html"))
572        {
573          html = 1;
574          docbook = 0;
575          xml = 0;
576          process_html = 1;
577        }
578      else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "info"))
579        {
580          html = 0;
581          docbook = 0;
582          xml = 0;
583        }
584      else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "plaintext"))
585        {
586          splitting = 0;
587          no_headers = 1;
588          html = 0;
589          docbook = 0;
590          xml = 0;
591          process_plaintext = 1;
592        }
593      else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "xml"))
594        {
595          splitting = 0;
596          html = 0;
597          docbook = 0;
598          xml = 1;
599          process_xml = 1;
600        }
601      else
602        fprintf (stderr,
603            _("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"),
604                 progname, getenv ("TEXINFO_OUTPUT_FORMAT"));
605    }
606
607  /* Parse argument flags from the input line. */
608  while ((c = getopt_long (argc, argv, "D:de:E:f:hI:i:o:p:P:r:s:t:U:vV:wx",
609                           long_options, &ind)) != EOF)
610    {
611      if (c == 0 && long_options[ind].flag == 0)
612        c = long_options[ind].val;
613
614      switch (c)
615        {
616        case 'C':  /* --css-include */
617          css_include = xstrdup (optarg);
618          break;
619
620        case 'D':
621        case 'U':
622          /* User specified variable to set or clear. */
623          if (xml && !docbook)
624            {
625              COMMAND_LINE_DEFINE *new = xmalloc (sizeof (COMMAND_LINE_DEFINE));
626              new->action = (c == 'D') ? SET : CLEAR;
627              new->define = xstrdup (optarg);
628              new->next = command_line_defines;
629              command_line_defines = new;
630            }
631          else
632            handle_variable_internal ((c == 'D' ? SET : CLEAR), optarg);
633          break;
634
635        case 'd': /* --docbook */
636          splitting = 0;
637          xml = 1;
638          docbook = 1;
639          html = 0;
640	  process_docbook = 1;
641          break;
642
643        case 'e': /* --error-limit */
644          if (sscanf (optarg, "%d", &max_error_level) != 1)
645            {
646              fprintf (stderr,
647                      _("%s: %s arg must be numeric, not `%s'.\n"),
648                      progname, "--error-limit", optarg);
649              usage (1);
650            }
651          break;
652
653        case 'E': /* --macro-expand */
654          if (!macro_expansion_output_stream)
655            {
656              macro_expansion_filename = optarg;
657              macro_expansion_output_stream
658                = strcmp (optarg, "-") == 0 ? stdout : fopen (optarg, "w");
659              if (!macro_expansion_output_stream)
660                error (_("%s: could not open macro expansion output `%s'"),
661                       progname, optarg);
662            }
663          else
664            fprintf (stderr,
665                     _("%s: ignoring second macro expansion output `%s'.\n"),
666                     progname, optarg);
667          break;
668
669        case 'f': /* --fill-column */
670          if (sscanf (optarg, "%d", &fill_column) != 1)
671            {
672              fprintf (stderr,
673                       _("%s: %s arg must be numeric, not `%s'.\n"),
674                       progname, "--fill-column", optarg);
675              usage (1);
676            }
677          break;
678
679        case 'h': /* --help */
680          usage (0);
681          break;
682
683        case 'I':
684          /* Append user-specified dir to include file path. */
685          append_to_include_path (optarg);
686          break;
687
688        case 'i':
689          if (sscanf (optarg, "%d", &xml_indentation_increment) != 1)
690            {
691              fprintf (stderr,
692                     _("%s: %s arg must be numeric, not `%s'.\n"),
693                     progname, "--output-indent", optarg);
694              usage (1);
695            }
696          break;
697
698        case 'o': /* --output */
699          command_output_filename = xstrdup (optarg);
700          save_command_output_filename = command_output_filename;
701          break;
702
703        case 'p': /* --paragraph-indent */
704          if (set_paragraph_indent (optarg) < 0)
705            {
706              fprintf (stderr,
707   _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"),
708                       progname, optarg);
709              usage (1);
710            }
711          break;
712
713        case 'P':
714          /* Prepend user-specified include dir to include path. */
715          prepend_to_include_path (optarg);
716          break;
717
718        case 'r': /* --reference-limit */
719          if (sscanf (optarg, "%d", &reference_warning_limit) != 1)
720            {
721              fprintf (stderr,
722                     _("%s: %s arg must be numeric, not `%s'.\n"),
723                     progname, "--reference-limit", optarg);
724              usage (1);
725            }
726          break;
727
728        case 's': /* --footnote-style */
729          if (set_footnote_style (optarg) < 0)
730            {
731              fprintf (stderr,
732        _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"),
733                       progname, optarg);
734              usage (1);
735            }
736          footnote_style_preset = 1;
737          break;
738
739        case 'S': /* --split-size */
740          if (sscanf (optarg, "%d", &split_size) != 1)
741            {
742              fprintf (stderr,
743                     _("%s: %s arg must be numeric, not `%s'.\n"),
744                     progname, "--split-size", optarg);
745              usage (1);
746            }
747          break;
748
749        case 't': /* --plaintext */
750          splitting = 0;
751          no_headers = 1;
752          html = 0;
753          docbook = 0;
754          xml = 0;
755          process_plaintext = 1;
756          break;
757
758        case 'v':
759          verbose_mode++;
760          break;
761
762        case 'V': /* --version */
763          print_version_info ();
764          puts ("");
765          puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
766          printf (_("There is NO warranty.  You may redistribute this software\n\
767under the terms of the GNU General Public License.\n\
768For more information about these matters, see the files named COPYING.\n"));
769          xexit (0);
770          break;
771
772        case 'w': /* --html */
773          xml = 0;
774          docbook = 0;
775          html = 1;
776          process_html = 1;
777          break;
778
779        case 'x': /* --xml */
780          splitting = 0;
781          html = 0;
782          docbook = 0;
783          xml = 1;
784          process_xml = 1;
785          break;
786
787        case '?':
788          usage (1);
789          break;
790        }
791    }
792
793  if (macro_expansion_output_stream)
794    validating = 0;
795
796  if (!validating)
797    expensive_validation = 0;
798
799  if (optind == argc)
800    {
801      /* Check to see if input is a file.  If so, process that. */
802      if (!isatty (fileno (stdin)))
803        reading_from_stdin = 1;
804      else
805        {
806          fprintf (stderr, _("%s: missing file argument.\n"), progname);
807          usage (1);
808        }
809    }
810
811  if (no_headers)
812    {
813      /* If the user did not specify an output file, use stdout. */
814      if (!command_output_filename)
815        command_output_filename = xstrdup ("-");
816
817      if (html && splitting && !STREQ (command_output_filename, "-"))
818        { /* --no-headers --no-split --html indicates confusion. */
819          fprintf (stderr,
820                  "%s: can't split --html output to `%s' with --no-headers.\n",
821                   progname, command_output_filename);
822          usage (1);
823        }
824
825      /* --no-headers implies --no-split.  */
826      splitting = 0;
827    }
828
829  if (process_info == -1)
830    { /* no explicit --[no-]ifinfo option, so we'll do @ifinfo
831         if we're generating info or (for compatibility) plain text.  */
832      process_info = !html && !xml;
833    }
834
835  if (process_plaintext == -1)
836    { /* no explicit --[no-]ifplaintext option, so we'll do @ifplaintext
837         if we're generating plain text.  */
838      process_plaintext = no_headers && !html && !xml;
839    }
840
841  if (verbose_mode)
842    print_version_info ();
843
844  /* Remaining arguments are file names of texinfo files.
845     Convert them, one by one. */
846  if (!reading_from_stdin)
847    {
848      while (optind != argc)
849        convert_from_file (argv[optind++]);
850    }
851  else
852    convert_from_stream (stdin, "stdin");
853
854  xexit (errors_printed ? 2 : 0);
855  return 0; /* Avoid bogus warnings.  */
856}
857
858/* Hacking tokens and strings.  */
859
860/* Return the next token as a string pointer.  We cons the string.  This
861   `token' means simply a command name.  */
862
863/* = is so @alias works.  ^ and _ are so macros can be used in math mode
864   without a space following.  Possibly we should simply allow alpha, to
865   be compatible with TeX.  */
866#define COMMAND_CHAR(c) (!cr_or_whitespace(c) \
867                         && (c) != '{' \
868                         && (c) != '}' \
869                         && (c) != '=' \
870                         && (c) != '_' \
871                         && (c) != '^' \
872                         )
873
874static char *
875read_token (void)
876{
877  int i, character;
878  char *result;
879
880  /* If the first character to be read is self-delimiting, then that
881     is the command itself. */
882  character = curchar ();
883  if (self_delimiting (character))
884    {
885      input_text_offset++;
886
887      if (character == '\n')
888        line_number++;
889
890      result = xstrdup (" ");
891      *result = character;
892      return result;
893    }
894
895  for (i = 0; ((input_text_offset != input_text_length)
896               && (character = curchar ())
897               && COMMAND_CHAR (character));
898       i++, input_text_offset++);
899  result = xmalloc (i + 1);
900  memcpy (result, &input_text[input_text_offset - i], i);
901  result[i] = 0;
902  return result;
903}
904
905/* Return nonzero if CHARACTER is self-delimiting. */
906int
907self_delimiting (int character)
908{
909  /* @; and @\ are not Texinfo commands, but they are listed here
910     anyway.  I don't know why.  --karl, 10aug96.  */
911  return strchr ("~{|}`^\\@?=;:./-,*\'\" !\n\t", character) != NULL;
912}
913
914/* Clear whitespace from the front and end of string. */
915void
916canon_white (char *string)
917{
918  char *p = string;
919  unsigned len;
920
921  if (!*p)
922    return;
923
924  do
925    {
926      if (!cr_or_whitespace (*p))
927	break;
928      ++p;
929    }
930  while (*p);
931
932  len = strlen (p);
933  while (len && cr_or_whitespace (p[len-1]))
934    --len;
935
936  if (p != string)
937    memmove (string, p, len);
938
939  string[len] = 0;
940}
941
942/* Bash STRING, replacing all whitespace with just one space. */
943void
944fix_whitespace (char *string)
945{
946  char *temp = xmalloc (strlen (string) + 1);
947  int string_index = 0;
948  int temp_index = 0;
949  int c;
950
951  canon_white (string);
952
953  while (string[string_index])
954    {
955      c = temp[temp_index++] = string[string_index++];
956
957      if (c == ' ' || c == '\n' || c == '\t')
958        {
959          temp[temp_index - 1] = ' ';
960          while ((c = string[string_index]) && (c == ' ' ||
961                                                c == '\t' ||
962                                                c == '\n'))
963            string_index++;
964        }
965    }
966  temp[temp_index] = 0;
967  strcpy (string, temp);
968  free (temp);
969}
970
971/* Discard text until the desired string is found.  The string is
972   included in the discarded text. */
973void
974discard_until (char *string)
975{
976  int temp = search_forward (string, input_text_offset);
977
978  int tt = (temp < 0) ? input_text_length : temp + strlen (string);
979  int from = input_text_offset;
980
981  /* Find out what line we are on. */
982  while (from != tt)
983    if (input_text[from++] == '\n')
984      line_number++;
985
986  if (temp < 0)
987    {
988      /* not found, move current position to end of string */
989      input_text_offset = input_text_length;
990      if (strcmp (string, "\n") != 0)
991        { /* Give a more descriptive feedback, if we are looking for ``@end ''
992             during macro execution.  That means someone used a multiline
993             command as an argument to, say, @section ... style commands.  */
994          char *end_block = xmalloc (8);
995          sprintf (end_block, "\n%cend ", COMMAND_PREFIX);
996          if (executing_string && strstr (string, end_block))
997            line_error (_("Multiline command %c%s used improperly"),
998                COMMAND_PREFIX, command);
999          else
1000            line_error (_("Expected `%s'"), string);
1001          free (end_block);
1002          return;
1003        }
1004    }
1005  else
1006    /* found, move current position to after the found string */
1007    input_text_offset = temp + strlen (string);
1008}
1009
1010/* Read characters from the file until we are at MATCH.
1011   Place the characters read into STRING.
1012   On exit input_text_offset is after the match string.
1013   Return the offset where the string starts. */
1014int
1015get_until (char *match, char **string)
1016{
1017  int len, current_point, x, new_point, tem;
1018
1019  current_point = x = input_text_offset;
1020  new_point = search_forward (match, input_text_offset);
1021
1022  if (new_point < 0)
1023    new_point = input_text_length;
1024  len = new_point - current_point;
1025
1026  /* Keep track of which line number we are at. */
1027  tem = new_point + (strlen (match) - 1);
1028  while (x != tem)
1029    if (input_text[x++] == '\n')
1030      line_number++;
1031
1032  *string = xmalloc (len + 1);
1033
1034  memcpy (*string, &input_text[current_point], len);
1035  (*string)[len] = 0;
1036
1037  /* Now leave input_text_offset in a consistent state. */
1038  input_text_offset = tem;
1039
1040  if (input_text_offset > input_text_length)
1041    input_text_offset = input_text_length;
1042
1043  return new_point;
1044}
1045
1046/* Replace input_text[FROM .. TO] with its expansion.  */
1047void
1048replace_with_expansion (int from, int *to)
1049{
1050  char *xp;
1051  unsigned xp_len, new_len;
1052  char *old_input = input_text;
1053  unsigned raw_len = *to - from;
1054  char *str;
1055
1056  /* The rest of the code here moves large buffers, so let's
1057     not waste time if the input cannot possibly expand
1058     into anything.  Unfortunately, we cannot avoid expansion
1059     when we see things like @code etc., even if they only
1060     asked for expansion of macros, since any Texinfo command
1061     can be potentially redefined with a macro.  */
1062  if (only_macro_expansion &&
1063      memchr (input_text + from, COMMAND_PREFIX, raw_len) == 0)
1064    return;
1065
1066  /* Get original string from input.  */
1067  str = xmalloc (raw_len + 1);
1068  memcpy (str, input_text + from, raw_len);
1069  str[raw_len] = 0;
1070
1071  /* We are going to relocate input_text, so we had better output
1072     pending portion of input_text now, before the pointer changes.  */
1073  if (macro_expansion_output_stream && !executing_string
1074      && !me_inhibit_expansion)
1075    append_to_expansion_output (from);
1076
1077  /* Expand it.  */
1078  xp = expansion (str, 0);
1079  xp_len = strlen (xp);
1080  free (str);
1081
1082  /* Plunk the expansion into the middle of `input_text' --
1083     which is terminated by a newline, not a null.  Avoid
1084     expensive move of the rest of the input if the expansion
1085     has the same length as the original string.  */
1086  if (xp_len != raw_len)
1087    {
1088      new_len = from + xp_len + input_text_length - *to + 1;
1089      if (executing_string)
1090        { /* If we are in execute_string, we might need to update
1091             the relevant element in the execution_strings[] array,
1092             since it could have to be relocated from under our
1093             feet.  (input_text is reallocated here as well, if needed.)  */
1094          maybe_update_execution_strings (&input_text, new_len);
1095        }
1096      else if (new_len > input_text_length + 1)
1097        /* Don't bother to realloc if we have enough space.  */
1098        input_text = xrealloc (input_text, new_len);
1099
1100      memmove (input_text + from + xp_len,
1101               input_text + *to, input_text_length - *to + 1);
1102
1103      *to += xp_len - raw_len;
1104      /* Since we change input_text_length here, the comparison above
1105         isn't really valid, but it seems the worst that might happen is
1106         an extra xrealloc or two, so let's not worry.  */
1107      input_text_length += xp_len - raw_len;
1108    }
1109  memcpy (input_text + from, xp, xp_len);
1110  free (xp);
1111
1112  /* Synchronize the macro-expansion pointers with our new input_text.  */
1113  if (input_text != old_input)
1114    forget_itext (old_input);
1115  if (macro_expansion_output_stream && !executing_string)
1116    remember_itext (input_text, from);
1117}
1118
1119/* Read characters from the file until we are at MATCH or end of line.
1120   Place the characters read into STRING.  If EXPAND is nonzero,
1121   expand the text before looking for MATCH for those cases where
1122   MATCH might be produced by some macro.  */
1123void
1124get_until_in_line (int expand, char *match, char **string)
1125{
1126  int real_bottom = input_text_length;
1127  int limit = search_forward ("\n", input_text_offset);
1128  if (limit < 0)
1129    limit = input_text_length;
1130
1131  /* Replace input_text[input_text_offset .. limit-1] with its expansion.
1132     This allows the node names and menu entries themselves to be
1133     constructed via a macro, as in:
1134        @macro foo{p, q}
1135        Together: \p\ & \q\.
1136        @end macro
1137
1138        @node @foo{A,B}, next, prev, top
1139
1140     Otherwise, the `,' separating the macro args A and B is taken as
1141     the node argument separator, so the node name is `@foo{A'.  This
1142     expansion is only necessary on the first call, since we expand the
1143     whole line then.  */
1144  if (expand)
1145    {
1146      replace_with_expansion (input_text_offset, &limit);
1147    }
1148
1149  real_bottom = input_text_length;
1150  input_text_length = limit;
1151  get_until (match, string);
1152  input_text_length = real_bottom;
1153}
1154
1155void
1156get_rest_of_line (int expand, char **string)
1157{
1158  xml_no_para ++;
1159  if (expand)
1160    {
1161      char *tem;
1162
1163      /* Don't expand non-macros in input, since we want them
1164         intact in the macro-expanded output.  */
1165      only_macro_expansion++;
1166      get_until_in_line (1, "\n", &tem);
1167      only_macro_expansion--;
1168      *string = expansion (tem, 0);
1169      free (tem);
1170    }
1171  else
1172    get_until_in_line (0, "\n", string);
1173
1174  canon_white (*string);
1175
1176  if (curchar () == '\n')       /* as opposed to the end of the file... */
1177    {
1178      line_number++;
1179      input_text_offset++;
1180    }
1181  xml_no_para --;
1182}
1183
1184/* Backup the input pointer to the previous character, keeping track
1185   of the current line number. */
1186void
1187backup_input_pointer (void)
1188{
1189  if (input_text_offset)
1190    {
1191      input_text_offset--;
1192      if (curchar () == '\n')
1193        line_number--;
1194    }
1195}
1196
1197/* Read characters from the file until we are at MATCH or closing brace.
1198   Place the characters read into STRING.  */
1199void
1200get_until_in_braces (char *match, char **string)
1201{
1202  char *temp;
1203  int i, brace = 0;
1204  int match_len = strlen (match);
1205
1206  for (i = input_text_offset; i < input_text_length; i++)
1207    {
1208      if (i < input_text_length - 1 && input_text[i] == '@')
1209        {
1210          i++;                  /* skip commands like @, and @{ */
1211          continue;
1212        }
1213      else if (input_text[i] == '{')
1214        brace++;
1215      else if (input_text[i] == '}')
1216        {
1217          brace--;
1218          /* If looking for a brace, don't stop at the interior brace,
1219             like after "baz" in "@foo{something @bar{baz} more}".  */
1220          if (brace == 0)
1221            continue;
1222        }
1223      else if (input_text[i] == '\n')
1224        line_number++;
1225
1226      if (brace < 0 ||
1227          (brace == 0 && strncmp (input_text + i, match, match_len) == 0))
1228        break;
1229    }
1230
1231  match_len = i - input_text_offset;
1232  temp = xmalloc (2 + match_len);
1233  memcpy (temp, input_text + input_text_offset, match_len);
1234  temp[match_len] = 0;
1235  input_text_offset = i;
1236  *string = temp;
1237}
1238
1239
1240
1241/* Converting a file.  */
1242
1243/* Convert the file named by NAME.  The output is saved on the file
1244   named as the argument to the @setfilename command. */
1245static char *suffixes[] = {
1246  /* ".txi" is checked first so that on 8+3 DOS filesystems, if they
1247     have "texinfo.txi" and "texinfo.tex" in the same directory, the
1248     former is used rather than the latter, due to file name truncation.  */
1249  ".txi",
1250  ".texinfo",
1251  ".texi",
1252  ".txinfo",
1253  "",
1254  NULL
1255};
1256
1257static void
1258initialize_conversion (void)
1259{
1260  init_tag_table ();
1261  init_indices ();
1262  init_internals ();
1263  init_paragraph ();
1264
1265  /* This is used for splitting the output file and for doing section
1266     headings.  It was previously initialized in `init_paragraph', but its
1267     use there loses with the `init_paragraph' calls done by the
1268     multitable code; the tag indices get reset to zero.  */
1269  output_position = 0;
1270}
1271
1272/* Reverse the chain of structures in LIST.  Output the new head
1273   of the chain.  You should always assign the output value of this
1274   function to something, or you will lose the chain. */
1275GENERIC_LIST *
1276reverse_list (GENERIC_LIST *list)
1277{
1278  GENERIC_LIST *next;
1279  GENERIC_LIST *prev = NULL;
1280
1281  while (list)
1282    {
1283      next = list->next;
1284      list->next = prev;
1285      prev = list;
1286      list = next;
1287    }
1288  return prev;
1289}
1290
1291/* We read in multiples of 4k, simply because it is a typical pipe size
1292   on unix systems. */
1293#define READ_BUFFER_GROWTH (4 * 4096)
1294
1295/* Convert the Texinfo file coming from the open stream STREAM.  Assume the
1296   source of the stream is named NAME. */
1297static void
1298convert_from_stream (FILE *stream, char *name)
1299{
1300  char *buffer = NULL;
1301  int buffer_offset = 0, buffer_size = 0;
1302
1303  initialize_conversion ();
1304
1305  /* Read until the end of the stream.  This isn't strictly correct, since
1306     the texinfo input may end before the stream ends, but it is a quick
1307     working hueristic. */
1308  while (!feof (stream))
1309    {
1310      int count;
1311
1312      if (buffer_offset + (READ_BUFFER_GROWTH + 1) >= buffer_size)
1313        buffer = (char *)
1314          xrealloc (buffer, (buffer_size += READ_BUFFER_GROWTH));
1315
1316      count = fread (buffer + buffer_offset, 1, READ_BUFFER_GROWTH, stream);
1317
1318      if (count < 0)
1319        {
1320          perror (name);
1321          xexit (1);
1322        }
1323
1324      buffer_offset += count;
1325      if (count == 0)
1326        break;
1327    }
1328
1329  /* Set the globals to the new file. */
1330  input_text = buffer;
1331  input_text_length = buffer_offset;
1332  input_filename = xstrdup (name);
1333  node_filename = xstrdup (name);
1334  input_text_offset = 0;
1335  line_number = 1;
1336
1337  /* Not strictly necessary.  This magic prevents read_token () from doing
1338     extra unnecessary work each time it is called (that is a lot of times).
1339     The INPUT_TEXT_LENGTH is one past the actual end of the text. */
1340  input_text[input_text_length] = '\n';
1341
1342  convert_from_loaded_file (name);
1343}
1344
1345static void
1346convert_from_file (char *name)
1347{
1348  int i;
1349  char *filename = xmalloc (strlen (name) + 50);
1350
1351  /* Prepend file directory to the search path, so relative links work.  */
1352  prepend_to_include_path (pathname_part (name));
1353
1354  initialize_conversion ();
1355
1356  /* Try to load the file specified by NAME, concatenated with our
1357     various suffixes.  Prefer files like `makeinfo.texi' to
1358     `makeinfo'.  */
1359  for (i = 0; suffixes[i]; i++)
1360    {
1361      strcpy (filename, name);
1362      strcat (filename, suffixes[i]);
1363
1364      if (find_and_load (filename, 1))
1365        break;
1366
1367      if (!suffixes[i][0] && strrchr (filename, '.'))
1368        {
1369          fs_error (filename);
1370          free (filename);
1371          return;
1372        }
1373    }
1374
1375  if (!suffixes[i])
1376    {
1377      fs_error (name);
1378      free (filename);
1379      return;
1380    }
1381
1382  input_filename = filename;
1383
1384  convert_from_loaded_file (name);
1385
1386  /* Pop the prepended path, so multiple filenames in the
1387     command line do not screw each others include paths.  */
1388  pop_path_from_include_path ();
1389}
1390
1391static int
1392create_html_directory (char *dir, int can_remove_file)
1393{
1394  struct stat st;
1395
1396  /* Already exists.  */
1397  if (stat (dir, &st) == 0)
1398    {
1399      /* And it's a directory, so silently reuse it.  */
1400      if (S_ISDIR (st.st_mode))
1401        return 1;
1402      /* Not a directory, so move it out of the way if we are allowed.  */
1403      else if (can_remove_file)
1404        {
1405          if (unlink (dir) != 0)
1406            return 0;
1407        }
1408      else
1409        return 0;
1410    }
1411
1412  if (mkdir (dir, 0777) == 0)
1413    /* Success!  */
1414    return 1;
1415  else
1416    return 0;
1417}
1418
1419/* Given OUTPUT_FILENAME == ``/foo/bar/baz.html'', return
1420   "/foo/bar/baz/baz.html".  This routine is called only if html && splitting.
1421
1422  Split html output goes into the subdirectory of the toplevel
1423  filename, without extension.  For example:
1424      @setfilename foo.info
1425  produces output in files foo/index.html, foo/second-node.html, ...
1426
1427  But if the user said -o foo.whatever on the cmd line, then use
1428  foo.whatever unchanged.  */
1429
1430static char *
1431insert_toplevel_subdirectory (char *output_filename)
1432{
1433  static const char index_name[] = "index.html";
1434  char *dir, *subdir, *base, *basename, *p;
1435  char buf[PATH_MAX];
1436  const int index_len = sizeof (index_name) - 1;
1437
1438  strcpy (buf, output_filename);
1439  dir = pathname_part (buf);   /* directory of output_filename */
1440  base = filename_part (buf);  /* strips suffix, too */
1441  basename = xstrdup (base);   /* remember real @setfilename name */
1442  p = dir + strlen (dir) - 1;
1443  if (p > dir && IS_SLASH (*p))
1444    *p = 0;
1445  p = strrchr (base, '.');
1446  if (p)
1447    *p = 0;
1448
1449  /* Split html output goes into subdirectory of toplevel name. */
1450  if (save_command_output_filename
1451      && STREQ (output_filename, save_command_output_filename))
1452    subdir = basename;  /* from user, use unchanged */
1453  else
1454    subdir = base;      /* implicit, omit suffix */
1455
1456  free (output_filename);
1457  output_filename = xmalloc (strlen (dir) + 1
1458                             + strlen (basename) + 1
1459                             + index_len
1460                             + 1);
1461  strcpy (output_filename, dir);
1462  if (strlen (dir))
1463    strcat (output_filename, "/");
1464  strcat (output_filename, subdir);
1465
1466  /* First try, do not remove existing file.  */
1467  if (!create_html_directory (output_filename, 0))
1468    {
1469      /* That failed, try subdir name with .html.
1470         Remove it if it exists.  */
1471      strcpy (output_filename, dir);
1472      if (strlen (dir))
1473        strcat (output_filename, "/");
1474      strcat (output_filename, basename);
1475
1476      if (!create_html_directory (output_filename, 1))
1477        {
1478          /* Last try failed too :-\  */
1479          line_error (_("Can't create directory `%s': %s"),
1480              output_filename, strerror (errno));
1481          xexit (1);
1482        }
1483    }
1484
1485  strcat (output_filename, "/");
1486  strcat (output_filename, index_name);
1487  return output_filename;
1488}
1489
1490/* FIXME: this is way too hairy */
1491static void
1492convert_from_loaded_file (char *name)
1493{
1494  char *real_output_filename = NULL;
1495
1496  remember_itext (input_text, 0);
1497
1498  input_text_offset = 0;
1499
1500  /* Avoid the `\input texinfo' line in HTML output (assuming it starts
1501     the file).  */
1502  if (looking_at ("\\input"))
1503    discard_until ("\n");
1504
1505  /* Search this file looking for the special string which starts conversion.
1506     Once found, we may truly begin. */
1507  while (input_text_offset >= 0)
1508    {
1509      input_text_offset =
1510        search_forward (setfilename_search, input_text_offset);
1511
1512      if (input_text_offset == 0
1513          || (input_text_offset > 0
1514              && input_text[input_text_offset -1] == '\n'))
1515        break;
1516      else if (input_text_offset > 0)
1517        input_text_offset++;
1518    }
1519
1520  if (input_text_offset < 0)
1521    {
1522      if (!command_output_filename)
1523        {
1524#if defined (REQUIRE_SETFILENAME)
1525          error (_("No `%s' found in `%s'"), setfilename_search, name);
1526          goto finished;
1527#else
1528          command_output_filename = output_name_from_input_name (name);
1529#endif /* !REQUIRE_SETFILENAME */
1530        }
1531
1532      {
1533        int i, end_of_first_line;
1534
1535        /* Find the end of the first line in the file. */
1536        for (i = 0; i < input_text_length - 1; i++)
1537          if (input_text[i] == '\n')
1538            break;
1539
1540        end_of_first_line = i + 1;
1541
1542        for (i = 0; i < end_of_first_line; i++)
1543          {
1544            if ((input_text[i] == '\\') &&
1545                (strncmp (input_text + i + 1, "input", 5) == 0))
1546              {
1547                input_text_offset = i;
1548                break;
1549              }
1550          }
1551      }
1552    }
1553  else
1554    input_text_offset += strlen (setfilename_search);
1555
1556  if (!command_output_filename)
1557    {
1558      get_until ("\n", &output_filename); /* read rest of line */
1559      if (html || xml)
1560        { /* Change any extension to .html or .xml.  */
1561          char *html_name, *directory_part, *basename_part, *temp;
1562
1563          canon_white (output_filename);
1564          directory_part = pathname_part (output_filename);
1565
1566          basename_part = filename_part (output_filename);
1567
1568          /* Zap any existing extension.  */
1569          temp = strrchr (basename_part, '.');
1570          if (temp)
1571            *temp = 0;
1572
1573          /* Construct new filename.  */
1574          html_name = xmalloc (strlen (directory_part)
1575                               + strlen (basename_part) + 6);
1576          strcpy (html_name, directory_part);
1577          strcat (html_name, basename_part);
1578          strcat (html_name, html ? ".html" : ".xml");
1579
1580          /* Replace name from @setfilename with the html name.  */
1581          free (output_filename);
1582          output_filename = html_name;
1583        }
1584    }
1585  else
1586    {
1587      if (input_text_offset != -1)
1588        discard_until ("\n");
1589      else
1590        input_text_offset = 0;
1591
1592      real_output_filename = output_filename = command_output_filename;
1593      command_output_filename = NULL;  /* for included files or whatever */
1594    }
1595
1596  canon_white (output_filename);
1597  toplevel_output_filename = xstrdup (output_filename);
1598
1599  if (real_output_filename && strcmp (real_output_filename, "-") == 0)
1600    {
1601      if (macro_expansion_filename
1602          && strcmp (macro_expansion_filename, "-") == 0)
1603        {
1604          fprintf (stderr,
1605  _("%s: Skipping macro expansion to stdout as Info output is going there.\n"),
1606                   progname);
1607          macro_expansion_output_stream = NULL;
1608        }
1609      real_output_filename = xstrdup (real_output_filename);
1610      output_stream = stdout;
1611      splitting = 0;            /* Cannot split when writing to stdout. */
1612    }
1613  else
1614    {
1615      if (html && splitting)
1616        {
1617          if (FILENAME_CMP (output_filename, NULL_DEVICE) == 0
1618              || FILENAME_CMP (output_filename, ALSO_NULL_DEVICE) == 0)
1619            splitting = 0;
1620          else
1621            output_filename = insert_toplevel_subdirectory (output_filename);
1622          real_output_filename = xstrdup (output_filename);
1623        }
1624      else if (!real_output_filename)
1625        real_output_filename = expand_filename (output_filename, name);
1626      else
1627        real_output_filename = xstrdup (real_output_filename);
1628
1629      output_stream = fopen (real_output_filename, "w");
1630    }
1631
1632  set_current_output_filename (real_output_filename);
1633
1634  if (xml && !docbook)
1635    xml_begin_document (filename_part (output_filename));
1636
1637  if (verbose_mode)
1638    printf (_("Making %s file `%s' from `%s'.\n"),
1639            no_headers ? "text"
1640            : html ? "HTML"
1641            : xml ? "XML"
1642            : "info",
1643            output_filename, input_filename);
1644
1645  if (output_stream == NULL)
1646    {
1647      fs_error (real_output_filename);
1648      goto finished;
1649    }
1650
1651  /* Make the displayable filename from output_filename.  Only the base
1652     portion of the filename need be displayed. */
1653  flush_output ();              /* in case there was no @bye */
1654  if (output_stream != stdout)
1655    pretty_output_filename = filename_part (output_filename);
1656  else
1657    pretty_output_filename = xstrdup ("stdout");
1658
1659  /* For this file only, count the number of newlines from the top of
1660     the file to here.  This way, we keep track of line numbers for
1661     error reporting.  Line_number starts at 1, since the user isn't
1662     zero-based. */
1663  {
1664    int temp = 0;
1665    line_number = 1;
1666    while (temp != input_text_offset)
1667      if (input_text[temp++] == '\n')
1668        line_number++;
1669  }
1670
1671  /* html fixxme: should output this as trailer on first page.  */
1672  if (!no_headers && !html && !xml)
1673    add_word_args (_("This is %s, produced by makeinfo version %s from %s.\n"),
1674                   output_filename, VERSION, input_filename);
1675
1676  close_paragraph ();
1677
1678  if (xml && !docbook)
1679    {
1680      /* Just before the real main loop, let's handle the defines.  */
1681      COMMAND_LINE_DEFINE *temp;
1682
1683      for (temp = command_line_defines; temp; temp = temp->next)
1684        {
1685          handle_variable_internal (temp->action, temp->define);
1686          free(temp->define);
1687        }
1688    }
1689
1690  reader_loop ();
1691  if (xml)
1692    xml_end_document ();
1693
1694
1695finished:
1696  discard_insertions (0);
1697  close_paragraph ();
1698  flush_file_stack ();
1699
1700  if (macro_expansion_output_stream)
1701    {
1702      fclose (macro_expansion_output_stream);
1703      if (errors_printed && !force
1704          && strcmp (macro_expansion_filename, "-") != 0
1705          && FILENAME_CMP (macro_expansion_filename, NULL_DEVICE) != 0
1706          && FILENAME_CMP (macro_expansion_filename, ALSO_NULL_DEVICE) != 0)
1707        {
1708          fprintf (stderr,
1709_("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
1710                   progname, macro_expansion_filename);
1711          if (unlink (macro_expansion_filename) < 0)
1712            perror (macro_expansion_filename);
1713        }
1714    }
1715
1716  if (output_stream)
1717    {
1718      output_pending_notes ();
1719
1720      if (html)
1721        {
1722          no_indent = 1;
1723          start_paragraph ();
1724          add_word ("</body></html>\n");
1725          close_paragraph ();
1726        }
1727
1728      /* maybe we want local variables in info output.  */
1729      {
1730        char *trailer = info_trailer ();
1731	if (!xml && !docbook && trailer)
1732          {
1733            if (html)
1734              insert_string ("<!--");
1735            insert_string (trailer);
1736            free (trailer);
1737            if (html)
1738              insert_string ("\n-->\n");
1739          }
1740      }
1741
1742      /* Write stuff makeinfo generates after @bye, ie. info_trailer.  */
1743      flush_output ();
1744
1745      if (output_stream != stdout)
1746        fclose (output_stream);
1747
1748      /* If validating, then validate the entire file right now. */
1749      if (validating)
1750        validate_file (tag_table);
1751
1752      handle_delayed_writes ();
1753
1754      if (tag_table)
1755        {
1756          tag_table = (TAG_ENTRY *) reverse_list ((GENERIC_LIST *) tag_table);
1757          if (!no_headers && !html && !STREQ (current_output_filename, "-"))
1758            write_tag_table (real_output_filename);
1759        }
1760
1761      if (splitting && !html && (!errors_printed || force))
1762        {
1763          clean_old_split_files (real_output_filename);
1764          split_file (real_output_filename, split_size);
1765        }
1766      else if (errors_printed
1767               && !force
1768               && strcmp (real_output_filename, "-") != 0
1769               && FILENAME_CMP (real_output_filename, NULL_DEVICE) != 0
1770               && FILENAME_CMP (real_output_filename, ALSO_NULL_DEVICE) != 0)
1771        { /* If there were errors, and no --force, remove the output.  */
1772          fprintf (stderr,
1773  _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
1774                   progname, real_output_filename);
1775          if (unlink (real_output_filename) < 0)
1776            perror (real_output_filename);
1777        }
1778    }
1779  free (real_output_filename);
1780}
1781
1782/* If enable_encoding is set and @documentencoding is used, return a
1783   Local Variables section (as a malloc-ed string) so that Emacs'
1784   locale features can work.  Else return NULL.  */
1785char *
1786info_trailer (void)
1787{
1788  char *encoding;
1789
1790  if (!enable_encoding)
1791    return NULL;
1792
1793  encoding = current_document_encoding ();
1794
1795  if (encoding && *encoding)
1796    {
1797#define LV_FMT "\n\037\nLocal Variables:\ncoding: %s\nEnd:\n"
1798      char *lv = xmalloc (sizeof (LV_FMT) + strlen (encoding));
1799      sprintf (lv, LV_FMT, encoding);
1800      free (encoding);
1801      return lv;
1802    }
1803
1804  free (encoding);
1805  return NULL;
1806}
1807
1808void
1809free_and_clear (char **pointer)
1810{
1811  if (*pointer)
1812    {
1813      free (*pointer);
1814      *pointer = NULL;
1815    }
1816}
1817
1818 /* Initialize some state. */
1819static void
1820init_internals (void)
1821{
1822  free_and_clear (&output_filename);
1823  free_and_clear (&command);
1824  free_and_clear (&input_filename);
1825  free_node_references ();
1826  free_node_node_references ();
1827  toc_free ();
1828  init_insertion_stack ();
1829  init_brace_stack ();
1830  current_node = NULL; /* sometimes already freed */
1831  command_index = 0;
1832  in_menu = 0;
1833  in_detailmenu = 0;
1834  top_node_seen = 0;
1835  non_top_node_seen = 0;
1836  node_number = -1;
1837}
1838
1839void
1840init_paragraph (void)
1841{
1842  free (output_paragraph);
1843  output_paragraph = xmalloc (paragraph_buffer_len);
1844  output_paragraph[0] = 0;
1845  output_paragraph_offset = 0;
1846  output_column = 0;
1847  paragraph_is_open = 0;
1848  current_indent = 0;
1849  meta_char_pos = 0;
1850}
1851
1852/* This is called from `reader_loop' when we are at the * beginning a
1853   menu line.  */
1854
1855static void
1856handle_menu_entry (void)
1857{
1858  char *tem;
1859
1860  /* Ugh, glean_node_from_menu wants to read the * itself.  */
1861  input_text_offset--;
1862
1863  /* Find node name in menu entry and save it in references list for
1864     later validation.  Use followed_reference type for detailmenu
1865     references since we don't want to use them for default node pointers.  */
1866  tem = glean_node_from_menu (1, in_detailmenu
1867                                 ? followed_reference : menu_reference);
1868
1869  if (html && tem)
1870    { /* Start a menu item with the cleaned-up line.  Put an anchor
1871         around the start text (before `:' or the node name). */
1872      char *string;
1873
1874      discard_until ("* ");
1875
1876      /* The line number was already incremented in reader_loop when we
1877         saw the newline, and discard_until has now incremented again.  */
1878      line_number--;
1879
1880      if (had_menu_commentary)
1881        {
1882          add_html_block_elt ("<ul class=\"menu\">\n");
1883          had_menu_commentary = 0;
1884          in_paragraph = 0;
1885        }
1886
1887      if (in_paragraph)
1888        {
1889          add_html_block_elt ("</p>\n");
1890          add_html_block_elt ("<ul class=\"menu\">\n");
1891          in_paragraph = 0;
1892        }
1893
1894      in_menu_item = 1;
1895
1896      add_html_block_elt ("<li><a");
1897      if (next_menu_item_number <= 9)
1898        {
1899          add_word(" accesskey=");
1900          add_word_args("\"%d\"", next_menu_item_number);
1901          next_menu_item_number++;
1902        }
1903      add_word (" href=\"");
1904      string = expansion (tem, 0);
1905      add_anchor_name (string, 1);
1906      add_word ("\">");
1907      free (string);
1908
1909      /* The menu item may use macros, so expand them now.  */
1910      only_macro_expansion++;
1911      get_until_in_line (1, ":", &string);
1912      only_macro_expansion--;
1913      execute_string ("%s", string); /* get escaping done */
1914      free (string);
1915
1916      add_word ("</a>");
1917
1918      if (looking_at ("::"))
1919        discard_until (":");
1920      else
1921        { /* discard the node name */
1922          get_until_in_line (0, ".", &string);
1923          free (string);
1924        }
1925      input_text_offset++;      /* discard the second colon or the period */
1926
1927      /* Insert a colon only if there is a description of this menu item.  */
1928      {
1929        int save_input_text_offset = input_text_offset;
1930        int save_line_number = line_number;
1931        char *test_string;
1932        get_rest_of_line (0, &test_string);
1933        if (strlen (test_string) > 0)
1934          add_word (": ");
1935        input_text_offset = save_input_text_offset;
1936        line_number = save_line_number;
1937      }
1938    }
1939  else if (xml && tem)
1940    {
1941      xml_start_menu_entry (tem);
1942    }
1943  else if (tem)
1944    { /* For Info output, we can just use the input and the main case in
1945         reader_loop where we output what comes in.  Just move off the *
1946         so the next time through reader_loop we don't end up back here.  */
1947      add_char ('*');
1948      input_text_offset += 2; /* undo the pointer back-up above.  */
1949    }
1950
1951  if (tem)
1952    free (tem);
1953}
1954
1955/* Find the command corresponding to STRING.  If the command is found,
1956   return a pointer to the data structure.  Otherwise return -1.  */
1957static COMMAND *
1958get_command_entry (char *string)
1959{
1960  int i;
1961
1962  for (i = 0; command_table[i].name; i++)
1963    if (strcmp (command_table[i].name, string) == 0)
1964      return &command_table[i];
1965
1966  /* This command is not in our predefined command table.  Perhaps
1967     it is a user defined command. */
1968  for (i = 0; i < user_command_array_len; i++)
1969    if (user_command_array[i] &&
1970        (strcmp (user_command_array[i]->name, string) == 0))
1971      return user_command_array[i];
1972
1973  /* We never heard of this command. */
1974  return (COMMAND *) -1;
1975}
1976
1977/* input_text_offset is right at the command prefix character.
1978   Read the next token to determine what to do.  Return zero
1979   if there's no known command or macro after the prefix character.  */
1980static int
1981read_command (void)
1982{
1983  COMMAND *entry;
1984  int old_text_offset = input_text_offset++;
1985
1986  free_and_clear (&command);
1987  command = read_token ();
1988
1989  /* Check to see if this command is a macro.  If so, execute it here. */
1990  {
1991    MACRO_DEF *def;
1992
1993    def = find_macro (command);
1994
1995    if (def)
1996      {
1997        /* We disallow recursive use of a macro call.  Inhibit the expansion
1998           of this macro during the life of its execution. */
1999        if (!(def->flags & ME_RECURSE))
2000          def->inhibited = 1;
2001
2002        executing_macro++;
2003        execute_macro (def);
2004        executing_macro--;
2005
2006        if (!(def->flags & ME_RECURSE))
2007          def->inhibited = 0;
2008
2009        return 1;
2010      }
2011  }
2012
2013  if (only_macro_expansion)
2014    {
2015      /* Back up to the place where we were called, so the
2016         caller will have a chance to process this non-macro.  */
2017      input_text_offset = old_text_offset;
2018      return 0;
2019    }
2020
2021  /* Perform alias expansion */
2022  command = alias_expand (command);
2023
2024  if (enclosure_command (command))
2025    {
2026      remember_brace (enclosure_expand);
2027      enclosure_expand (START, output_paragraph_offset, 0);
2028      return 0;
2029    }
2030
2031  entry = get_command_entry (command);
2032  if (entry == (COMMAND *)-1)
2033    {
2034      line_error (_("Unknown command `%s'"), command);
2035      return 0;
2036    }
2037
2038  if (entry->argument_in_braces == BRACE_ARGS)
2039    remember_brace (entry->proc);
2040  else if (entry->argument_in_braces == MAYBE_BRACE_ARGS)
2041    {
2042      if (curchar () == '{')
2043        remember_brace (entry->proc);
2044      else
2045        { /* No braces, so arg is next char.  */
2046          int ch;
2047          int saved_offset = output_paragraph_offset;
2048          (*(entry->proc)) (START, output_paragraph_offset, 0);
2049
2050          /* Possibilities left for the next character: @ (error), }
2051             (error), whitespace (skip) anything else (normal char).  */
2052          skip_whitespace ();
2053          ch = curchar ();
2054          if (ch == '@')
2055            {
2056           line_error (_("Use braces to give a command as an argument to @%s"),
2057               entry->name);
2058              return 0;
2059            }
2060          else if (ch == '}')
2061            {
2062              /* Our caller will give the error message, because this }
2063                 won't match anything.  */
2064              return 0;
2065            }
2066
2067          add_char (ch);
2068          input_text_offset++;
2069          (*(entry->proc)) (END, saved_offset, output_paragraph_offset);
2070          return 1;
2071        }
2072    }
2073
2074  /* Get here if we have BRACE_ARGS, NO_BRACE_ARGS, or MAYBE_BRACE_ARGS
2075     with braces.  */
2076  (*(entry->proc)) (START, output_paragraph_offset, 0);
2077  return 1;
2078}
2079
2080/* Okay, we are ready to start the conversion.  Call the reader on
2081   some text, and fill the text as it is output.  Handle commands by
2082   remembering things like open braces and the current file position on a
2083   stack, and when the corresponding close brace is found, you can call
2084   the function with the proper arguments.  Although the filling isn't
2085   necessary for HTML, it should do no harm.  */
2086void
2087reader_loop (void)
2088{
2089  int character;
2090  int done = 0;
2091
2092  while (!done)
2093    {
2094      if (input_text_offset >= input_text_length)
2095        break;
2096
2097      character = curchar ();
2098
2099      /* If only_macro_expansion, only handle macros and leave
2100         everything else intact.  */
2101      if (!only_macro_expansion && !in_fixed_width_font
2102          && ((!html && !xml) || escape_html)
2103          && (character == '\'' || character == '`')
2104          && input_text[input_text_offset + 1] == character)
2105        {
2106          if (html)
2107            {
2108              input_text_offset += 2;
2109              add_word (character == '`' ? "&ldquo;" : "&rdquo;");
2110              continue;
2111            }
2112          else if (xml)
2113            {
2114              input_text_offset += 2;
2115              xml_insert_entity (character == '`' ? "ldquo" : "rdquo");
2116              continue;
2117            }
2118          else
2119            {
2120              input_text_offset++;
2121              character = '"';
2122            }
2123        }
2124
2125      /* Convert --- to --.  */
2126      if (!only_macro_expansion && character == '-' && !in_fixed_width_font
2127          && ((!html && !xml) || escape_html))
2128        {
2129          int dash_count = 0;
2130
2131          /* Get the number of consequtive dashes.  */
2132          while (input_text[input_text_offset] == '-')
2133            {
2134              dash_count++;
2135              input_text_offset++;
2136            }
2137
2138          /* Eat one dash.  */
2139          dash_count--;
2140
2141          if (html || xml)
2142            {
2143              if (dash_count == 0)
2144                add_char ('-');
2145              else
2146                while (dash_count > 0)
2147                  {
2148                    if (dash_count >= 2)
2149                      {
2150                        if (html)
2151                          add_word ("&mdash;");
2152                        else
2153                          xml_insert_entity ("mdash");
2154                        dash_count -= 2;
2155                      }
2156                    else if (dash_count >= 1)
2157                      {
2158                        if (html)
2159                          add_word ("&ndash;");
2160                        else
2161                          xml_insert_entity ("ndash");
2162                        dash_count--;
2163                      }
2164                  }
2165            }
2166          else
2167            {
2168              add_char ('-');
2169              while (--dash_count > 0)
2170                add_char ('-');
2171            }
2172
2173          continue;
2174        }
2175
2176      /* If this is a whitespace character, then check to see if the line
2177         is blank.  If so, advance to the carriage return. */
2178      if (!only_macro_expansion && whitespace (character))
2179        {
2180          int i = input_text_offset + 1;
2181
2182          while (i < input_text_length && whitespace (input_text[i]))
2183            i++;
2184
2185          if (i == input_text_length || input_text[i] == '\n')
2186            {
2187              if (i == input_text_length)
2188                i--;
2189
2190              input_text_offset = i;
2191              character = curchar ();
2192            }
2193        }
2194
2195      if (character == '\n')
2196        line_number++;
2197
2198      switch (character)
2199        {
2200        case '*': /* perhaps we are at a menu */
2201          /* We used to check for this in the \n case but an @c in a
2202             menu swallows its newline, so check here instead.  */
2203          if (!only_macro_expansion && in_menu
2204              && input_text_offset + 1 < input_text_length
2205              && input_text[input_text_offset-1] == '\n')
2206            handle_menu_entry ();
2207          else
2208            { /* Duplicate code from below, but not worth twisting the
2209                 fallthroughs to get down there.  */
2210              add_char (character);
2211              input_text_offset++;
2212            }
2213          break;
2214
2215        /* Escapes for HTML unless we're outputting raw HTML.  Do
2216           this always, even if SGML rules don't require it since
2217           that's easier and safer for non-conforming browsers. */
2218        case '&':
2219          if (html && escape_html)
2220            add_word ("&amp;");
2221          else
2222            add_char (character);
2223          input_text_offset++;
2224          break;
2225
2226        case '<':
2227          if (html && escape_html)
2228            add_word ("&lt;");
2229          else if (xml && escape_html)
2230            xml_insert_entity ("lt");
2231          else
2232            add_char (character);
2233          input_text_offset++;
2234          break;
2235
2236        case '>':
2237          if (html && escape_html)
2238            add_word ("&gt;");
2239          else if (xml && escape_html)
2240            xml_insert_entity ("gt");
2241          else
2242            add_char (character);
2243          input_text_offset++;
2244          break;
2245
2246        case COMMAND_PREFIX: /* @ */
2247          if (read_command () || !only_macro_expansion)
2248            break;
2249
2250        /* FALLTHROUGH (usually) */
2251        case '{':
2252          /* Special case.  We're not supposed to see this character by itself.
2253             If we do, it means there is a syntax error in the input text.
2254             Report the error here, but remember this brace on the stack so
2255             we can ignore its partner. */
2256          if (!only_macro_expansion)
2257            {
2258              if (command && !STREQ (command, "math"))
2259                {
2260                  line_error (_("Misplaced %c"), '{');
2261                  remember_brace (misplaced_brace);
2262                }
2263              else
2264                /* We don't mind `extra' braces inside @math.  */
2265                remember_brace (cm_no_op);
2266              /* remember_brace advances input_text_offset.  */
2267              break;
2268            }
2269
2270        /* FALLTHROUGH (usually) */
2271        case '}':
2272          if (!only_macro_expansion)
2273            {
2274              pop_and_call_brace ();
2275              input_text_offset++;
2276              break;
2277            }
2278
2279        /* FALLTHROUGH (usually) */
2280        default:
2281          add_char (character);
2282          input_text_offset++;
2283        }
2284    }
2285  if (macro_expansion_output_stream && !only_macro_expansion)
2286    maybe_write_itext (input_text, input_text_offset);
2287}
2288
2289static void
2290init_brace_stack (void)
2291{
2292  brace_stack = NULL;
2293}
2294
2295/* Remember the current output position here.  Save PROC
2296   along with it so you can call it later. */
2297static void
2298remember_brace_1 (COMMAND_FUNCTION (*proc), int position)
2299{
2300  BRACE_ELEMENT *new = xmalloc (sizeof (BRACE_ELEMENT));
2301  new->next = brace_stack;
2302  new->proc = proc;
2303  new->command = command ? xstrdup (command) : "";
2304  new->pos = position;
2305  new->line = line_number;
2306  new->in_fixed_width_font = in_fixed_width_font;
2307  brace_stack = new;
2308}
2309
2310static void
2311remember_brace (COMMAND_FUNCTION (*proc))
2312{
2313  if (curchar () != '{')
2314    line_error (_("%c%s expected braces"), COMMAND_PREFIX, command);
2315  else
2316    input_text_offset++;
2317  remember_brace_1 (proc, output_paragraph_offset);
2318}
2319
2320/* Pop the top of the brace stack, and call the associated function
2321   with the args END and POS. */
2322static void
2323pop_and_call_brace (void)
2324{
2325  if (brace_stack == NULL)
2326    {
2327      line_error (_("Unmatched }"));
2328      return;
2329    }
2330
2331  {
2332    BRACE_ELEMENT *temp;
2333
2334    int pos = brace_stack->pos;
2335    COMMAND_FUNCTION *proc = brace_stack->proc;
2336    in_fixed_width_font = brace_stack->in_fixed_width_font;
2337
2338    /* Reset current command, so the proc can know who it is.  This is
2339       used in cm_accent.  */
2340    command = brace_stack->command;
2341
2342    temp = brace_stack->next;
2343    free (brace_stack);
2344    brace_stack = temp;
2345
2346    (*proc) (END, pos, output_paragraph_offset);
2347  }
2348}
2349
2350/* Shift all of the markers in `brace_stack' by AMOUNT. */
2351static void
2352adjust_braces_following (int here, int amount)
2353{
2354  BRACE_ELEMENT *stack = brace_stack;
2355
2356  while (stack)
2357    {
2358      if (stack->pos >= here)
2359        stack->pos += amount;
2360      stack = stack->next;
2361    }
2362}
2363
2364/* Return the string which invokes PROC; a pointer to a function.
2365   Always returns the first function in the command table if more than
2366   one matches PROC.  */
2367static const char *
2368find_proc_name (COMMAND_FUNCTION (*proc))
2369{
2370  int i;
2371
2372  for (i = 0; command_table[i].name; i++)
2373    if (proc == command_table[i].proc)
2374      return command_table[i].name;
2375  return _("NO_NAME!");
2376}
2377
2378/* You call discard_braces () when you shouldn't have any braces on the stack.
2379   I used to think that this happens for commands that don't take arguments
2380   in braces, but that was wrong because of things like @code{foo @@}.  So now
2381   I only detect it at the beginning of nodes. */
2382void
2383discard_braces (void)
2384{
2385  if (!brace_stack)
2386    return;
2387
2388  while (brace_stack)
2389    {
2390      if (brace_stack->proc != misplaced_brace)
2391        {
2392          const char *proc_name;
2393
2394          proc_name = find_proc_name (brace_stack->proc);
2395          file_line_error (input_filename, brace_stack->line,
2396                           _("%c%s missing close brace"), COMMAND_PREFIX,
2397                           proc_name);
2398          pop_and_call_brace ();
2399        }
2400      else
2401        {
2402          BRACE_ELEMENT *temp;
2403          temp = brace_stack->next;
2404          free (brace_stack);
2405          brace_stack = temp;
2406        }
2407    }
2408}
2409
2410static int
2411get_char_len (int character)
2412{
2413  /* Return the printed length of the character. */
2414  int len;
2415
2416  switch (character)
2417    {
2418    case '\t':
2419      len = (output_column + 8) & 0xf7;
2420      if (len > fill_column)
2421        len = fill_column - output_column;
2422      else
2423        len = len - output_column;
2424      break;
2425
2426    case '\n':
2427      len = fill_column - output_column;
2428      break;
2429
2430    default:
2431      /* ASCII control characters appear as two characters in the output
2432         (e.g., ^A).  But characters with the high bit set are just one
2433         on suitable terminals, so don't count them as two for line
2434         breaking purposes.  */
2435      if (0 <= character && character < ' ')
2436        len = 2;
2437      else
2438        len = 1;
2439    }
2440  return len;
2441}
2442
2443void
2444#if defined (VA_FPRINTF) && __STDC__
2445add_word_args (const char *format, ...)
2446#else
2447add_word_args (format, va_alist)
2448    const char *format;
2449    va_dcl
2450#endif
2451{
2452  char buffer[2000]; /* xx no fixed limits */
2453#ifdef VA_FPRINTF
2454  va_list ap;
2455#endif
2456
2457  VA_START (ap, format);
2458#ifdef VA_SPRINTF
2459  VA_SPRINTF (buffer, format, ap);
2460#else
2461  sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8);
2462#endif /* not VA_SPRINTF */
2463  va_end (ap);
2464  add_word (buffer);
2465}
2466
2467/* Add STRING to output_paragraph. */
2468void
2469add_word (char *string)
2470{
2471  while (*string)
2472    add_char (*string++);
2473}
2474
2475/* Like add_word, but inhibits conversion of whitespace into &nbsp;.
2476   Use this to output HTML directives with embedded blanks, to make
2477   them @w-safe.  */
2478void
2479add_html_elt (char *string)
2480{
2481  in_html_elt++;
2482  add_word (string);
2483  in_html_elt--;
2484}
2485
2486/* These two functions below, add_html_block_elt and add_html_block_elt_args,
2487   are mixtures of add_html_elt and add_word_args.  They inform makeinfo that
2488   the current HTML element being inserted should not be enclosed in a <p>
2489   element.  */
2490void
2491add_html_block_elt (char *string)
2492{
2493  in_html_block_level_elt++;
2494  add_word (string);
2495  in_html_block_level_elt--;
2496}
2497
2498void
2499#if defined (VA_FPRINTF) && __STDC__
2500add_html_block_elt_args (const char *format, ...)
2501#else
2502add_html_block_elt_args (format, va_alist)
2503    const char *format;
2504    va_dcl
2505#endif
2506{
2507  char buffer[2000]; /* xx no fixed limits */
2508#ifdef VA_FPRINTF
2509  va_list ap;
2510#endif
2511
2512  VA_START (ap, format);
2513#ifdef VA_SPRINTF
2514  VA_SPRINTF (buffer, format, ap);
2515#else
2516  sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8);
2517#endif /* not VA_SPRINTF */
2518  va_end (ap);
2519  add_html_block_elt (buffer);
2520}
2521
2522/* Here is another awful kludge, used in add_char.  Ordinarily, macro
2523   expansions take place in the body of the document, and therefore we
2524   should html_output_head when we see one.  But there's an exception: a
2525   macro call might take place within @copying, and that does not start
2526   the real output, even though we fully expand the copying text.
2527
2528   So we need to be able to check if we are defining the @copying text.
2529   We do this by looking back through the insertion stack.  */
2530static int
2531defining_copying (void)
2532{
2533  INSERTION_ELT *i;
2534  for (i = insertion_stack; i; i = i->next)
2535    {
2536      if (i->insertion == copying)
2537        return 1;
2538    }
2539  return 0;
2540}
2541
2542
2543/* Add the character to the current paragraph.  If filling_enabled is
2544   nonzero, then do filling as well. */
2545void
2546add_char (int character)
2547{
2548  if (xml)
2549    {
2550      xml_add_char (character);
2551      return;
2552    }
2553
2554  /* If we are avoiding outputting headers, and we are currently
2555     in a menu, then simply return.  But if we're only expanding macros,
2556     then we're being called from glean_node_from_menu to try to
2557     remember a menu reference, and we need that so we can do defaulting.  */
2558  if (no_headers && !only_macro_expansion && (in_menu || in_detailmenu))
2559    return;
2560
2561  /* If we are adding a character now, then we don't have to
2562     ignore close_paragraph () calls any more. */
2563  if (must_start_paragraph && character != '\n')
2564    {
2565      must_start_paragraph = 0;
2566      line_already_broken = 0;  /* The line is no longer broken. */
2567      if (current_indent > output_column)
2568        {
2569          indent (current_indent - output_column);
2570          output_column = current_indent;
2571        }
2572    }
2573
2574  if (non_splitting_words
2575      && !(html && in_html_elt)
2576      && strchr (" \t\n", character))
2577    {
2578      if (html || docbook)
2579        { /* Seems cleaner to use &nbsp; than an 8-bit char.  */
2580          int saved_escape_html = escape_html;
2581          escape_html = 0;
2582          add_word ("&nbsp");
2583          escape_html = saved_escape_html;
2584          character = ';';
2585        }
2586      else
2587        character = META (' '); /* unmeta-d in flush_output */
2588    }
2589
2590  insertion_paragraph_closed = 0;
2591
2592  switch (character)
2593    {
2594    case '\n':
2595      if (!filling_enabled && !(html && (in_menu || in_detailmenu)))
2596        {
2597          insert ('\n');
2598
2599          if (force_flush_right)
2600            {
2601              close_paragraph ();
2602              /* Hack to force single blank lines out in this mode. */
2603              flush_output ();
2604            }
2605
2606          output_column = 0;
2607
2608          if (!no_indent && paragraph_is_open)
2609            indent (output_column = current_indent);
2610          break;
2611        }
2612      else if (end_of_sentence_p ())
2613        /* CHARACTER is newline, and filling is enabled. */
2614        {
2615          insert (' ');
2616          output_column++;
2617          last_inserted_character = character;
2618        }
2619
2620      if (last_char_was_newline)
2621        {
2622          if (html)
2623            last_char_was_newline++;
2624          close_paragraph ();
2625          pending_indent = 0;
2626        }
2627      else
2628        {
2629          last_char_was_newline = 1;
2630          if (html)
2631            insert ('\n');
2632          else
2633            insert (' ');
2634          output_column++;
2635        }
2636      break;
2637
2638    default: /* not at newline */
2639      {
2640        int len = get_char_len (character);
2641        int suppress_insert = 0;
2642
2643        if ((character == ' ') && (last_char_was_newline))
2644          {
2645            if (!paragraph_is_open)
2646              {
2647                pending_indent++;
2648                return;
2649              }
2650          }
2651
2652        /* This is sad, but it seems desirable to not force any
2653           particular order on the front matter commands.  This way,
2654           the document can do @settitle, @documentlanguage, etc, in
2655           any order and with any omissions, and we'll still output
2656           the html <head> `just in time'.  */
2657        if ((executing_macro || !executing_string)
2658            && !only_macro_expansion
2659            && html && !html_output_head_p && !defining_copying ())
2660          html_output_head ();
2661
2662        if (!paragraph_is_open)
2663          {
2664            start_paragraph ();
2665            /* If the paragraph is supposed to be indented a certain
2666               way, then discard all of the pending whitespace.
2667               Otherwise, we let the whitespace stay. */
2668            if (!paragraph_start_indent)
2669              indent (pending_indent);
2670            pending_indent = 0;
2671
2672            /* This check for in_html_block_level_elt prevents <p> from being
2673               inserted when we already have html markup starting a paragraph,
2674               as with <ul> and <h1> and the like.  */
2675            if (html && !in_html_block_level_elt)
2676              {
2677                if ((in_menu || in_detailmenu) && in_menu_item)
2678                  {
2679                    insert_string ("</li></ul>\n");
2680                    in_menu_item = 0;
2681                  }
2682                insert_string ("<p>");
2683                in_paragraph = 1;
2684                adjust_braces_following (0, 3); /* adjust for <p> */
2685              }
2686          }
2687
2688        output_column += len;
2689        if (output_column > fill_column)
2690          {
2691            if (filling_enabled && !html)
2692              {
2693                int temp = output_paragraph_offset;
2694                while (--temp > 0 && output_paragraph[temp] != '\n')
2695                  {
2696                    /* If we have found a space, we have the place to break
2697                       the line. */
2698                    if (output_paragraph[temp] == ' ')
2699                      {
2700                        /* Remove trailing whitespace from output. */
2701                        while (temp && whitespace (output_paragraph[temp - 1]))
2702                          temp--;
2703
2704                        /* If we went back all the way to the newline of the
2705                           preceding line, it probably means that the word we
2706                           are adding is itself wider than the space that the
2707                           indentation and the fill_column let us use.  In
2708                           that case, do NOT insert another newline, since it
2709                           won't help.  Just indent to current_indent and
2710                           leave it alone, since that's the most we can do.  */
2711                        if (temp && output_paragraph[temp - 1] != '\n')
2712                          output_paragraph[temp++] = '\n';
2713
2714                        /* We have correctly broken the line where we want
2715                           to.  What we don't want is spaces following where
2716                           we have decided to break the line.  We get rid of
2717                           them. */
2718                        {
2719                          int t1 = temp;
2720
2721                          for (;; t1++)
2722                            {
2723                              if (t1 == output_paragraph_offset)
2724                                {
2725                                  if (whitespace (character))
2726                                    suppress_insert = 1;
2727                                  break;
2728                                }
2729                              if (!whitespace (output_paragraph[t1]))
2730                                break;
2731                            }
2732
2733                          if (t1 != temp)
2734                            {
2735                              adjust_braces_following (temp, (- (t1 - temp)));
2736                              memmove (&output_paragraph[temp],
2737                                       &output_paragraph[t1],
2738                                       output_paragraph_offset - t1);
2739                              output_paragraph_offset -= (t1 - temp);
2740                            }
2741                        }
2742
2743                        /* Filled, but now indent if that is right. */
2744                        if (indented_fill && current_indent > 0)
2745                          {
2746                            int buffer_len = ((output_paragraph_offset - temp)
2747                                              + current_indent);
2748                            char *temp_buffer = xmalloc (buffer_len);
2749                            int indentation = 0;
2750
2751                            /* We have to shift any markers that are in
2752                               front of the wrap point. */
2753                            adjust_braces_following (temp, current_indent);
2754
2755                            while (current_indent > 0 &&
2756                                   indentation != current_indent)
2757                              temp_buffer[indentation++] = ' ';
2758
2759                            memcpy ((char *) &temp_buffer[current_indent],
2760                                     (char *) &output_paragraph[temp],
2761                                     buffer_len - current_indent);
2762
2763                            if (output_paragraph_offset + buffer_len
2764                                >= paragraph_buffer_len)
2765                              {
2766                                unsigned char *tt = xrealloc
2767                                  (output_paragraph,
2768                                   (paragraph_buffer_len += buffer_len));
2769                                output_paragraph = tt;
2770                              }
2771                            memcpy ((char *) &output_paragraph[temp],
2772                                     temp_buffer, buffer_len);
2773                            output_paragraph_offset += current_indent;
2774                            free (temp_buffer);
2775                          }
2776                        output_column = 0;
2777                        while (temp < output_paragraph_offset)
2778                          output_column +=
2779                            get_char_len (output_paragraph[temp++]);
2780                        output_column += len;
2781                        break;
2782                      }
2783                  }
2784              }
2785          }
2786
2787        if (!suppress_insert)
2788          {
2789            insert (character);
2790            last_inserted_character = character;
2791          }
2792        last_char_was_newline = 0;
2793        line_already_broken = 0;
2794      }
2795    }
2796}
2797
2798/* Add a character and store its position in meta_char_pos.  */
2799void
2800add_meta_char (int character)
2801{
2802  meta_char_pos = output_paragraph_offset;
2803  add_char (character);
2804}
2805
2806/* Insert CHARACTER into `output_paragraph'. */
2807void
2808insert (int character)
2809{
2810  /* We don't want to strip trailing whitespace in multitables.  Otherwise
2811     horizontal separators confuse the font locking in Info mode in Emacs,
2812     because it looks like a @subsection.  Adding a trailing space to those
2813     lines fixes it.  */
2814  if (character == '\n' && !html && !xml && !multitable_active)
2815    {
2816      while (output_paragraph_offset
2817	     && whitespace (output_paragraph[output_paragraph_offset-1]))
2818	output_paragraph_offset--;
2819    }
2820
2821  output_paragraph[output_paragraph_offset++] = character;
2822  if (output_paragraph_offset == paragraph_buffer_len)
2823    {
2824      output_paragraph =
2825        xrealloc (output_paragraph, (paragraph_buffer_len += 100));
2826    }
2827}
2828
2829/* Insert the null-terminated string STRING into `output_paragraph'.  */
2830void
2831insert_string (const char *string)
2832{
2833  while (*string)
2834    insert (*string++);
2835}
2836
2837
2838/* Sentences might have these characters after the period (or whatever).  */
2839#define POST_SENTENCE(c) ((c) == ')' || (c) == '\'' || (c) == '"' \
2840                          || (c) == ']')
2841
2842/* Return true if at an end-of-sentence character, possibly followed by
2843   post-sentence punctuation to ignore.  */
2844static int
2845end_of_sentence_p (void)
2846{
2847  int loc = output_paragraph_offset - 1;
2848
2849  /* If nothing has been output, don't check output_paragraph[-1].  */
2850  if (loc < 0)
2851    return 0;
2852
2853  /* A post-sentence character that is at meta_char_pos is not really
2854     a post-sentence character; it was produced by a markup such as
2855     @samp.  We don't want the period inside @samp to be treated as a
2856     sentence ender. */
2857  while (loc > 0
2858         && loc != meta_char_pos && POST_SENTENCE (output_paragraph[loc]))
2859    loc--;
2860  return loc != meta_char_pos && sentence_ender (output_paragraph[loc]);
2861}
2862
2863
2864/* Remove upto COUNT characters of whitespace from the
2865   the current output line.  If COUNT is less than zero,
2866   then remove until none left. */
2867void
2868kill_self_indent (int count)
2869{
2870  /* Handle infinite case first. */
2871  if (count < 0)
2872    {
2873      output_column = 0;
2874      while (output_paragraph_offset)
2875        {
2876          if (whitespace (output_paragraph[output_paragraph_offset - 1]))
2877            output_paragraph_offset--;
2878          else
2879            break;
2880        }
2881    }
2882  else
2883    {
2884      while (output_paragraph_offset && count--)
2885        if (whitespace (output_paragraph[output_paragraph_offset - 1]))
2886          output_paragraph_offset--;
2887        else
2888          break;
2889    }
2890}
2891
2892/* Nonzero means do not honor calls to flush_output (). */
2893static int flushing_ignored = 0;
2894
2895/* Prevent calls to flush_output () from having any effect. */
2896void
2897inhibit_output_flushing (void)
2898{
2899  flushing_ignored++;
2900}
2901
2902/* Allow calls to flush_output () to write the paragraph data. */
2903void
2904uninhibit_output_flushing (void)
2905{
2906  flushing_ignored--;
2907}
2908
2909void
2910flush_output (void)
2911{
2912  int i;
2913
2914  if (!output_paragraph_offset || flushing_ignored)
2915    return;
2916
2917  for (i = 0; i < output_paragraph_offset; i++)
2918    {
2919      if (output_paragraph[i] == '\n')
2920        {
2921          output_line_number++;
2922          node_line_number++;
2923        }
2924
2925      /* If we turned on the 8th bit for a space inside @w, turn it
2926         back off for output.  This might be problematic, since the
2927         0x80 character may be used in 8-bit character sets.  Sigh.
2928         In any case, don't do this for HTML, since the nbsp character
2929         is valid input and must be passed along to the browser.  */
2930      if (!html && (output_paragraph[i] & meta_character_bit))
2931        {
2932          int temp = UNMETA (output_paragraph[i]);
2933          if (temp == ' ')
2934            output_paragraph[i] &= 0x7f;
2935        }
2936    }
2937
2938  fwrite (output_paragraph, 1, output_paragraph_offset, output_stream);
2939
2940  output_position += output_paragraph_offset;
2941  output_paragraph_offset = 0;
2942  meta_char_pos = 0;
2943}
2944
2945/* How to close a paragraph controlling the number of lines between
2946   this one and the last one. */
2947
2948/* Paragraph spacing is controlled by this variable.  It is the number of
2949   blank lines that you wish to appear between paragraphs.  A value of
2950   1 creates a single blank line between paragraphs. */
2951int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING;
2952
2953static void
2954close_paragraph_with_lines (int lines)
2955{
2956  int old_spacing = paragraph_spacing;
2957  paragraph_spacing = lines;
2958  close_paragraph ();
2959  paragraph_spacing = old_spacing;
2960}
2961
2962/* Close the current paragraph, leaving no blank lines between them. */
2963void
2964close_single_paragraph (void)
2965{
2966  close_paragraph_with_lines (0);
2967}
2968
2969/* Close a paragraph after an insertion has ended. */
2970void
2971close_insertion_paragraph (void)
2972{
2973  if (!insertion_paragraph_closed)
2974    {
2975      /* Close the current paragraph, breaking the line. */
2976      close_single_paragraph ();
2977
2978      /* Start a new paragraph, with the correct indentation for the now
2979         current insertion level (one above the one that we are ending). */
2980      start_paragraph ();
2981
2982      /* Tell `close_paragraph' that the previous line has already been
2983         broken, so it should insert one less newline. */
2984      line_already_broken = 1;
2985
2986      /* Tell functions such as `add_char' we've already found a newline. */
2987      ignore_blank_line ();
2988    }
2989  else
2990    {
2991      /* If the insertion paragraph is closed already, then we are seeing
2992         two `@end' commands in a row.  Note that the first one we saw was
2993         handled in the first part of this if-then-else clause, and at that
2994         time `start_paragraph' was called, partially to handle the proper
2995         indentation of the current line.  However, the indentation level
2996         may have just changed again, so we may have to outdent the current
2997         line to the new indentation level. */
2998      if (current_indent < output_column)
2999        kill_self_indent (output_column - current_indent);
3000    }
3001
3002  insertion_paragraph_closed = 1;
3003}
3004
3005/* Close the currently open paragraph. */
3006void
3007close_paragraph (void)
3008{
3009  int i;
3010
3011  /* We don't need these newlines in XML and Docbook outputs for
3012     paragraph seperation.  We have <para> element for that.  */
3013  if (xml)
3014    return;
3015
3016  /* The insertion paragraph is no longer closed. */
3017  insertion_paragraph_closed = 0;
3018
3019  if (paragraph_is_open && !must_start_paragraph)
3020    {
3021      int tindex = output_paragraph_offset;
3022
3023      /* Back up to last non-newline/space character, forcing all such
3024         subsequent characters to be newlines.  This isn't strictly
3025         necessary, but a couple of functions use the presence of a newline
3026         to make decisions. */
3027      for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex)
3028        {
3029          int c = output_paragraph[tindex];
3030
3031          if (c == ' '|| c == '\n')
3032            output_paragraph[tindex] = '\n';
3033          else
3034            break;
3035        }
3036
3037      /* All trailing whitespace is ignored. */
3038      output_paragraph_offset = ++tindex;
3039
3040      /* Break the line if that is appropriate. */
3041      if (paragraph_spacing >= 0)
3042        insert ('\n');
3043
3044      /* Add as many blank lines as is specified in `paragraph_spacing'. */
3045      if (!force_flush_right)
3046        {
3047          for (i = 0; i < (paragraph_spacing - line_already_broken); i++)
3048            {
3049              insert ('\n');
3050              /* Don't need anything extra for HTML in usual case of no
3051                 extra paragraph spacing.  */
3052              if (html && i > 0)
3053                insert_string ("<br>");
3054            }
3055        }
3056
3057      /* If we are doing flush right indentation, then do it now
3058         on the paragraph (really a single line). */
3059      if (force_flush_right)
3060        do_flush_right_indentation ();
3061
3062      flush_output ();
3063      paragraph_is_open = 0;
3064      no_indent = 0;
3065      output_column = 0;
3066    }
3067
3068  ignore_blank_line ();
3069}
3070
3071/* Make the last line just read look as if it were only a newline. */
3072void
3073ignore_blank_line (void)
3074{
3075  last_inserted_character = '\n';
3076  last_char_was_newline = 1;
3077}
3078
3079/* Align the end of the text in output_paragraph with fill_column. */
3080static void
3081do_flush_right_indentation (void)
3082{
3083  char *temp;
3084  int temp_len;
3085
3086  kill_self_indent (-1);
3087
3088  if (output_paragraph[0] != '\n')
3089    {
3090      output_paragraph[output_paragraph_offset] = 0;
3091
3092      if (output_paragraph_offset < fill_column)
3093        {
3094          int i;
3095
3096          if (fill_column >= paragraph_buffer_len)
3097            output_paragraph =
3098              xrealloc (output_paragraph,
3099                        (paragraph_buffer_len += fill_column));
3100
3101          temp_len = strlen ((char *)output_paragraph);
3102          temp = xmalloc (temp_len + 1);
3103          memcpy (temp, (char *)output_paragraph, temp_len);
3104
3105          for (i = 0; i < fill_column - output_paragraph_offset; i++)
3106            output_paragraph[i] = ' ';
3107
3108          memcpy ((char *)output_paragraph + i, temp, temp_len);
3109          free (temp);
3110          output_paragraph_offset = fill_column;
3111          adjust_braces_following (0, i);
3112        }
3113    }
3114}
3115
3116/* Begin a new paragraph. */
3117void
3118start_paragraph (void)
3119{
3120  /* First close existing one. */
3121  if (paragraph_is_open)
3122    close_paragraph ();
3123
3124  /* In either case, the insertion paragraph is no longer closed. */
3125  insertion_paragraph_closed = 0;
3126
3127  /* However, the paragraph is open! */
3128  paragraph_is_open = 1;
3129
3130  /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph ()
3131     had to be called before we would allow any other paragraph operations
3132     to have an effect. */
3133  if (!must_start_paragraph)
3134    {
3135      int amount_to_indent = 0;
3136
3137      /* If doing indentation, then insert the appropriate amount. */
3138      if (!no_indent)
3139        {
3140          if (inhibit_paragraph_indentation)
3141            {
3142              amount_to_indent = current_indent;
3143              if (inhibit_paragraph_indentation < 0)
3144                inhibit_paragraph_indentation++;
3145            }
3146          else if (paragraph_start_indent < 0)
3147            amount_to_indent = current_indent;
3148          else
3149            amount_to_indent = current_indent + paragraph_start_indent;
3150
3151          if (amount_to_indent >= output_column)
3152            {
3153              amount_to_indent -= output_column;
3154              indent (amount_to_indent);
3155              output_column += amount_to_indent;
3156            }
3157        }
3158    }
3159  else
3160    must_start_paragraph = 0;
3161}
3162
3163/* Insert the indentation specified by AMOUNT. */
3164void
3165indent (int amount)
3166{
3167  /* For every START_POS saved within the brace stack which will be affected
3168     by this indentation, bump that start pos forward. */
3169  adjust_braces_following (output_paragraph_offset, amount);
3170
3171  while (--amount >= 0)
3172    insert (' ');
3173}
3174
3175/* Search forward for STRING in input_text.
3176   FROM says where where to start. */
3177int
3178search_forward (char *string, int from)
3179{
3180  int len = strlen (string);
3181
3182  while (from < input_text_length)
3183    {
3184      if (strncmp (input_text + from, string, len) == 0)
3185        return from;
3186      from++;
3187    }
3188  return -1;
3189}
3190
3191/* search_forward until n characters.  */
3192int
3193search_forward_until_pos (char *string, int from, int end_pos)
3194{
3195  int save_input_text_length = input_text_length;
3196  input_text_length = end_pos;
3197
3198  from = search_forward (string, from);
3199
3200  input_text_length = save_input_text_length;
3201
3202  return from;
3203}
3204
3205/* Return next non-whitespace and non-cr character.  */
3206int
3207next_nonwhitespace_character (void)
3208{
3209  /* First check the current input_text.  Start from the next char because
3210     we already have input_text[input_text_offset] in ``current''.  */
3211  int pos = input_text_offset + 1;
3212
3213  while (pos < input_text_length)
3214    {
3215      if (!cr_or_whitespace(input_text[pos]))
3216        return input_text[pos];
3217      pos++;
3218    }
3219
3220  { /* Can't find a valid character, so go through filestack
3221       in case we are doing @include or expanding a macro.  */
3222    FSTACK *tos = filestack;
3223
3224    while (tos)
3225      {
3226        int tmp_input_text_length = filestack->size;
3227        int tmp_input_text_offset = filestack->offset;
3228        char *tmp_input_text = filestack->text;
3229
3230        while (tmp_input_text_offset < tmp_input_text_length)
3231          {
3232            if (!cr_or_whitespace(tmp_input_text[tmp_input_text_offset]))
3233              return tmp_input_text[tmp_input_text_offset];
3234            tmp_input_text_offset++;
3235          }
3236
3237        tos = tos->next;
3238      }
3239  }
3240
3241  return -1;
3242}
3243
3244/* An external image is a reference, kind of.  The parsing is (not
3245   coincidentally) similar, anyway.  */
3246void
3247cm_image (int arg)
3248{
3249  char *name_arg, *w_arg, *h_arg, *alt_arg, *ext_arg;
3250
3251  if (arg == END)
3252    return;
3253
3254  name_arg = get_xref_token (1); /* expands all macros in image */
3255  w_arg = get_xref_token (0);
3256  h_arg = get_xref_token (0);
3257  alt_arg = get_xref_token (1); /* expands all macros in alt text */
3258  ext_arg = get_xref_token (0);
3259
3260  if (*name_arg)
3261    {
3262      struct stat file_info;
3263      char *pathname = NULL;
3264      char *fullname = xmalloc (strlen (name_arg)
3265                       + (ext_arg && *ext_arg ? strlen (ext_arg) + 1: 4) + 1);
3266
3267      if (ext_arg && *ext_arg)
3268        {
3269          sprintf (fullname, "%s%s", name_arg, ext_arg);
3270          if (access (fullname, R_OK) != 0)
3271            pathname = get_file_info_in_path (fullname, include_files_path,
3272                                              &file_info);
3273
3274	  if (pathname == NULL)
3275	    {
3276	      /* Backwards compatibility (4.6 <= version < 4.7):
3277		 try prefixing @image's EXTENSION parameter with a period. */
3278	      sprintf (fullname, "%s.%s", name_arg, ext_arg);
3279	      if (access (fullname, R_OK) != 0)
3280		pathname = get_file_info_in_path (fullname, include_files_path,
3281						  &file_info);
3282	    }
3283        }
3284      else
3285        {
3286          sprintf (fullname, "%s.png", name_arg);
3287          if (access (fullname, R_OK) != 0) {
3288            pathname = get_file_info_in_path (fullname,
3289                                              include_files_path, &file_info);
3290            if (pathname == NULL) {
3291              sprintf (fullname, "%s.jpg", name_arg);
3292              if (access (fullname, R_OK) != 0) {
3293                sprintf (fullname, "%s.gif", name_arg);
3294                if (access (fullname, R_OK) != 0) {
3295                  pathname = get_file_info_in_path (fullname,
3296                                               include_files_path, &file_info);
3297                }
3298              }
3299            }
3300          }
3301        }
3302
3303      if (html)
3304        {
3305          int image_in_div = 0;
3306
3307          if (pathname == NULL && access (fullname, R_OK) != 0)
3308            {
3309              line_error(_("@image file `%s' (for HTML) not readable: %s"),
3310                             fullname, strerror (errno));
3311              return;
3312            }
3313          if (pathname != NULL && access (pathname, R_OK) != 0)
3314            {
3315              line_error (_("No such file `%s'"),
3316                          fullname);
3317              return;
3318            }
3319
3320          if (!paragraph_is_open)
3321            {
3322              add_html_block_elt ("<div class=\"block-image\">");
3323              image_in_div = 1;
3324            }
3325
3326          add_html_elt ("<img src=");
3327          add_word_args ("\"%s\"", fullname);
3328          add_html_elt (" alt=");
3329          add_word_args ("\"%s\">",
3330              escape_string (*alt_arg ? text_expansion (alt_arg) : fullname));
3331
3332          if (image_in_div)
3333            add_html_block_elt ("</div>");
3334        }
3335      else if (xml && docbook)
3336        xml_insert_docbook_image (name_arg);
3337      else if (xml)
3338        {
3339          extern int xml_in_para;
3340          extern int xml_no_para;
3341          int elt = xml_in_para ? INLINEIMAGE : IMAGE;
3342
3343          if (!xml_in_para)
3344            xml_no_para++;
3345
3346          xml_insert_element_with_attribute (elt,
3347              START, "width=\"%s\" height=\"%s\" name=\"%s\" extension=\"%s\"",
3348              w_arg, h_arg, name_arg, ext_arg);
3349          xml_insert_element (IMAGEALTTEXT, START);
3350          execute_string ("%s", alt_arg);
3351          xml_insert_element (IMAGEALTTEXT, END);
3352          xml_insert_element (elt, END);
3353
3354          if (!xml_in_para)
3355            xml_no_para--;
3356        }
3357      else
3358        { /* Try to open foo.EXT or foo.txt.  */
3359          FILE *image_file;
3360          char *txtpath = NULL;
3361          char *txtname = xmalloc (strlen (name_arg)
3362                                   + (ext_arg && *ext_arg
3363                                      ? strlen (ext_arg) : 4) + 1);
3364          strcpy (txtname, name_arg);
3365          strcat (txtname, ".txt");
3366          image_file = fopen (txtname, "r");
3367          if (image_file == NULL)
3368            {
3369              txtpath = get_file_info_in_path (txtname,
3370                                               include_files_path, &file_info);
3371              if (txtpath != NULL)
3372                image_file = fopen (txtpath, "r");
3373            }
3374
3375          if (image_file != NULL
3376              || access (fullname, R_OK) == 0
3377              || (pathname != NULL && access (pathname, R_OK) == 0))
3378            {
3379              int ch;
3380              int save_inhibit_indentation = inhibit_paragraph_indentation;
3381              int save_filling_enabled = filling_enabled;
3382              int image_in_brackets = paragraph_is_open;
3383
3384              /* Write magic ^@^H[image ...^@^H] cookie in the info file, if
3385                 there's an accompanying bitmap.  Otherwise just include the
3386                 text image.  In the plaintext output, always include the text
3387                 image without the magic cookie.  */
3388              int use_magic_cookie = !no_headers
3389                && access (fullname, R_OK) == 0 && !STREQ (fullname, txtname);
3390
3391              inhibit_paragraph_indentation = 1;
3392              filling_enabled = 0;
3393              last_char_was_newline = 0;
3394
3395              if (use_magic_cookie)
3396                {
3397                  add_char ('\0');
3398                  add_word ("\010[image");
3399
3400                  if (access (fullname, R_OK) == 0
3401                      || (pathname != NULL && access (pathname, R_OK) == 0))
3402                    add_word_args (" src=\"%s\"", fullname);
3403
3404                  if (*alt_arg)
3405                    add_word_args (" alt=\"%s\"", alt_arg);
3406                }
3407
3408              if (image_file != NULL)
3409                {
3410                  if (use_magic_cookie)
3411                    add_word (" text=\"");
3412
3413                  if (image_in_brackets)
3414                    add_char ('[');
3415
3416                  /* Maybe we need to remove the final newline if the image
3417                     file is only one line to allow in-line images.  On the
3418                     other hand, they could just make the file without a
3419                     final newline.  */
3420                  while ((ch = getc (image_file)) != EOF)
3421                    {
3422                      if (use_magic_cookie && (ch == '"' || ch == '\\'))
3423                        add_char ('\\');
3424                      add_char (ch);
3425                    }
3426
3427                  if (image_in_brackets)
3428                    add_char (']');
3429
3430                  if (use_magic_cookie)
3431                    add_char ('"');
3432
3433                  if (fclose (image_file) != 0)
3434                    perror (txtname);
3435                }
3436
3437              if (use_magic_cookie)
3438                {
3439                  add_char ('\0');
3440                  add_word ("\010]");
3441                }
3442
3443              inhibit_paragraph_indentation = save_inhibit_indentation;
3444              filling_enabled = save_filling_enabled;
3445            }
3446          else
3447            warning (_("@image file `%s' (for text) unreadable: %s"),
3448                        txtname, strerror (errno));
3449        }
3450
3451      free (fullname);
3452      if (pathname)
3453        free (pathname);
3454    }
3455  else
3456    line_error (_("@image missing filename argument"));
3457
3458  if (name_arg)
3459    free (name_arg);
3460  if (w_arg)
3461    free (w_arg);
3462  if (h_arg)
3463    free (h_arg);
3464  if (alt_arg)
3465    free (alt_arg);
3466  if (ext_arg)
3467    free (ext_arg);
3468}
3469
3470/* Conditionals.  */
3471
3472/* A structure which contains `defined' variables. */
3473typedef struct defines {
3474  struct defines *next;
3475  char *name;
3476  char *value;
3477} DEFINE;
3478
3479/* The linked list of `set' defines. */
3480DEFINE *defines = NULL;
3481
3482/* Add NAME to the list of `set' defines. */
3483static void
3484set (char *name, char *value)
3485{
3486  DEFINE *temp;
3487
3488  for (temp = defines; temp; temp = temp->next)
3489    if (strcmp (name, temp->name) == 0)
3490      {
3491        free (temp->value);
3492        temp->value = xstrdup (value);
3493        return;
3494      }
3495
3496  temp = xmalloc (sizeof (DEFINE));
3497  temp->next = defines;
3498  temp->name = xstrdup (name);
3499  temp->value = xstrdup (value);
3500  defines = temp;
3501
3502  if (xml && !docbook)
3503    {
3504      xml_insert_element_with_attribute (SETVALUE, START, "name=\"%s\"", name);
3505      execute_string ("%s", value);
3506      xml_insert_element (SETVALUE, END);
3507    }
3508}
3509
3510/* Remove NAME from the list of `set' defines. */
3511static void
3512clear (char *name)
3513{
3514  DEFINE *temp, *last;
3515
3516  last = NULL;
3517  temp = defines;
3518
3519  while (temp)
3520    {
3521      if (strcmp (temp->name, name) == 0)
3522        {
3523          if (last)
3524            last->next = temp->next;
3525          else
3526            defines = temp->next;
3527
3528          free (temp->name);
3529          free (temp->value);
3530          free (temp);
3531          break;
3532        }
3533      last = temp;
3534      temp = temp->next;
3535    }
3536
3537  if (xml && !docbook)
3538    {
3539      xml_insert_element_with_attribute (CLEARVALUE, START, "name=\"%s\"", name);
3540      xml_insert_element (CLEARVALUE, END);
3541    }
3542}
3543
3544/* Return the value of NAME.  The return value is NULL if NAME is unset. */
3545static char *
3546set_p (char *name)
3547{
3548  DEFINE *temp;
3549
3550  for (temp = defines; temp; temp = temp->next)
3551    if (strcmp (temp->name, name) == 0)
3552      return temp->value;
3553
3554  return NULL;
3555}
3556
3557/* Create a variable whose name appears as the first word on this line. */
3558void
3559cm_set (void)
3560{
3561  handle_variable (SET);
3562}
3563
3564/* Remove a variable whose name appears as the first word on this line. */
3565void
3566cm_clear (void)
3567{
3568  handle_variable (CLEAR);
3569}
3570
3571void
3572cm_ifset (void)
3573{
3574  handle_variable (IFSET);
3575}
3576
3577void
3578cm_ifclear (void)
3579{
3580  handle_variable (IFCLEAR);
3581}
3582
3583/* This command takes braces, but we parse the contents specially, so we
3584   don't use the standard brace popping code.
3585
3586   The syntax @ifeq{arg1, arg2, texinfo-commands} performs texinfo-commands
3587   if ARG1 and ARG2 caselessly string compare to the same string, otherwise,
3588   it produces no output. */
3589void
3590cm_ifeq (void)
3591{
3592  char **arglist;
3593
3594  arglist = get_brace_args (0);
3595
3596  if (arglist)
3597    {
3598      if (array_len (arglist) > 1)
3599        {
3600          if ((strcasecmp (arglist[0], arglist[1]) == 0) &&
3601              (arglist[2]))
3602            execute_string ("%s\n", arglist[2]);
3603        }
3604
3605      free_array (arglist);
3606    }
3607}
3608
3609void
3610cm_value (int arg, int start_pos, int end_pos)
3611{
3612  static int value_level = 0, saved_meta_pos = -1;
3613
3614  /* xml_add_char() skips any content inside menus when output format is
3615     Docbook, so @value{} is no use there.  Also start_pos and end_pos does not
3616     get updated, causing name to be empty string.  So just return.  */
3617   if (docbook && in_menu)
3618     return;
3619
3620  /* All the text after @value{ upto the matching } will eventually
3621     disappear from output_paragraph, when this function is called
3622     with ARG == END.  If the text produced until then sets
3623     meta_char_pos, we will need to restore it to the value it had
3624     before @value was seen.  So we need to save the previous value
3625     of meta_char_pos here.  */
3626  if (arg == START)
3627    {
3628      /* If we are already inside some outer @value, don't overwrite
3629         the value saved in saved_meta_pos.  */
3630      if (!value_level)
3631        saved_meta_pos = meta_char_pos;
3632      value_level++;
3633      /* While the argument of @value is processed, we need to inhibit
3634         textual transformations like "--" into "-", since @set didn't
3635         do that when it grabbed the name of the variable.  */
3636      in_fixed_width_font++;
3637    }
3638  else
3639    {
3640      char *name = (char *) &output_paragraph[start_pos];
3641      char *value;
3642      output_paragraph[end_pos] = 0;
3643      name = xstrdup (name);
3644      value = set_p (name);
3645      output_column -= end_pos - start_pos;
3646      output_paragraph_offset = start_pos;
3647
3648      /* Restore the previous value of meta_char_pos if the stuff
3649         inside this @value{} moved it.  */
3650      if (saved_meta_pos == -1) /* can't happen inside @value{} */
3651        abort ();
3652      if (value_level == 1
3653          && meta_char_pos >= start_pos && meta_char_pos < end_pos)
3654        {
3655          meta_char_pos = saved_meta_pos;
3656          saved_meta_pos = -1;
3657        }
3658      value_level--;
3659      /* No need to decrement in_fixed_width_font, since before
3660         we are called with arg == END, the reader loop already
3661         popped the brace stack, which restored in_fixed_width_font,
3662         among other things.  */
3663
3664      if (value)
3665	{
3666	  /* We need to get past the closing brace since the value may
3667	     expand to a context-sensitive macro (e.g. @xref) and produce
3668	     spurious warnings */
3669	  input_text_offset++;
3670	  execute_string ("%s", value);
3671	  input_text_offset--;
3672	}
3673      else
3674	{
3675          warning (_("undefined flag: %s"), name);
3676          add_word_args (_("{No value for `%s'}"), name);
3677	}
3678
3679      free (name);
3680    }
3681}
3682
3683/* Set, clear, or conditionalize based on ACTION. */
3684static void
3685handle_variable (int action)
3686{
3687  char *name;
3688
3689  get_rest_of_line (0, &name);
3690  /* If we hit the end of text in get_rest_of_line, backing up
3691     input pointer will cause the last character of the last line
3692     be pushed back onto the input, which is wrong.  */
3693  if (input_text_offset < input_text_length)
3694    backup_input_pointer ();
3695  handle_variable_internal (action, name);
3696  free (name);
3697}
3698
3699static void
3700handle_variable_internal (int action, char *name)
3701{
3702  char *temp;
3703  int delimiter, additional_text_present = 0;
3704
3705  /* Only the first word of NAME is a valid tag. */
3706  temp = name;
3707  delimiter = 0;
3708  while (*temp && (delimiter || !whitespace (*temp)))
3709    {
3710/* #if defined (SET_WITH_EQUAL) */
3711      if (*temp == '"' || *temp == '\'')
3712        {
3713          if (*temp == delimiter)
3714            delimiter = 0;
3715          else
3716            delimiter = *temp;
3717        }
3718/* #endif SET_WITH_EQUAL */
3719      temp++;
3720    }
3721
3722  if (*temp)
3723    additional_text_present++;
3724
3725  *temp = 0;
3726
3727  if (!*name)
3728    line_error (_("%c%s requires a name"), COMMAND_PREFIX, command);
3729  else
3730    {
3731      switch (action)
3732        {
3733        case SET:
3734          {
3735            char *value;
3736
3737#if defined (SET_WITH_EQUAL)
3738            /* Allow a value to be saved along with a variable.  The value is
3739               the text following an `=' sign in NAME, if any is present. */
3740
3741            for (value = name; *value && *value != '='; value++);
3742
3743            if (*value)
3744              *value++ = 0;
3745
3746            if (*value == '"' || *value == '\'')
3747              {
3748                value++;
3749                value[strlen (value) - 1] = 0;
3750              }
3751
3752#else /* !SET_WITH_EQUAL */
3753            /* The VALUE of NAME is the remainder of the line sans
3754               whitespace. */
3755            if (additional_text_present)
3756              {
3757                value = temp + 1;
3758                canon_white (value);
3759              }
3760            else
3761              value = "";
3762#endif /* !SET_WITH_VALUE */
3763
3764            set (name, value);
3765          }
3766          break;
3767
3768        case CLEAR:
3769          clear (name);
3770          break;
3771
3772        case IFSET:
3773        case IFCLEAR:
3774          /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set,
3775             read lines from the the file until we reach a matching
3776             "@end CONDITION".  This means that we only take note of
3777             "@ifset/clear" and "@end" commands. */
3778          {
3779            char condition[8];
3780            int condition_len;
3781            int orig_line_number = line_number;
3782
3783            if (action == IFSET)
3784              strcpy (condition, "ifset");
3785            else
3786              strcpy (condition, "ifclear");
3787
3788            condition_len = strlen (condition);
3789
3790          if ((action == IFSET && !set_p (name))
3791              || (action == IFCLEAR && set_p (name)))
3792            {
3793              int level = 0, done = 0;
3794
3795              while (!done && input_text_offset < input_text_length)
3796                {
3797                  char *freeable_line, *line;
3798
3799                  get_rest_of_line (0, &freeable_line);
3800
3801                  for (line = freeable_line; whitespace (*line); line++);
3802
3803                  if (*line == COMMAND_PREFIX &&
3804                      (strncmp (line + 1, condition, condition_len) == 0))
3805                    level++;
3806                  else if (strncmp (line, "@end", 4) == 0)
3807                    {
3808                      char *cname = line + 4;
3809                      char *temp;
3810
3811                      while (*cname && whitespace (*cname))
3812                        cname++;
3813                      temp = cname;
3814
3815                      while (*temp && !whitespace (*temp))
3816                        temp++;
3817                      *temp = 0;
3818
3819                      if (strcmp (cname, condition) == 0)
3820                        {
3821                          if (!level)
3822                            {
3823                              done = 1;
3824                            }
3825                          else
3826                            level--;
3827                        }
3828                    }
3829                  free (freeable_line);
3830                }
3831
3832              if (!done)
3833                file_line_error (input_filename, orig_line_number,
3834                                 _("Reached eof before matching @end %s"),
3835                                 condition);
3836
3837              /* We found the end of a false @ifset/ifclear.  If we are
3838                 in a menu, back up over the newline that ends the ifset,
3839                 since that newline may also begin the next menu entry. */
3840              break;
3841            }
3842          else
3843            {
3844              if (action == IFSET)
3845                begin_insertion (ifset);
3846              else
3847                begin_insertion (ifclear);
3848            }
3849          }
3850          break;
3851        }
3852    }
3853}
3854
3855/* Execution of random text not in file. */
3856typedef struct {
3857  char *string;                 /* The string buffer. */
3858  int size;                     /* The size of the buffer. */
3859  int in_use;                   /* Nonzero means string currently in use. */
3860} EXECUTION_STRING;
3861
3862static EXECUTION_STRING **execution_strings = NULL;
3863static int execution_strings_index = 0;
3864static int execution_strings_slots = 0;
3865
3866static EXECUTION_STRING *
3867get_execution_string (int initial_size)
3868{
3869  int i = 0;
3870  EXECUTION_STRING *es = NULL;
3871
3872  if (execution_strings)
3873    {
3874      for (i = 0; i < execution_strings_index; i++)
3875        if (execution_strings[i] && (execution_strings[i]->in_use == 0))
3876          {
3877            es = execution_strings[i];
3878            break;
3879          }
3880    }
3881
3882  if (!es)
3883    {
3884      if (execution_strings_index + 1 >= execution_strings_slots)
3885        {
3886          execution_strings = xrealloc
3887            (execution_strings,
3888             (execution_strings_slots += 3) * sizeof (EXECUTION_STRING *));
3889          for (; i < execution_strings_slots; i++)
3890            execution_strings[i] = NULL;
3891        }
3892
3893      execution_strings[execution_strings_index] =
3894        xmalloc (sizeof (EXECUTION_STRING));
3895      es = execution_strings[execution_strings_index];
3896      execution_strings_index++;
3897
3898      es->size = 0;
3899      es->string = NULL;
3900      es->in_use = 0;
3901    }
3902
3903  if (initial_size > es->size)
3904    {
3905      es->string = xrealloc (es->string, initial_size);
3906      es->size = initial_size;
3907    }
3908  return es;
3909}
3910
3911/* Given a pointer to TEXT and its desired length NEW_LEN, find TEXT's
3912   entry in the execution_strings[] array and change the .STRING and
3913   .SIZE members of that entry as appropriate.  */
3914void
3915maybe_update_execution_strings (char **text, unsigned int new_len)
3916{
3917  int i = 0;
3918
3919  if (execution_strings)
3920    {
3921      for (i = 0; i < execution_strings_index; i++)
3922        if (execution_strings[i] && (execution_strings[i]->in_use == 1) &&
3923            execution_strings[i]->string == *text)
3924          {
3925            /* Don't ever shrink the string storage in execution_strings[]!
3926               execute_string assumes that it is always big enough to store
3927               every possible execution_string, and will break if that's
3928               not true.  So we only enlarge the string storage if the
3929               current size isn't big enough.  */
3930            if (execution_strings[i]->size < new_len)
3931              {
3932                execution_strings[i]->string =
3933                  *text = xrealloc (*text, new_len + 1);
3934                execution_strings[i]->size = new_len + 1;
3935              }
3936            return;
3937          }
3938    }
3939  /* We should *never* end up here, since if we are inside
3940     execute_string, TEXT is always in execution_strings[].  */
3941  abort ();
3942}
3943
3944/* FIXME: this is an arbitrary limit.  */
3945#define EXECUTE_STRING_MAX 16*1024
3946
3947/* Execute the string produced by formatting the ARGs with FORMAT.  This
3948   is like submitting a new file with @include. */
3949void
3950#if defined (VA_FPRINTF) && __STDC__
3951execute_string (char *format, ...)
3952#else
3953execute_string (format, va_alist)
3954    char *format;
3955    va_dcl
3956#endif
3957{
3958  EXECUTION_STRING *es;
3959  char *temp_string, *temp_input_filename;
3960#ifdef VA_FPRINTF
3961  va_list ap;
3962#endif
3963  int insertion_level_at_start = insertion_level;
3964
3965  es = get_execution_string (EXECUTE_STRING_MAX);
3966  temp_string = es->string;
3967  es->in_use = 1;
3968
3969  VA_START (ap, format);
3970#ifdef VA_SPRINTF
3971  VA_SPRINTF (temp_string, format, ap);
3972#else
3973  sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
3974#endif /* not VA_SPRINTF */
3975  va_end (ap);
3976
3977  pushfile ();
3978  input_text_offset = 0;
3979  input_text = temp_string;
3980  input_text_length = strlen (temp_string);
3981  input_filename = xstrdup (input_filename);
3982  temp_input_filename = input_filename;
3983
3984  executing_string++;
3985  reader_loop ();
3986
3987  /* If insertion stack level changes during execution, that means a multiline
3988     command is used inside braces or @section ... kind of commands.  */
3989  if (insertion_level_at_start != insertion_level && !executing_macro)
3990    {
3991      line_error (_("Multiline command %c%s used improperly"),
3992          COMMAND_PREFIX,
3993          command);
3994      /* We also need to keep insertion_level intact to make sure warnings are
3995         issued for @end ... command.  */
3996      while (insertion_level > insertion_level_at_start)
3997        pop_insertion ();
3998    }
3999
4000  popfile ();
4001  executing_string--;
4002  es->in_use = 0;
4003  free (temp_input_filename);
4004}
4005
4006
4007/* Return what would be output for STR (in newly-malloced memory), i.e.,
4008   expand Texinfo commands according to the current output format.  If
4009   IMPLICIT_CODE is set, expand @code{STR}.  This is generally used for
4010   short texts; filling, indentation, and html escapes are disabled.  */
4011
4012char *
4013expansion (char *str, int implicit_code)
4014{
4015  return maybe_escaped_expansion (str, implicit_code, 0);
4016}
4017
4018
4019/* Do HTML escapes according to DO_HTML_ESCAPE.  Needed in
4020   cm_printindex, q.v.  */
4021
4022char *
4023maybe_escaped_expansion (char *str, int implicit_code, int do_html_escape)
4024{
4025  char *result;
4026
4027  /* Inhibit indentation and filling, so that extra newlines
4028     are not added to the expansion.  (This is undesirable if
4029     we write the expanded text to macro_expansion_output_stream.)  */
4030  int saved_filling_enabled = filling_enabled;
4031  int saved_indented_fill = indented_fill;
4032  int saved_no_indent = no_indent;
4033  int saved_escape_html = escape_html;
4034
4035  filling_enabled = 0;
4036  indented_fill = 0;
4037  no_indent = 1;
4038  escape_html = do_html_escape;
4039
4040  result = full_expansion (str, implicit_code);
4041
4042  filling_enabled = saved_filling_enabled;
4043  indented_fill = saved_indented_fill;
4044  no_indent = saved_no_indent;
4045  escape_html = saved_escape_html;
4046
4047  return result;
4048}
4049
4050
4051/* Expand STR (or @code{STR} if IMPLICIT_CODE is nonzero).  No change to
4052   any formatting parameters -- filling, indentation, html escapes,
4053   etc., are not reset.  Always returned in new memory.  */
4054
4055char *
4056full_expansion (char *str, int implicit_code)
4057{
4058  int length;
4059  char *result;
4060
4061  /* Inhibit any real output.  */
4062  int start = output_paragraph_offset;
4063  int saved_paragraph_is_open = paragraph_is_open;
4064  int saved_output_column = output_column;
4065
4066  /* More output state to save.  */
4067  int saved_meta_pos = meta_char_pos;
4068  int saved_last_char = last_inserted_character;
4069  int saved_last_nl = last_char_was_newline;
4070
4071  /* If we are called in the middle of processing a command, we need
4072     to dup and save the global variable `command' (which holds the
4073     name of this command), since the recursive reader loop will free
4074     it from under our feet if it finds any macros in STR.  */
4075  char *saved_command = command ? xstrdup (command) : NULL;
4076
4077  inhibit_output_flushing ();
4078  paragraph_is_open = 1;
4079  if (strlen (str) > (implicit_code
4080                      ? EXECUTE_STRING_MAX - 1 - sizeof("@code{}")
4081                      : EXECUTE_STRING_MAX - 1))
4082    line_error (_("`%.40s...' is too long for expansion; not expanded"), str);
4083  else
4084    execute_string (implicit_code ? "@code{%s}" : "%s", str);
4085  uninhibit_output_flushing ();
4086
4087  /* Copy the expansion from the buffer.  */
4088  length = output_paragraph_offset - start;
4089  result = xmalloc (1 + length);
4090  memcpy (result, (char *) (output_paragraph + start), length);
4091  result[length] = 0;
4092
4093  /* Pretend it never happened.  */
4094  free_and_clear (&command);
4095  command = saved_command;
4096
4097  output_paragraph_offset = start;
4098  paragraph_is_open = saved_paragraph_is_open;
4099  output_column = saved_output_column;
4100
4101  meta_char_pos = saved_meta_pos;
4102  last_inserted_character = saved_last_char;
4103  last_char_was_newline = saved_last_nl;
4104
4105  return result;
4106}
4107
4108
4109/* Return text (info) expansion of STR no matter what the current output
4110   format is.  */
4111
4112char *
4113text_expansion (char *str)
4114{
4115  char *ret;
4116  int save_html = html;
4117  int save_xml = xml;
4118  int save_docbook = docbook;
4119
4120  html = 0;
4121  xml = 0;
4122  docbook = 0;
4123  ret = expansion (str, 0);
4124  html = save_html;
4125  xml = save_xml;
4126  docbook = save_docbook;
4127
4128  return ret;
4129}
4130
4131
4132/* Set the paragraph indentation variable to the value specified in STRING.
4133   Values can be:
4134     `asis': Don't change existing indentation.
4135     `none': Remove existing indentation.
4136        NUM: Indent NUM spaces at the starts of paragraphs.
4137             If NUM is zero, we assume `none'.
4138   Returns 0 if successful, or nonzero if STRING isn't one of the above. */
4139int
4140set_paragraph_indent (char *string)
4141{
4142  if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
4143    paragraph_start_indent = 0;
4144  else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
4145    paragraph_start_indent = -1;
4146  else
4147    {
4148      if (sscanf (string, "%d", &paragraph_start_indent) != 1)
4149        return -1;
4150      else
4151        {
4152          if (paragraph_start_indent == 0)
4153            paragraph_start_indent = -1;
4154        }
4155    }
4156  return 0;
4157}
4158