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