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