source: trunk/third/texinfo/makeinfo/makeinfo.c @ 18945

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