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