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