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