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