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