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