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