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