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