156164Sru/* makeinfo -- convert Texinfo source into other formats. 2146520Sru $Id: makeinfo.c,v 1.74 2004/12/19 17:15:42 karl Exp $ 321495Sjmacd 4116530Sru Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 5146520Sru 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 621495Sjmacd 721495Sjmacd This program is free software; you can redistribute it and/or modify 821495Sjmacd it under the terms of the GNU General Public License as published by 921495Sjmacd the Free Software Foundation; either version 2, or (at your option) 1021495Sjmacd any later version. 1121495Sjmacd 1221495Sjmacd This program is distributed in the hope that it will be useful, 1321495Sjmacd but WITHOUT ANY WARRANTY; without even the implied warranty of 1421495Sjmacd MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1521495Sjmacd GNU General Public License for more details. 1621495Sjmacd 1721495Sjmacd You should have received a copy of the GNU General Public License 1821495Sjmacd along with this program; if not, write to the Free Software 1921495Sjmacd Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2021495Sjmacd 21146520Sru Original author of makeinfo: Brian Fox (bfox@ai.mit.edu). */ 2221495Sjmacd 2342664Smarkm#include "system.h" 2442664Smarkm#include "getopt.h" 2542664Smarkm 2656164Sru#define COMPILING_MAKEINFO 2756164Sru#include "makeinfo.h" 2856164Sru#include "cmds.h" 2956164Sru#include "files.h" 30146520Sru#include "float.h" 3156164Sru#include "footnote.h" 3256164Sru#include "html.h" 3356164Sru#include "index.h" 3456164Sru#include "insertion.h" 35116530Sru#include "lang.h" 3656164Sru#include "macro.h" 3756164Sru#include "node.h" 38146520Sru#include "sectioning.h" 3956164Sru#include "toc.h" 4093142Sru#include "xml.h" 4142664Smarkm 4242664Smarkm/* You can change some of the behavior of Makeinfo by changing the 4321495Sjmacd following defines: */ 4421495Sjmacd 4521495Sjmacd/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which 4621495Sjmacd appear within an @table, @ftable, or @itemize environment to have 4721495Sjmacd standard paragraph indentation. Without this, such paragraphs have 4821495Sjmacd no starting indentation. */ 4921495Sjmacd/* #define INDENT_PARAGRAPHS_IN_TABLE */ 5021495Sjmacd 5121495Sjmacd/* Define PARAGRAPH_START_INDENT to be the amount of indentation that 5221495Sjmacd the first lines of paragraphs receive by default, where no other 5321495Sjmacd value has been specified. Users can change this value on the command 5421495Sjmacd line, with the --paragraph-indent option, or within the texinfo file, 5521495Sjmacd with the @paragraphindent command. */ 5621495Sjmacd#define PARAGRAPH_START_INDENT 3 5721495Sjmacd 5821495Sjmacd/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you 5921495Sjmacd wish to appear between paragraphs. A value of 1 creates a single blank 6021495Sjmacd line between paragraphs. Paragraphs are defined by 2 or more consecutive 6121495Sjmacd newlines in the input file (i.e., one or more blank lines). */ 6221495Sjmacd#define DEFAULT_PARAGRAPH_SPACING 1 6321495Sjmacd 6456164Sru/* Global variables. */ 6521495Sjmacd 6621495Sjmacd/* The output file name. */ 6756164Sruchar *output_filename = NULL; 6821495Sjmacd 6921495Sjmacd/* Name of the output file that the user elected to pass on the command line. 7021495Sjmacd Such a name overrides any name found with the @setfilename command. */ 7156164Sruchar *command_output_filename = NULL; 72100516Srustatic char *save_command_output_filename = NULL; 7321495Sjmacd 7421495Sjmacd#define INITIAL_PARAGRAPH_SPACE 5000 7521495Sjmacdint paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE; 7621495Sjmacd 7721495Sjmacd/* The amount of indentation to add at the starts of paragraphs. 7821495Sjmacd 0 means don't change existing indentation at paragraph starts. 7921495Sjmacd > 0 is amount to indent new paragraphs by. 8021495Sjmacd < 0 means indent to column zero by removing indentation if necessary. 8121495Sjmacd 8221495Sjmacd This is normally zero, but some people prefer paragraph starts to be 8321495Sjmacd somewhat more indented than paragraph bodies. A pretty value for 8421495Sjmacd this is 3. */ 8521495Sjmacdint paragraph_start_indent = PARAGRAPH_START_INDENT; 8621495Sjmacd 8721495Sjmacd/* Indentation that is pending insertion. We have this for hacking lines 8821495Sjmacd which look blank, but contain whitespace. We want to treat those as 8921495Sjmacd blank lines. */ 9021495Sjmacdint pending_indent = 0; 9121495Sjmacd 9221495Sjmacd/* The index in our internal command table of the currently 9321495Sjmacd executing command. */ 9421495Sjmacdint command_index; 9521495Sjmacd 9621495Sjmacd/* A search string which is used to find the first @setfilename. */ 9721495Sjmacdchar setfilename_search[] = 9821495Sjmacd { COMMAND_PREFIX, 9942664Smarkm 's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 }; 10021495Sjmacd 10142664Smarkm/* Values for calling handle_variable_internal (). */ 10242664Smarkm#define SET 1 10342664Smarkm#define CLEAR 2 10442664Smarkm#define IFSET 3 10542664Smarkm#define IFCLEAR 4 10642664Smarkm 10721495Sjmacd/* Flags controlling the operation of the program. */ 10821495Sjmacd 10942664Smarkm/* Default is to remove output if there were errors. */ 11042664Smarkmint force = 0; 11142664Smarkm 11221495Sjmacd/* Default is to notify users of bad choices. */ 11321495Sjmacdint print_warnings = 1; 11421495Sjmacd 11521495Sjmacd/* Number of errors that we tolerate on a given fileset. */ 11621495Sjmacdint max_error_level = 100; 11721495Sjmacd 11856164Sru/* The actual last inserted character. Note that this may be something 11956164Sru other than NEWLINE even if last_char_was_newline is 1. */ 12056164Sruint last_inserted_character = 0; 12121495Sjmacd 12256164Sru/* Nonzero means that a newline character has already been 12356164Sru inserted, so close_paragraph () should insert one less. */ 12456164Sruint line_already_broken = 0; 12521495Sjmacd 12656164Sru/* When nonzero we have finished an insertion (see end_insertion ()) and we 12756164Sru want to ignore false continued paragraph closings. */ 12856164Sruint insertion_paragraph_closed = 0; 12921495Sjmacd 13056164Sru/* Nonzero means attempt to make all of the lines have fill_column width. */ 13156164Sruint do_justification = 0; 13221495Sjmacd 13393142Sru/* Nonzero means don't replace whitespace with in HTML mode. */ 13493142Sruint in_html_elt = 0; 13593142Sru 136146520Sru/* Nonzero means we are inserting a block level HTML element that must not be 137146520Sru enclosed in a <p>, such as <ul>, <ol> and <h?>. */ 138146520Sruint in_html_block_level_elt = 0; 139146520Sru 140114477Sru/* True when expanding a macro definition. */ 141114477Srustatic int executing_macro = 0; 142114477Sru 143146520Sru/* True when we are inside a <li> block of a menu. */ 144146520Srustatic int in_menu_item = 0; 145146520Sru 14621495Sjmacdtypedef struct brace_element 14721495Sjmacd{ 14821495Sjmacd struct brace_element *next; 14921495Sjmacd COMMAND_FUNCTION *proc; 15056164Sru char *command; 15121495Sjmacd int pos, line; 15221495Sjmacd int in_fixed_width_font; 15321495Sjmacd} BRACE_ELEMENT; 15421495Sjmacd 15556164SruBRACE_ELEMENT *brace_stack = NULL; 15621495Sjmacd 157146520Srustatic void convert_from_file (char *name); 158146520Srustatic void convert_from_loaded_file (char *name); 159146520Srustatic void convert_from_stream (FILE *stream, char *name); 160146520Srustatic void do_flush_right_indentation (void); 161146520Srustatic void handle_variable (int action); 162146520Srustatic void handle_variable_internal (int action, char *name); 163146520Srustatic void init_brace_stack (void); 164146520Srustatic void init_internals (void); 165146520Srustatic void pop_and_call_brace (void); 166146520Srustatic void remember_brace (COMMAND_FUNCTION (*proc)); 167146520Srustatic int end_of_sentence_p (void); 16821495Sjmacd 169146520Sruvoid maybe_update_execution_strings (char **text, unsigned int new_len); 17021495Sjmacd 17156164Sru/* Error handling. */ 17221495Sjmacd 17342664Smarkm/* Number of errors encountered. */ 17442664Smarkmint errors_printed = 0; 17542664Smarkm 176146520Sru/* Remember that an error has been printed. If more than 177146520Sru max_error_level have been printed, then exit the program. */ 178146520Srustatic void 179146520Sruremember_error (void) 180146520Sru{ 181146520Sru errors_printed++; 182146520Sru if (max_error_level && (errors_printed > max_error_level)) 183146520Sru { 184146520Sru fprintf (stderr, _("Too many errors! Gave up.\n")); 185146520Sru flush_file_stack (); 186146520Sru if (errors_printed - max_error_level < 2) 187146520Sru cm_bye (); 188146520Sru xexit (1); 189146520Sru } 190146520Sru} 191146520Sru 19242664Smarkm/* Print the last error gotten from the file system. */ 19342664Smarkmint 194146520Srufs_error (char *filename) 19542664Smarkm{ 19642664Smarkm remember_error (); 19742664Smarkm perror (filename); 19856164Sru return 0; 19942664Smarkm} 20042664Smarkm 20142664Smarkm/* Print an error message, and return false. */ 20242664Smarkmvoid 20342664Smarkm#if defined (VA_FPRINTF) && __STDC__ 204116530Sruerror (const char *format, ...) 20542664Smarkm#else 20642664Smarkmerror (format, va_alist) 207116530Sru const char *format; 20842664Smarkm va_dcl 20942664Smarkm#endif 21042664Smarkm{ 21142664Smarkm#ifdef VA_FPRINTF 21242664Smarkm va_list ap; 21342664Smarkm#endif 21442664Smarkm 21542664Smarkm remember_error (); 21642664Smarkm 21742664Smarkm VA_START (ap, format); 21842664Smarkm#ifdef VA_FPRINTF 21942664Smarkm VA_FPRINTF (stderr, format, ap); 22042664Smarkm#else 22142664Smarkm fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); 22242664Smarkm#endif /* not VA_FPRINTF */ 22342664Smarkm va_end (ap); 22442664Smarkm 22542664Smarkm putc ('\n', stderr); 22642664Smarkm} 22742664Smarkm 22893142Sru/* Just like error (), but print the input file and line number as well. */ 22942664Smarkmvoid 23042664Smarkm#if defined (VA_FPRINTF) && __STDC__ 231116530Srufile_line_error (char *infile, int lno, const char *format, ...) 23293142Sru#else 23393142Srufile_line_error (infile, lno, format, va_alist) 23493142Sru char *infile; 23593142Sru int lno; 236116530Sru const char *format; 23793142Sru va_dcl 23893142Sru#endif 23993142Sru{ 24093142Sru#ifdef VA_FPRINTF 24193142Sru va_list ap; 24293142Sru#endif 24393142Sru 24493142Sru remember_error (); 24593142Sru fprintf (stderr, "%s:%d: ", infile, lno); 24693142Sru 24793142Sru VA_START (ap, format); 24893142Sru#ifdef VA_FPRINTF 24993142Sru VA_FPRINTF (stderr, format, ap); 25093142Sru#else 25193142Sru fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); 25293142Sru#endif /* not VA_FPRINTF */ 25393142Sru va_end (ap); 25493142Sru 25593142Sru fprintf (stderr, ".\n"); 25693142Sru} 25793142Sru 25893142Sru/* Just like file_line_error (), but take the input file and the line 25993142Sru number from global variables. */ 26093142Sruvoid 26193142Sru#if defined (VA_FPRINTF) && __STDC__ 262116530Sruline_error (const char *format, ...) 26342664Smarkm#else 26442664Smarkmline_error (format, va_alist) 265116530Sru const char *format; 26642664Smarkm va_dcl 26742664Smarkm#endif 26842664Smarkm{ 26942664Smarkm#ifdef VA_FPRINTF 27042664Smarkm va_list ap; 27142664Smarkm#endif 27242664Smarkm 27342664Smarkm remember_error (); 27442664Smarkm fprintf (stderr, "%s:%d: ", input_filename, line_number); 27542664Smarkm 27642664Smarkm VA_START (ap, format); 27742664Smarkm#ifdef VA_FPRINTF 27842664Smarkm VA_FPRINTF (stderr, format, ap); 27942664Smarkm#else 28042664Smarkm fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); 28142664Smarkm#endif /* not VA_FPRINTF */ 28242664Smarkm va_end (ap); 28342664Smarkm 28442664Smarkm fprintf (stderr, ".\n"); 28542664Smarkm} 28642664Smarkm 28742664Smarkmvoid 28842664Smarkm#if defined (VA_FPRINTF) && __STDC__ 289116530Sruwarning (const char *format, ...) 29042664Smarkm#else 29142664Smarkmwarning (format, va_alist) 292116530Sru const char *format; 29342664Smarkm va_dcl 29442664Smarkm#endif 29542664Smarkm{ 29642664Smarkm#ifdef VA_FPRINTF 29742664Smarkm va_list ap; 29842664Smarkm#endif 29942664Smarkm 30042664Smarkm if (print_warnings) 30142664Smarkm { 30242664Smarkm fprintf (stderr, _("%s:%d: warning: "), input_filename, line_number); 30342664Smarkm 30442664Smarkm VA_START (ap, format); 30542664Smarkm#ifdef VA_FPRINTF 30642664Smarkm VA_FPRINTF (stderr, format, ap); 30742664Smarkm#else 30842664Smarkm fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); 30942664Smarkm#endif /* not VA_FPRINTF */ 31042664Smarkm va_end (ap); 31142664Smarkm 31242664Smarkm fprintf (stderr, ".\n"); 31342664Smarkm } 31442664Smarkm} 31542664Smarkm 31642664Smarkm 31756164Sru/* The other side of a malformed expression. */ 318146520Srustatic void 319146520Srumisplaced_brace (void) 32056164Sru{ 32156164Sru line_error (_("Misplaced %c"), '}'); 32256164Sru} 32342664Smarkm 32456164Sru/* Main. */ 32521495Sjmacd 32656164Sru/* Display the version info of this invocation of Makeinfo. */ 32756164Srustatic void 328146520Sruprint_version_info (void) 32956164Sru{ 33056164Sru printf ("makeinfo (GNU %s) %s\n", PACKAGE, VERSION); 33156164Sru} 33256164Sru 33356164Sru/* If EXIT_VALUE is zero, print the full usage message to stdout. 33456164Sru Otherwise, just say to use --help for more info. 33556164Sru Then exit with EXIT_VALUE. */ 33656164Srustatic void 337146520Sruusage (int exit_value) 33856164Sru{ 33956164Sru if (exit_value != 0) 34056164Sru fprintf (stderr, _("Try `%s --help' for more information.\n"), progname); 34156164Sru else 34256164Sru { 34393142Sru printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n"), progname); 344116530Sru puts (""); 345100516Sru 34693142Sru puts (_("\ 34793142SruTranslate Texinfo source documentation to various other formats, by default\n\ 34893142SruInfo files suitable for reading online with Emacs or standalone GNU Info.\n")); 34993142Sru 35056164Sru printf (_("\ 35193142SruGeneral options:\n\ 35293142Sru --error-limit=NUM quit after NUM errors (default %d).\n\ 35393142Sru --force preserve output even if errors.\n\ 35493142Sru --help display this help and exit.\n\ 35593142Sru --no-validate suppress node cross-reference validation.\n\ 35693142Sru --no-warn suppress warnings (but not errors).\n\ 35793142Sru --reference-limit=NUM warn about at most NUM references (default %d).\n\ 35893142Sru -v, --verbose explain what is being done.\n\ 35993142Sru --version display version information and exit.\n"), 36093142Sru max_error_level, reference_warning_limit); 361146520Sru puts (""); 36293142Sru 36393142Sru /* xgettext: no-wrap */ 364114477Sru puts (_("\ 36593142SruOutput format selection (default is to produce Info):\n\ 366146520Sru --docbook output Docbook XML rather than Info.\n\ 36793142Sru --html output HTML rather than Info.\n\ 368114477Sru --xml output Texinfo XML rather than Info.\n\ 369146520Sru --plaintext output plain text rather than Info.\n\ 37093142Sru")); 37193142Sru 372114477Sru puts (_("\ 37393142SruGeneral output options:\n\ 37493142Sru -E, --macro-expand FILE output macro-expanded source to FILE.\n\ 37593142Sru ignoring any @setfilename.\n\ 376100516Sru --no-headers suppress node separators, Node: lines, and menus\n\ 377100516Sru from Info output (thus producing plain text)\n\ 378100516Sru or from HTML (thus producing shorter output);\n\ 379100516Sru also, write to standard output by default.\n\ 38093142Sru --no-split suppress splitting of Info or HTML output,\n\ 38193142Sru generate only one output file.\n\ 38293142Sru --number-sections output chapter and sectioning numbers.\n\ 38393142Sru -o, --output=FILE output to FILE (directory if split HTML),\n\ 38493142Sru")); 38593142Sru 386114477Sru printf (_("\ 38793142SruOptions for Info and plain text:\n\ 38893142Sru --enable-encoding output accented and special characters in\n\ 38993142Sru Info output based on @documentencoding.\n\ 39093142Sru --fill-column=NUM break Info lines at NUM characters (default %d).\n\ 39193142Sru --footnote-style=STYLE output footnotes in Info according to STYLE:\n\ 39293142Sru `separate' to put them in their own node;\n\ 39393142Sru `end' to put them at the end of the node\n\ 39493142Sru in which they are defined (default).\n\ 39593142Sru --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).\n\ 39693142Sru If VAL is `none', do not indent; if VAL is\n\ 39793142Sru `asis', preserve existing indentation.\n\ 39893142Sru --split-size=NUM split Info files at size NUM (default %d).\n"), 39993142Sru fill_column, paragraph_start_indent, 40093142Sru DEFAULT_SPLIT_SIZE); 401146520Sru puts (""); 402114477Sru 403114477Sru puts (_("\ 404116530SruOptions for HTML:\n\ 405116530Sru --css-include=FILE include FILE in HTML <style> output;\n\ 406116530Sru read stdin if FILE is -.\n\ 407116530Sru")); 408116530Sru 409146520Sru printf (_("\ 410146520SruOptions for XML and Docbook:\n\ 411146520Sru --output-indent=VAL indent XML elements by VAL spaces (default %d).\n\ 412146520Sru If VAL is 0, ignorable whitespace is dropped.\n\ 413146520Sru"), xml_indentation_increment); 414146520Sru puts (""); 415146520Sru 416116530Sru puts (_("\ 41793142SruInput file options:\n\ 418116530Sru --commands-in-node-names allow @ commands in node names.\n\ 419116530Sru -D VAR define the variable VAR, as with @set.\n\ 420116530Sru -I DIR append DIR to the @include search path.\n\ 421116530Sru -P DIR prepend DIR to the @include search path.\n\ 422116530Sru -U VAR undefine the variable VAR, as with @clear.\n\ 42393142Sru")); 424100516Sru 425114477Sru puts (_("\ 42693142SruConditional processing in input:\n\ 427146520Sru --ifdocbook process @ifdocbook and @docbook even if\n\ 428146520Sru not generating Docbook.\n\ 429100516Sru --ifhtml process @ifhtml and @html even if not generating HTML.\n\ 430100516Sru --ifinfo process @ifinfo even if not generating Info.\n\ 431100516Sru --ifplaintext process @ifplaintext even if not generating plain text.\n\ 432100516Sru --iftex process @iftex and @tex; implies --no-split.\n\ 433114477Sru --ifxml process @ifxml and @xml.\n\ 434146520Sru --no-ifdocbook do not process @ifdocbook and @docbook text.\n\ 435100516Sru --no-ifhtml do not process @ifhtml and @html text.\n\ 436100516Sru --no-ifinfo do not process @ifinfo text.\n\ 437100516Sru --no-ifplaintext do not process @ifplaintext text.\n\ 438100516Sru --no-iftex do not process @iftex and @tex text.\n\ 439114477Sru --no-ifxml do not process @ifxml and @xml text.\n\ 440146520Sru\n\ 441146520Sru Also, for the --no-ifFORMAT options, do process @ifnotFORMAT text.\n\ 44293142Sru")); 44393142Sru 444114477Sru puts (_("\ 44593142Sru The defaults for the @if... conditionals depend on the output format:\n\ 44693142Sru if generating HTML, --ifhtml is on and the others are off;\n\ 447100516Sru if generating Info, --ifinfo is on and the others are off;\n\ 448100516Sru if generating plain text, --ifplaintext is on and the others are off;\n\ 449116530Sru if generating XML, --ifxml is on and the others are off.\n\ 45093142Sru")); 45193142Sru 452114477Sru fputs (_("\ 45356164SruExamples:\n\ 45493142Sru makeinfo foo.texi write Info to foo's @setfilename\n\ 455100516Sru makeinfo --html foo.texi write HTML to @setfilename\n\ 456114477Sru makeinfo --xml foo.texi write Texinfo XML to @setfilename\n\ 457100516Sru makeinfo --docbook foo.texi write DocBook XML to @setfilename\n\ 458100516Sru makeinfo --no-headers foo.texi write plain text to standard output\n\ 459100516Sru\n\ 460100516Sru makeinfo --html --no-headers foo.texi write html without node lines, menus\n\ 46193142Sru makeinfo --number-sections foo.texi write Info with numbered sections\n\ 46293142Sru makeinfo --no-split foo.texi write one Info file however big\n\ 463100516Sru"), stdout); 46493142Sru 465114477Sru puts (_("\n\ 46656164SruEmail bug reports to bug-texinfo@gnu.org,\n\ 467100516Srugeneral questions and discussion to help-texinfo@gnu.org.\n\ 468100516SruTexinfo home page: http://www.gnu.org/software/texinfo/")); 469100516Sru 470114477Sru } /* end of full help */ 471114477Sru 47256164Sru xexit (exit_value); 47356164Sru} 47456164Sru 47556164Srustruct option long_options[] = 47656164Sru{ 47756164Sru { "commands-in-node-names", 0, &expensive_validation, 1 }, 478116530Sru { "css-include", 1, 0, 'C' }, 47993142Sru { "docbook", 0, 0, 'd' }, 48093142Sru { "enable-encoding", 0, &enable_encoding, 1 }, 48156164Sru { "error-limit", 1, 0, 'e' }, 48256164Sru { "fill-column", 1, 0, 'f' }, 48356164Sru { "footnote-style", 1, 0, 's' }, 48456164Sru { "force", 0, &force, 1 }, 48556164Sru { "help", 0, 0, 'h' }, 48656164Sru { "html", 0, 0, 'w' }, 487146520Sru { "ifdocbook", 0, &process_docbook, 1 }, 48856164Sru { "ifhtml", 0, &process_html, 1 }, 48956164Sru { "ifinfo", 0, &process_info, 1 }, 490100516Sru { "ifplaintext", 0, &process_plaintext, 1 }, 49156164Sru { "iftex", 0, &process_tex, 1 }, 492114477Sru { "ifxml", 0, &process_xml, 1 }, 49356164Sru { "macro-expand", 1, 0, 'E' }, 49456164Sru { "no-headers", 0, &no_headers, 1 }, 495146520Sru { "no-ifdocbook", 0, &process_docbook, 0 }, 49656164Sru { "no-ifhtml", 0, &process_html, 0 }, 49756164Sru { "no-ifinfo", 0, &process_info, 0 }, 498100516Sru { "no-ifplaintext", 0, &process_plaintext, 0 }, 49956164Sru { "no-iftex", 0, &process_tex, 0 }, 500114477Sru { "no-ifxml", 0, &process_xml, 0 }, 50156164Sru { "no-number-footnotes", 0, &number_footnotes, 0 }, 50256164Sru { "no-number-sections", 0, &number_sections, 0 }, 50356164Sru { "no-pointer-validate", 0, &validating, 0 }, 50456164Sru { "no-split", 0, &splitting, 0 }, 50556164Sru { "no-validate", 0, &validating, 0 }, 50656164Sru { "no-warn", 0, &print_warnings, 0 }, 50756164Sru { "number-footnotes", 0, &number_footnotes, 1 }, 50856164Sru { "number-sections", 0, &number_sections, 1 }, 50956164Sru { "output", 1, 0, 'o' }, 510146520Sru { "output-indent", 1, 0, 'i' }, 51156164Sru { "paragraph-indent", 1, 0, 'p' }, 512146520Sru { "plaintext", 0, 0, 't' }, 51356164Sru { "reference-limit", 1, 0, 'r' }, 51493142Sru { "split-size", 1, 0, 'S'}, 51556164Sru { "verbose", 0, &verbose_mode, 1 }, 51656164Sru { "version", 0, 0, 'V' }, 51793142Sru { "xml", 0, 0, 'x' }, 51856164Sru {NULL, 0, NULL, 0} 51956164Sru}; 52056164Sru 521146520Sru/* We use handle_variable_internal for -D and -U, and it depends on 522146520Sru execute_string, which depends on input_filename, which is not defined 523146520Sru while we are handling options. :-\ So we save these defines in this 524146520Sru struct, and handle them later. */ 525146520Srutypedef struct command_line_define 526146520Sru{ 527146520Sru struct command_line_define *next; 528146520Sru int action; 529146520Sru char *define; 530146520Sru} COMMAND_LINE_DEFINE; 531146520Sru 532146520Srustatic COMMAND_LINE_DEFINE *command_line_defines = NULL; 533146520Sru 53421495Sjmacd/* For each file mentioned in the command line, process it, turning 53521495Sjmacd Texinfo commands into wonderfully formatted output text. */ 53621495Sjmacdint 537146520Srumain (int argc, char **argv) 53821495Sjmacd{ 53921495Sjmacd int c, ind; 54021495Sjmacd int reading_from_stdin = 0; 54121495Sjmacd 54242664Smarkm#ifdef HAVE_SETLOCALE 54342664Smarkm /* Do not use LC_ALL, because LC_NUMERIC screws up the scanf parsing 54442664Smarkm of the argument to @multicolumn. */ 54542664Smarkm setlocale (LC_TIME, ""); 546146520Sru#ifdef LC_MESSAGES /* ultrix */ 54742664Smarkm setlocale (LC_MESSAGES, ""); 548146520Sru#endif 54956164Sru setlocale (LC_CTYPE, ""); 55056164Sru setlocale (LC_COLLATE, ""); 55142664Smarkm#endif 55242664Smarkm 553146520Sru#ifdef ENABLE_NLS 55442664Smarkm /* Set the text message domain. */ 55542664Smarkm bindtextdomain (PACKAGE, LOCALEDIR); 55642664Smarkm textdomain (PACKAGE); 557146520Sru#endif 55842664Smarkm 559146520Sru /* If TEXINFO_OUTPUT_FORMAT envvar is set, use it to set default output. 560146520Sru Can be overridden with one of the output options. */ 561146520Sru if (getenv ("TEXINFO_OUTPUT_FORMAT") != NULL) 562146520Sru { 563146520Sru if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "docbook")) 564146520Sru { 565146520Sru splitting = 0; 566146520Sru html = 0; 567146520Sru docbook = 1; 568146520Sru xml = 1; 569146520Sru process_docbook = 1; 570146520Sru } 571146520Sru else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "html")) 572146520Sru { 573146520Sru html = 1; 574146520Sru docbook = 0; 575146520Sru xml = 0; 576146520Sru process_html = 1; 577146520Sru } 578146520Sru else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "info")) 579146520Sru { 580146520Sru html = 0; 581146520Sru docbook = 0; 582146520Sru xml = 0; 583146520Sru } 584146520Sru else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "plaintext")) 585146520Sru { 586146520Sru splitting = 0; 587146520Sru no_headers = 1; 588146520Sru html = 0; 589146520Sru docbook = 0; 590146520Sru xml = 0; 591146520Sru process_plaintext = 1; 592146520Sru } 593146520Sru else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "xml")) 594146520Sru { 595146520Sru splitting = 0; 596146520Sru html = 0; 597146520Sru docbook = 0; 598146520Sru xml = 1; 599146520Sru process_xml = 1; 600146520Sru } 601146520Sru else 602146520Sru fprintf (stderr, 603146520Sru _("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"), 604146520Sru progname, getenv ("TEXINFO_OUTPUT_FORMAT")); 605146520Sru } 606146520Sru 60721495Sjmacd /* Parse argument flags from the input line. */ 608146520Sru while ((c = getopt_long (argc, argv, "D:de:E:f:hI:i:o:p:P:r:s:t:U:vV:wx", 60942664Smarkm long_options, &ind)) != EOF) 61021495Sjmacd { 61121495Sjmacd if (c == 0 && long_options[ind].flag == 0) 61242664Smarkm c = long_options[ind].val; 61321495Sjmacd 61421495Sjmacd switch (c) 61542664Smarkm { 616116530Sru case 'C': /* --css-include */ 617116530Sru css_include = xstrdup (optarg); 618116530Sru break; 619116530Sru 62042664Smarkm case 'D': 62142664Smarkm case 'U': 62242664Smarkm /* User specified variable to set or clear. */ 623146520Sru if (xml && !docbook) 624146520Sru { 625146520Sru COMMAND_LINE_DEFINE *new = xmalloc (sizeof (COMMAND_LINE_DEFINE)); 626146520Sru new->action = (c == 'D') ? SET : CLEAR; 627146520Sru new->define = xstrdup (optarg); 628146520Sru new->next = command_line_defines; 629146520Sru command_line_defines = new; 630146520Sru } 631146520Sru else 632146520Sru handle_variable_internal ((c == 'D' ? SET : CLEAR), optarg); 63342664Smarkm break; 63421495Sjmacd 63593142Sru case 'd': /* --docbook */ 63693142Sru splitting = 0; 637114477Sru xml = 1; 638114477Sru docbook = 1; 639146520Sru html = 0; 640146520Sru process_docbook = 1; 64193142Sru break; 64293142Sru 64356164Sru case 'e': /* --error-limit */ 64442664Smarkm if (sscanf (optarg, "%d", &max_error_level) != 1) 64542664Smarkm { 64642664Smarkm fprintf (stderr, 64742664Smarkm _("%s: %s arg must be numeric, not `%s'.\n"), 648146520Sru progname, "--error-limit", optarg); 64993142Sru usage (1); 65042664Smarkm } 65142664Smarkm break; 65221495Sjmacd 65356164Sru case 'E': /* --macro-expand */ 65442664Smarkm if (!macro_expansion_output_stream) 65542664Smarkm { 65642664Smarkm macro_expansion_filename = optarg; 65742664Smarkm macro_expansion_output_stream 65842664Smarkm = strcmp (optarg, "-") == 0 ? stdout : fopen (optarg, "w"); 65942664Smarkm if (!macro_expansion_output_stream) 660146520Sru error (_("%s: could not open macro expansion output `%s'"), 661146520Sru progname, optarg); 66242664Smarkm } 66342664Smarkm else 664146520Sru fprintf (stderr, 665146520Sru _("%s: ignoring second macro expansion output `%s'.\n"), 666146520Sru progname, optarg); 66742664Smarkm break; 66821495Sjmacd 66956164Sru case 'f': /* --fill-column */ 67042664Smarkm if (sscanf (optarg, "%d", &fill_column) != 1) 67142664Smarkm { 67242664Smarkm fprintf (stderr, 67356164Sru _("%s: %s arg must be numeric, not `%s'.\n"), 674146520Sru progname, "--fill-column", optarg); 67556164Sru usage (1); 67642664Smarkm } 67742664Smarkm break; 67821495Sjmacd 67956164Sru case 'h': /* --help */ 68056164Sru usage (0); 68142664Smarkm break; 68221495Sjmacd 68342664Smarkm case 'I': 68442664Smarkm /* Append user-specified dir to include file path. */ 685146520Sru append_to_include_path (optarg); 686146520Sru break; 68721495Sjmacd 688146520Sru case 'i': 689146520Sru if (sscanf (optarg, "%d", &xml_indentation_increment) != 1) 690146520Sru { 691146520Sru fprintf (stderr, 692146520Sru _("%s: %s arg must be numeric, not `%s'.\n"), 693146520Sru progname, "--output-indent", optarg); 694146520Sru usage (1); 695146520Sru } 69642664Smarkm break; 69721495Sjmacd 69856164Sru case 'o': /* --output */ 69942664Smarkm command_output_filename = xstrdup (optarg); 700100516Sru save_command_output_filename = command_output_filename; 70142664Smarkm break; 70221495Sjmacd 70356164Sru case 'p': /* --paragraph-indent */ 70442664Smarkm if (set_paragraph_indent (optarg) < 0) 70542664Smarkm { 70642664Smarkm fprintf (stderr, 70756164Sru _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), 70821495Sjmacd progname, optarg); 70956164Sru usage (1); 71042664Smarkm } 71142664Smarkm break; 71221495Sjmacd 71342664Smarkm case 'P': 71442664Smarkm /* Prepend user-specified include dir to include path. */ 715146520Sru prepend_to_include_path (optarg); 71642664Smarkm break; 71756164Sru 71856164Sru case 'r': /* --reference-limit */ 71942664Smarkm if (sscanf (optarg, "%d", &reference_warning_limit) != 1) 72042664Smarkm { 72142664Smarkm fprintf (stderr, 72256164Sru _("%s: %s arg must be numeric, not `%s'.\n"), 723146520Sru progname, "--reference-limit", optarg); 72456164Sru usage (1); 72542664Smarkm } 72642664Smarkm break; 72742664Smarkm 72856164Sru case 's': /* --footnote-style */ 72942664Smarkm if (set_footnote_style (optarg) < 0) 73042664Smarkm { 73142664Smarkm fprintf (stderr, 732146520Sru _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), 73321495Sjmacd progname, optarg); 73456164Sru usage (1); 73542664Smarkm } 73642664Smarkm footnote_style_preset = 1; 73742664Smarkm break; 73821495Sjmacd 739114477Sru case 'S': /* --split-size */ 74093142Sru if (sscanf (optarg, "%d", &split_size) != 1) 74193142Sru { 74293142Sru fprintf (stderr, 74393142Sru _("%s: %s arg must be numeric, not `%s'.\n"), 744146520Sru progname, "--split-size", optarg); 74593142Sru usage (1); 74693142Sru } 747114477Sru break; 74893142Sru 749146520Sru case 't': /* --plaintext */ 750146520Sru splitting = 0; 751146520Sru no_headers = 1; 752146520Sru html = 0; 753146520Sru docbook = 0; 754146520Sru xml = 0; 755146520Sru process_plaintext = 1; 756146520Sru break; 757146520Sru 75856164Sru case 'v': 75956164Sru verbose_mode++; 76056164Sru break; 76156164Sru 76256164Sru case 'V': /* --version */ 76342664Smarkm print_version_info (); 76456164Sru puts (""); 765146520Sru puts ("Copyright (C) 2004 Free Software Foundation, Inc."); 766146520Sru printf (_("There is NO warranty. You may redistribute this software\n\ 76721495Sjmacdunder the terms of the GNU General Public License.\n\ 768146520SruFor more information about these matters, see the files named COPYING.\n")); 769114477Sru xexit (0); 77042664Smarkm break; 77121495Sjmacd 77256164Sru case 'w': /* --html */ 773146520Sru xml = 0; 774146520Sru docbook = 0; 77556164Sru html = 1; 77656164Sru process_html = 1; 77756164Sru break; 77856164Sru 77993142Sru case 'x': /* --xml */ 78093142Sru splitting = 0; 781146520Sru html = 0; 782146520Sru docbook = 0; 783114477Sru xml = 1; 784114477Sru process_xml = 1; 78593142Sru break; 786116530Sru 78742664Smarkm case '?': 78856164Sru usage (1); 78942664Smarkm break; 79042664Smarkm } 79121495Sjmacd } 79221495Sjmacd 793146520Sru if (macro_expansion_output_stream) 794146520Sru validating = 0; 795146520Sru 79656164Sru if (!validating) 79756164Sru expensive_validation = 0; 79856164Sru 79921495Sjmacd if (optind == argc) 80021495Sjmacd { 80121495Sjmacd /* Check to see if input is a file. If so, process that. */ 80221495Sjmacd if (!isatty (fileno (stdin))) 80342664Smarkm reading_from_stdin = 1; 80421495Sjmacd else 80521495Sjmacd { 80642664Smarkm fprintf (stderr, _("%s: missing file argument.\n"), progname); 80756164Sru usage (1); 80821495Sjmacd } 80921495Sjmacd } 81021495Sjmacd 81121495Sjmacd if (no_headers) 81221495Sjmacd { 813146520Sru /* If the user did not specify an output file, use stdout. */ 814146520Sru if (!command_output_filename) 815146520Sru command_output_filename = xstrdup ("-"); 816146520Sru 817116530Sru if (html && splitting && !STREQ (command_output_filename, "-")) 81856164Sru { /* --no-headers --no-split --html indicates confusion. */ 81956164Sru fprintf (stderr, 820116530Sru "%s: can't split --html output to `%s' with --no-headers.\n", 821116530Sru progname, command_output_filename); 82256164Sru usage (1); 82356164Sru } 82456164Sru 82556164Sru /* --no-headers implies --no-split. */ 82621495Sjmacd splitting = 0; 82721495Sjmacd } 828116530Sru 829100516Sru if (process_info == -1) 830100516Sru { /* no explicit --[no-]ifinfo option, so we'll do @ifinfo 831100516Sru if we're generating info or (for compatibility) plain text. */ 832100516Sru process_info = !html && !xml; 833100516Sru } 83421495Sjmacd 835100516Sru if (process_plaintext == -1) 836100516Sru { /* no explicit --[no-]ifplaintext option, so we'll do @ifplaintext 837100516Sru if we're generating plain text. */ 838100516Sru process_plaintext = no_headers && !html && !xml; 839100516Sru } 840116530Sru 84121495Sjmacd if (verbose_mode) 84221495Sjmacd print_version_info (); 84321495Sjmacd 84421495Sjmacd /* Remaining arguments are file names of texinfo files. 84521495Sjmacd Convert them, one by one. */ 84621495Sjmacd if (!reading_from_stdin) 84721495Sjmacd { 84821495Sjmacd while (optind != argc) 84942664Smarkm convert_from_file (argv[optind++]); 85021495Sjmacd } 85121495Sjmacd else 85221495Sjmacd convert_from_stream (stdin, "stdin"); 85321495Sjmacd 854116530Sru xexit (errors_printed ? 2 : 0); 855116530Sru return 0; /* Avoid bogus warnings. */ 85621495Sjmacd} 85721495Sjmacd 85856164Sru/* Hacking tokens and strings. */ 85921495Sjmacd 860114477Sru/* Return the next token as a string pointer. We cons the string. This 861114477Sru `token' means simply a command name. */ 862114477Sru 863114477Sru/* = is so @alias works. ^ and _ are so macros can be used in math mode 864114477Sru without a space following. Possibly we should simply allow alpha, to 865114477Sru be compatible with TeX. */ 866114477Sru#define COMMAND_CHAR(c) (!cr_or_whitespace(c) \ 867114477Sru && (c) != '{' \ 868114477Sru && (c) != '}' \ 869114477Sru && (c) != '=' \ 870114477Sru && (c) != '_' \ 871114477Sru && (c) != '^' \ 872114477Sru ) 873114477Sru 874146520Srustatic char * 875146520Sruread_token (void) 87621495Sjmacd{ 87721495Sjmacd int i, character; 87821495Sjmacd char *result; 87921495Sjmacd 88021495Sjmacd /* If the first character to be read is self-delimiting, then that 88121495Sjmacd is the command itself. */ 88221495Sjmacd character = curchar (); 88321495Sjmacd if (self_delimiting (character)) 88421495Sjmacd { 88521495Sjmacd input_text_offset++; 88621495Sjmacd 88721495Sjmacd if (character == '\n') 88842664Smarkm line_number++; 88921495Sjmacd 89042664Smarkm result = xstrdup (" "); 89121495Sjmacd *result = character; 89256164Sru return result; 89321495Sjmacd } 89421495Sjmacd 89556164Sru for (i = 0; ((input_text_offset != input_text_length) 89642664Smarkm && (character = curchar ()) 897114477Sru && COMMAND_CHAR (character)); 89821495Sjmacd i++, input_text_offset++); 89956164Sru result = xmalloc (i + 1); 90021495Sjmacd memcpy (result, &input_text[input_text_offset - i], i); 90142664Smarkm result[i] = 0; 90256164Sru return result; 90321495Sjmacd} 90421495Sjmacd 90542664Smarkm/* Return nonzero if CHARACTER is self-delimiting. */ 90621495Sjmacdint 907146520Sruself_delimiting (int character) 90821495Sjmacd{ 90921495Sjmacd /* @; and @\ are not Texinfo commands, but they are listed here 91021495Sjmacd anyway. I don't know why. --karl, 10aug96. */ 911116530Sru return strchr ("~{|}`^\\@?=;:./-,*\'\" !\n\t", character) != NULL; 91221495Sjmacd} 91321495Sjmacd 91421495Sjmacd/* Clear whitespace from the front and end of string. */ 91521495Sjmacdvoid 916146520Srucanon_white (char *string) 91721495Sjmacd{ 918146520Sru char *p = string; 919146520Sru unsigned len; 92021495Sjmacd 921146520Sru if (!*p) 92221495Sjmacd return; 92321495Sjmacd 924146520Sru do 92521495Sjmacd { 926146520Sru if (!cr_or_whitespace (*p)) 927146520Sru break; 928146520Sru ++p; 92921495Sjmacd } 930146520Sru while (*p); 931146520Sru 932146520Sru len = strlen (p); 933146520Sru while (len && cr_or_whitespace (p[len-1])) 934146520Sru --len; 935146520Sru 936146520Sru if (p != string) 937146520Sru memmove (string, p, len); 938146520Sru 939146520Sru string[len] = 0; 94021495Sjmacd} 94121495Sjmacd 94221495Sjmacd/* Bash STRING, replacing all whitespace with just one space. */ 94321495Sjmacdvoid 944146520Srufix_whitespace (char *string) 94521495Sjmacd{ 94656164Sru char *temp = xmalloc (strlen (string) + 1); 94721495Sjmacd int string_index = 0; 94821495Sjmacd int temp_index = 0; 94921495Sjmacd int c; 95021495Sjmacd 95121495Sjmacd canon_white (string); 95221495Sjmacd 95321495Sjmacd while (string[string_index]) 95421495Sjmacd { 95521495Sjmacd c = temp[temp_index++] = string[string_index++]; 95621495Sjmacd 95721495Sjmacd if (c == ' ' || c == '\n' || c == '\t') 95842664Smarkm { 95942664Smarkm temp[temp_index - 1] = ' '; 96042664Smarkm while ((c = string[string_index]) && (c == ' ' || 96142664Smarkm c == '\t' || 96242664Smarkm c == '\n')) 96342664Smarkm string_index++; 96442664Smarkm } 96521495Sjmacd } 96642664Smarkm temp[temp_index] = 0; 96721495Sjmacd strcpy (string, temp); 96821495Sjmacd free (temp); 96921495Sjmacd} 97021495Sjmacd 97121495Sjmacd/* Discard text until the desired string is found. The string is 97221495Sjmacd included in the discarded text. */ 97321495Sjmacdvoid 974146520Srudiscard_until (char *string) 97521495Sjmacd{ 97621495Sjmacd int temp = search_forward (string, input_text_offset); 97721495Sjmacd 97856164Sru int tt = (temp < 0) ? input_text_length : temp + strlen (string); 97921495Sjmacd int from = input_text_offset; 98021495Sjmacd 98121495Sjmacd /* Find out what line we are on. */ 98221495Sjmacd while (from != tt) 98321495Sjmacd if (input_text[from++] == '\n') 98421495Sjmacd line_number++; 98521495Sjmacd 98621495Sjmacd if (temp < 0) 98721495Sjmacd { 988146520Sru /* not found, move current position to end of string */ 989146520Sru input_text_offset = input_text_length; 99021495Sjmacd if (strcmp (string, "\n") != 0) 991146520Sru { /* Give a more descriptive feedback, if we are looking for ``@end '' 992146520Sru during macro execution. That means someone used a multiline 993146520Sru command as an argument to, say, @section ... style commands. */ 994146520Sru char *end_block = xmalloc (8); 995146520Sru sprintf (end_block, "\n%cend ", COMMAND_PREFIX); 996146520Sru if (executing_string && strstr (string, end_block)) 997146520Sru line_error (_("Multiline command %c%s used improperly"), 998146520Sru COMMAND_PREFIX, command); 999146520Sru else 1000146520Sru line_error (_("Expected `%s'"), string); 1001146520Sru free (end_block); 100242664Smarkm return; 100342664Smarkm } 100421495Sjmacd } 100521495Sjmacd else 1006146520Sru /* found, move current position to after the found string */ 1007146520Sru input_text_offset = temp + strlen (string); 100821495Sjmacd} 100921495Sjmacd 101021495Sjmacd/* Read characters from the file until we are at MATCH. 101121495Sjmacd Place the characters read into STRING. 101221495Sjmacd On exit input_text_offset is after the match string. 101321495Sjmacd Return the offset where the string starts. */ 101421495Sjmacdint 1015146520Sruget_until (char *match, char **string) 101621495Sjmacd{ 101721495Sjmacd int len, current_point, x, new_point, tem; 101821495Sjmacd 101921495Sjmacd current_point = x = input_text_offset; 102021495Sjmacd new_point = search_forward (match, input_text_offset); 102121495Sjmacd 102221495Sjmacd if (new_point < 0) 102356164Sru new_point = input_text_length; 102421495Sjmacd len = new_point - current_point; 102521495Sjmacd 102621495Sjmacd /* Keep track of which line number we are at. */ 102721495Sjmacd tem = new_point + (strlen (match) - 1); 102821495Sjmacd while (x != tem) 102921495Sjmacd if (input_text[x++] == '\n') 103021495Sjmacd line_number++; 103121495Sjmacd 103256164Sru *string = xmalloc (len + 1); 103321495Sjmacd 103421495Sjmacd memcpy (*string, &input_text[current_point], len); 103542664Smarkm (*string)[len] = 0; 103621495Sjmacd 103721495Sjmacd /* Now leave input_text_offset in a consistent state. */ 103821495Sjmacd input_text_offset = tem; 103921495Sjmacd 104056164Sru if (input_text_offset > input_text_length) 104156164Sru input_text_offset = input_text_length; 104221495Sjmacd 104356164Sru return new_point; 104421495Sjmacd} 104521495Sjmacd 104656164Sru/* Replace input_text[FROM .. TO] with its expansion. */ 104756164Sruvoid 1048146520Srureplace_with_expansion (int from, int *to) 104956164Sru{ 105056164Sru char *xp; 105156164Sru unsigned xp_len, new_len; 105256164Sru char *old_input = input_text; 105356164Sru unsigned raw_len = *to - from; 105456164Sru char *str; 105556164Sru 105656164Sru /* The rest of the code here moves large buffers, so let's 105756164Sru not waste time if the input cannot possibly expand 105856164Sru into anything. Unfortunately, we cannot avoid expansion 105956164Sru when we see things like @code etc., even if they only 106056164Sru asked for expansion of macros, since any Texinfo command 106156164Sru can be potentially redefined with a macro. */ 106256164Sru if (only_macro_expansion && 106356164Sru memchr (input_text + from, COMMAND_PREFIX, raw_len) == 0) 106456164Sru return; 106556164Sru 106656164Sru /* Get original string from input. */ 106756164Sru str = xmalloc (raw_len + 1); 106856164Sru memcpy (str, input_text + from, raw_len); 106956164Sru str[raw_len] = 0; 107056164Sru 107156164Sru /* We are going to relocate input_text, so we had better output 107256164Sru pending portion of input_text now, before the pointer changes. */ 107356164Sru if (macro_expansion_output_stream && !executing_string 107456164Sru && !me_inhibit_expansion) 107556164Sru append_to_expansion_output (from); 107656164Sru 107756164Sru /* Expand it. */ 107856164Sru xp = expansion (str, 0); 107956164Sru xp_len = strlen (xp); 108056164Sru free (str); 108156164Sru 108256164Sru /* Plunk the expansion into the middle of `input_text' -- 108356164Sru which is terminated by a newline, not a null. Avoid 108456164Sru expensive move of the rest of the input if the expansion 108556164Sru has the same length as the original string. */ 108656164Sru if (xp_len != raw_len) 108756164Sru { 108856164Sru new_len = from + xp_len + input_text_length - *to + 1; 108956164Sru if (executing_string) 109056164Sru { /* If we are in execute_string, we might need to update 109156164Sru the relevant element in the execution_strings[] array, 109256164Sru since it could have to be relocated from under our 109356164Sru feet. (input_text is reallocated here as well, if needed.) */ 109456164Sru maybe_update_execution_strings (&input_text, new_len); 109556164Sru } 109656164Sru else if (new_len > input_text_length + 1) 109756164Sru /* Don't bother to realloc if we have enough space. */ 109856164Sru input_text = xrealloc (input_text, new_len); 109956164Sru 110056164Sru memmove (input_text + from + xp_len, 110156164Sru input_text + *to, input_text_length - *to + 1); 110256164Sru 110356164Sru *to += xp_len - raw_len; 110456164Sru /* Since we change input_text_length here, the comparison above 110556164Sru isn't really valid, but it seems the worst that might happen is 110656164Sru an extra xrealloc or two, so let's not worry. */ 110756164Sru input_text_length += xp_len - raw_len; 110856164Sru } 110956164Sru memcpy (input_text + from, xp, xp_len); 111056164Sru free (xp); 111156164Sru 111256164Sru /* Synchronize the macro-expansion pointers with our new input_text. */ 111356164Sru if (input_text != old_input) 111456164Sru forget_itext (old_input); 111556164Sru if (macro_expansion_output_stream && !executing_string) 111656164Sru remember_itext (input_text, from); 111756164Sru} 111856164Sru 111921495Sjmacd/* Read characters from the file until we are at MATCH or end of line. 112056164Sru Place the characters read into STRING. If EXPAND is nonzero, 112156164Sru expand the text before looking for MATCH for those cases where 112256164Sru MATCH might be produced by some macro. */ 112321495Sjmacdvoid 1124146520Sruget_until_in_line (int expand, char *match, char **string) 112521495Sjmacd{ 112656164Sru int real_bottom = input_text_length; 112742664Smarkm int limit = search_forward ("\n", input_text_offset); 112842664Smarkm if (limit < 0) 112956164Sru limit = input_text_length; 113021495Sjmacd 113156164Sru /* Replace input_text[input_text_offset .. limit-1] with its expansion. 113256164Sru This allows the node names and menu entries themselves to be 113356164Sru constructed via a macro, as in: 113442664Smarkm @macro foo{p, q} 113542664Smarkm Together: \p\ & \q\. 113642664Smarkm @end macro 113721495Sjmacd 113842664Smarkm @node @foo{A,B}, next, prev, top 113956164Sru 114042664Smarkm Otherwise, the `,' separating the macro args A and B is taken as 114142664Smarkm the node argument separator, so the node name is `@foo{A'. This 114242664Smarkm expansion is only necessary on the first call, since we expand the 114356164Sru whole line then. */ 114456164Sru if (expand) 114542664Smarkm { 114656164Sru replace_with_expansion (input_text_offset, &limit); 114742664Smarkm } 114842664Smarkm 114956164Sru real_bottom = input_text_length; 115056164Sru input_text_length = limit; 115121495Sjmacd get_until (match, string); 115256164Sru input_text_length = real_bottom; 115321495Sjmacd} 115421495Sjmacd 115521495Sjmacdvoid 1156146520Sruget_rest_of_line (int expand, char **string) 115721495Sjmacd{ 115893142Sru xml_no_para ++; 115956164Sru if (expand) 116056164Sru { 116156164Sru char *tem; 116256164Sru 116356164Sru /* Don't expand non-macros in input, since we want them 1164114477Sru intact in the macro-expanded output. */ 116556164Sru only_macro_expansion++; 116656164Sru get_until_in_line (1, "\n", &tem); 116756164Sru only_macro_expansion--; 116856164Sru *string = expansion (tem, 0); 116956164Sru free (tem); 117056164Sru } 117156164Sru else 117256164Sru get_until_in_line (0, "\n", string); 117356164Sru 117421495Sjmacd canon_white (*string); 117521495Sjmacd 117642664Smarkm if (curchar () == '\n') /* as opposed to the end of the file... */ 117721495Sjmacd { 117821495Sjmacd line_number++; 117921495Sjmacd input_text_offset++; 118021495Sjmacd } 118193142Sru xml_no_para --; 118221495Sjmacd} 118321495Sjmacd 118421495Sjmacd/* Backup the input pointer to the previous character, keeping track 118521495Sjmacd of the current line number. */ 118621495Sjmacdvoid 1187146520Srubackup_input_pointer (void) 118821495Sjmacd{ 118921495Sjmacd if (input_text_offset) 119021495Sjmacd { 119121495Sjmacd input_text_offset--; 119221495Sjmacd if (curchar () == '\n') 119342664Smarkm line_number--; 119421495Sjmacd } 119521495Sjmacd} 119621495Sjmacd 119721495Sjmacd/* Read characters from the file until we are at MATCH or closing brace. 119821495Sjmacd Place the characters read into STRING. */ 119921495Sjmacdvoid 1200146520Sruget_until_in_braces (char *match, char **string) 120121495Sjmacd{ 120242664Smarkm char *temp; 120321495Sjmacd int i, brace = 0; 120421495Sjmacd int match_len = strlen (match); 120521495Sjmacd 120656164Sru for (i = input_text_offset; i < input_text_length; i++) 120721495Sjmacd { 120893142Sru if (i < input_text_length - 1 && input_text[i] == '@') 120993142Sru { 1210114477Sru i++; /* skip commands like @, and @{ */ 121193142Sru continue; 121293142Sru } 121393142Sru else if (input_text[i] == '{') 121442664Smarkm brace++; 121521495Sjmacd else if (input_text[i] == '}') 121693142Sru { 121793142Sru brace--; 121893142Sru /* If looking for a brace, don't stop at the interior brace, 121993142Sru like after "baz" in "@foo{something @bar{baz} more}". */ 122093142Sru if (brace == 0) 122193142Sru continue; 122293142Sru } 122321495Sjmacd else if (input_text[i] == '\n') 122442664Smarkm line_number++; 122521495Sjmacd 122621495Sjmacd if (brace < 0 || 122742664Smarkm (brace == 0 && strncmp (input_text + i, match, match_len) == 0)) 122842664Smarkm break; 122921495Sjmacd } 123021495Sjmacd 123121495Sjmacd match_len = i - input_text_offset; 123256164Sru temp = xmalloc (2 + match_len); 123356164Sru memcpy (temp, input_text + input_text_offset, match_len); 123442664Smarkm temp[match_len] = 0; 123521495Sjmacd input_text_offset = i; 123621495Sjmacd *string = temp; 123721495Sjmacd} 1238116530Sru 1239116530Sru 124021495Sjmacd 124156164Sru/* Converting a file. */ 124221495Sjmacd 124321495Sjmacd/* Convert the file named by NAME. The output is saved on the file 124421495Sjmacd named as the argument to the @setfilename command. */ 124521495Sjmacdstatic char *suffixes[] = { 124656164Sru /* ".txi" is checked first so that on 8+3 DOS filesystems, if they 124756164Sru have "texinfo.txi" and "texinfo.tex" in the same directory, the 124856164Sru former is used rather than the latter, due to file name truncation. */ 124956164Sru ".txi", 125021495Sjmacd ".texinfo", 125121495Sjmacd ".texi", 125221495Sjmacd ".txinfo", 125321495Sjmacd "", 125456164Sru NULL 125521495Sjmacd}; 125621495Sjmacd 1257146520Srustatic void 1258146520Sruinitialize_conversion (void) 125921495Sjmacd{ 126021495Sjmacd init_tag_table (); 126121495Sjmacd init_indices (); 126221495Sjmacd init_internals (); 126321495Sjmacd init_paragraph (); 126421495Sjmacd 126521495Sjmacd /* This is used for splitting the output file and for doing section 126621495Sjmacd headings. It was previously initialized in `init_paragraph', but its 126721495Sjmacd use there loses with the `init_paragraph' calls done by the 126821495Sjmacd multitable code; the tag indices get reset to zero. */ 126921495Sjmacd output_position = 0; 127021495Sjmacd} 127121495Sjmacd 127256164Sru/* Reverse the chain of structures in LIST. Output the new head 127356164Sru of the chain. You should always assign the output value of this 127456164Sru function to something, or you will lose the chain. */ 127556164SruGENERIC_LIST * 1276146520Srureverse_list (GENERIC_LIST *list) 127756164Sru{ 127856164Sru GENERIC_LIST *next; 127956164Sru GENERIC_LIST *prev = NULL; 128056164Sru 128156164Sru while (list) 128256164Sru { 128356164Sru next = list->next; 128456164Sru list->next = prev; 128556164Sru prev = list; 128656164Sru list = next; 128756164Sru } 128856164Sru return prev; 128956164Sru} 129056164Sru 129121495Sjmacd/* We read in multiples of 4k, simply because it is a typical pipe size 129221495Sjmacd on unix systems. */ 129321495Sjmacd#define READ_BUFFER_GROWTH (4 * 4096) 129421495Sjmacd 129542664Smarkm/* Convert the Texinfo file coming from the open stream STREAM. Assume the 129621495Sjmacd source of the stream is named NAME. */ 1297146520Srustatic void 1298146520Sruconvert_from_stream (FILE *stream, char *name) 129921495Sjmacd{ 130056164Sru char *buffer = NULL; 130121495Sjmacd int buffer_offset = 0, buffer_size = 0; 130221495Sjmacd 130321495Sjmacd initialize_conversion (); 130421495Sjmacd 130521495Sjmacd /* Read until the end of the stream. This isn't strictly correct, since 130621495Sjmacd the texinfo input may end before the stream ends, but it is a quick 130721495Sjmacd working hueristic. */ 130821495Sjmacd while (!feof (stream)) 130921495Sjmacd { 131021495Sjmacd int count; 131121495Sjmacd 131221495Sjmacd if (buffer_offset + (READ_BUFFER_GROWTH + 1) >= buffer_size) 131342664Smarkm buffer = (char *) 131442664Smarkm xrealloc (buffer, (buffer_size += READ_BUFFER_GROWTH)); 131521495Sjmacd 131621495Sjmacd count = fread (buffer + buffer_offset, 1, READ_BUFFER_GROWTH, stream); 131721495Sjmacd 131821495Sjmacd if (count < 0) 131942664Smarkm { 132042664Smarkm perror (name); 132156164Sru xexit (1); 132242664Smarkm } 132321495Sjmacd 132421495Sjmacd buffer_offset += count; 132521495Sjmacd if (count == 0) 132642664Smarkm break; 132721495Sjmacd } 132821495Sjmacd 132921495Sjmacd /* Set the globals to the new file. */ 133021495Sjmacd input_text = buffer; 133156164Sru input_text_length = buffer_offset; 133242664Smarkm input_filename = xstrdup (name); 133342664Smarkm node_filename = xstrdup (name); 133421495Sjmacd input_text_offset = 0; 133521495Sjmacd line_number = 1; 133621495Sjmacd 133721495Sjmacd /* Not strictly necessary. This magic prevents read_token () from doing 133821495Sjmacd extra unnecessary work each time it is called (that is a lot of times). 133956164Sru The INPUT_TEXT_LENGTH is one past the actual end of the text. */ 134056164Sru input_text[input_text_length] = '\n'; 134121495Sjmacd 134221495Sjmacd convert_from_loaded_file (name); 134321495Sjmacd} 134421495Sjmacd 1345146520Srustatic void 1346146520Sruconvert_from_file (char *name) 134721495Sjmacd{ 134856164Sru int i; 134956164Sru char *filename = xmalloc (strlen (name) + 50); 135021495Sjmacd 1351146520Sru /* Prepend file directory to the search path, so relative links work. */ 1352146520Sru prepend_to_include_path (pathname_part (name)); 1353146520Sru 135421495Sjmacd initialize_conversion (); 135521495Sjmacd 135621495Sjmacd /* Try to load the file specified by NAME, concatenated with our 135721495Sjmacd various suffixes. Prefer files like `makeinfo.texi' to 135821495Sjmacd `makeinfo'. */ 135921495Sjmacd for (i = 0; suffixes[i]; i++) 136021495Sjmacd { 136121495Sjmacd strcpy (filename, name); 136221495Sjmacd strcat (filename, suffixes[i]); 136321495Sjmacd 1364146520Sru if (find_and_load (filename, 1)) 136542664Smarkm break; 136621495Sjmacd 136721495Sjmacd if (!suffixes[i][0] && strrchr (filename, '.')) 136842664Smarkm { 136942664Smarkm fs_error (filename); 137042664Smarkm free (filename); 137142664Smarkm return; 137242664Smarkm } 137321495Sjmacd } 137421495Sjmacd 137521495Sjmacd if (!suffixes[i]) 137621495Sjmacd { 137721495Sjmacd fs_error (name); 137821495Sjmacd free (filename); 137921495Sjmacd return; 138021495Sjmacd } 138121495Sjmacd 138221495Sjmacd input_filename = filename; 138321495Sjmacd 138421495Sjmacd convert_from_loaded_file (name); 1385146520Sru 1386146520Sru /* Pop the prepended path, so multiple filenames in the 1387146520Sru command line do not screw each others include paths. */ 1388146520Sru pop_path_from_include_path (); 138921495Sjmacd} 139056164Sru 1391146520Srustatic int 1392146520Srucreate_html_directory (char *dir, int can_remove_file) 1393146520Sru{ 1394146520Sru struct stat st; 1395146520Sru 1396146520Sru /* Already exists. */ 1397146520Sru if (stat (dir, &st) == 0) 1398146520Sru { 1399146520Sru /* And it's a directory, so silently reuse it. */ 1400146520Sru if (S_ISDIR (st.st_mode)) 1401146520Sru return 1; 1402146520Sru /* Not a directory, so move it out of the way if we are allowed. */ 1403146520Sru else if (can_remove_file) 1404146520Sru { 1405146520Sru if (unlink (dir) != 0) 1406146520Sru return 0; 1407146520Sru } 1408146520Sru else 1409146520Sru return 0; 1410146520Sru } 1411146520Sru 1412146520Sru if (mkdir (dir, 0777) == 0) 1413146520Sru /* Success! */ 1414146520Sru return 1; 1415146520Sru else 1416146520Sru return 0; 1417146520Sru} 1418146520Sru 141993142Sru/* Given OUTPUT_FILENAME == ``/foo/bar/baz.html'', return 1420100516Sru "/foo/bar/baz/baz.html". This routine is called only if html && splitting. 1421116530Sru 142293142Sru Split html output goes into the subdirectory of the toplevel 142393142Sru filename, without extension. For example: 142493142Sru @setfilename foo.info 1425100516Sru produces output in files foo/index.html, foo/second-node.html, ... 1426116530Sru 1427100516Sru But if the user said -o foo.whatever on the cmd line, then use 1428100516Sru foo.whatever unchanged. */ 142993142Sru 143093142Srustatic char * 1431146520Sruinsert_toplevel_subdirectory (char *output_filename) 143293142Sru{ 1433116530Sru static const char index_name[] = "index.html"; 143493142Sru char *dir, *subdir, *base, *basename, *p; 143593142Sru char buf[PATH_MAX]; 143693142Sru const int index_len = sizeof (index_name) - 1; 143793142Sru 143893142Sru strcpy (buf, output_filename); 1439116530Sru dir = pathname_part (buf); /* directory of output_filename */ 1440116530Sru base = filename_part (buf); /* strips suffix, too */ 1441116530Sru basename = xstrdup (base); /* remember real @setfilename name */ 144293142Sru p = dir + strlen (dir) - 1; 144393142Sru if (p > dir && IS_SLASH (*p)) 144493142Sru *p = 0; 144593142Sru p = strrchr (base, '.'); 144693142Sru if (p) 144793142Sru *p = 0; 1448100516Sru 144993142Sru /* Split html output goes into subdirectory of toplevel name. */ 1450116530Sru if (save_command_output_filename 1451116530Sru && STREQ (output_filename, save_command_output_filename)) 1452116530Sru subdir = basename; /* from user, use unchanged */ 1453116530Sru else 1454116530Sru subdir = base; /* implicit, omit suffix */ 145593142Sru 145693142Sru free (output_filename); 1457100516Sru output_filename = xmalloc (strlen (dir) + 1 1458114477Sru + strlen (basename) + 1 1459114477Sru + index_len 1460114477Sru + 1); 146193142Sru strcpy (output_filename, dir); 146293142Sru if (strlen (dir)) 146393142Sru strcat (output_filename, "/"); 146493142Sru strcat (output_filename, subdir); 1465146520Sru 1466146520Sru /* First try, do not remove existing file. */ 1467146520Sru if (!create_html_directory (output_filename, 0)) 1468146520Sru { 1469146520Sru /* That failed, try subdir name with .html. 1470146520Sru Remove it if it exists. */ 147193142Sru strcpy (output_filename, dir); 147293142Sru if (strlen (dir)) 147393142Sru strcat (output_filename, "/"); 147493142Sru strcat (output_filename, basename); 1475146520Sru 1476146520Sru if (!create_html_directory (output_filename, 1)) 1477114477Sru { 1478146520Sru /* Last try failed too :-\ */ 147993142Sru line_error (_("Can't create directory `%s': %s"), 1480146520Sru output_filename, strerror (errno)); 1481114477Sru xexit (1); 148293142Sru } 148393142Sru } 1484146520Sru 1485146520Sru strcat (output_filename, "/"); 148693142Sru strcat (output_filename, index_name); 148793142Sru return output_filename; 148893142Sru} 148993142Sru 149093142Sru/* FIXME: this is way too hairy */ 1491146520Srustatic void 1492146520Sruconvert_from_loaded_file (char *name) 149321495Sjmacd{ 149456164Sru char *real_output_filename = NULL; 149521495Sjmacd 149621495Sjmacd remember_itext (input_text, 0); 149721495Sjmacd 149856164Sru input_text_offset = 0; 149956164Sru 150056164Sru /* Avoid the `\input texinfo' line in HTML output (assuming it starts 150156164Sru the file). */ 150256164Sru if (looking_at ("\\input")) 150356164Sru discard_until ("\n"); 150456164Sru 150521495Sjmacd /* Search this file looking for the special string which starts conversion. 150621495Sjmacd Once found, we may truly begin. */ 150721495Sjmacd while (input_text_offset >= 0) 150821495Sjmacd { 150921495Sjmacd input_text_offset = 151042664Smarkm search_forward (setfilename_search, input_text_offset); 151121495Sjmacd 151256164Sru if (input_text_offset == 0 151356164Sru || (input_text_offset > 0 151456164Sru && input_text[input_text_offset -1] == '\n')) 151542664Smarkm break; 151621495Sjmacd else if (input_text_offset > 0) 151742664Smarkm input_text_offset++; 151821495Sjmacd } 151921495Sjmacd 152021495Sjmacd if (input_text_offset < 0) 152121495Sjmacd { 152221495Sjmacd if (!command_output_filename) 152342664Smarkm { 152421495Sjmacd#if defined (REQUIRE_SETFILENAME) 152542664Smarkm error (_("No `%s' found in `%s'"), setfilename_search, name); 152642664Smarkm goto finished; 152721495Sjmacd#else 152856164Sru command_output_filename = output_name_from_input_name (name); 152956164Sru#endif /* !REQUIRE_SETFILENAME */ 153056164Sru } 1531116530Sru 153256164Sru { 153356164Sru int i, end_of_first_line; 153421495Sjmacd 153556164Sru /* Find the end of the first line in the file. */ 153656164Sru for (i = 0; i < input_text_length - 1; i++) 153756164Sru if (input_text[i] == '\n') 153856164Sru break; 153921495Sjmacd 154056164Sru end_of_first_line = i + 1; 154121495Sjmacd 154256164Sru for (i = 0; i < end_of_first_line; i++) 154356164Sru { 154456164Sru if ((input_text[i] == '\\') && 154556164Sru (strncmp (input_text + i + 1, "input", 5) == 0)) 154656164Sru { 154756164Sru input_text_offset = i; 154856164Sru break; 154956164Sru } 155056164Sru } 155156164Sru } 155221495Sjmacd } 155321495Sjmacd else 155421495Sjmacd input_text_offset += strlen (setfilename_search); 155521495Sjmacd 155621495Sjmacd if (!command_output_filename) 155756164Sru { 155856164Sru get_until ("\n", &output_filename); /* read rest of line */ 155993142Sru if (html || xml) 156093142Sru { /* Change any extension to .html or .xml. */ 156156164Sru char *html_name, *directory_part, *basename_part, *temp; 156256164Sru 156356164Sru canon_white (output_filename); 156456164Sru directory_part = pathname_part (output_filename); 156593142Sru 156656164Sru basename_part = filename_part (output_filename); 156756164Sru 156856164Sru /* Zap any existing extension. */ 156956164Sru temp = strrchr (basename_part, '.'); 157056164Sru if (temp) 157156164Sru *temp = 0; 157256164Sru 157356164Sru /* Construct new filename. */ 157456164Sru html_name = xmalloc (strlen (directory_part) 157556164Sru + strlen (basename_part) + 6); 157656164Sru strcpy (html_name, directory_part); 157756164Sru strcat (html_name, basename_part); 157893142Sru strcat (html_name, html ? ".html" : ".xml"); 157956164Sru 158056164Sru /* Replace name from @setfilename with the html name. */ 158156164Sru free (output_filename); 158256164Sru output_filename = html_name; 158356164Sru } 158456164Sru } 158521495Sjmacd else 158621495Sjmacd { 158721495Sjmacd if (input_text_offset != -1) 158842664Smarkm discard_until ("\n"); 158921495Sjmacd else 159042664Smarkm input_text_offset = 0; 159121495Sjmacd 159221495Sjmacd real_output_filename = output_filename = command_output_filename; 1593100516Sru command_output_filename = NULL; /* for included files or whatever */ 159421495Sjmacd } 159521495Sjmacd 159621495Sjmacd canon_white (output_filename); 159793142Sru toplevel_output_filename = xstrdup (output_filename); 159821495Sjmacd 159942664Smarkm if (real_output_filename && strcmp (real_output_filename, "-") == 0) 160021495Sjmacd { 160142664Smarkm if (macro_expansion_filename 160242664Smarkm && strcmp (macro_expansion_filename, "-") == 0) 160342664Smarkm { 160493142Sru fprintf (stderr, 160593142Sru _("%s: Skipping macro expansion to stdout as Info output is going there.\n"), 160642664Smarkm progname); 160742664Smarkm macro_expansion_output_stream = NULL; 160842664Smarkm } 160942664Smarkm real_output_filename = xstrdup (real_output_filename); 161021495Sjmacd output_stream = stdout; 161142664Smarkm splitting = 0; /* Cannot split when writing to stdout. */ 161221495Sjmacd } 161321495Sjmacd else 161421495Sjmacd { 161593142Sru if (html && splitting) 161693142Sru { 1617114477Sru if (FILENAME_CMP (output_filename, NULL_DEVICE) == 0 1618114477Sru || FILENAME_CMP (output_filename, ALSO_NULL_DEVICE) == 0) 1619114477Sru splitting = 0; 1620114477Sru else 1621114477Sru output_filename = insert_toplevel_subdirectory (output_filename); 162293142Sru real_output_filename = xstrdup (output_filename); 162393142Sru } 162493142Sru else if (!real_output_filename) 162542664Smarkm real_output_filename = expand_filename (output_filename, name); 162621495Sjmacd else 162742664Smarkm real_output_filename = xstrdup (real_output_filename); 162821495Sjmacd 162921495Sjmacd output_stream = fopen (real_output_filename, "w"); 163021495Sjmacd } 163121495Sjmacd 163256164Sru set_current_output_filename (real_output_filename); 163356164Sru 1634146520Sru if (xml && !docbook) 1635146520Sru xml_begin_document (filename_part (output_filename)); 1636146520Sru 163756164Sru if (verbose_mode) 163842664Smarkm printf (_("Making %s file `%s' from `%s'.\n"), 163993142Sru no_headers ? "text" 164093142Sru : html ? "HTML" 164193142Sru : xml ? "XML" 164293142Sru : "info", 164356164Sru output_filename, input_filename); 164421495Sjmacd 164521495Sjmacd if (output_stream == NULL) 164621495Sjmacd { 164721495Sjmacd fs_error (real_output_filename); 164821495Sjmacd goto finished; 164921495Sjmacd } 165021495Sjmacd 165121495Sjmacd /* Make the displayable filename from output_filename. Only the base 165221495Sjmacd portion of the filename need be displayed. */ 1653114477Sru flush_output (); /* in case there was no @bye */ 165421495Sjmacd if (output_stream != stdout) 165521495Sjmacd pretty_output_filename = filename_part (output_filename); 165621495Sjmacd else 165742664Smarkm pretty_output_filename = xstrdup ("stdout"); 165821495Sjmacd 165921495Sjmacd /* For this file only, count the number of newlines from the top of 166021495Sjmacd the file to here. This way, we keep track of line numbers for 166121495Sjmacd error reporting. Line_number starts at 1, since the user isn't 166221495Sjmacd zero-based. */ 166321495Sjmacd { 166421495Sjmacd int temp = 0; 166521495Sjmacd line_number = 1; 166621495Sjmacd while (temp != input_text_offset) 166721495Sjmacd if (input_text[temp++] == '\n') 166842664Smarkm line_number++; 166921495Sjmacd } 167021495Sjmacd 167156164Sru /* html fixxme: should output this as trailer on first page. */ 167293142Sru if (!no_headers && !html && !xml) 167356164Sru add_word_args (_("This is %s, produced by makeinfo version %s from %s.\n"), 167456164Sru output_filename, VERSION, input_filename); 167521495Sjmacd 167621495Sjmacd close_paragraph (); 1677146520Sru 1678146520Sru if (xml && !docbook) 1679146520Sru { 1680146520Sru /* Just before the real main loop, let's handle the defines. */ 1681146520Sru COMMAND_LINE_DEFINE *temp; 1682146520Sru 1683146520Sru for (temp = command_line_defines; temp; temp = temp->next) 1684146520Sru { 1685146520Sru handle_variable_internal (temp->action, temp->define); 1686146520Sru free(temp->define); 1687146520Sru } 1688146520Sru } 1689146520Sru 169021495Sjmacd reader_loop (); 169193142Sru if (xml) 169293142Sru xml_end_document (); 169321495Sjmacd 1694116530Sru 169521495Sjmacdfinished: 169642664Smarkm discard_insertions (0); 169721495Sjmacd close_paragraph (); 169821495Sjmacd flush_file_stack (); 169921495Sjmacd 170021495Sjmacd if (macro_expansion_output_stream) 170142664Smarkm { 170242664Smarkm fclose (macro_expansion_output_stream); 170342664Smarkm if (errors_printed && !force 170442664Smarkm && strcmp (macro_expansion_filename, "-") != 0 170556164Sru && FILENAME_CMP (macro_expansion_filename, NULL_DEVICE) != 0 170656164Sru && FILENAME_CMP (macro_expansion_filename, ALSO_NULL_DEVICE) != 0) 170742664Smarkm { 1708146520Sru fprintf (stderr, 1709146520Sru_("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"), 171042664Smarkm progname, macro_expansion_filename); 171142664Smarkm if (unlink (macro_expansion_filename) < 0) 171242664Smarkm perror (macro_expansion_filename); 171342664Smarkm } 171442664Smarkm } 171521495Sjmacd 171642664Smarkm if (output_stream) 171721495Sjmacd { 171821495Sjmacd output_pending_notes (); 171921495Sjmacd 172056164Sru if (html) 172156164Sru { 1722146520Sru no_indent = 1; 172356164Sru start_paragraph (); 172456164Sru add_word ("</body></html>\n"); 172556164Sru close_paragraph (); 172656164Sru } 172756164Sru 1728116530Sru /* maybe we want local variables in info output. */ 1729116530Sru { 1730116530Sru char *trailer = info_trailer (); 1731146520Sru if (!xml && !docbook && trailer) 1732116530Sru { 1733146520Sru if (html) 1734146520Sru insert_string ("<!--"); 1735116530Sru insert_string (trailer); 1736116530Sru free (trailer); 1737146520Sru if (html) 1738146520Sru insert_string ("\n-->\n"); 1739116530Sru } 1740116530Sru } 1741116530Sru 1742146520Sru /* Write stuff makeinfo generates after @bye, ie. info_trailer. */ 1743146520Sru flush_output (); 1744116530Sru 174521495Sjmacd if (output_stream != stdout) 174642664Smarkm fclose (output_stream); 174721495Sjmacd 174821495Sjmacd /* If validating, then validate the entire file right now. */ 174921495Sjmacd if (validating) 175042664Smarkm validate_file (tag_table); 175121495Sjmacd 1752146520Sru handle_delayed_writes (); 175356164Sru 1754146520Sru if (tag_table) 1755146520Sru { 1756146520Sru tag_table = (TAG_ENTRY *) reverse_list ((GENERIC_LIST *) tag_table); 1757146520Sru if (!no_headers && !html && !STREQ (current_output_filename, "-")) 1758146520Sru write_tag_table (real_output_filename); 1759146520Sru } 1760146520Sru 176156164Sru if (splitting && !html && (!errors_printed || force)) 1762146520Sru { 1763146520Sru clean_old_split_files (real_output_filename); 1764146520Sru split_file (real_output_filename, split_size); 1765146520Sru } 176656164Sru else if (errors_printed 176756164Sru && !force 176842664Smarkm && strcmp (real_output_filename, "-") != 0 176956164Sru && FILENAME_CMP (real_output_filename, NULL_DEVICE) != 0 177056164Sru && FILENAME_CMP (real_output_filename, ALSO_NULL_DEVICE) != 0) 177142664Smarkm { /* If there were errors, and no --force, remove the output. */ 1772146520Sru fprintf (stderr, 1773146520Sru _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"), 177442664Smarkm progname, real_output_filename); 177542664Smarkm if (unlink (real_output_filename) < 0) 177642664Smarkm perror (real_output_filename); 177742664Smarkm } 177821495Sjmacd } 177921495Sjmacd free (real_output_filename); 178021495Sjmacd} 1781116530Sru 1782146520Sru/* If enable_encoding is set and @documentencoding is used, return a 1783146520Sru Local Variables section (as a malloc-ed string) so that Emacs' 1784146520Sru locale features can work. Else return NULL. */ 1785116530Sruchar * 1786146520Sruinfo_trailer (void) 1787116530Sru{ 1788146520Sru char *encoding; 1789146520Sru 1790146520Sru if (!enable_encoding) 1791116530Sru return NULL; 1792116530Sru 1793146520Sru encoding = current_document_encoding (); 1794146520Sru 1795146520Sru if (encoding && *encoding) 1796146520Sru { 1797116530Sru#define LV_FMT "\n\037\nLocal Variables:\ncoding: %s\nEnd:\n" 1798146520Sru char *lv = xmalloc (sizeof (LV_FMT) + strlen (encoding)); 1799146520Sru sprintf (lv, LV_FMT, encoding); 1800146520Sru free (encoding); 1801146520Sru return lv; 1802146520Sru } 1803146520Sru 1804146520Sru free (encoding); 1805146520Sru return NULL; 1806116530Sru} 1807116530Sru 180821495Sjmacdvoid 1809146520Srufree_and_clear (char **pointer) 181021495Sjmacd{ 181142664Smarkm if (*pointer) 181221495Sjmacd { 181321495Sjmacd free (*pointer); 181456164Sru *pointer = NULL; 181521495Sjmacd } 181621495Sjmacd} 181721495Sjmacd 181821495Sjmacd /* Initialize some state. */ 1819146520Srustatic void 1820146520Sruinit_internals (void) 182121495Sjmacd{ 182221495Sjmacd free_and_clear (&output_filename); 182321495Sjmacd free_and_clear (&command); 182421495Sjmacd free_and_clear (&input_filename); 182521495Sjmacd free_node_references (); 182656164Sru free_node_node_references (); 182756164Sru toc_free (); 182821495Sjmacd init_insertion_stack (); 182921495Sjmacd init_brace_stack (); 183042664Smarkm current_node = NULL; /* sometimes already freed */ 183121495Sjmacd command_index = 0; 183221495Sjmacd in_menu = 0; 183321495Sjmacd in_detailmenu = 0; 183421495Sjmacd top_node_seen = 0; 183521495Sjmacd non_top_node_seen = 0; 183656164Sru node_number = -1; 183721495Sjmacd} 183821495Sjmacd 183921495Sjmacdvoid 1840146520Sruinit_paragraph (void) 184121495Sjmacd{ 1842146520Sru free (output_paragraph); 184356164Sru output_paragraph = xmalloc (paragraph_buffer_len); 184442664Smarkm output_paragraph[0] = 0; 184521495Sjmacd output_paragraph_offset = 0; 184621495Sjmacd output_column = 0; 184721495Sjmacd paragraph_is_open = 0; 184821495Sjmacd current_indent = 0; 184956164Sru meta_char_pos = 0; 185021495Sjmacd} 185156164Sru 185256164Sru/* This is called from `reader_loop' when we are at the * beginning a 185356164Sru menu line. */ 185421495Sjmacd 185556164Srustatic void 1856146520Sruhandle_menu_entry (void) 185721495Sjmacd{ 185856164Sru char *tem; 1859116530Sru 186056164Sru /* Ugh, glean_node_from_menu wants to read the * itself. */ 186156164Sru input_text_offset--; 1862116530Sru 186356164Sru /* Find node name in menu entry and save it in references list for 186456164Sru later validation. Use followed_reference type for detailmenu 186556164Sru references since we don't want to use them for default node pointers. */ 186656164Sru tem = glean_node_from_menu (1, in_detailmenu 186756164Sru ? followed_reference : menu_reference); 186821495Sjmacd 186956164Sru if (html && tem) 187056164Sru { /* Start a menu item with the cleaned-up line. Put an anchor 187156164Sru around the start text (before `:' or the node name). */ 187256164Sru char *string; 187321495Sjmacd 187456164Sru discard_until ("* "); 187521495Sjmacd 187656164Sru /* The line number was already incremented in reader_loop when we 187756164Sru saw the newline, and discard_until has now incremented again. */ 187856164Sru line_number--; 187921495Sjmacd 188056164Sru if (had_menu_commentary) 188142664Smarkm { 1882146520Sru add_html_block_elt ("<ul class=\"menu\">\n"); 188356164Sru had_menu_commentary = 0; 188456164Sru in_paragraph = 0; 188542664Smarkm } 1886116530Sru 188756164Sru if (in_paragraph) 188842664Smarkm { 1889146520Sru add_html_block_elt ("</p>\n"); 1890146520Sru add_html_block_elt ("<ul class=\"menu\">\n"); 189156164Sru in_paragraph = 0; 189242664Smarkm } 189321495Sjmacd 1894146520Sru in_menu_item = 1; 1895146520Sru 1896146520Sru add_html_block_elt ("<li><a"); 1897100516Sru if (next_menu_item_number <= 9) 1898114477Sru { 1899114477Sru add_word(" accesskey="); 1900114477Sru add_word_args("\"%d\"", next_menu_item_number); 1901114477Sru next_menu_item_number++; 1902114477Sru } 1903100516Sru add_word (" href=\""); 190456164Sru string = expansion (tem, 0); 190556164Sru add_anchor_name (string, 1); 190656164Sru add_word ("\">"); 190756164Sru free (string); 190821495Sjmacd 190956164Sru /* The menu item may use macros, so expand them now. */ 191056164Sru only_macro_expansion++; 191156164Sru get_until_in_line (1, ":", &string); 191256164Sru only_macro_expansion--; 191356164Sru execute_string ("%s", string); /* get escaping done */ 191456164Sru free (string); 191521495Sjmacd 191656164Sru add_word ("</a>"); 191721495Sjmacd 191856164Sru if (looking_at ("::")) 191956164Sru discard_until (":"); 192056164Sru else 192156164Sru { /* discard the node name */ 192256164Sru get_until_in_line (0, ".", &string); 192356164Sru free (string); 192442664Smarkm } 1925114477Sru input_text_offset++; /* discard the second colon or the period */ 1926146520Sru 1927146520Sru /* Insert a colon only if there is a description of this menu item. */ 1928146520Sru { 1929146520Sru int save_input_text_offset = input_text_offset; 1930146520Sru int save_line_number = line_number; 1931146520Sru char *test_string; 1932146520Sru get_rest_of_line (0, &test_string); 1933146520Sru if (strlen (test_string) > 0) 1934146520Sru add_word (": "); 1935146520Sru input_text_offset = save_input_text_offset; 1936146520Sru line_number = save_line_number; 1937146520Sru } 193821495Sjmacd } 193993142Sru else if (xml && tem) 1940116530Sru { 194193142Sru xml_start_menu_entry (tem); 194293142Sru } 194356164Sru else if (tem) 194456164Sru { /* For Info output, we can just use the input and the main case in 194556164Sru reader_loop where we output what comes in. Just move off the * 194656164Sru so the next time through reader_loop we don't end up back here. */ 194756164Sru add_char ('*'); 194856164Sru input_text_offset += 2; /* undo the pointer back-up above. */ 194956164Sru } 195056164Sru 195156164Sru if (tem) 195256164Sru free (tem); 195321495Sjmacd} 195456164Sru 195556164Sru/* Find the command corresponding to STRING. If the command is found, 195656164Sru return a pointer to the data structure. Otherwise return -1. */ 195756164Srustatic COMMAND * 1958146520Sruget_command_entry (char *string) 195921495Sjmacd{ 196056164Sru int i; 196121495Sjmacd 196242664Smarkm for (i = 0; command_table[i].name; i++) 196342664Smarkm if (strcmp (command_table[i].name, string) == 0) 196456164Sru return &command_table[i]; 196521495Sjmacd 196621495Sjmacd /* This command is not in our predefined command table. Perhaps 196721495Sjmacd it is a user defined command. */ 196821495Sjmacd for (i = 0; i < user_command_array_len; i++) 196921495Sjmacd if (user_command_array[i] && 197042664Smarkm (strcmp (user_command_array[i]->name, string) == 0)) 197156164Sru return user_command_array[i]; 197221495Sjmacd 197342664Smarkm /* We never heard of this command. */ 197456164Sru return (COMMAND *) -1; 197521495Sjmacd} 197656164Sru 197721495Sjmacd/* input_text_offset is right at the command prefix character. 197856164Sru Read the next token to determine what to do. Return zero 197956164Sru if there's no known command or macro after the prefix character. */ 198056164Srustatic int 1981146520Sruread_command (void) 198221495Sjmacd{ 198321495Sjmacd COMMAND *entry; 198456164Sru int old_text_offset = input_text_offset++; 198521495Sjmacd 198621495Sjmacd free_and_clear (&command); 198721495Sjmacd command = read_token (); 198821495Sjmacd 198921495Sjmacd /* Check to see if this command is a macro. If so, execute it here. */ 199021495Sjmacd { 199121495Sjmacd MACRO_DEF *def; 199221495Sjmacd 199321495Sjmacd def = find_macro (command); 199421495Sjmacd 199521495Sjmacd if (def) 199621495Sjmacd { 199742664Smarkm /* We disallow recursive use of a macro call. Inhibit the expansion 199842664Smarkm of this macro during the life of its execution. */ 199942664Smarkm if (!(def->flags & ME_RECURSE)) 200042664Smarkm def->inhibited = 1; 200121495Sjmacd 2002114477Sru executing_macro++; 200342664Smarkm execute_macro (def); 2004114477Sru executing_macro--; 200521495Sjmacd 200642664Smarkm if (!(def->flags & ME_RECURSE)) 200742664Smarkm def->inhibited = 0; 200821495Sjmacd 200956164Sru return 1; 201021495Sjmacd } 2011146520Sru } 201221495Sjmacd 201356164Sru if (only_macro_expansion) 201456164Sru { 201556164Sru /* Back up to the place where we were called, so the 201656164Sru caller will have a chance to process this non-macro. */ 201756164Sru input_text_offset = old_text_offset; 201856164Sru return 0; 201956164Sru } 202056164Sru 202156164Sru /* Perform alias expansion */ 202256164Sru command = alias_expand (command); 202356164Sru 202456164Sru if (enclosure_command (command)) 202556164Sru { 202656164Sru remember_brace (enclosure_expand); 202756164Sru enclosure_expand (START, output_paragraph_offset, 0); 202856164Sru return 0; 202956164Sru } 203056164Sru 203121495Sjmacd entry = get_command_entry (command); 203221495Sjmacd if (entry == (COMMAND *)-1) 203321495Sjmacd { 203442664Smarkm line_error (_("Unknown command `%s'"), command); 203556164Sru return 0; 203621495Sjmacd } 203721495Sjmacd 203856164Sru if (entry->argument_in_braces == BRACE_ARGS) 203921495Sjmacd remember_brace (entry->proc); 204056164Sru else if (entry->argument_in_braces == MAYBE_BRACE_ARGS) 204156164Sru { 204256164Sru if (curchar () == '{') 204356164Sru remember_brace (entry->proc); 204456164Sru else 204556164Sru { /* No braces, so arg is next char. */ 204656164Sru int ch; 204756164Sru int saved_offset = output_paragraph_offset; 204856164Sru (*(entry->proc)) (START, output_paragraph_offset, 0); 204921495Sjmacd 205056164Sru /* Possibilities left for the next character: @ (error), } 205156164Sru (error), whitespace (skip) anything else (normal char). */ 205256164Sru skip_whitespace (); 205356164Sru ch = curchar (); 205456164Sru if (ch == '@') 205556164Sru { 205656164Sru line_error (_("Use braces to give a command as an argument to @%s"), 205756164Sru entry->name); 205856164Sru return 0; 205956164Sru } 206056164Sru else if (ch == '}') 206156164Sru { 206256164Sru /* Our caller will give the error message, because this } 206356164Sru won't match anything. */ 206456164Sru return 0; 206556164Sru } 206656164Sru 206756164Sru add_char (ch); 206856164Sru input_text_offset++; 206956164Sru (*(entry->proc)) (END, saved_offset, output_paragraph_offset); 207056164Sru return 1; 207156164Sru } 207256164Sru } 207356164Sru 207456164Sru /* Get here if we have BRACE_ARGS, NO_BRACE_ARGS, or MAYBE_BRACE_ARGS 207556164Sru with braces. */ 207621495Sjmacd (*(entry->proc)) (START, output_paragraph_offset, 0); 207756164Sru return 1; 207821495Sjmacd} 207921495Sjmacd 208056164Sru/* Okay, we are ready to start the conversion. Call the reader on 208156164Sru some text, and fill the text as it is output. Handle commands by 208256164Sru remembering things like open braces and the current file position on a 208356164Sru stack, and when the corresponding close brace is found, you can call 208456164Sru the function with the proper arguments. Although the filling isn't 208556164Sru necessary for HTML, it should do no harm. */ 208656164Sruvoid 2087146520Srureader_loop (void) 208821495Sjmacd{ 208956164Sru int character; 209056164Sru int done = 0; 209121495Sjmacd 209256164Sru while (!done) 209356164Sru { 209456164Sru if (input_text_offset >= input_text_length) 209556164Sru break; 209656164Sru 209756164Sru character = curchar (); 209856164Sru 209956164Sru /* If only_macro_expansion, only handle macros and leave 210056164Sru everything else intact. */ 210156164Sru if (!only_macro_expansion && !in_fixed_width_font 2102146520Sru && ((!html && !xml) || escape_html) 210356164Sru && (character == '\'' || character == '`') 210456164Sru && input_text[input_text_offset + 1] == character) 210556164Sru { 2106146520Sru if (html) 2107146520Sru { 2108146520Sru input_text_offset += 2; 2109146520Sru add_word (character == '`' ? "“" : "”"); 2110146520Sru continue; 2111146520Sru } 2112146520Sru else if (xml) 2113146520Sru { 2114146520Sru input_text_offset += 2; 2115146520Sru xml_insert_entity (character == '`' ? "ldquo" : "rdquo"); 2116146520Sru continue; 2117146520Sru } 2118146520Sru else 2119146520Sru { 2120146520Sru input_text_offset++; 2121146520Sru character = '"'; 2122146520Sru } 212356164Sru } 212456164Sru 212556164Sru /* Convert --- to --. */ 2126146520Sru if (!only_macro_expansion && character == '-' && !in_fixed_width_font 2127146520Sru && ((!html && !xml) || escape_html)) 212856164Sru { 2129146520Sru int dash_count = 0; 2130146520Sru 2131146520Sru /* Get the number of consequtive dashes. */ 2132146520Sru while (input_text[input_text_offset] == '-') 213356164Sru { 2134146520Sru dash_count++; 213556164Sru input_text_offset++; 213656164Sru } 2137146520Sru 2138146520Sru /* Eat one dash. */ 2139146520Sru dash_count--; 2140146520Sru 2141146520Sru if (html || xml) 2142146520Sru { 2143146520Sru if (dash_count == 0) 2144146520Sru add_char ('-'); 2145146520Sru else 2146146520Sru while (dash_count > 0) 2147146520Sru { 2148146520Sru if (dash_count >= 2) 2149146520Sru { 2150146520Sru if (html) 2151146520Sru add_word ("—"); 2152146520Sru else 2153146520Sru xml_insert_entity ("mdash"); 2154146520Sru dash_count -= 2; 2155146520Sru } 2156146520Sru else if (dash_count >= 1) 2157146520Sru { 2158146520Sru if (html) 2159146520Sru add_word ("–"); 2160146520Sru else 2161146520Sru xml_insert_entity ("ndash"); 2162146520Sru dash_count--; 2163146520Sru } 2164146520Sru } 2165146520Sru } 2166146520Sru else 2167146520Sru { 2168146520Sru add_char ('-'); 2169146520Sru while (--dash_count > 0) 2170146520Sru add_char ('-'); 2171146520Sru } 2172146520Sru 2173146520Sru continue; 217456164Sru } 217556164Sru 217656164Sru /* If this is a whitespace character, then check to see if the line 217756164Sru is blank. If so, advance to the carriage return. */ 217856164Sru if (!only_macro_expansion && whitespace (character)) 217956164Sru { 218056164Sru int i = input_text_offset + 1; 218156164Sru 218256164Sru while (i < input_text_length && whitespace (input_text[i])) 218356164Sru i++; 218456164Sru 218556164Sru if (i == input_text_length || input_text[i] == '\n') 218656164Sru { 218756164Sru if (i == input_text_length) 218856164Sru i--; 218956164Sru 219056164Sru input_text_offset = i; 219156164Sru character = curchar (); 219256164Sru } 219356164Sru } 219456164Sru 219556164Sru if (character == '\n') 219656164Sru line_number++; 219756164Sru 219856164Sru switch (character) 219956164Sru { 220056164Sru case '*': /* perhaps we are at a menu */ 220156164Sru /* We used to check for this in the \n case but an @c in a 220256164Sru menu swallows its newline, so check here instead. */ 220356164Sru if (!only_macro_expansion && in_menu 220456164Sru && input_text_offset + 1 < input_text_length 220556164Sru && input_text[input_text_offset-1] == '\n') 220656164Sru handle_menu_entry (); 220756164Sru else 220856164Sru { /* Duplicate code from below, but not worth twisting the 220956164Sru fallthroughs to get down there. */ 221056164Sru add_char (character); 221156164Sru input_text_offset++; 221256164Sru } 221356164Sru break; 2214116530Sru 221556164Sru /* Escapes for HTML unless we're outputting raw HTML. Do 221656164Sru this always, even if SGML rules don't require it since 221756164Sru that's easier and safer for non-conforming browsers. */ 221856164Sru case '&': 221956164Sru if (html && escape_html) 222056164Sru add_word ("&"); 222156164Sru else 222256164Sru add_char (character); 222356164Sru input_text_offset++; 222456164Sru break; 222556164Sru 222656164Sru case '<': 222756164Sru if (html && escape_html) 222856164Sru add_word ("<"); 2229114477Sru else if (xml && escape_html) 2230114477Sru xml_insert_entity ("lt"); 223156164Sru else 223256164Sru add_char (character); 223356164Sru input_text_offset++; 223456164Sru break; 223556164Sru 223656164Sru case '>': 223756164Sru if (html && escape_html) 223856164Sru add_word (">"); 2239114477Sru else if (xml && escape_html) 2240114477Sru xml_insert_entity ("gt"); 224156164Sru else 224256164Sru add_char (character); 224356164Sru input_text_offset++; 224456164Sru break; 224556164Sru 224656164Sru case COMMAND_PREFIX: /* @ */ 224756164Sru if (read_command () || !only_macro_expansion) 224856164Sru break; 224956164Sru 225056164Sru /* FALLTHROUGH (usually) */ 225156164Sru case '{': 225256164Sru /* Special case. We're not supposed to see this character by itself. 225356164Sru If we do, it means there is a syntax error in the input text. 225456164Sru Report the error here, but remember this brace on the stack so 225556164Sru we can ignore its partner. */ 225656164Sru if (!only_macro_expansion) 225756164Sru { 2258114477Sru if (command && !STREQ (command, "math")) 225993142Sru { 226093142Sru line_error (_("Misplaced %c"), '{'); 226193142Sru remember_brace (misplaced_brace); 226293142Sru } 226393142Sru else 2264146520Sru /* We don't mind `extra' braces inside @math. */ 2265146520Sru remember_brace (cm_no_op); 226656164Sru /* remember_brace advances input_text_offset. */ 226756164Sru break; 226856164Sru } 226956164Sru 227056164Sru /* FALLTHROUGH (usually) */ 227156164Sru case '}': 227256164Sru if (!only_macro_expansion) 227356164Sru { 227456164Sru pop_and_call_brace (); 227556164Sru input_text_offset++; 227656164Sru break; 227756164Sru } 227856164Sru 227956164Sru /* FALLTHROUGH (usually) */ 228056164Sru default: 228156164Sru add_char (character); 228256164Sru input_text_offset++; 228356164Sru } 228456164Sru } 228556164Sru if (macro_expansion_output_stream && !only_macro_expansion) 228656164Sru maybe_write_itext (input_text, input_text_offset); 228721495Sjmacd} 228856164Sru 2289146520Srustatic void 2290146520Sruinit_brace_stack (void) 229121495Sjmacd{ 229256164Sru brace_stack = NULL; 229321495Sjmacd} 229421495Sjmacd 229521495Sjmacd/* Remember the current output position here. Save PROC 229621495Sjmacd along with it so you can call it later. */ 2297146520Srustatic void 2298146520Sruremember_brace_1 (COMMAND_FUNCTION (*proc), int position) 229921495Sjmacd{ 230056164Sru BRACE_ELEMENT *new = xmalloc (sizeof (BRACE_ELEMENT)); 230121495Sjmacd new->next = brace_stack; 230221495Sjmacd new->proc = proc; 230393142Sru new->command = command ? xstrdup (command) : ""; 230421495Sjmacd new->pos = position; 230521495Sjmacd new->line = line_number; 230621495Sjmacd new->in_fixed_width_font = in_fixed_width_font; 230721495Sjmacd brace_stack = new; 230821495Sjmacd} 230921495Sjmacd 2310146520Srustatic void 2311146520Sruremember_brace (COMMAND_FUNCTION (*proc)) 2312146520Sru{ 2313146520Sru if (curchar () != '{') 2314146520Sru line_error (_("%c%s expected braces"), COMMAND_PREFIX, command); 2315146520Sru else 2316146520Sru input_text_offset++; 2317146520Sru remember_brace_1 (proc, output_paragraph_offset); 2318146520Sru} 2319146520Sru 232021495Sjmacd/* Pop the top of the brace stack, and call the associated function 232121495Sjmacd with the args END and POS. */ 2322146520Srustatic void 2323146520Srupop_and_call_brace (void) 232421495Sjmacd{ 232556164Sru if (brace_stack == NULL) 232621495Sjmacd { 232742664Smarkm line_error (_("Unmatched }")); 232821495Sjmacd return; 232921495Sjmacd } 233021495Sjmacd 233156164Sru { 233256164Sru BRACE_ELEMENT *temp; 233321495Sjmacd 233456164Sru int pos = brace_stack->pos; 233556164Sru COMMAND_FUNCTION *proc = brace_stack->proc; 233656164Sru in_fixed_width_font = brace_stack->in_fixed_width_font; 233756164Sru 233856164Sru /* Reset current command, so the proc can know who it is. This is 233956164Sru used in cm_accent. */ 234056164Sru command = brace_stack->command; 234156164Sru 234256164Sru temp = brace_stack->next; 234356164Sru free (brace_stack); 234456164Sru brace_stack = temp; 234556164Sru 234656164Sru (*proc) (END, pos, output_paragraph_offset); 234756164Sru } 234821495Sjmacd} 234921495Sjmacd 235021495Sjmacd/* Shift all of the markers in `brace_stack' by AMOUNT. */ 2351146520Srustatic void 2352146520Sruadjust_braces_following (int here, int amount) 235321495Sjmacd{ 235456164Sru BRACE_ELEMENT *stack = brace_stack; 235521495Sjmacd 235621495Sjmacd while (stack) 235721495Sjmacd { 235821495Sjmacd if (stack->pos >= here) 235942664Smarkm stack->pos += amount; 236021495Sjmacd stack = stack->next; 236121495Sjmacd } 236221495Sjmacd} 236321495Sjmacd 236456164Sru/* Return the string which invokes PROC; a pointer to a function. 236556164Sru Always returns the first function in the command table if more than 236656164Sru one matches PROC. */ 2367116530Srustatic const char * 2368146520Srufind_proc_name (COMMAND_FUNCTION (*proc)) 236956164Sru{ 237056164Sru int i; 237156164Sru 237256164Sru for (i = 0; command_table[i].name; i++) 237356164Sru if (proc == command_table[i].proc) 237456164Sru return command_table[i].name; 237556164Sru return _("NO_NAME!"); 237656164Sru} 237756164Sru 237821495Sjmacd/* You call discard_braces () when you shouldn't have any braces on the stack. 237921495Sjmacd I used to think that this happens for commands that don't take arguments 238021495Sjmacd in braces, but that was wrong because of things like @code{foo @@}. So now 238121495Sjmacd I only detect it at the beginning of nodes. */ 238221495Sjmacdvoid 2383146520Srudiscard_braces (void) 238421495Sjmacd{ 238521495Sjmacd if (!brace_stack) 238621495Sjmacd return; 238721495Sjmacd 238821495Sjmacd while (brace_stack) 238921495Sjmacd { 239021495Sjmacd if (brace_stack->proc != misplaced_brace) 239142664Smarkm { 2392116530Sru const char *proc_name; 239321495Sjmacd 239442664Smarkm proc_name = find_proc_name (brace_stack->proc); 239593142Sru file_line_error (input_filename, brace_stack->line, 2396114477Sru _("%c%s missing close brace"), COMMAND_PREFIX, 2397114477Sru proc_name); 239842664Smarkm pop_and_call_brace (); 239942664Smarkm } 240021495Sjmacd else 240142664Smarkm { 240242664Smarkm BRACE_ELEMENT *temp; 240342664Smarkm temp = brace_stack->next; 240442664Smarkm free (brace_stack); 240542664Smarkm brace_stack = temp; 240642664Smarkm } 240721495Sjmacd } 240821495Sjmacd} 240921495Sjmacd 2410146520Srustatic int 2411146520Sruget_char_len (int character) 241221495Sjmacd{ 241321495Sjmacd /* Return the printed length of the character. */ 241421495Sjmacd int len; 241521495Sjmacd 241621495Sjmacd switch (character) 241721495Sjmacd { 241821495Sjmacd case '\t': 241921495Sjmacd len = (output_column + 8) & 0xf7; 242021495Sjmacd if (len > fill_column) 242142664Smarkm len = fill_column - output_column; 242221495Sjmacd else 242342664Smarkm len = len - output_column; 242421495Sjmacd break; 242521495Sjmacd 242621495Sjmacd case '\n': 242721495Sjmacd len = fill_column - output_column; 242821495Sjmacd break; 242921495Sjmacd 243021495Sjmacd default: 243142664Smarkm /* ASCII control characters appear as two characters in the output 243242664Smarkm (e.g., ^A). But characters with the high bit set are just one 243342664Smarkm on suitable terminals, so don't count them as two for line 243442664Smarkm breaking purposes. */ 243542664Smarkm if (0 <= character && character < ' ') 243642664Smarkm len = 2; 243721495Sjmacd else 243842664Smarkm len = 1; 243921495Sjmacd } 244056164Sru return len; 244121495Sjmacd} 244256164Sru 244321495Sjmacdvoid 244442664Smarkm#if defined (VA_FPRINTF) && __STDC__ 2445116530Sruadd_word_args (const char *format, ...) 244642664Smarkm#else 244742664Smarkmadd_word_args (format, va_alist) 2448116530Sru const char *format; 244942664Smarkm va_dcl 245042664Smarkm#endif 245121495Sjmacd{ 245256164Sru char buffer[2000]; /* xx no fixed limits */ 245342664Smarkm#ifdef VA_FPRINTF 245442664Smarkm va_list ap; 245542664Smarkm#endif 245621495Sjmacd 245742664Smarkm VA_START (ap, format); 245842664Smarkm#ifdef VA_SPRINTF 245942664Smarkm VA_SPRINTF (buffer, format, ap); 246042664Smarkm#else 246156164Sru sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8); 246242664Smarkm#endif /* not VA_SPRINTF */ 246342664Smarkm va_end (ap); 246421495Sjmacd add_word (buffer); 246521495Sjmacd} 246621495Sjmacd 246721495Sjmacd/* Add STRING to output_paragraph. */ 246821495Sjmacdvoid 2469146520Sruadd_word (char *string) 247021495Sjmacd{ 247121495Sjmacd while (*string) 247221495Sjmacd add_char (*string++); 247321495Sjmacd} 247421495Sjmacd 247593142Sru/* Like add_word, but inhibits conversion of whitespace into . 247693142Sru Use this to output HTML directives with embedded blanks, to make 247793142Sru them @w-safe. */ 247893142Sruvoid 2479146520Sruadd_html_elt (char *string) 248093142Sru{ 248193142Sru in_html_elt++; 248293142Sru add_word (string); 248393142Sru in_html_elt--; 248493142Sru} 248593142Sru 2486146520Sru/* These two functions below, add_html_block_elt and add_html_block_elt_args, 2487146520Sru are mixtures of add_html_elt and add_word_args. They inform makeinfo that 2488146520Sru the current HTML element being inserted should not be enclosed in a <p> 2489146520Sru element. */ 2490146520Sruvoid 2491146520Sruadd_html_block_elt (char *string) 2492146520Sru{ 2493146520Sru in_html_block_level_elt++; 2494146520Sru add_word (string); 2495146520Sru in_html_block_level_elt--; 2496146520Sru} 2497146520Sru 2498146520Sruvoid 2499146520Sru#if defined (VA_FPRINTF) && __STDC__ 2500146520Sruadd_html_block_elt_args (const char *format, ...) 2501146520Sru#else 2502146520Sruadd_html_block_elt_args (format, va_alist) 2503146520Sru const char *format; 2504146520Sru va_dcl 2505146520Sru#endif 2506146520Sru{ 2507146520Sru char buffer[2000]; /* xx no fixed limits */ 2508146520Sru#ifdef VA_FPRINTF 2509146520Sru va_list ap; 2510146520Sru#endif 2511146520Sru 2512146520Sru VA_START (ap, format); 2513146520Sru#ifdef VA_SPRINTF 2514146520Sru VA_SPRINTF (buffer, format, ap); 2515146520Sru#else 2516146520Sru sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8); 2517146520Sru#endif /* not VA_SPRINTF */ 2518146520Sru va_end (ap); 2519146520Sru add_html_block_elt (buffer); 2520146520Sru} 2521146520Sru 2522116530Sru/* Here is another awful kludge, used in add_char. Ordinarily, macro 2523116530Sru expansions take place in the body of the document, and therefore we 2524116530Sru should html_output_head when we see one. But there's an exception: a 2525116530Sru macro call might take place within @copying, and that does not start 2526116530Sru the real output, even though we fully expand the copying text. 2527116530Sru 2528116530Sru So we need to be able to check if we are defining the @copying text. 2529116530Sru We do this by looking back through the insertion stack. */ 2530116530Srustatic int 2531146520Srudefining_copying (void) 2532116530Sru{ 2533116530Sru INSERTION_ELT *i; 2534116530Sru for (i = insertion_stack; i; i = i->next) 2535116530Sru { 2536116530Sru if (i->insertion == copying) 2537116530Sru return 1; 2538116530Sru } 2539116530Sru return 0; 2540116530Sru} 2541116530Sru 2542116530Sru 254321495Sjmacd/* Add the character to the current paragraph. If filling_enabled is 254442664Smarkm nonzero, then do filling as well. */ 254521495Sjmacdvoid 2546146520Sruadd_char (int character) 254721495Sjmacd{ 254893142Sru if (xml) 254993142Sru { 255093142Sru xml_add_char (character); 255193142Sru return; 255293142Sru } 255393142Sru 255421495Sjmacd /* If we are avoiding outputting headers, and we are currently 255556164Sru in a menu, then simply return. But if we're only expanding macros, 255656164Sru then we're being called from glean_node_from_menu to try to 255756164Sru remember a menu reference, and we need that so we can do defaulting. */ 255856164Sru if (no_headers && !only_macro_expansion && (in_menu || in_detailmenu)) 255921495Sjmacd return; 256021495Sjmacd 256121495Sjmacd /* If we are adding a character now, then we don't have to 256221495Sjmacd ignore close_paragraph () calls any more. */ 256321495Sjmacd if (must_start_paragraph && character != '\n') 256421495Sjmacd { 256521495Sjmacd must_start_paragraph = 0; 256642664Smarkm line_already_broken = 0; /* The line is no longer broken. */ 256721495Sjmacd if (current_indent > output_column) 256842664Smarkm { 256942664Smarkm indent (current_indent - output_column); 257042664Smarkm output_column = current_indent; 257142664Smarkm } 257221495Sjmacd } 257321495Sjmacd 257493142Sru if (non_splitting_words 257593142Sru && !(html && in_html_elt) 257693142Sru && strchr (" \t\n", character)) 257756164Sru { 257893142Sru if (html || docbook) 257956164Sru { /* Seems cleaner to use than an 8-bit char. */ 2580116530Sru int saved_escape_html = escape_html; 2581116530Sru escape_html = 0; 258256164Sru add_word (" "); 2583116530Sru escape_html = saved_escape_html; 258456164Sru character = ';'; 258556164Sru } 258656164Sru else 258756164Sru character = META (' '); /* unmeta-d in flush_output */ 258856164Sru } 258921495Sjmacd 259021495Sjmacd insertion_paragraph_closed = 0; 259121495Sjmacd 259221495Sjmacd switch (character) 259321495Sjmacd { 259421495Sjmacd case '\n': 2595114477Sru if (!filling_enabled && !(html && (in_menu || in_detailmenu))) 259642664Smarkm { 259742664Smarkm insert ('\n'); 259821495Sjmacd 259942664Smarkm if (force_flush_right) 260042664Smarkm { 260142664Smarkm close_paragraph (); 260242664Smarkm /* Hack to force single blank lines out in this mode. */ 260342664Smarkm flush_output (); 260442664Smarkm } 260521495Sjmacd 260642664Smarkm output_column = 0; 260721495Sjmacd 260842664Smarkm if (!no_indent && paragraph_is_open) 260942664Smarkm indent (output_column = current_indent); 261042664Smarkm break; 261142664Smarkm } 261256164Sru else if (end_of_sentence_p ()) 261356164Sru /* CHARACTER is newline, and filling is enabled. */ 261442664Smarkm { 261556164Sru insert (' '); 261656164Sru output_column++; 261756164Sru last_inserted_character = character; 261842664Smarkm } 261921495Sjmacd 262021495Sjmacd if (last_char_was_newline) 262142664Smarkm { 262256164Sru if (html) 262356164Sru last_char_was_newline++; 262442664Smarkm close_paragraph (); 262542664Smarkm pending_indent = 0; 262642664Smarkm } 262721495Sjmacd else 262842664Smarkm { 262942664Smarkm last_char_was_newline = 1; 263056164Sru if (html) 263156164Sru insert ('\n'); 263256164Sru else 263356164Sru insert (' '); 263442664Smarkm output_column++; 263542664Smarkm } 263621495Sjmacd break; 263721495Sjmacd 263856164Sru default: /* not at newline */ 263921495Sjmacd { 264042664Smarkm int len = get_char_len (character); 264142664Smarkm int suppress_insert = 0; 264221495Sjmacd 264342664Smarkm if ((character == ' ') && (last_char_was_newline)) 264442664Smarkm { 264542664Smarkm if (!paragraph_is_open) 264642664Smarkm { 264742664Smarkm pending_indent++; 264842664Smarkm return; 264942664Smarkm } 265042664Smarkm } 265121495Sjmacd 2652114477Sru /* This is sad, but it seems desirable to not force any 2653114477Sru particular order on the front matter commands. This way, 2654114477Sru the document can do @settitle, @documentlanguage, etc, in 2655114477Sru any order and with any omissions, and we'll still output 2656114477Sru the html <head> `just in time'. */ 2657114477Sru if ((executing_macro || !executing_string) 2658146520Sru && !only_macro_expansion 2659116530Sru && html && !html_output_head_p && !defining_copying ()) 2660114477Sru html_output_head (); 266193142Sru 266242664Smarkm if (!paragraph_is_open) 266342664Smarkm { 266442664Smarkm start_paragraph (); 266556164Sru /* If the paragraph is supposed to be indented a certain 266656164Sru way, then discard all of the pending whitespace. 266756164Sru Otherwise, we let the whitespace stay. */ 266842664Smarkm if (!paragraph_start_indent) 266942664Smarkm indent (pending_indent); 267042664Smarkm pending_indent = 0; 267156164Sru 2672146520Sru /* This check for in_html_block_level_elt prevents <p> from being 2673146520Sru inserted when we already have html markup starting a paragraph, 2674146520Sru as with <ul> and <h1> and the like. */ 2675146520Sru if (html && !in_html_block_level_elt) 267656164Sru { 2677146520Sru if ((in_menu || in_detailmenu) && in_menu_item) 2678146520Sru { 2679146520Sru insert_string ("</li></ul>\n"); 2680146520Sru in_menu_item = 0; 2681146520Sru } 268256164Sru insert_string ("<p>"); 268356164Sru in_paragraph = 1; 268456164Sru adjust_braces_following (0, 3); /* adjust for <p> */ 268556164Sru } 268642664Smarkm } 268721495Sjmacd 268856164Sru output_column += len; 268956164Sru if (output_column > fill_column) 269042664Smarkm { 269156164Sru if (filling_enabled && !html) 269242664Smarkm { 269342664Smarkm int temp = output_paragraph_offset; 269442664Smarkm while (--temp > 0 && output_paragraph[temp] != '\n') 269542664Smarkm { 269642664Smarkm /* If we have found a space, we have the place to break 269742664Smarkm the line. */ 269842664Smarkm if (output_paragraph[temp] == ' ') 269942664Smarkm { 270042664Smarkm /* Remove trailing whitespace from output. */ 270142664Smarkm while (temp && whitespace (output_paragraph[temp - 1])) 270242664Smarkm temp--; 270321495Sjmacd 270456164Sru /* If we went back all the way to the newline of the 270556164Sru preceding line, it probably means that the word we 270656164Sru are adding is itself wider than the space that the 270756164Sru indentation and the fill_column let us use. In 270856164Sru that case, do NOT insert another newline, since it 270956164Sru won't help. Just indent to current_indent and 271056164Sru leave it alone, since that's the most we can do. */ 271156164Sru if (temp && output_paragraph[temp - 1] != '\n') 271256164Sru output_paragraph[temp++] = '\n'; 271321495Sjmacd 271442664Smarkm /* We have correctly broken the line where we want 271542664Smarkm to. What we don't want is spaces following where 271642664Smarkm we have decided to break the line. We get rid of 271742664Smarkm them. */ 271842664Smarkm { 271942664Smarkm int t1 = temp; 272021495Sjmacd 272142664Smarkm for (;; t1++) 272242664Smarkm { 272342664Smarkm if (t1 == output_paragraph_offset) 272442664Smarkm { 272542664Smarkm if (whitespace (character)) 272642664Smarkm suppress_insert = 1; 272742664Smarkm break; 272842664Smarkm } 272942664Smarkm if (!whitespace (output_paragraph[t1])) 273042664Smarkm break; 273142664Smarkm } 273221495Sjmacd 273342664Smarkm if (t1 != temp) 273442664Smarkm { 273542664Smarkm adjust_braces_following (temp, (- (t1 - temp))); 2736146520Sru memmove (&output_paragraph[temp], 2737146520Sru &output_paragraph[t1], 2738146520Sru output_paragraph_offset - t1); 273942664Smarkm output_paragraph_offset -= (t1 - temp); 274042664Smarkm } 274142664Smarkm } 274221495Sjmacd 274342664Smarkm /* Filled, but now indent if that is right. */ 274456164Sru if (indented_fill && current_indent > 0) 274542664Smarkm { 274642664Smarkm int buffer_len = ((output_paragraph_offset - temp) 274742664Smarkm + current_indent); 274856164Sru char *temp_buffer = xmalloc (buffer_len); 274942664Smarkm int indentation = 0; 275021495Sjmacd 275142664Smarkm /* We have to shift any markers that are in 275242664Smarkm front of the wrap point. */ 275342664Smarkm adjust_braces_following (temp, current_indent); 275421495Sjmacd 275542664Smarkm while (current_indent > 0 && 275642664Smarkm indentation != current_indent) 275742664Smarkm temp_buffer[indentation++] = ' '; 275821495Sjmacd 275956164Sru memcpy ((char *) &temp_buffer[current_indent], 276042664Smarkm (char *) &output_paragraph[temp], 276142664Smarkm buffer_len - current_indent); 276221495Sjmacd 276342664Smarkm if (output_paragraph_offset + buffer_len 276442664Smarkm >= paragraph_buffer_len) 276542664Smarkm { 276642664Smarkm unsigned char *tt = xrealloc 276742664Smarkm (output_paragraph, 276842664Smarkm (paragraph_buffer_len += buffer_len)); 276942664Smarkm output_paragraph = tt; 277042664Smarkm } 277156164Sru memcpy ((char *) &output_paragraph[temp], 277242664Smarkm temp_buffer, buffer_len); 277342664Smarkm output_paragraph_offset += current_indent; 277442664Smarkm free (temp_buffer); 277542664Smarkm } 277642664Smarkm output_column = 0; 277742664Smarkm while (temp < output_paragraph_offset) 277842664Smarkm output_column += 277942664Smarkm get_char_len (output_paragraph[temp++]); 278042664Smarkm output_column += len; 278142664Smarkm break; 278242664Smarkm } 278342664Smarkm } 278442664Smarkm } 278542664Smarkm } 278621495Sjmacd 278742664Smarkm if (!suppress_insert) 278842664Smarkm { 278942664Smarkm insert (character); 279042664Smarkm last_inserted_character = character; 279142664Smarkm } 279242664Smarkm last_char_was_newline = 0; 279342664Smarkm line_already_broken = 0; 279421495Sjmacd } 279521495Sjmacd } 279621495Sjmacd} 279721495Sjmacd 279856164Sru/* Add a character and store its position in meta_char_pos. */ 279956164Sruvoid 2800146520Sruadd_meta_char (int character) 280156164Sru{ 280256164Sru meta_char_pos = output_paragraph_offset; 280356164Sru add_char (character); 280456164Sru} 280556164Sru 280621495Sjmacd/* Insert CHARACTER into `output_paragraph'. */ 280721495Sjmacdvoid 2808146520Sruinsert (int character) 280921495Sjmacd{ 2810146520Sru /* We don't want to strip trailing whitespace in multitables. Otherwise 2811146520Sru horizontal separators confuse the font locking in Info mode in Emacs, 2812146520Sru because it looks like a @subsection. Adding a trailing space to those 2813146520Sru lines fixes it. */ 2814146520Sru if (character == '\n' && !html && !xml && !multitable_active) 2815146520Sru { 2816146520Sru while (output_paragraph_offset 2817146520Sru && whitespace (output_paragraph[output_paragraph_offset-1])) 2818146520Sru output_paragraph_offset--; 2819146520Sru } 2820146520Sru 282121495Sjmacd output_paragraph[output_paragraph_offset++] = character; 282221495Sjmacd if (output_paragraph_offset == paragraph_buffer_len) 282321495Sjmacd { 282421495Sjmacd output_paragraph = 282542664Smarkm xrealloc (output_paragraph, (paragraph_buffer_len += 100)); 282621495Sjmacd } 282721495Sjmacd} 282821495Sjmacd 282921495Sjmacd/* Insert the null-terminated string STRING into `output_paragraph'. */ 283021495Sjmacdvoid 2831146520Sruinsert_string (const char *string) 283221495Sjmacd{ 283321495Sjmacd while (*string) 283421495Sjmacd insert (*string++); 283521495Sjmacd} 283621495Sjmacd 283742664Smarkm 283842664Smarkm/* Sentences might have these characters after the period (or whatever). */ 283956164Sru#define POST_SENTENCE(c) ((c) == ')' || (c) == '\'' || (c) == '"' \ 284042664Smarkm || (c) == ']') 284142664Smarkm 284242664Smarkm/* Return true if at an end-of-sentence character, possibly followed by 284342664Smarkm post-sentence punctuation to ignore. */ 284442664Smarkmstatic int 2845146520Sruend_of_sentence_p (void) 284642664Smarkm{ 284742664Smarkm int loc = output_paragraph_offset - 1; 284856164Sru 284956164Sru /* If nothing has been output, don't check output_paragraph[-1]. */ 285056164Sru if (loc < 0) 285156164Sru return 0; 285256164Sru 285356164Sru /* A post-sentence character that is at meta_char_pos is not really 285456164Sru a post-sentence character; it was produced by a markup such as 285556164Sru @samp. We don't want the period inside @samp to be treated as a 285656164Sru sentence ender. */ 285756164Sru while (loc > 0 285856164Sru && loc != meta_char_pos && POST_SENTENCE (output_paragraph[loc])) 285942664Smarkm loc--; 286056164Sru return loc != meta_char_pos && sentence_ender (output_paragraph[loc]); 286142664Smarkm} 286242664Smarkm 286342664Smarkm 286421495Sjmacd/* Remove upto COUNT characters of whitespace from the 286521495Sjmacd the current output line. If COUNT is less than zero, 286621495Sjmacd then remove until none left. */ 286721495Sjmacdvoid 2868146520Srukill_self_indent (int count) 286921495Sjmacd{ 287021495Sjmacd /* Handle infinite case first. */ 287121495Sjmacd if (count < 0) 287221495Sjmacd { 287321495Sjmacd output_column = 0; 287421495Sjmacd while (output_paragraph_offset) 287542664Smarkm { 287642664Smarkm if (whitespace (output_paragraph[output_paragraph_offset - 1])) 287742664Smarkm output_paragraph_offset--; 287842664Smarkm else 287942664Smarkm break; 288042664Smarkm } 288121495Sjmacd } 288221495Sjmacd else 288321495Sjmacd { 288421495Sjmacd while (output_paragraph_offset && count--) 288542664Smarkm if (whitespace (output_paragraph[output_paragraph_offset - 1])) 288642664Smarkm output_paragraph_offset--; 288742664Smarkm else 288842664Smarkm break; 288921495Sjmacd } 289021495Sjmacd} 289121495Sjmacd 289242664Smarkm/* Nonzero means do not honor calls to flush_output (). */ 289321495Sjmacdstatic int flushing_ignored = 0; 289421495Sjmacd 289521495Sjmacd/* Prevent calls to flush_output () from having any effect. */ 289621495Sjmacdvoid 2897146520Sruinhibit_output_flushing (void) 289821495Sjmacd{ 289921495Sjmacd flushing_ignored++; 290021495Sjmacd} 290121495Sjmacd 290221495Sjmacd/* Allow calls to flush_output () to write the paragraph data. */ 290321495Sjmacdvoid 2904146520Sruuninhibit_output_flushing (void) 290521495Sjmacd{ 290621495Sjmacd flushing_ignored--; 290721495Sjmacd} 290821495Sjmacd 290921495Sjmacdvoid 2910146520Sruflush_output (void) 291121495Sjmacd{ 291256164Sru int i; 291321495Sjmacd 291421495Sjmacd if (!output_paragraph_offset || flushing_ignored) 291521495Sjmacd return; 291621495Sjmacd 291721495Sjmacd for (i = 0; i < output_paragraph_offset; i++) 291821495Sjmacd { 2919146520Sru if (output_paragraph[i] == '\n') 2920146520Sru { 2921146520Sru output_line_number++; 2922146520Sru node_line_number++; 2923146520Sru } 2924146520Sru 292556164Sru /* If we turned on the 8th bit for a space inside @w, turn it 292656164Sru back off for output. This might be problematic, since the 292756164Sru 0x80 character may be used in 8-bit character sets. Sigh. 292856164Sru In any case, don't do this for HTML, since the nbsp character 292956164Sru is valid input and must be passed along to the browser. */ 293056164Sru if (!html && (output_paragraph[i] & meta_character_bit)) 293121495Sjmacd { 293221495Sjmacd int temp = UNMETA (output_paragraph[i]); 293321495Sjmacd if (temp == ' ') 293442664Smarkm output_paragraph[i] &= 0x7f; 293521495Sjmacd } 293621495Sjmacd } 293721495Sjmacd 293821495Sjmacd fwrite (output_paragraph, 1, output_paragraph_offset, output_stream); 293921495Sjmacd 294021495Sjmacd output_position += output_paragraph_offset; 294121495Sjmacd output_paragraph_offset = 0; 294256164Sru meta_char_pos = 0; 294321495Sjmacd} 294421495Sjmacd 294521495Sjmacd/* How to close a paragraph controlling the number of lines between 294621495Sjmacd this one and the last one. */ 294721495Sjmacd 294821495Sjmacd/* Paragraph spacing is controlled by this variable. It is the number of 294921495Sjmacd blank lines that you wish to appear between paragraphs. A value of 295021495Sjmacd 1 creates a single blank line between paragraphs. */ 295121495Sjmacdint paragraph_spacing = DEFAULT_PARAGRAPH_SPACING; 295221495Sjmacd 295356164Srustatic void 2954146520Sruclose_paragraph_with_lines (int lines) 295556164Sru{ 295656164Sru int old_spacing = paragraph_spacing; 295756164Sru paragraph_spacing = lines; 295856164Sru close_paragraph (); 295956164Sru paragraph_spacing = old_spacing; 296056164Sru} 296156164Sru 296221495Sjmacd/* Close the current paragraph, leaving no blank lines between them. */ 296321495Sjmacdvoid 2964146520Sruclose_single_paragraph (void) 296521495Sjmacd{ 296621495Sjmacd close_paragraph_with_lines (0); 296721495Sjmacd} 296821495Sjmacd 296921495Sjmacd/* Close a paragraph after an insertion has ended. */ 297021495Sjmacdvoid 2971146520Sruclose_insertion_paragraph (void) 297221495Sjmacd{ 297321495Sjmacd if (!insertion_paragraph_closed) 297421495Sjmacd { 297521495Sjmacd /* Close the current paragraph, breaking the line. */ 297621495Sjmacd close_single_paragraph (); 297721495Sjmacd 297842664Smarkm /* Start a new paragraph, with the correct indentation for the now 297942664Smarkm current insertion level (one above the one that we are ending). */ 298021495Sjmacd start_paragraph (); 298121495Sjmacd 298242664Smarkm /* Tell `close_paragraph' that the previous line has already been 298342664Smarkm broken, so it should insert one less newline. */ 298421495Sjmacd line_already_broken = 1; 298521495Sjmacd 298642664Smarkm /* Tell functions such as `add_char' we've already found a newline. */ 298721495Sjmacd ignore_blank_line (); 298821495Sjmacd } 298921495Sjmacd else 299021495Sjmacd { 299121495Sjmacd /* If the insertion paragraph is closed already, then we are seeing 299242664Smarkm two `@end' commands in a row. Note that the first one we saw was 299342664Smarkm handled in the first part of this if-then-else clause, and at that 299442664Smarkm time `start_paragraph' was called, partially to handle the proper 299542664Smarkm indentation of the current line. However, the indentation level 299642664Smarkm may have just changed again, so we may have to outdent the current 299742664Smarkm line to the new indentation level. */ 299821495Sjmacd if (current_indent < output_column) 299942664Smarkm kill_self_indent (output_column - current_indent); 300021495Sjmacd } 300121495Sjmacd 300221495Sjmacd insertion_paragraph_closed = 1; 300321495Sjmacd} 300421495Sjmacd 300521495Sjmacd/* Close the currently open paragraph. */ 300621495Sjmacdvoid 3007146520Sruclose_paragraph (void) 300821495Sjmacd{ 300956164Sru int i; 301021495Sjmacd 3011146520Sru /* We don't need these newlines in XML and Docbook outputs for 3012146520Sru paragraph seperation. We have <para> element for that. */ 3013146520Sru if (xml) 3014146520Sru return; 3015146520Sru 301621495Sjmacd /* The insertion paragraph is no longer closed. */ 301721495Sjmacd insertion_paragraph_closed = 0; 301821495Sjmacd 301921495Sjmacd if (paragraph_is_open && !must_start_paragraph) 302021495Sjmacd { 3021146520Sru int tindex = output_paragraph_offset; 302221495Sjmacd 302321495Sjmacd /* Back up to last non-newline/space character, forcing all such 302442664Smarkm subsequent characters to be newlines. This isn't strictly 302542664Smarkm necessary, but a couple of functions use the presence of a newline 302642664Smarkm to make decisions. */ 302721495Sjmacd for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex) 302842664Smarkm { 3029146520Sru int c = output_paragraph[tindex]; 303021495Sjmacd 303142664Smarkm if (c == ' '|| c == '\n') 303242664Smarkm output_paragraph[tindex] = '\n'; 303342664Smarkm else 303442664Smarkm break; 303542664Smarkm } 303621495Sjmacd 303721495Sjmacd /* All trailing whitespace is ignored. */ 303821495Sjmacd output_paragraph_offset = ++tindex; 303921495Sjmacd 304021495Sjmacd /* Break the line if that is appropriate. */ 304121495Sjmacd if (paragraph_spacing >= 0) 304242664Smarkm insert ('\n'); 304321495Sjmacd 304442664Smarkm /* Add as many blank lines as is specified in `paragraph_spacing'. */ 304521495Sjmacd if (!force_flush_right) 304642664Smarkm { 304742664Smarkm for (i = 0; i < (paragraph_spacing - line_already_broken); i++) 304856164Sru { 304956164Sru insert ('\n'); 305056164Sru /* Don't need anything extra for HTML in usual case of no 305156164Sru extra paragraph spacing. */ 305256164Sru if (html && i > 0) 305356164Sru insert_string ("<br>"); 305456164Sru } 305542664Smarkm } 305621495Sjmacd 305721495Sjmacd /* If we are doing flush right indentation, then do it now 305842664Smarkm on the paragraph (really a single line). */ 305921495Sjmacd if (force_flush_right) 306042664Smarkm do_flush_right_indentation (); 306121495Sjmacd 306221495Sjmacd flush_output (); 306321495Sjmacd paragraph_is_open = 0; 306421495Sjmacd no_indent = 0; 306521495Sjmacd output_column = 0; 306621495Sjmacd } 306756164Sru 306821495Sjmacd ignore_blank_line (); 306921495Sjmacd} 307021495Sjmacd 307121495Sjmacd/* Make the last line just read look as if it were only a newline. */ 307221495Sjmacdvoid 3073146520Sruignore_blank_line (void) 307421495Sjmacd{ 307521495Sjmacd last_inserted_character = '\n'; 307621495Sjmacd last_char_was_newline = 1; 307721495Sjmacd} 307821495Sjmacd 307921495Sjmacd/* Align the end of the text in output_paragraph with fill_column. */ 3080146520Srustatic void 3081146520Srudo_flush_right_indentation (void) 308221495Sjmacd{ 308321495Sjmacd char *temp; 308421495Sjmacd int temp_len; 308521495Sjmacd 308621495Sjmacd kill_self_indent (-1); 308721495Sjmacd 308821495Sjmacd if (output_paragraph[0] != '\n') 308921495Sjmacd { 309042664Smarkm output_paragraph[output_paragraph_offset] = 0; 309121495Sjmacd 309221495Sjmacd if (output_paragraph_offset < fill_column) 309342664Smarkm { 309456164Sru int i; 309521495Sjmacd 309642664Smarkm if (fill_column >= paragraph_buffer_len) 309742664Smarkm output_paragraph = 309842664Smarkm xrealloc (output_paragraph, 309942664Smarkm (paragraph_buffer_len += fill_column)); 310021495Sjmacd 310142664Smarkm temp_len = strlen ((char *)output_paragraph); 310256164Sru temp = xmalloc (temp_len + 1); 310342664Smarkm memcpy (temp, (char *)output_paragraph, temp_len); 310421495Sjmacd 310542664Smarkm for (i = 0; i < fill_column - output_paragraph_offset; i++) 310642664Smarkm output_paragraph[i] = ' '; 310721495Sjmacd 310842664Smarkm memcpy ((char *)output_paragraph + i, temp, temp_len); 310942664Smarkm free (temp); 311042664Smarkm output_paragraph_offset = fill_column; 311156164Sru adjust_braces_following (0, i); 311242664Smarkm } 311321495Sjmacd } 311421495Sjmacd} 311521495Sjmacd 311621495Sjmacd/* Begin a new paragraph. */ 311721495Sjmacdvoid 3118146520Srustart_paragraph (void) 311921495Sjmacd{ 312021495Sjmacd /* First close existing one. */ 312121495Sjmacd if (paragraph_is_open) 312221495Sjmacd close_paragraph (); 312321495Sjmacd 312421495Sjmacd /* In either case, the insertion paragraph is no longer closed. */ 312521495Sjmacd insertion_paragraph_closed = 0; 312621495Sjmacd 312721495Sjmacd /* However, the paragraph is open! */ 312821495Sjmacd paragraph_is_open = 1; 312921495Sjmacd 313021495Sjmacd /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph () 313121495Sjmacd had to be called before we would allow any other paragraph operations 313221495Sjmacd to have an effect. */ 313321495Sjmacd if (!must_start_paragraph) 313421495Sjmacd { 313521495Sjmacd int amount_to_indent = 0; 313621495Sjmacd 313721495Sjmacd /* If doing indentation, then insert the appropriate amount. */ 313821495Sjmacd if (!no_indent) 313942664Smarkm { 314042664Smarkm if (inhibit_paragraph_indentation) 314142664Smarkm { 314242664Smarkm amount_to_indent = current_indent; 314342664Smarkm if (inhibit_paragraph_indentation < 0) 314442664Smarkm inhibit_paragraph_indentation++; 314542664Smarkm } 314642664Smarkm else if (paragraph_start_indent < 0) 314742664Smarkm amount_to_indent = current_indent; 314842664Smarkm else 314942664Smarkm amount_to_indent = current_indent + paragraph_start_indent; 315021495Sjmacd 315142664Smarkm if (amount_to_indent >= output_column) 315242664Smarkm { 315342664Smarkm amount_to_indent -= output_column; 315442664Smarkm indent (amount_to_indent); 315542664Smarkm output_column += amount_to_indent; 315642664Smarkm } 315742664Smarkm } 315821495Sjmacd } 315921495Sjmacd else 316021495Sjmacd must_start_paragraph = 0; 316121495Sjmacd} 316221495Sjmacd 316321495Sjmacd/* Insert the indentation specified by AMOUNT. */ 316421495Sjmacdvoid 3165146520Sruindent (int amount) 316621495Sjmacd{ 316721495Sjmacd /* For every START_POS saved within the brace stack which will be affected 316821495Sjmacd by this indentation, bump that start pos forward. */ 316956164Sru adjust_braces_following (output_paragraph_offset, amount); 317021495Sjmacd 317121495Sjmacd while (--amount >= 0) 317221495Sjmacd insert (' '); 317321495Sjmacd} 317421495Sjmacd 317521495Sjmacd/* Search forward for STRING in input_text. 317621495Sjmacd FROM says where where to start. */ 317721495Sjmacdint 3178146520Srusearch_forward (char *string, int from) 317921495Sjmacd{ 318021495Sjmacd int len = strlen (string); 318121495Sjmacd 318256164Sru while (from < input_text_length) 318321495Sjmacd { 318421495Sjmacd if (strncmp (input_text + from, string, len) == 0) 318556164Sru return from; 318621495Sjmacd from++; 318721495Sjmacd } 318856164Sru return -1; 318921495Sjmacd} 319021495Sjmacd 3191146520Sru/* search_forward until n characters. */ 3192146520Sruint 3193146520Srusearch_forward_until_pos (char *string, int from, int end_pos) 319421495Sjmacd{ 3195146520Sru int save_input_text_length = input_text_length; 3196146520Sru input_text_length = end_pos; 319721495Sjmacd 3198146520Sru from = search_forward (string, from); 3199114477Sru 3200146520Sru input_text_length = save_input_text_length; 320121495Sjmacd 3202146520Sru return from; 320321495Sjmacd} 320421495Sjmacd 3205146520Sru/* Return next non-whitespace and non-cr character. */ 3206146520Sruint 3207146520Srunext_nonwhitespace_character (void) 320821495Sjmacd{ 3209146520Sru /* First check the current input_text. Start from the next char because 3210146520Sru we already have input_text[input_text_offset] in ``current''. */ 3211146520Sru int pos = input_text_offset + 1; 321221495Sjmacd 3213146520Sru while (pos < input_text_length) 321421495Sjmacd { 3215146520Sru if (!cr_or_whitespace(input_text[pos])) 3216146520Sru return input_text[pos]; 3217146520Sru pos++; 321821495Sjmacd } 321921495Sjmacd 3220146520Sru { /* Can't find a valid character, so go through filestack 3221146520Sru in case we are doing @include or expanding a macro. */ 3222146520Sru FSTACK *tos = filestack; 322356164Sru 3224146520Sru while (tos) 3225146520Sru { 3226146520Sru int tmp_input_text_length = filestack->size; 3227146520Sru int tmp_input_text_offset = filestack->offset; 3228146520Sru char *tmp_input_text = filestack->text; 322921495Sjmacd 3230146520Sru while (tmp_input_text_offset < tmp_input_text_length) 3231146520Sru { 3232146520Sru if (!cr_or_whitespace(tmp_input_text[tmp_input_text_offset])) 3233146520Sru return tmp_input_text[tmp_input_text_offset]; 3234146520Sru tmp_input_text_offset++; 3235146520Sru } 323693142Sru 3237146520Sru tos = tos->next; 3238146520Sru } 3239146520Sru } 324093142Sru 3241146520Sru return -1; 324221495Sjmacd} 3243146520Sru 324442664Smarkm/* An external image is a reference, kind of. The parsing is (not 324542664Smarkm coincidentally) similar, anyway. */ 324642664Smarkmvoid 3247146520Srucm_image (int arg) 324842664Smarkm{ 3249114477Sru char *name_arg, *w_arg, *h_arg, *alt_arg, *ext_arg; 325056164Sru 325156164Sru if (arg == END) 325256164Sru return; 325356164Sru 325456164Sru name_arg = get_xref_token (1); /* expands all macros in image */ 3255114477Sru w_arg = get_xref_token (0); 3256114477Sru h_arg = get_xref_token (0); 325793142Sru alt_arg = get_xref_token (1); /* expands all macros in alt text */ 325893142Sru ext_arg = get_xref_token (0); 325956164Sru 326056164Sru if (*name_arg) 326142664Smarkm { 3262116530Sru struct stat file_info; 3263116530Sru char *pathname = NULL; 326493142Sru char *fullname = xmalloc (strlen (name_arg) 3265146520Sru + (ext_arg && *ext_arg ? strlen (ext_arg) + 1: 4) + 1); 326656164Sru 3267116530Sru if (ext_arg && *ext_arg) 326893142Sru { 3269146520Sru sprintf (fullname, "%s%s", name_arg, ext_arg); 3270116530Sru if (access (fullname, R_OK) != 0) 3271116530Sru pathname = get_file_info_in_path (fullname, include_files_path, 3272116530Sru &file_info); 3273146520Sru 3274146520Sru if (pathname == NULL) 3275146520Sru { 3276146520Sru /* Backwards compatibility (4.6 <= version < 4.7): 3277146520Sru try prefixing @image's EXTENSION parameter with a period. */ 3278146520Sru sprintf (fullname, "%s.%s", name_arg, ext_arg); 3279146520Sru if (access (fullname, R_OK) != 0) 3280146520Sru pathname = get_file_info_in_path (fullname, include_files_path, 3281146520Sru &file_info); 3282146520Sru } 3283116530Sru } 3284116530Sru else 3285116530Sru { 3286116530Sru sprintf (fullname, "%s.png", name_arg); 3287146520Sru if (access (fullname, R_OK) != 0) { 3288146520Sru pathname = get_file_info_in_path (fullname, 3289146520Sru include_files_path, &file_info); 3290146520Sru if (pathname == NULL) { 3291146520Sru sprintf (fullname, "%s.jpg", name_arg); 3292146520Sru if (access (fullname, R_OK) != 0) { 3293146520Sru sprintf (fullname, "%s.gif", name_arg); 3294146520Sru if (access (fullname, R_OK) != 0) { 3295146520Sru pathname = get_file_info_in_path (fullname, 3296116530Sru include_files_path, &file_info); 3297114477Sru } 3298146520Sru } 3299114477Sru } 3300146520Sru } 3301116530Sru } 3302116530Sru 3303116530Sru if (html) 3304116530Sru { 3305146520Sru int image_in_div = 0; 3306146520Sru 3307116530Sru if (pathname == NULL && access (fullname, R_OK) != 0) 3308114477Sru { 3309116530Sru line_error(_("@image file `%s' (for HTML) not readable: %s"), 3310116530Sru fullname, strerror (errno)); 3311116530Sru return; 3312116530Sru } 3313116530Sru if (pathname != NULL && access (pathname, R_OK) != 0) 331456164Sru { 3315116530Sru line_error (_("No such file `%s'"), 3316116530Sru fullname); 3317116530Sru return; 3318114477Sru } 331956164Sru 3320146520Sru if (!paragraph_is_open) 3321146520Sru { 3322146520Sru add_html_block_elt ("<div class=\"block-image\">"); 3323146520Sru image_in_div = 1; 3324146520Sru } 3325146520Sru 3326114477Sru add_html_elt ("<img src="); 332793142Sru add_word_args ("\"%s\"", fullname); 3328114477Sru add_html_elt (" alt="); 3329146520Sru add_word_args ("\"%s\">", 3330146520Sru escape_string (*alt_arg ? text_expansion (alt_arg) : fullname)); 3331146520Sru 3332146520Sru if (image_in_div) 3333146520Sru add_html_block_elt ("</div>"); 333456164Sru } 333593142Sru else if (xml && docbook) 3336114477Sru xml_insert_docbook_image (name_arg); 333793142Sru else if (xml) 3338114477Sru { 3339146520Sru extern int xml_in_para; 3340146520Sru extern int xml_no_para; 3341146520Sru int elt = xml_in_para ? INLINEIMAGE : IMAGE; 3342146520Sru 3343146520Sru if (!xml_in_para) 3344146520Sru xml_no_para++; 3345146520Sru 3346146520Sru xml_insert_element_with_attribute (elt, 3347146520Sru START, "width=\"%s\" height=\"%s\" name=\"%s\" extension=\"%s\"", 3348146520Sru w_arg, h_arg, name_arg, ext_arg); 3349146520Sru xml_insert_element (IMAGEALTTEXT, START); 3350146520Sru execute_string ("%s", alt_arg); 3351146520Sru xml_insert_element (IMAGEALTTEXT, END); 3352146520Sru xml_insert_element (elt, END); 3353146520Sru 3354146520Sru if (!xml_in_para) 3355146520Sru xml_no_para--; 3356114477Sru } 335756164Sru else 3358116530Sru { /* Try to open foo.EXT or foo.txt. */ 335942664Smarkm FILE *image_file; 3360116530Sru char *txtpath = NULL; 3361116530Sru char *txtname = xmalloc (strlen (name_arg) 3362116530Sru + (ext_arg && *ext_arg 3363146520Sru ? strlen (ext_arg) : 4) + 1); 3364116530Sru strcpy (txtname, name_arg); 3365116530Sru strcat (txtname, ".txt"); 3366116530Sru image_file = fopen (txtname, "r"); 3367116530Sru if (image_file == NULL) 336842664Smarkm { 3369116530Sru txtpath = get_file_info_in_path (txtname, 3370116530Sru include_files_path, &file_info); 3371116530Sru if (txtpath != NULL) 3372116530Sru image_file = fopen (txtpath, "r"); 3373116530Sru } 3374116530Sru 3375116530Sru if (image_file != NULL 3376116530Sru || access (fullname, R_OK) == 0 3377116530Sru || (pathname != NULL && access (pathname, R_OK) == 0)) 3378116530Sru { 337942664Smarkm int ch; 338042664Smarkm int save_inhibit_indentation = inhibit_paragraph_indentation; 338142664Smarkm int save_filling_enabled = filling_enabled; 3382146520Sru int image_in_brackets = paragraph_is_open; 338356164Sru 3384146520Sru /* Write magic ^@^H[image ...^@^H] cookie in the info file, if 3385146520Sru there's an accompanying bitmap. Otherwise just include the 3386146520Sru text image. In the plaintext output, always include the text 3387146520Sru image without the magic cookie. */ 3388146520Sru int use_magic_cookie = !no_headers 3389146520Sru && access (fullname, R_OK) == 0 && !STREQ (fullname, txtname); 3390146520Sru 339142664Smarkm inhibit_paragraph_indentation = 1; 339242664Smarkm filling_enabled = 0; 339342664Smarkm last_char_was_newline = 0; 339456164Sru 3395146520Sru if (use_magic_cookie) 3396146520Sru { 3397146520Sru add_char ('\0'); 3398146520Sru add_word ("\010[image"); 339956164Sru 3400146520Sru if (access (fullname, R_OK) == 0 3401146520Sru || (pathname != NULL && access (pathname, R_OK) == 0)) 3402146520Sru add_word_args (" src=\"%s\"", fullname); 3403116530Sru 3404146520Sru if (*alt_arg) 3405146520Sru add_word_args (" alt=\"%s\"", alt_arg); 3406146520Sru } 3407116530Sru 3408116530Sru if (image_file != NULL) 3409116530Sru { 3410146520Sru if (use_magic_cookie) 3411146520Sru add_word (" text=\""); 3412146520Sru 3413146520Sru if (image_in_brackets) 3414146520Sru add_char ('['); 3415146520Sru 3416116530Sru /* Maybe we need to remove the final newline if the image 3417116530Sru file is only one line to allow in-line images. On the 3418116530Sru other hand, they could just make the file without a 3419116530Sru final newline. */ 3420116530Sru while ((ch = getc (image_file)) != EOF) 3421116530Sru { 3422146520Sru if (use_magic_cookie && (ch == '"' || ch == '\\')) 3423116530Sru add_char ('\\'); 3424116530Sru add_char (ch); 3425116530Sru } 3426116530Sru 3427146520Sru if (image_in_brackets) 3428146520Sru add_char (']'); 3429146520Sru 3430146520Sru if (use_magic_cookie) 3431146520Sru add_char ('"'); 3432146520Sru 3433116530Sru if (fclose (image_file) != 0) 3434116530Sru perror (txtname); 3435116530Sru } 3436116530Sru 3437146520Sru if (use_magic_cookie) 3438146520Sru { 3439146520Sru add_char ('\0'); 3440146520Sru add_word ("\010]"); 3441146520Sru } 3442146520Sru 344342664Smarkm inhibit_paragraph_indentation = save_inhibit_indentation; 344442664Smarkm filling_enabled = save_filling_enabled; 344542664Smarkm } 344642664Smarkm else 3447146520Sru warning (_("@image file `%s' (for text) unreadable: %s"), 3448116530Sru txtname, strerror (errno)); 344942664Smarkm } 345042664Smarkm 345156164Sru free (fullname); 3452116530Sru if (pathname) 3453116530Sru free (pathname); 345442664Smarkm } 345521495Sjmacd else 345656164Sru line_error (_("@image missing filename argument")); 345721495Sjmacd 345856164Sru if (name_arg) 345956164Sru free (name_arg); 3460114477Sru if (w_arg) 3461114477Sru free (w_arg); 3462114477Sru if (h_arg) 3463114477Sru free (h_arg); 346493142Sru if (alt_arg) 346593142Sru free (alt_arg); 346693142Sru if (ext_arg) 346793142Sru free (ext_arg); 346821495Sjmacd} 346921495Sjmacd 347056164Sru/* Conditionals. */ 347121495Sjmacd 347221495Sjmacd/* A structure which contains `defined' variables. */ 347321495Sjmacdtypedef struct defines { 347421495Sjmacd struct defines *next; 347521495Sjmacd char *name; 347621495Sjmacd char *value; 347721495Sjmacd} DEFINE; 347821495Sjmacd 347921495Sjmacd/* The linked list of `set' defines. */ 348056164SruDEFINE *defines = NULL; 348121495Sjmacd 348221495Sjmacd/* Add NAME to the list of `set' defines. */ 3483146520Srustatic void 3484146520Sruset (char *name, char *value) 348521495Sjmacd{ 348621495Sjmacd DEFINE *temp; 348721495Sjmacd 348821495Sjmacd for (temp = defines; temp; temp = temp->next) 348921495Sjmacd if (strcmp (name, temp->name) == 0) 349021495Sjmacd { 349142664Smarkm free (temp->value); 349242664Smarkm temp->value = xstrdup (value); 349342664Smarkm return; 349421495Sjmacd } 349521495Sjmacd 349656164Sru temp = xmalloc (sizeof (DEFINE)); 349721495Sjmacd temp->next = defines; 349842664Smarkm temp->name = xstrdup (name); 349942664Smarkm temp->value = xstrdup (value); 350021495Sjmacd defines = temp; 3501146520Sru 3502146520Sru if (xml && !docbook) 3503146520Sru { 3504146520Sru xml_insert_element_with_attribute (SETVALUE, START, "name=\"%s\"", name); 3505146520Sru execute_string ("%s", value); 3506146520Sru xml_insert_element (SETVALUE, END); 3507146520Sru } 350821495Sjmacd} 350921495Sjmacd 351021495Sjmacd/* Remove NAME from the list of `set' defines. */ 3511146520Srustatic void 3512146520Sruclear (char *name) 351321495Sjmacd{ 351456164Sru DEFINE *temp, *last; 351521495Sjmacd 351656164Sru last = NULL; 351721495Sjmacd temp = defines; 351821495Sjmacd 351921495Sjmacd while (temp) 352021495Sjmacd { 352121495Sjmacd if (strcmp (temp->name, name) == 0) 352242664Smarkm { 352342664Smarkm if (last) 352442664Smarkm last->next = temp->next; 352542664Smarkm else 352642664Smarkm defines = temp->next; 352721495Sjmacd 352842664Smarkm free (temp->name); 352942664Smarkm free (temp->value); 353042664Smarkm free (temp); 353142664Smarkm break; 353242664Smarkm } 353321495Sjmacd last = temp; 353421495Sjmacd temp = temp->next; 353521495Sjmacd } 3536146520Sru 3537146520Sru if (xml && !docbook) 3538146520Sru { 3539146520Sru xml_insert_element_with_attribute (CLEARVALUE, START, "name=\"%s\"", name); 3540146520Sru xml_insert_element (CLEARVALUE, END); 3541146520Sru } 354221495Sjmacd} 354321495Sjmacd 354421495Sjmacd/* Return the value of NAME. The return value is NULL if NAME is unset. */ 3545146520Srustatic char * 3546146520Sruset_p (char *name) 354721495Sjmacd{ 354856164Sru DEFINE *temp; 354921495Sjmacd 355021495Sjmacd for (temp = defines; temp; temp = temp->next) 355121495Sjmacd if (strcmp (temp->name, name) == 0) 355256164Sru return temp->value; 355321495Sjmacd 355456164Sru return NULL; 355521495Sjmacd} 355621495Sjmacd 355721495Sjmacd/* Create a variable whose name appears as the first word on this line. */ 355821495Sjmacdvoid 3559146520Srucm_set (void) 356021495Sjmacd{ 356121495Sjmacd handle_variable (SET); 356221495Sjmacd} 356321495Sjmacd 356421495Sjmacd/* Remove a variable whose name appears as the first word on this line. */ 356521495Sjmacdvoid 3566146520Srucm_clear (void) 356721495Sjmacd{ 356821495Sjmacd handle_variable (CLEAR); 356921495Sjmacd} 357021495Sjmacd 357121495Sjmacdvoid 3572146520Srucm_ifset (void) 357321495Sjmacd{ 357421495Sjmacd handle_variable (IFSET); 357521495Sjmacd} 357621495Sjmacd 357721495Sjmacdvoid 3578146520Srucm_ifclear (void) 357921495Sjmacd{ 358021495Sjmacd handle_variable (IFCLEAR); 358121495Sjmacd} 358221495Sjmacd 358321495Sjmacd/* This command takes braces, but we parse the contents specially, so we 358421495Sjmacd don't use the standard brace popping code. 358521495Sjmacd 358621495Sjmacd The syntax @ifeq{arg1, arg2, texinfo-commands} performs texinfo-commands 358721495Sjmacd if ARG1 and ARG2 caselessly string compare to the same string, otherwise, 358821495Sjmacd it produces no output. */ 358921495Sjmacdvoid 3590146520Srucm_ifeq (void) 359121495Sjmacd{ 359221495Sjmacd char **arglist; 359321495Sjmacd 359421495Sjmacd arglist = get_brace_args (0); 359521495Sjmacd 359621495Sjmacd if (arglist) 359721495Sjmacd { 359821495Sjmacd if (array_len (arglist) > 1) 359942664Smarkm { 360042664Smarkm if ((strcasecmp (arglist[0], arglist[1]) == 0) && 360156164Sru (arglist[2])) 360242664Smarkm execute_string ("%s\n", arglist[2]); 360342664Smarkm } 360421495Sjmacd 360521495Sjmacd free_array (arglist); 360621495Sjmacd } 360721495Sjmacd} 360821495Sjmacd 360921495Sjmacdvoid 3610146520Srucm_value (int arg, int start_pos, int end_pos) 361121495Sjmacd{ 361256164Sru static int value_level = 0, saved_meta_pos = -1; 361356164Sru 3614146520Sru /* xml_add_char() skips any content inside menus when output format is 3615146520Sru Docbook, so @value{} is no use there. Also start_pos and end_pos does not 3616146520Sru get updated, causing name to be empty string. So just return. */ 3617146520Sru if (docbook && in_menu) 3618146520Sru return; 3619146520Sru 362056164Sru /* All the text after @value{ upto the matching } will eventually 362156164Sru disappear from output_paragraph, when this function is called 362256164Sru with ARG == END. If the text produced until then sets 362356164Sru meta_char_pos, we will need to restore it to the value it had 362456164Sru before @value was seen. So we need to save the previous value 362556164Sru of meta_char_pos here. */ 362656164Sru if (arg == START) 362721495Sjmacd { 362856164Sru /* If we are already inside some outer @value, don't overwrite 362956164Sru the value saved in saved_meta_pos. */ 363056164Sru if (!value_level) 363156164Sru saved_meta_pos = meta_char_pos; 363256164Sru value_level++; 363356164Sru /* While the argument of @value is processed, we need to inhibit 3634114477Sru textual transformations like "--" into "-", since @set didn't 3635114477Sru do that when it grabbed the name of the variable. */ 363656164Sru in_fixed_width_font++; 363756164Sru } 363856164Sru else 363956164Sru { 364042664Smarkm char *name = (char *) &output_paragraph[start_pos]; 364142664Smarkm char *value; 364242664Smarkm output_paragraph[end_pos] = 0; 364342664Smarkm name = xstrdup (name); 364421495Sjmacd value = set_p (name); 364521495Sjmacd output_column -= end_pos - start_pos; 364621495Sjmacd output_paragraph_offset = start_pos; 364721495Sjmacd 364856164Sru /* Restore the previous value of meta_char_pos if the stuff 364956164Sru inside this @value{} moved it. */ 365056164Sru if (saved_meta_pos == -1) /* can't happen inside @value{} */ 365156164Sru abort (); 365256164Sru if (value_level == 1 365356164Sru && meta_char_pos >= start_pos && meta_char_pos < end_pos) 365456164Sru { 365556164Sru meta_char_pos = saved_meta_pos; 365656164Sru saved_meta_pos = -1; 365756164Sru } 365856164Sru value_level--; 365956164Sru /* No need to decrement in_fixed_width_font, since before 3660114477Sru we are called with arg == END, the reader loop already 3661114477Sru popped the brace stack, which restored in_fixed_width_font, 3662114477Sru among other things. */ 366356164Sru 366421495Sjmacd if (value) 3665146520Sru { 3666146520Sru /* We need to get past the closing brace since the value may 3667146520Sru expand to a context-sensitive macro (e.g. @xref) and produce 3668146520Sru spurious warnings */ 3669146520Sru input_text_offset++; 3670146520Sru execute_string ("%s", value); 3671146520Sru input_text_offset--; 3672146520Sru } 367321495Sjmacd else 3674116530Sru { 3675146520Sru warning (_("undefined flag: %s"), name); 3676146520Sru add_word_args (_("{No value for `%s'}"), name); 3677116530Sru } 367821495Sjmacd 367921495Sjmacd free (name); 368021495Sjmacd } 368121495Sjmacd} 368221495Sjmacd 368321495Sjmacd/* Set, clear, or conditionalize based on ACTION. */ 3684146520Srustatic void 3685146520Sruhandle_variable (int action) 368621495Sjmacd{ 368721495Sjmacd char *name; 368821495Sjmacd 368956164Sru get_rest_of_line (0, &name); 369056164Sru /* If we hit the end of text in get_rest_of_line, backing up 369156164Sru input pointer will cause the last character of the last line 369256164Sru be pushed back onto the input, which is wrong. */ 369356164Sru if (input_text_offset < input_text_length) 369456164Sru backup_input_pointer (); 369521495Sjmacd handle_variable_internal (action, name); 369621495Sjmacd free (name); 369721495Sjmacd} 369821495Sjmacd 3699146520Srustatic void 3700146520Sruhandle_variable_internal (int action, char *name) 370121495Sjmacd{ 370221495Sjmacd char *temp; 370321495Sjmacd int delimiter, additional_text_present = 0; 370421495Sjmacd 370521495Sjmacd /* Only the first word of NAME is a valid tag. */ 370621495Sjmacd temp = name; 370721495Sjmacd delimiter = 0; 370821495Sjmacd while (*temp && (delimiter || !whitespace (*temp))) 370921495Sjmacd { 371021495Sjmacd/* #if defined (SET_WITH_EQUAL) */ 371121495Sjmacd if (*temp == '"' || *temp == '\'') 371242664Smarkm { 371342664Smarkm if (*temp == delimiter) 371442664Smarkm delimiter = 0; 371542664Smarkm else 371642664Smarkm delimiter = *temp; 371742664Smarkm } 371821495Sjmacd/* #endif SET_WITH_EQUAL */ 371921495Sjmacd temp++; 372021495Sjmacd } 372121495Sjmacd 372221495Sjmacd if (*temp) 372321495Sjmacd additional_text_present++; 372421495Sjmacd 372542664Smarkm *temp = 0; 372621495Sjmacd 372721495Sjmacd if (!*name) 372842664Smarkm line_error (_("%c%s requires a name"), COMMAND_PREFIX, command); 372921495Sjmacd else 373021495Sjmacd { 373121495Sjmacd switch (action) 373242664Smarkm { 373342664Smarkm case SET: 373442664Smarkm { 373542664Smarkm char *value; 373621495Sjmacd 373721495Sjmacd#if defined (SET_WITH_EQUAL) 373842664Smarkm /* Allow a value to be saved along with a variable. The value is 373942664Smarkm the text following an `=' sign in NAME, if any is present. */ 374021495Sjmacd 374142664Smarkm for (value = name; *value && *value != '='; value++); 374221495Sjmacd 374342664Smarkm if (*value) 374442664Smarkm *value++ = 0; 374521495Sjmacd 374642664Smarkm if (*value == '"' || *value == '\'') 374742664Smarkm { 374842664Smarkm value++; 374942664Smarkm value[strlen (value) - 1] = 0; 375042664Smarkm } 375121495Sjmacd 375221495Sjmacd#else /* !SET_WITH_EQUAL */ 375342664Smarkm /* The VALUE of NAME is the remainder of the line sans 375442664Smarkm whitespace. */ 375542664Smarkm if (additional_text_present) 375642664Smarkm { 375742664Smarkm value = temp + 1; 375842664Smarkm canon_white (value); 375942664Smarkm } 376042664Smarkm else 376142664Smarkm value = ""; 376221495Sjmacd#endif /* !SET_WITH_VALUE */ 376321495Sjmacd 376442664Smarkm set (name, value); 376542664Smarkm } 376642664Smarkm break; 376721495Sjmacd 376842664Smarkm case CLEAR: 376942664Smarkm clear (name); 377042664Smarkm break; 377121495Sjmacd 377242664Smarkm case IFSET: 377342664Smarkm case IFCLEAR: 377442664Smarkm /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set, 377542664Smarkm read lines from the the file until we reach a matching 377642664Smarkm "@end CONDITION". This means that we only take note of 377742664Smarkm "@ifset/clear" and "@end" commands. */ 377842664Smarkm { 377942664Smarkm char condition[8]; 378042664Smarkm int condition_len; 378142664Smarkm int orig_line_number = line_number; 378221495Sjmacd 378342664Smarkm if (action == IFSET) 378442664Smarkm strcpy (condition, "ifset"); 378542664Smarkm else 378642664Smarkm strcpy (condition, "ifclear"); 378721495Sjmacd 378842664Smarkm condition_len = strlen (condition); 378921495Sjmacd 379042664Smarkm if ((action == IFSET && !set_p (name)) 379142664Smarkm || (action == IFCLEAR && set_p (name))) 379242664Smarkm { 379342664Smarkm int level = 0, done = 0; 379421495Sjmacd 379556164Sru while (!done && input_text_offset < input_text_length) 379642664Smarkm { 379742664Smarkm char *freeable_line, *line; 379821495Sjmacd 379956164Sru get_rest_of_line (0, &freeable_line); 380021495Sjmacd 380142664Smarkm for (line = freeable_line; whitespace (*line); line++); 380221495Sjmacd 380342664Smarkm if (*line == COMMAND_PREFIX && 380442664Smarkm (strncmp (line + 1, condition, condition_len) == 0)) 380542664Smarkm level++; 380642664Smarkm else if (strncmp (line, "@end", 4) == 0) 380742664Smarkm { 380842664Smarkm char *cname = line + 4; 380942664Smarkm char *temp; 381021495Sjmacd 381142664Smarkm while (*cname && whitespace (*cname)) 381242664Smarkm cname++; 381342664Smarkm temp = cname; 381421495Sjmacd 381542664Smarkm while (*temp && !whitespace (*temp)) 381642664Smarkm temp++; 381742664Smarkm *temp = 0; 381821495Sjmacd 381942664Smarkm if (strcmp (cname, condition) == 0) 382042664Smarkm { 382142664Smarkm if (!level) 382242664Smarkm { 382342664Smarkm done = 1; 382442664Smarkm } 382542664Smarkm else 382642664Smarkm level--; 382742664Smarkm } 382842664Smarkm } 382942664Smarkm free (freeable_line); 383042664Smarkm } 383156164Sru 383242664Smarkm if (!done) 3833114477Sru file_line_error (input_filename, orig_line_number, 3834114477Sru _("Reached eof before matching @end %s"), 3835114477Sru condition); 383656164Sru 383742664Smarkm /* We found the end of a false @ifset/ifclear. If we are 383842664Smarkm in a menu, back up over the newline that ends the ifset, 383942664Smarkm since that newline may also begin the next menu entry. */ 384042664Smarkm break; 384142664Smarkm } 384242664Smarkm else 384342664Smarkm { 384442664Smarkm if (action == IFSET) 384542664Smarkm begin_insertion (ifset); 384642664Smarkm else 384742664Smarkm begin_insertion (ifclear); 384842664Smarkm } 384942664Smarkm } 385042664Smarkm break; 385142664Smarkm } 385221495Sjmacd } 385321495Sjmacd} 385421495Sjmacd 385521495Sjmacd/* Execution of random text not in file. */ 385621495Sjmacdtypedef struct { 385742664Smarkm char *string; /* The string buffer. */ 385842664Smarkm int size; /* The size of the buffer. */ 385942664Smarkm int in_use; /* Nonzero means string currently in use. */ 386021495Sjmacd} EXECUTION_STRING; 386121495Sjmacd 386256164Srustatic EXECUTION_STRING **execution_strings = NULL; 386321495Sjmacdstatic int execution_strings_index = 0; 386421495Sjmacdstatic int execution_strings_slots = 0; 386521495Sjmacd 3866146520Srustatic EXECUTION_STRING * 3867146520Sruget_execution_string (int initial_size) 386821495Sjmacd{ 386956164Sru int i = 0; 387056164Sru EXECUTION_STRING *es = NULL; 387121495Sjmacd 387221495Sjmacd if (execution_strings) 387321495Sjmacd { 387421495Sjmacd for (i = 0; i < execution_strings_index; i++) 387542664Smarkm if (execution_strings[i] && (execution_strings[i]->in_use == 0)) 387642664Smarkm { 387742664Smarkm es = execution_strings[i]; 387842664Smarkm break; 387942664Smarkm } 388021495Sjmacd } 388121495Sjmacd 388221495Sjmacd if (!es) 388321495Sjmacd { 388421495Sjmacd if (execution_strings_index + 1 >= execution_strings_slots) 388542664Smarkm { 388656164Sru execution_strings = xrealloc 388742664Smarkm (execution_strings, 388842664Smarkm (execution_strings_slots += 3) * sizeof (EXECUTION_STRING *)); 388942664Smarkm for (; i < execution_strings_slots; i++) 389056164Sru execution_strings[i] = NULL; 389142664Smarkm } 389221495Sjmacd 389321495Sjmacd execution_strings[execution_strings_index] = 389456164Sru xmalloc (sizeof (EXECUTION_STRING)); 389521495Sjmacd es = execution_strings[execution_strings_index]; 389621495Sjmacd execution_strings_index++; 389721495Sjmacd 389821495Sjmacd es->size = 0; 389956164Sru es->string = NULL; 390021495Sjmacd es->in_use = 0; 390121495Sjmacd } 390221495Sjmacd 390321495Sjmacd if (initial_size > es->size) 390421495Sjmacd { 390556164Sru es->string = xrealloc (es->string, initial_size); 390621495Sjmacd es->size = initial_size; 390721495Sjmacd } 390856164Sru return es; 390921495Sjmacd} 391021495Sjmacd 391156164Sru/* Given a pointer to TEXT and its desired length NEW_LEN, find TEXT's 391256164Sru entry in the execution_strings[] array and change the .STRING and 391356164Sru .SIZE members of that entry as appropriate. */ 391456164Sruvoid 3915146520Srumaybe_update_execution_strings (char **text, unsigned int new_len) 391656164Sru{ 391756164Sru int i = 0; 391856164Sru 391956164Sru if (execution_strings) 392056164Sru { 392156164Sru for (i = 0; i < execution_strings_index; i++) 392256164Sru if (execution_strings[i] && (execution_strings[i]->in_use == 1) && 392356164Sru execution_strings[i]->string == *text) 392456164Sru { 392556164Sru /* Don't ever shrink the string storage in execution_strings[]! 392656164Sru execute_string assumes that it is always big enough to store 392756164Sru every possible execution_string, and will break if that's 392856164Sru not true. So we only enlarge the string storage if the 392956164Sru current size isn't big enough. */ 393056164Sru if (execution_strings[i]->size < new_len) 393156164Sru { 393256164Sru execution_strings[i]->string = 393356164Sru *text = xrealloc (*text, new_len + 1); 393456164Sru execution_strings[i]->size = new_len + 1; 393556164Sru } 393656164Sru return; 393756164Sru } 393856164Sru } 393956164Sru /* We should *never* end up here, since if we are inside 394056164Sru execute_string, TEXT is always in execution_strings[]. */ 394156164Sru abort (); 394256164Sru} 394356164Sru 3944100516Sru/* FIXME: this is an arbitrary limit. */ 3945100516Sru#define EXECUTE_STRING_MAX 16*1024 3946100516Sru 394721495Sjmacd/* Execute the string produced by formatting the ARGs with FORMAT. This 394821495Sjmacd is like submitting a new file with @include. */ 394921495Sjmacdvoid 395042664Smarkm#if defined (VA_FPRINTF) && __STDC__ 395142664Smarkmexecute_string (char *format, ...) 395242664Smarkm#else 395342664Smarkmexecute_string (format, va_alist) 395442664Smarkm char *format; 395542664Smarkm va_dcl 395642664Smarkm#endif 395721495Sjmacd{ 395821495Sjmacd EXECUTION_STRING *es; 3959146520Sru char *temp_string, *temp_input_filename; 396042664Smarkm#ifdef VA_FPRINTF 396142664Smarkm va_list ap; 396242664Smarkm#endif 3963146520Sru int insertion_level_at_start = insertion_level; 396421495Sjmacd 3965100516Sru es = get_execution_string (EXECUTE_STRING_MAX); 396621495Sjmacd temp_string = es->string; 396721495Sjmacd es->in_use = 1; 396821495Sjmacd 396942664Smarkm VA_START (ap, format); 397042664Smarkm#ifdef VA_SPRINTF 397142664Smarkm VA_SPRINTF (temp_string, format, ap); 397242664Smarkm#else 397342664Smarkm sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8); 397442664Smarkm#endif /* not VA_SPRINTF */ 397542664Smarkm va_end (ap); 397621495Sjmacd 397721495Sjmacd pushfile (); 397821495Sjmacd input_text_offset = 0; 397921495Sjmacd input_text = temp_string; 3980146520Sru input_text_length = strlen (temp_string); 398142664Smarkm input_filename = xstrdup (input_filename); 3982146520Sru temp_input_filename = input_filename; 398321495Sjmacd 398421495Sjmacd executing_string++; 398521495Sjmacd reader_loop (); 398621495Sjmacd 3987146520Sru /* If insertion stack level changes during execution, that means a multiline 3988146520Sru command is used inside braces or @section ... kind of commands. */ 3989146520Sru if (insertion_level_at_start != insertion_level && !executing_macro) 3990146520Sru { 3991146520Sru line_error (_("Multiline command %c%s used improperly"), 3992146520Sru COMMAND_PREFIX, 3993146520Sru command); 3994146520Sru /* We also need to keep insertion_level intact to make sure warnings are 3995146520Sru issued for @end ... command. */ 3996146520Sru while (insertion_level > insertion_level_at_start) 3997146520Sru pop_insertion (); 3998146520Sru } 3999146520Sru 400021495Sjmacd popfile (); 400121495Sjmacd executing_string--; 400221495Sjmacd es->in_use = 0; 4003146520Sru free (temp_input_filename); 400421495Sjmacd} 400521495Sjmacd 400621495Sjmacd 400756164Sru/* Return what would be output for STR (in newly-malloced memory), i.e., 4008146520Sru expand Texinfo commands according to the current output format. If 4009146520Sru IMPLICIT_CODE is set, expand @code{STR}. This is generally used for 4010146520Sru short texts; filling, indentation, and html escapes are disabled. */ 401121495Sjmacd 401221495Sjmacdchar * 4013146520Sruexpansion (char *str, int implicit_code) 401421495Sjmacd{ 4015146520Sru return maybe_escaped_expansion (str, implicit_code, 0); 4016146520Sru} 4017146520Sru 4018146520Sru 4019146520Sru/* Do HTML escapes according to DO_HTML_ESCAPE. Needed in 4020146520Sru cm_printindex, q.v. */ 4021146520Sru 4022146520Sruchar * 4023146520Srumaybe_escaped_expansion (char *str, int implicit_code, int do_html_escape) 4024146520Sru{ 4025100516Sru char *result; 4026116530Sru 4027100516Sru /* Inhibit indentation and filling, so that extra newlines 4028100516Sru are not added to the expansion. (This is undesirable if 4029100516Sru we write the expanded text to macro_expansion_output_stream.) */ 4030100516Sru int saved_filling_enabled = filling_enabled; 4031100516Sru int saved_indented_fill = indented_fill; 4032100516Sru int saved_no_indent = no_indent; 4033100516Sru int saved_escape_html = escape_html; 4034100516Sru 4035100516Sru filling_enabled = 0; 4036100516Sru indented_fill = 0; 4037100516Sru no_indent = 1; 4038146520Sru escape_html = do_html_escape; 4039116530Sru 4040100516Sru result = full_expansion (str, implicit_code); 4041100516Sru 4042100516Sru filling_enabled = saved_filling_enabled; 4043100516Sru indented_fill = saved_indented_fill; 4044100516Sru no_indent = saved_no_indent; 4045116530Sru escape_html = saved_escape_html; 4046116530Sru 4047100516Sru return result; 4048100516Sru} 4049100516Sru 4050100516Sru 4051100516Sru/* Expand STR (or @code{STR} if IMPLICIT_CODE is nonzero). No change to 4052100516Sru any formatting parameters -- filling, indentation, html escapes, 4053146520Sru etc., are not reset. Always returned in new memory. */ 4054100516Sru 4055100516Sruchar * 4056146520Srufull_expansion (char *str, int implicit_code) 4057100516Sru{ 405821495Sjmacd int length; 405921495Sjmacd char *result; 406021495Sjmacd 406121495Sjmacd /* Inhibit any real output. */ 406221495Sjmacd int start = output_paragraph_offset; 406321495Sjmacd int saved_paragraph_is_open = paragraph_is_open; 406456164Sru int saved_output_column = output_column; 406521495Sjmacd 4066100516Sru /* More output state to save. */ 406756164Sru int saved_meta_pos = meta_char_pos; 406856164Sru int saved_last_char = last_inserted_character; 406956164Sru int saved_last_nl = last_char_was_newline; 407056164Sru 407156164Sru /* If we are called in the middle of processing a command, we need 407256164Sru to dup and save the global variable `command' (which holds the 407356164Sru name of this command), since the recursive reader loop will free 407456164Sru it from under our feet if it finds any macros in STR. */ 407556164Sru char *saved_command = command ? xstrdup (command) : NULL; 407656164Sru 407721495Sjmacd inhibit_output_flushing (); 407842664Smarkm paragraph_is_open = 1; 4079100516Sru if (strlen (str) > (implicit_code 4080114477Sru ? EXECUTE_STRING_MAX - 1 - sizeof("@code{}") 4081114477Sru : EXECUTE_STRING_MAX - 1)) 4082100516Sru line_error (_("`%.40s...' is too long for expansion; not expanded"), str); 4083100516Sru else 4084100516Sru execute_string (implicit_code ? "@code{%s}" : "%s", str); 408521495Sjmacd uninhibit_output_flushing (); 408621495Sjmacd 408721495Sjmacd /* Copy the expansion from the buffer. */ 408821495Sjmacd length = output_paragraph_offset - start; 408921495Sjmacd result = xmalloc (1 + length); 409021495Sjmacd memcpy (result, (char *) (output_paragraph + start), length); 409121495Sjmacd result[length] = 0; 409256164Sru 409321495Sjmacd /* Pretend it never happened. */ 409456164Sru free_and_clear (&command); 409556164Sru command = saved_command; 4096100516Sru 409721495Sjmacd output_paragraph_offset = start; 409821495Sjmacd paragraph_is_open = saved_paragraph_is_open; 409956164Sru output_column = saved_output_column; 4100100516Sru 410156164Sru meta_char_pos = saved_meta_pos; 410256164Sru last_inserted_character = saved_last_char; 410356164Sru last_char_was_newline = saved_last_nl; 410421495Sjmacd 410521495Sjmacd return result; 410621495Sjmacd} 410721495Sjmacd 410821495Sjmacd 410956164Sru/* Return text (info) expansion of STR no matter what the current output 411056164Sru format is. */ 411121495Sjmacd 411221495Sjmacdchar * 4113146520Srutext_expansion (char *str) 411421495Sjmacd{ 411556164Sru char *ret; 411656164Sru int save_html = html; 4117100516Sru int save_xml = xml; 4118146520Sru int save_docbook = docbook; 4119116530Sru 412056164Sru html = 0; 4121100516Sru xml = 0; 4122146520Sru docbook = 0; 412356164Sru ret = expansion (str, 0); 412456164Sru html = save_html; 4125100516Sru xml = save_xml; 4126146520Sru docbook = save_docbook; 4127116530Sru 412856164Sru return ret; 412921495Sjmacd} 413021495Sjmacd 413121495Sjmacd 413242664Smarkm/* Set the paragraph indentation variable to the value specified in STRING. 413342664Smarkm Values can be: 413442664Smarkm `asis': Don't change existing indentation. 413542664Smarkm `none': Remove existing indentation. 413642664Smarkm NUM: Indent NUM spaces at the starts of paragraphs. 413742664Smarkm If NUM is zero, we assume `none'. 413842664Smarkm Returns 0 if successful, or nonzero if STRING isn't one of the above. */ 413942664Smarkmint 4140146520Sruset_paragraph_indent (char *string) 414142664Smarkm{ 414242664Smarkm if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0) 414342664Smarkm paragraph_start_indent = 0; 414442664Smarkm else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0) 414542664Smarkm paragraph_start_indent = -1; 414642664Smarkm else 414742664Smarkm { 414842664Smarkm if (sscanf (string, "%d", ¶graph_start_indent) != 1) 414956164Sru return -1; 415042664Smarkm else 415142664Smarkm { 415242664Smarkm if (paragraph_start_indent == 0) 415342664Smarkm paragraph_start_indent = -1; 415442664Smarkm } 415542664Smarkm } 415656164Sru return 0; 415742664Smarkm} 4158