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