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