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