]> git.ipfire.org Git - thirdparty/gcc.git/blame - texinfo/makeinfo/makeinfo.c
typo typo fixes fixes
[thirdparty/gcc.git] / texinfo / makeinfo / makeinfo.c
CommitLineData
f8b2ac1e 1/* Makeinfo -- convert Texinfo source files into Info files.
d275726b 2 $Id: makeinfo.c,v 1.11 1998/07/06 21:58:00 law Exp $
6599da04 3
d275726b
JL
4 Copyright (C) 1987, 92, 93, 94, 95, 96, 97, 98
5 Free Software Foundation, Inc.
6599da04
JM
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
f8b2ac1e
JL
21 Makeinfo was authored by Brian Fox (bfox@ai.mit.edu). */
22
23/* Indent #pragma so that older Cpp's don't try to parse it. */
24#ifdef _AIX
25 #pragma alloca
26#endif /* _AIX */
6599da04
JM
27
28int major_version = 1;
f8b2ac1e
JL
29int minor_version = 68;
30
31#include "system.h"
32#include "getopt.h"
33
34#ifdef TM_IN_SYS_TIME
35#include <sys/time.h>
36#else
37#include <time.h>
38#endif /* !TM_IN_SYS_TIME */
39
40#ifdef __GNUC__
41# undef alloca
42# define alloca __builtin_alloca
43#else
44# ifdef HAVE_ALLOCA_H
45# include <alloca.h>
46# else
47# ifndef _AIX
48char *alloca ();
49# endif
50# endif
51#endif
52
53/* We'd like to take advantage of _doprnt if it's around, a la error.c,
54 but then we'd have no VA_SPRINTF. */
55#if HAVE_VPRINTF
56# if __STDC__
57# include <stdarg.h>
58# define VA_START(args, lastarg) va_start(args, lastarg)
59# else
60# include <varargs.h>
61# define VA_START(args, lastarg) va_start(args)
62# endif
63# define VA_FPRINTF(file, fmt, ap) vfprintf (file, fmt, ap)
64# define VA_SPRINTF(str, fmt, ap) vsprintf (str, fmt, ap)
65#else /* not HAVE_VPRINTF */
66# define VA_START(args, lastarg)
67# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
68# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
69# define va_end(args)
70#endif
6599da04 71
f8b2ac1e 72/* You can change some of the behavior of Makeinfo by changing the
6599da04
JM
73 following defines: */
74
75/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which
76 appear within an @table, @ftable, or @itemize environment to have
77 standard paragraph indentation. Without this, such paragraphs have
78 no starting indentation. */
79/* #define INDENT_PARAGRAPHS_IN_TABLE */
80
81/* Define DEFAULT_INDENTATION_INCREMENT as an integer which is the amount
82 that @example should increase indentation by. This incremement is used
83 for all insertions which indent the enclosed text. */
84#define DEFAULT_INDENTATION_INCREMENT 5
85
86/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
87 the first lines of paragraphs receive by default, where no other
88 value has been specified. Users can change this value on the command
89 line, with the --paragraph-indent option, or within the texinfo file,
90 with the @paragraphindent command. */
91#define PARAGRAPH_START_INDENT 3
92
93/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you
94 wish to appear between paragraphs. A value of 1 creates a single blank
95 line between paragraphs. Paragraphs are defined by 2 or more consecutive
96 newlines in the input file (i.e., one or more blank lines). */
97#define DEFAULT_PARAGRAPH_SPACING 1
98
99/* Define HAVE_MACROS to enable the macro facility of Texinfo. Using this
f8b2ac1e
JL
100 facility, users can create their own command procedures with
101 arguments. Must always be defined. */
6599da04
JM
102#define HAVE_MACROS
103
104
6599da04
JM
105#define COMPILING_MAKEINFO
106#include "makeinfo.h"
107
f8b2ac1e 108/* Nonzero means that we are currently hacking the insides of an
6599da04
JM
109 insertion which would use a fixed width font. */
110static int in_fixed_width_font = 0;
111
f8b2ac1e 112/* Nonzero means that start_paragraph () MUST be called before we pay
6599da04
JM
113 any attention to close_paragraph () calls. */
114int must_start_paragraph = 0;
115
f8b2ac1e 116/* Nonzero means a string is in execution, as opposed to a file. */
6599da04
JM
117static int executing_string = 0;
118
d275726b
JL
119/* Nonzero means a macro string is in execution, as opposed to a file. */
120static int me_executing_string = 0;
121
6599da04
JM
122#if defined (HAVE_MACROS)
123/* If non-NULL, this is an output stream to write the full macro expansion
f8b2ac1e 124 of the input text to. The result is another texinfo file, but
6599da04
JM
125 missing @include, @infoinclude, @macro, and macro invocations. Instead,
126 all of the text is placed within the file. */
127FILE *macro_expansion_output_stream = (FILE *)NULL;
f8b2ac1e 128char *macro_expansion_filename;
6599da04
JM
129
130/* Here is a structure used to remember input text strings and offsets
131 within them. */
132typedef struct {
f8b2ac1e
JL
133 char *pointer; /* Pointer to the input text. */
134 int offset; /* Offset of the last character output. */
6599da04
JM
135} ITEXT;
136
137static ITEXT **itext_info = (ITEXT **)NULL;
138static int itext_size = 0;
139
f8b2ac1e
JL
140/* Nonzero means to inhibit writing macro expansions to the output
141 stream, because it has already been written. */
6599da04
JM
142int me_inhibit_expansion = 0;
143
144ITEXT *remember_itext ();
145void forget_itext (), me_append_before_this_command ();
146void append_to_expansion_output (), write_region_to_macro_output ();
147void maybe_write_itext (), me_execute_string ();
148#endif /* HAVE_MACROS */
149
6599da04
JM
150\f
151/* **************************************************************** */
f8b2ac1e
JL
152/* */
153/* Global Variables */
154/* */
6599da04
JM
155/* **************************************************************** */
156
157/* Global pointer to argv[0]. */
158char *progname;
159
f8b2ac1e 160/* Return nonzero if STRING is the text at input_text + input_text_offset,
6599da04
JM
161 else zero. */
162#define looking_at(string) \
163 (strncmp (input_text + input_text_offset, string, strlen (string)) == 0)
164
165/* And writing to the output. */
166
167/* The output file name. */
168char *output_filename = (char *)NULL;
169char *pretty_output_filename;
170
171/* Name of the output file that the user elected to pass on the command line.
172 Such a name overrides any name found with the @setfilename command. */
173char *command_output_filename = (char *)NULL;
174
175/* A colon separated list of directories to search for files included
176 with @include. This can be controlled with the `-I' option to makeinfo. */
177char *include_files_path = (char *)NULL;
178
6599da04
JM
179/* Position in the output file. */
180int output_position;
181
182#define INITIAL_PARAGRAPH_SPACE 5000
183int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE;
184
f8b2ac1e 185/* Nonzero indicates that filling will take place on long lines. */
6599da04
JM
186int filling_enabled = 1;
187
f8b2ac1e 188/* Nonzero means that words are not to be split, even in long lines. This
6599da04
JM
189 gets changed for cm_w (). */
190int non_splitting_words = 0;
191
f8b2ac1e 192/* Nonzero indicates that filling a line also indents the new line. */
6599da04
JM
193int indented_fill = 0;
194
195/* The amount of indentation to add at the starts of paragraphs.
196 0 means don't change existing indentation at paragraph starts.
197 > 0 is amount to indent new paragraphs by.
198 < 0 means indent to column zero by removing indentation if necessary.
199
200 This is normally zero, but some people prefer paragraph starts to be
201 somewhat more indented than paragraph bodies. A pretty value for
202 this is 3. */
203int paragraph_start_indent = PARAGRAPH_START_INDENT;
204
f8b2ac1e 205/* Nonzero means that the use of paragraph_start_indent is inhibited.
6599da04
JM
206 @example uses this to line up the left columns of the example text.
207 A negative value for this variable is incremented each time it is used.
208 @noindent uses this to inhibit indentation for a single paragraph. */
209int inhibit_paragraph_indentation = 0;
210
211/* Indentation that is pending insertion. We have this for hacking lines
212 which look blank, but contain whitespace. We want to treat those as
213 blank lines. */
214int pending_indent = 0;
215
216/* The amount that indentation increases/decreases by. */
217int default_indentation_increment = DEFAULT_INDENTATION_INCREMENT;
218
f8b2ac1e 219/* Nonzero indicates that indentation is temporarily turned off. */
6599da04
JM
220int no_indent = 1;
221
f8b2ac1e 222/* Nonzero means forcing output text to be flushright. */
6599da04
JM
223int force_flush_right = 0;
224
f8b2ac1e 225/* Nonzero means that the footnote style for this document was set on
6599da04
JM
226 the command line, which overrides any other settings. */
227int footnote_style_preset = 0;
228
f8b2ac1e 229/* Nonzero means that we automatically number footnotes that have no
6599da04
JM
230 specified marker. */
231int number_footnotes = 1;
232
233/* The current footnote number in this node. Each time a new node is
234 started this is reset to 1. */
235int current_footnote_number = 1;
236
237/* Command name in the process of being hacked. */
238char *command;
239
240/* The index in our internal command table of the currently
241 executing command. */
242int command_index;
243
244/* A search string which is used to find a line defining a node. */
245char node_search_string[] =
f8b2ac1e 246 { '\n', COMMAND_PREFIX, 'n', 'o', 'd', 'e', ' ', 0 };
6599da04
JM
247
248/* A search string which is used to find a line defining a menu. */
249char menu_search_string[] =
f8b2ac1e 250 { '\n', COMMAND_PREFIX, 'm', 'e', 'n', 'u', 0 };
6599da04
JM
251
252/* A search string which is used to find the first @setfilename. */
253char setfilename_search[] =
254 { COMMAND_PREFIX,
f8b2ac1e 255 's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 };
6599da04
JM
256
257/* A stack of file information records. If a new file is read in with
258 "@input", we remember the old input file state on this stack. */
259typedef struct fstack
260{
261 struct fstack *next;
262 char *filename;
263 char *text;
264 int size;
265 int offset;
266 int line_number;
267} FSTACK;
268
269FSTACK *filestack = (FSTACK *) NULL;
270
271/* Stuff for nodes. */
272/* The current nodes node name. */
273char *current_node = (char *)NULL;
274
275/* The current nodes section level. */
276int current_section = 0;
277
278/* The filename of the current input file. This is never freed. */
279char *node_filename = (char *)NULL;
280
281/* What we remember for each node. */
282typedef struct tentry
283{
284 struct tentry *next_ent;
f8b2ac1e
JL
285 char *node; /* name of this node. */
286 char *prev; /* name of "Prev:" for this node. */
287 char *next; /* name of "Next:" for this node. */
288 char *up; /* name of "Up:" for this node. */
289 int position; /* output file position of this node. */
290 int line_no; /* defining line in source file. */
291 char *filename; /* The file that this node was found in. */
292 int touched; /* Nonzero means this node has been referenced. */
293 int flags; /* Room for growth. Right now, contains 1 bit. */
6599da04
JM
294} TAG_ENTRY;
295
296/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a,
297 we turn on this flag bit in node-b's tag entry. This means that when
298 it is time to validate node-b, we don't report an additional error
299 if there was no "Prev" field. */
300#define PREV_ERROR 0x1
301#define NEXT_ERROR 0x2
302#define UP_ERROR 0x4
f8b2ac1e
JL
303#define NO_WARN 0x8
304#define IS_TOP 0x10
6599da04
JM
305
306TAG_ENTRY *tag_table = (TAG_ENTRY *) NULL;
307
f8b2ac1e
JL
308/* Values for calling handle_variable_internal (). */
309#define SET 1
310#define CLEAR 2
311#define IFSET 3
312#define IFCLEAR 4
313
6599da04 314#if defined (HAVE_MACROS)
f8b2ac1e
JL
315#define ME_RECURSE 0x01
316#define ME_QUOTE_ARG 0x02
6599da04
JM
317
318/* Macro definitions for user-defined commands. */
319typedef struct {
f8b2ac1e
JL
320 char *name; /* Name of the macro. */
321 char **arglist; /* Args to replace when executing. */
322 char *body; /* Macro body. */
323 char *source_file; /* File where this macro is defined. */
324 int source_lineno; /* Line number within FILENAME. */
325 int inhibited; /* Nonzero means make find_macro () fail. */
326 int flags; /* ME_RECURSE, ME_QUOTE_ARG, etc. */
6599da04
JM
327} MACRO_DEF;
328
329void add_macro (), execute_macro ();
330MACRO_DEF *find_macro (), *delete_macro ();
331#endif /* HAVE_MACROS */
332
333/* Menu reference, *note reference, and validation hacking. */
334
335/* The various references that we know about. */
336enum reftype
337{
338 menu_reference, followed_reference
339};
340
341/* A structure to remember references with. A reference to a node is
342 either an entry in a menu, or a cross-reference made with [px]ref. */
343typedef struct node_ref
344{
345 struct node_ref *next;
f8b2ac1e
JL
346 char *node; /* Name of node referred to. */
347 char *containing_node; /* Name of node containing this reference. */
348 int line_no; /* Line number where the reference occurs. */
349 int section; /* Section level where the reference occurs. */
350 char *filename; /* Name of file where the reference occurs. */
351 enum reftype type; /* Type of reference, either menu or note. */
6599da04
JM
352} NODE_REF;
353
354/* The linked list of such structures. */
355NODE_REF *node_references = (NODE_REF *) NULL;
356
357/* Flag which tells us whether to examine menu lines or not. */
358int in_menu = 0;
359
360/* Flag which tells us how to examine menu lines. */
361int in_detailmenu = 0;
362
f8b2ac1e 363/* Nonzero means that we have seen "@top" once already. */
6599da04
JM
364int top_node_seen = 0;
365
f8b2ac1e 366/* Nonzero means that we have seen a non-"@top" node already. */
6599da04
JM
367int non_top_node_seen = 0;
368
369/* Flags controlling the operation of the program. */
370
f8b2ac1e
JL
371/* Default is to remove output if there were errors. */
372int force = 0;
373
6599da04
JM
374/* Default is to notify users of bad choices. */
375int print_warnings = 1;
376
377/* Default is to check node references. */
378int validating = 1;
379
f8b2ac1e 380/* Nonzero means do not output "Node: Foo" for node separations. */
6599da04
JM
381int no_headers = 0;
382
383/* Number of errors that we tolerate on a given fileset. */
384int max_error_level = 100;
385
386/* Maximum number of references to a single node before complaining. */
387int reference_warning_limit = 1000;
388
f8b2ac1e 389/* Nonzero means print out information about what is going on when it
6599da04
JM
390 is going on. */
391int verbose_mode = 0;
392
f8b2ac1e 393/* Nonzero means to be relaxed about the input file. This is useful when
6599da04
JM
394 we can successfully format the input, but it doesn't strictly match our
395 somewhat pedantic ideas of correctness. Right now, it affects what
396 @table and @itemize do without arguments. */
397int allow_lax_format = 0;
398
399/* The list of commands that we hack in texinfo. Each one
400 has an associated function. When the command is encountered in the
401 text, the associated function is called with START as the argument.
402 If the function expects arguments in braces, it remembers itself on
403 the stack. When the corresponding close brace is encountered, the
404 function is called with END as the argument. */
405
406#define START 0
407#define END 1
408
409typedef struct brace_element
410{
411 struct brace_element *next;
412 COMMAND_FUNCTION *proc;
413 int pos, line;
414 int in_fixed_width_font;
415} BRACE_ELEMENT;
416
417BRACE_ELEMENT *brace_stack = (BRACE_ELEMENT *) NULL;
418
6599da04
JM
419extern void do_multitable ();
420
421void print_version_info ();
422void usage ();
423void push_node_filename (), pop_node_filename ();
f8b2ac1e 424void remember_error (), flush_file_stack ();
6599da04
JM
425void convert_from_stream (), convert_from_file (), convert_from_loaded_file ();
426void init_internals (), init_paragraph (), init_brace_stack ();
427void init_insertion_stack (), init_indices ();
428void init_tag_table (), write_tag_table (), write_tag_table_internal ();
429void validate_file (), validate_other_references (), split_file ();
430void free_node_references (), do_enumeration (), handle_variable ();
431void handle_variable_internal ();
6599da04
JM
432void normalize_node_name ();
433void undefindex (), top_defindex (), gen_defindex ();
434void define_user_command ();
435void free_pending_notes (), output_pending_notes ();
436
f8b2ac1e
JL
437char **get_brace_args ();
438char *expansion ();
439int array_len ();
440void free_array ();
441static int end_of_sentence_p ();
442static void isolate_nodename ();
6599da04
JM
443void reader_loop (), read_command ();
444void remember_brace (), remember_brace_1 ();
445void pop_and_call_brace (), discard_braces ();
f8b2ac1e 446void add_word (), add_char (), insert (), flush_output ();
6599da04
JM
447void insert_string ();
448void close_paragraph_with_lines (), close_paragraph ();
449void ignore_blank_line ();
f8b2ac1e 450void do_flush_right_indentation (), discard_insertions ();
6599da04 451void start_paragraph (), indent ();
f8b2ac1e
JL
452#if defined (VA_FPRINTF) && __STDC__
453/* Unfortunately we must use prototypes if we are to use <stdarg.h>. */
454void add_word_args (char *, ...);
455void execute_string (char *, ...);
456#else
457void add_word_args ();
458void execute_string ();
459#endif /* will not use prototypes */
6599da04
JM
460\f
461void insert_self (), insert_space (), cm_ignore_line ();
462
463void
464 cm_TeX (), cm_asterisk (), cm_bullet (), cm_cite (),
465 cm_code (), cm_copyright (), cm_ctrl (), cm_dfn (), cm_dircategory (),
466 cm_direntry (), cm_dots (), cm_emph (), cm_enddots (),
f8b2ac1e
JL
467 cm_kbd (), cm_key (), cm_no_op (), cm_no_op_line_arg (),
468 cm_not_fixed_width (), cm_strong (), cm_var_sc (), cm_w (), cm_image ();
6599da04
JM
469
470/* Sectioning. */
471void
472 cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (),
473 cm_section (), cm_unnumberedsec (), cm_appendixsec (),
474 cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (),
475 cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (),
476 cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (),
477 cm_majorheading (), cm_raisesections (), cm_lowersections ();
478
f8b2ac1e 479/* All @def... commands map to cm_defun, most accent commands map to
6599da04
JM
480 cm_accent, most non-English letters map to cm_special_char. */
481void cm_defun (), cm_accent (), cm_special_char (), cm_dotless ();
482
483void
484 cm_node (), cm_menu (), cm_xref (), cm_ftable (), cm_vtable (), cm_pxref (),
f8b2ac1e
JL
485 cm_inforef (), cm_uref (), cm_email (), cm_quotation (),
486 cm_display (), cm_itemize (),
6599da04
JM
487 cm_enumerate (), cm_tab (), cm_table (), cm_itemx (), cm_noindent (),
488 cm_setfilename (), cm_br (), cm_sp (), cm_page (), cm_group (),
489 cm_center (), cm_include (), cm_bye (), cm_item (), cm_end (),
f8b2ac1e 490 cm_ifinfo (), cm_ifnothtml (), cm_ifnottex (), cm_kindex (), cm_cindex (),
6599da04
JM
491 cm_findex (), cm_pindex (), cm_vindex (), cm_tindex (),
492 cm_synindex (), cm_printindex (), cm_minus (), cm_footnote (),
493 cm_example (), cm_smallexample (), cm_lisp (), cm_format (), cm_exdent (),
f8b2ac1e 494 cm_defindex (), cm_defcodeindex (), cm_result (), cm_expansion (),
6599da04
JM
495 cm_equiv (), cm_print (), cm_error (), cm_point (), cm_today (),
496 cm_flushleft (), cm_flushright (), cm_smalllisp (), cm_finalout (),
497 cm_cartouche (), cm_detailmenu (), cm_multitable ();
498
499/* Conditionals. */
500void cm_set (), cm_clear (), cm_ifset (), cm_ifclear ();
501void cm_value (), cm_ifeq ();
502
503#if defined (HAVE_MACROS)
504/* Define a user-defined command which is simple substitution. */
505void cm_macro (), cm_unmacro ();
506#endif /* HAVE_MACROS */
507
508/* Options. */
509void cm_paragraphindent (), cm_footnotestyle ();
510
511/* Internals. */
512void command_name_condition (), misplaced_brace (), cm_obsolete (),
513 cm_ideprecated ();
514
515typedef struct
516{
517 char *name;
518 COMMAND_FUNCTION *proc;
519 int argument_in_braces;
520} COMMAND;
521
522/* Stuff for defining commands on the fly. */
523COMMAND **user_command_array = (COMMAND **) NULL;
524int user_command_array_len = 0;
525
526#define NO_BRACE_ARGS 0
527#define BRACE_ARGS 1
528
f8b2ac1e 529static COMMAND command_table[] = {
6599da04
JM
530 { "\t", insert_space, NO_BRACE_ARGS },
531 { "\n", insert_space, NO_BRACE_ARGS },
532 { " ", insert_self, NO_BRACE_ARGS },
533 { "!", insert_self, NO_BRACE_ARGS },
534 { "\"", insert_self, NO_BRACE_ARGS },
535 { "'", insert_self, NO_BRACE_ARGS },
536 { "*", cm_asterisk, NO_BRACE_ARGS },
537 { ",", cm_accent, BRACE_ARGS },
538 { "-", cm_no_op, NO_BRACE_ARGS },
539 { ".", insert_self, NO_BRACE_ARGS },
540 { ":", cm_no_op, NO_BRACE_ARGS },
541 { "=", insert_self, NO_BRACE_ARGS },
542 { "?", insert_self, NO_BRACE_ARGS },
543 { "@", insert_self, NO_BRACE_ARGS },
544 { "^", insert_self, NO_BRACE_ARGS },
545 { "`", insert_self, NO_BRACE_ARGS },
546 { "{", insert_self, NO_BRACE_ARGS },
547 { "|", cm_no_op, NO_BRACE_ARGS },
548 { "}", insert_self, NO_BRACE_ARGS },
549 { "~", insert_self, NO_BRACE_ARGS },
550 { "AA", insert_self, BRACE_ARGS },
551 { "AE", insert_self, BRACE_ARGS },
552 { "H", cm_accent, BRACE_ARGS },
553 { "L", cm_special_char, BRACE_ARGS },
554 { "O", cm_special_char, BRACE_ARGS },
555 { "OE", insert_self, BRACE_ARGS },
556 { "TeX", cm_TeX, BRACE_ARGS },
557 { "aa", insert_self, BRACE_ARGS },
558 { "ae", insert_self, BRACE_ARGS },
559 { "appendix", cm_appendix, NO_BRACE_ARGS },
560 { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
561 { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
562 { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
563 { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
564 { "asis", cm_no_op, BRACE_ARGS },
565 { "b", cm_not_fixed_width, BRACE_ARGS },
566 { "bullet", cm_bullet, BRACE_ARGS },
567 { "bye", cm_bye, NO_BRACE_ARGS },
568 { "c", cm_ignore_line, NO_BRACE_ARGS },
569 { "cartouche", cm_cartouche, NO_BRACE_ARGS },
570 { "center", cm_center, NO_BRACE_ARGS },
571 { "centerchap", cm_unnumbered, NO_BRACE_ARGS },
572 { "chapheading", cm_chapheading, NO_BRACE_ARGS },
573 { "chapter", cm_chapter, NO_BRACE_ARGS },
574 { "cindex", cm_cindex, NO_BRACE_ARGS },
575 { "cite", cm_cite, BRACE_ARGS },
576 { "clear", cm_clear, NO_BRACE_ARGS },
577 { "code", cm_code, BRACE_ARGS },
578 { "comment", cm_ignore_line, NO_BRACE_ARGS },
579 { "contents", cm_no_op, NO_BRACE_ARGS },
580 { "copyright", cm_copyright, BRACE_ARGS },
581 { "ctrl", cm_obsolete, BRACE_ARGS },
582 { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
583 { "defindex", cm_defindex, NO_BRACE_ARGS },
584/* The `def' commands. */
585 { "defcv", cm_defun, NO_BRACE_ARGS },
586 { "defcvx", cm_defun, NO_BRACE_ARGS },
587 { "deffn", cm_defun, NO_BRACE_ARGS },
588 { "deffnx", cm_defun, NO_BRACE_ARGS },
589 { "defivar", cm_defun, NO_BRACE_ARGS },
590 { "defivarx", cm_defun, NO_BRACE_ARGS },
591 { "defmac", cm_defun, NO_BRACE_ARGS },
592 { "defmacx", cm_defun, NO_BRACE_ARGS },
593 { "defmethod", cm_defun, NO_BRACE_ARGS },
594 { "defmethodx", cm_defun, NO_BRACE_ARGS },
595 { "defop", cm_defun, NO_BRACE_ARGS },
596 { "defopt", cm_defun, NO_BRACE_ARGS },
597 { "defoptx", cm_defun, NO_BRACE_ARGS },
598 { "defopx", cm_defun, NO_BRACE_ARGS },
599 { "defspec", cm_defun, NO_BRACE_ARGS },
600 { "defspecx", cm_defun, NO_BRACE_ARGS },
601 { "deftp", cm_defun, NO_BRACE_ARGS },
602 { "deftpx", cm_defun, NO_BRACE_ARGS },
603 { "deftypefn", cm_defun, NO_BRACE_ARGS },
604 { "deftypefnx", cm_defun, NO_BRACE_ARGS },
605 { "deftypefun", cm_defun, NO_BRACE_ARGS },
606 { "deftypefunx", cm_defun, NO_BRACE_ARGS },
607 { "deftypemethod", cm_defun, NO_BRACE_ARGS },
608 { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
609 { "deftypevar", cm_defun, NO_BRACE_ARGS },
610 { "deftypevarx", cm_defun, NO_BRACE_ARGS },
611 { "deftypevr", cm_defun, NO_BRACE_ARGS },
612 { "deftypevrx", cm_defun, NO_BRACE_ARGS },
613 { "defun", cm_defun, NO_BRACE_ARGS },
614 { "defunx", cm_defun, NO_BRACE_ARGS },
615 { "defvar", cm_defun, NO_BRACE_ARGS },
616 { "defvarx", cm_defun, NO_BRACE_ARGS },
617 { "defvr", cm_defun, NO_BRACE_ARGS },
618 { "defvrx", cm_defun, NO_BRACE_ARGS },
619/* The end of the `def' commands. */
620 { "detailmenu", cm_detailmenu, NO_BRACE_ARGS },
621 { "dfn", cm_dfn, BRACE_ARGS },
622 { "dircategory", cm_dircategory, NO_BRACE_ARGS },
623 { "direntry", cm_direntry, NO_BRACE_ARGS },
624 { "display", cm_display, NO_BRACE_ARGS },
625 { "dmn", cm_no_op, BRACE_ARGS },
626 { "dotaccent", cm_accent, BRACE_ARGS },
627 { "dotless", cm_dotless, BRACE_ARGS },
628 { "dots", cm_dots, BRACE_ARGS },
f8b2ac1e 629 { "email", cm_email, BRACE_ARGS },
6599da04
JM
630 { "emph", cm_emph, BRACE_ARGS },
631 { "end", cm_end, NO_BRACE_ARGS },
632 { "enddots", cm_enddots, BRACE_ARGS },
633 { "enumerate", cm_enumerate, NO_BRACE_ARGS },
634 { "equiv", cm_equiv, BRACE_ARGS },
635 { "error", cm_error, BRACE_ARGS },
636 { "example", cm_example, NO_BRACE_ARGS },
637 { "exclamdown", cm_special_char, BRACE_ARGS },
638 { "exdent", cm_exdent, NO_BRACE_ARGS },
639 { "expansion", cm_expansion, BRACE_ARGS },
640 { "file", cm_code, BRACE_ARGS },
641 { "finalout", cm_no_op, NO_BRACE_ARGS },
642 { "findex", cm_findex, NO_BRACE_ARGS },
643 { "flushleft", cm_flushleft, NO_BRACE_ARGS },
644 { "flushright", cm_flushright, NO_BRACE_ARGS },
645 { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
646 { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
647 { "format", cm_format, NO_BRACE_ARGS },
648 { "ftable", cm_ftable, NO_BRACE_ARGS },
649 { "group", cm_group, NO_BRACE_ARGS },
650 { "heading", cm_heading, NO_BRACE_ARGS },
651 { "headings", cm_ignore_line, NO_BRACE_ARGS },
f8b2ac1e 652 { "html", command_name_condition, NO_BRACE_ARGS },
6599da04
JM
653 { "hyphenation", cm_no_op, BRACE_ARGS },
654 { "i", cm_not_fixed_width, BRACE_ARGS },
655 { "ifclear", cm_ifclear, NO_BRACE_ARGS },
656 { "ifeq", cm_ifeq, NO_BRACE_ARGS },
657 { "ifhtml", command_name_condition, NO_BRACE_ARGS },
658 { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
f8b2ac1e
JL
659 { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS },
660 { "ifnotinfo", command_name_condition, NO_BRACE_ARGS },
661 { "ifnottex", cm_ifnottex, NO_BRACE_ARGS },
6599da04
JM
662 { "ifset", cm_ifset, NO_BRACE_ARGS },
663 { "iftex", command_name_condition, NO_BRACE_ARGS },
664 { "ignore", command_name_condition, NO_BRACE_ARGS },
f8b2ac1e 665 { "image", cm_image, BRACE_ARGS },
6599da04
JM
666 { "include", cm_include, NO_BRACE_ARGS },
667 { "inforef", cm_inforef, BRACE_ARGS },
668 { "item", cm_item, NO_BRACE_ARGS },
669 { "itemize", cm_itemize, NO_BRACE_ARGS },
670 { "itemx", cm_itemx, NO_BRACE_ARGS },
671 { "kbd", cm_kbd, BRACE_ARGS },
f8b2ac1e
JL
672 { "kbdinputstyle", cm_no_op_line_arg, NO_BRACE_ARGS },
673 { "key", cm_key, BRACE_ARGS },
6599da04
JM
674 { "kindex", cm_kindex, NO_BRACE_ARGS },
675 { "l", cm_special_char, BRACE_ARGS },
676 { "lisp", cm_lisp, NO_BRACE_ARGS },
677 { "lowersections", cm_lowersections, NO_BRACE_ARGS },
6599da04 678 { "macro", cm_macro, NO_BRACE_ARGS },
6599da04
JM
679 { "majorheading", cm_majorheading, NO_BRACE_ARGS },
680 { "math", cm_no_op, BRACE_ARGS },
681 { "menu", cm_menu, NO_BRACE_ARGS },
682 { "minus", cm_minus, BRACE_ARGS },
683 { "multitable", cm_multitable, NO_BRACE_ARGS },
684 { "need", cm_ignore_line, NO_BRACE_ARGS },
685 { "node", cm_node, NO_BRACE_ARGS },
686 { "noindent", cm_noindent, NO_BRACE_ARGS },
687 { "nwnode", cm_node, NO_BRACE_ARGS },
688 { "o", cm_special_char, BRACE_ARGS },
689 { "oe", insert_self, BRACE_ARGS },
690 { "page", cm_no_op, NO_BRACE_ARGS },
691 { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
692 { "pindex", cm_pindex, NO_BRACE_ARGS },
693 { "point", cm_point, BRACE_ARGS },
694 { "pounds", cm_special_char, BRACE_ARGS },
695 { "print", cm_print, BRACE_ARGS },
696 { "printindex", cm_printindex, NO_BRACE_ARGS },
697 { "pxref", cm_pxref, BRACE_ARGS },
698 { "questiondown", cm_special_char, BRACE_ARGS },
699 { "quotation", cm_quotation, NO_BRACE_ARGS },
700 { "r", cm_not_fixed_width, BRACE_ARGS },
701 { "raisesections", cm_raisesections, NO_BRACE_ARGS },
702 { "ref", cm_xref, BRACE_ARGS },
703 { "refill", cm_no_op, NO_BRACE_ARGS },
704 { "result", cm_result, BRACE_ARGS },
705 { "ringaccent", cm_accent, BRACE_ARGS },
706 { "samp", cm_code, BRACE_ARGS },
f8b2ac1e 707 { "sc", cm_var_sc, BRACE_ARGS },
6599da04
JM
708 { "section", cm_section, NO_BRACE_ARGS },
709 { "set", cm_set, NO_BRACE_ARGS },
710 { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
711 { "setchapterstyle", cm_obsolete, NO_BRACE_ARGS },
712 { "setfilename", cm_setfilename, NO_BRACE_ARGS },
713 { "settitle", cm_ignore_line, NO_BRACE_ARGS },
714 { "shortcontents", cm_no_op, NO_BRACE_ARGS },
715 { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
716 { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
717 { "smallexample", cm_smallexample, NO_BRACE_ARGS },
718 { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
719 { "sp", cm_sp, NO_BRACE_ARGS },
720 { "ss", insert_self, BRACE_ARGS },
721 { "strong", cm_strong, BRACE_ARGS },
722 { "subheading", cm_subheading, NO_BRACE_ARGS },
723 { "subsection", cm_subsection, NO_BRACE_ARGS },
724 { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
725 { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
726 { "summarycontents", cm_no_op, NO_BRACE_ARGS },
727 { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
728 { "synindex", cm_synindex, NO_BRACE_ARGS },
729 { "t", cm_no_op, BRACE_ARGS },
730 { "tab", cm_tab, NO_BRACE_ARGS },
731 { "table", cm_table, NO_BRACE_ARGS },
732 { "tex", command_name_condition, NO_BRACE_ARGS },
733 { "tieaccent", cm_accent, BRACE_ARGS },
734 { "tindex", cm_tindex, NO_BRACE_ARGS },
735 { "titlefont", cm_not_fixed_width, BRACE_ARGS },
736 { "titlepage", command_name_condition, NO_BRACE_ARGS },
737 { "today", cm_today, BRACE_ARGS },
738 { "top", cm_top, NO_BRACE_ARGS },
739 { "u", cm_accent, BRACE_ARGS },
740 { "ubaraccent", cm_accent, BRACE_ARGS },
741 { "udotaccent", cm_accent, BRACE_ARGS },
742#if defined (HAVE_MACROS)
743 { "unmacro", cm_unmacro, NO_BRACE_ARGS },
744#endif
745 { "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
746 { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
747 { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
748 { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
f8b2ac1e 749 { "uref", cm_uref, BRACE_ARGS },
6599da04
JM
750 { "url", cm_code, BRACE_ARGS },
751 { "v", cm_accent, BRACE_ARGS },
752 { "value", cm_value, BRACE_ARGS },
f8b2ac1e 753 { "var", cm_var_sc, BRACE_ARGS },
6599da04
JM
754 { "vindex", cm_vindex, NO_BRACE_ARGS },
755 { "vtable", cm_vtable, NO_BRACE_ARGS },
756 { "w", cm_w, BRACE_ARGS },
757 { "xref", cm_xref, BRACE_ARGS },
758
759 /* Deprecated commands. These used to be for italics. */
760 { "iappendix", cm_ideprecated, NO_BRACE_ARGS },
761 { "iappendixsec", cm_ideprecated, NO_BRACE_ARGS },
762 { "iappendixsection", cm_ideprecated, NO_BRACE_ARGS },
763 { "iappendixsubsec", cm_ideprecated, NO_BRACE_ARGS },
764 { "iappendixsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
765 { "ichapter", cm_ideprecated, NO_BRACE_ARGS },
766 { "isection", cm_ideprecated, NO_BRACE_ARGS },
767 { "isubsection", cm_ideprecated, NO_BRACE_ARGS },
768 { "isubsubsection", cm_ideprecated, NO_BRACE_ARGS },
769 { "iunnumbered", cm_ideprecated, NO_BRACE_ARGS },
770 { "iunnumberedsec", cm_ideprecated, NO_BRACE_ARGS },
771 { "iunnumberedsubsec", cm_ideprecated, NO_BRACE_ARGS },
772 { "iunnumberedsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
773
f8b2ac1e 774 /* Now @include does what this was used to. */
6599da04
JM
775 { "infoinclude", cm_obsolete, NO_BRACE_ARGS },
776 { "titlespec", cm_obsolete, NO_BRACE_ARGS },
777
f8b2ac1e 778 { NULL, NULL, NO_BRACE_ARGS }
b99bb832
JL
779};
780
6599da04
JM
781struct option long_options[] =
782{
f8b2ac1e
JL
783 { "error-limit", 1, 0, 'e' }, /* formerly -el */
784 { "fill-column", 1, 0, 'f' }, /* formerly -fc */
785 { "footnote-style", 1, 0, 's' }, /* formerly -ft */
786 { "force", 0, 0, 'F' }, /* do not remove output */
787 { "no-headers", 0, &no_headers, 1 }, /* do not output Node: foo */
6599da04 788 { "no-pointer-validate", 0, &validating, 0 }, /* formerly -nv */
f8b2ac1e
JL
789 { "no-validate", 0, &validating, 0 }, /* formerly -nv */
790 { "no-split", 0, &splitting, 0 }, /* formerly -ns */
791 { "no-warn", 0, &print_warnings, 0 }, /* formerly -nw */
6599da04 792 { "macro-expand", 1, 0, 'E' },
6599da04
JM
793 { "number-footnotes", 0, &number_footnotes, 1 },
794 { "no-number-footnotes", 0, &number_footnotes, 0 },
795 { "output", 1, 0, 'o' },
f8b2ac1e
JL
796 { "paragraph-indent", 1, 0, 'p' }, /* formerly -pi */
797 { "reference-limit", 1, 0, 'r' }, /* formerly -rl */
798 { "verbose", 0, &verbose_mode, 1 }, /* formerly -verbose */
6599da04
JM
799 { "help", 0, 0, 'h' },
800 { "version", 0, 0, 'V' },
801 {NULL, 0, NULL, 0}
802};
803\f
f8b2ac1e
JL
804/* **************************************************************** */
805/* */
806/* Error Handling */
807/* */
808/* **************************************************************** */
809
810/* Number of errors encountered. */
811int errors_printed = 0;
6599da04 812
f8b2ac1e
JL
813/* Print the last error gotten from the file system. */
814int
815fs_error (filename)
816 char *filename;
817{
818 remember_error ();
819 perror (filename);
820 return (0);
821}
822
823/* Print an error message, and return false. */
824void
825#if defined (VA_FPRINTF) && __STDC__
826error (char *format, ...)
827#else
828error (format, va_alist)
829 char *format;
830 va_dcl
831#endif
832{
833#ifdef VA_FPRINTF
834 va_list ap;
835#endif
836
837 remember_error ();
838
839 VA_START (ap, format);
840#ifdef VA_FPRINTF
841 VA_FPRINTF (stderr, format, ap);
842#else
843 fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
844#endif /* not VA_FPRINTF */
845 va_end (ap);
846
847 putc ('\n', stderr);
848}
849
850/* Just like error (), but print the line number as well. */
851void
852#if defined (VA_FPRINTF) && __STDC__
853line_error (char *format, ...)
854#else
855line_error (format, va_alist)
856 char *format;
857 va_dcl
858#endif
859{
860#ifdef VA_FPRINTF
861 va_list ap;
862#endif
863
864 remember_error ();
865 fprintf (stderr, "%s:%d: ", input_filename, line_number);
866
867 VA_START (ap, format);
868#ifdef VA_FPRINTF
869 VA_FPRINTF (stderr, format, ap);
870#else
871 fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
872#endif /* not VA_FPRINTF */
873 va_end (ap);
874
875 fprintf (stderr, ".\n");
876}
877
878void
879#if defined (VA_FPRINTF) && __STDC__
880warning (char *format, ...)
881#else
882warning (format, va_alist)
883 char *format;
884 va_dcl
885#endif
886{
887#ifdef VA_FPRINTF
888 va_list ap;
889#endif
890
891 if (print_warnings)
892 {
893 fprintf (stderr, _("%s:%d: warning: "), input_filename, line_number);
894
895 VA_START (ap, format);
896#ifdef VA_FPRINTF
897 VA_FPRINTF (stderr, format, ap);
898#else
899 fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8);
900#endif /* not VA_FPRINTF */
901 va_end (ap);
902
903 fprintf (stderr, ".\n");
904 }
905}
906
907
908/* Remember that an error has been printed. If more than
909 max_error_level have been printed, then exit the program. */
910void
911remember_error ()
912{
913 errors_printed++;
914 if (max_error_level && (errors_printed > max_error_level))
915 {
916 fprintf (stderr, _("Too many errors! Gave up.\n"));
917 flush_file_stack ();
918 cm_bye ();
919 exit (FATAL);
920 }
921}
922\f
6599da04 923/* **************************************************************** */
f8b2ac1e
JL
924/* */
925/* Main () Start of code */
926/* */
6599da04
JM
927/* **************************************************************** */
928
929/* For each file mentioned in the command line, process it, turning
930 Texinfo commands into wonderfully formatted output text. */
931int
932main (argc, argv)
933 int argc;
934 char **argv;
935{
936 extern int errors_printed;
937 char *filename_part ();
938 int c, ind;
939 int reading_from_stdin = 0;
940
941 /* The name of this program is the last filename in argv[0]. */
942 progname = filename_part (argv[0]);
943
f8b2ac1e
JL
944#ifdef HAVE_SETLOCALE
945 /* Do not use LC_ALL, because LC_NUMERIC screws up the scanf parsing
946 of the argument to @multicolumn. */
947 setlocale (LC_TIME, "");
948 setlocale (LC_MESSAGES, "");
949#endif
950
951 /* Set the text message domain. */
952 bindtextdomain (PACKAGE, LOCALEDIR);
953 textdomain (PACKAGE);
954
6599da04 955 /* Parse argument flags from the input line. */
f8b2ac1e
JL
956 while ((c = getopt_long (argc, argv, "D:e:E:f:I:o:p:P:r:s:U:V",
957 long_options, &ind)) != EOF)
6599da04
JM
958 {
959 if (c == 0 && long_options[ind].flag == 0)
f8b2ac1e 960 c = long_options[ind].val;
6599da04
JM
961
962 switch (c)
f8b2ac1e
JL
963 {
964 case 'D':
965 case 'U':
966 /* User specified variable to set or clear. */
967 handle_variable_internal ((c == 'D') ? SET : CLEAR, optarg);
968 break;
969
970 case 'e':
971 /* User specified error level. */
972 if (sscanf (optarg, "%d", &max_error_level) != 1)
973 {
974 fprintf (stderr,
975 _("%s: %s arg must be numeric, not `%s'.\n"),
976 "--error-limit", progname, optarg);
977 usage (stderr, FATAL);
978 }
979 break;
980
981 case 'E':
982 /* User specified a macro expansion output file. */
983 if (!macro_expansion_output_stream)
984 {
985 macro_expansion_filename = optarg;
986 macro_expansion_output_stream
987 = strcmp (optarg, "-") == 0 ? stdout : fopen (optarg, "w");
988 if (!macro_expansion_output_stream)
989 error (_("Couldn't open macro expansion output `%s'"), optarg);
990 }
991 else
992 error (_("Cannot specify more than one macro expansion output"));
993 break;
994
995 case 'f':
996 /* User specified fill_column. */
997 if (sscanf (optarg, "%d", &fill_column) != 1)
998 {
999 fprintf (stderr,
1000 _("%s: %s arg must be numeric, not `%s'.\n"),
1001 "--fill-column", progname, optarg);
1002 usage (FATAL);
1003 }
1004 break;
1005
1006 case 'F':
1007 force++; /* Do not remove erroneous output. */
1008 break;
1009
1010 case 'h':
1011 usage (NO_ERROR);
1012 break;
1013
1014 case 'I':
1015 /* Append user-specified dir to include file path. */
1016 if (!include_files_path)
1017 include_files_path = xstrdup (".");
1018
1019 include_files_path = (char *)
1020 xrealloc (include_files_path,
1021 2 + strlen (include_files_path) + strlen (optarg));
1022 strcat (include_files_path, ":");
1023 strcat (include_files_path, optarg);
1024 break;
1025
1026 case 'o':
1027 /* User specified output file. */
1028 command_output_filename = xstrdup (optarg);
1029 break;
1030
1031 case 'p':
1032 /* User specified paragraph indent (paragraph_start_index). */
1033 if (set_paragraph_indent (optarg) < 0)
1034 {
1035 fprintf (stderr,
1036 _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"),
6599da04 1037 progname, optarg);
f8b2ac1e
JL
1038 usage (FATAL);
1039 }
1040 break;
1041
1042 case 'P':
1043 /* Prepend user-specified include dir to include path. */
1044 if (!include_files_path)
1045 {
1046 include_files_path = xstrdup (optarg);
1047 include_files_path = (char *) xrealloc (include_files_path,
1048 strlen (include_files_path) + 3); /* 3 for ":.\0" */
1049 strcat (include_files_path, ":.");
1050 }
1051 else
1052 {
1053 char *tmp = xstrdup (include_files_path);
1054 include_files_path = (char *) xrealloc (include_files_path,
1055 strlen (include_files_path) + strlen (optarg) + 2); /* 2 for ":\0" */
1056 strcpy (include_files_path, optarg);
1057 strcat (include_files_path, ":");
1058 strcat (include_files_path, tmp);
1059 free (tmp);
1060 }
1061 break;
1062
1063 case 'r':
1064 /* User specified reference warning limit. */
1065 if (sscanf (optarg, "%d", &reference_warning_limit) != 1)
1066 {
1067 fprintf (stderr,
1068 _("%s: %s arg must be numeric, not `%s'.\n"),
1069 "--reference-limit", progname, optarg);
1070 usage (FATAL);
1071 }
1072 break;
1073
1074 case 's':
1075 /* User specified footnote style. */
1076 if (set_footnote_style (optarg) < 0)
1077 {
1078 fprintf (stderr,
1079 _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"),
6599da04 1080 progname, optarg);
f8b2ac1e
JL
1081 usage (FATAL);
1082 }
1083 footnote_style_preset = 1;
1084 break;
1085
1086 case 'V':
1087 /* User requested version info. */
1088 print_version_info ();
d275726b 1089 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
6599da04
JM
1090There is NO warranty. You may redistribute this software\n\
1091under the terms of the GNU General Public License.\n\
d275726b
JL
1092For more information about these matters, see the files named COPYING.\n"),
1093 "1998");
f8b2ac1e
JL
1094 exit (NO_ERROR);
1095 break;
6599da04 1096
f8b2ac1e
JL
1097 case '?':
1098 usage (FATAL);
1099 break;
1100 }
6599da04
JM
1101 }
1102
1103 if (optind == argc)
1104 {
1105 /* Check to see if input is a file. If so, process that. */
1106 if (!isatty (fileno (stdin)))
f8b2ac1e 1107 reading_from_stdin = 1;
6599da04
JM
1108 else
1109 {
f8b2ac1e
JL
1110 fprintf (stderr, _("%s: missing file argument.\n"), progname);
1111 usage (FATAL);
6599da04
JM
1112 }
1113 }
1114
1115 /* If the user has specified --no-headers, this should imply --no-split.
1116 Do that here. I think it might also imply that we should ignore the
1117 setfilename at the top of the file, but this might break some FSF things,
1118 so I will hold off on that. */
1119 if (no_headers)
1120 {
1121 splitting = 0;
1122
f8b2ac1e 1123 /* If the user has not specified an output file, use stdout. */
6599da04 1124 if (!command_output_filename)
f8b2ac1e 1125 command_output_filename = xstrdup ("-");
6599da04
JM
1126 }
1127
1128 if (verbose_mode)
1129 print_version_info ();
1130
1131 /* Remaining arguments are file names of texinfo files.
1132 Convert them, one by one. */
1133 if (!reading_from_stdin)
1134 {
1135 while (optind != argc)
f8b2ac1e 1136 convert_from_file (argv[optind++]);
6599da04
JM
1137 }
1138 else
1139 convert_from_stream (stdin, "stdin");
1140
1141 if (errors_printed)
1142 return (SYNTAX);
1143 else
1144 return (NO_ERROR);
1145}
1146
1147/* Display the version info of this invocation of Makeinfo. */
1148void
1149print_version_info ()
1150{
d275726b 1151 printf ("makeinfo (GNU %s %s) %d.%d\n", PACKAGE, VERSION,
f8b2ac1e 1152 major_version, minor_version);
6599da04
JM
1153}
1154
6599da04
JM
1155/* If EXIT_VALUE is zero, print the full usage message to stdout.
1156 Otherwise, just say to use --help for more info.
1157 Then exit with EXIT_VALUE. */
1158void
1159usage (exit_value)
1160 int exit_value;
1161{
1162 if (exit_value != 0)
f8b2ac1e 1163 fprintf (stderr, _("Try `%s --help' for more information.\n"), progname);
6599da04 1164 else
f8b2ac1e 1165 printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n\
6599da04
JM
1166\n\
1167Translate Texinfo source documentation to a format suitable for reading\n\
1168with GNU Info.\n\
1169\n\
1170Options:\n\
1171-D VAR define a variable, as with @set.\n\
f8b2ac1e
JL
1172-E MACRO-OFILE process macros only, output texinfo source.\n\
1173-I DIR append DIR to the @include directory search path.\n\
1174-P DIR prepend DIR to the @include directory search path.\n\
6599da04
JM
1175-U VAR undefine a variable, as with @clear.\n\
1176--error-limit NUM quit after NUM errors (default %d).\n\
1177--fill-column NUM break lines at NUM characters (default %d).\n\
1178--footnote-style STYLE output footnotes according to STYLE:\n\
1179 `separate' to place footnotes in their own node,\n\
1180 `end' to place the footnotes at the end of\n\
1181 the node in which they are defined (the default).\n\
f8b2ac1e 1182--force preserve output even if errors.\n\
6599da04
JM
1183--help display this help and exit.\n\
1184--no-validate suppress node cross-reference validation.\n\
1185--no-warn suppress warnings (but not errors).\n\
1186--no-split suppress splitting of large files.\n\
1187--no-headers suppress node separators and Node: Foo headers.\n\
1188--output FILE, -o FILE output to FILE, and ignore any @setfilename.\n\
f8b2ac1e
JL
1189--paragraph-indent VAL indent paragraphs with VAL spaces (default %d).\n\
1190 if VAL is `none', do not indent; if VAL is `asis',\n\
1191 preserve any existing indentation.\n\
6599da04
JM
1192--reference-limit NUM complain about at most NUM references (default %d).\n\
1193--verbose report about what is being done.\n\
1194--version display version information and exit.\n\
1195\n\
d275726b 1196Email bug reports to bug-texinfo@gnu.org.\n\
f8b2ac1e 1197"),
d275726b
JL
1198 progname, max_error_level, fill_column,
1199 paragraph_start_indent, reference_warning_limit);
6599da04
JM
1200 exit (exit_value);
1201}
1202\f
1203/* Manipulating Lists */
1204
1205typedef struct generic_list {
1206 struct generic_list *next;
1207} GENERIC_LIST;
1208
1209/* Reverse the chain of structures in LIST. Output the new head
1210 of the chain. You should always assign the output value of this
1211 function to something, or you will lose the chain. */
1212GENERIC_LIST *
1213reverse_list (list)
1214 register GENERIC_LIST *list;
1215{
1216 register GENERIC_LIST *next;
1217 register GENERIC_LIST *prev = (GENERIC_LIST *) NULL;
1218
1219 while (list)
1220 {
1221 next = list->next;
1222 list->next = prev;
1223 prev = list;
1224 list = next;
1225 }
1226 return (prev);
1227}
1228\f
1229/* Pushing and Popping Files */
1230
1231/* Find and load the file named FILENAME. Return a pointer to
1232 the loaded file, or NULL if it can't be loaded. */
1233char *
1234find_and_load (filename)
1235 char *filename;
1236{
1237 struct stat fileinfo;
1238 long file_size;
f8b2ac1e 1239 int file = -1, count = 0;
6599da04
JM
1240 char *fullpath, *result, *get_file_info_in_path ();
1241
1242 result = fullpath = (char *)NULL;
1243
1244 fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo);
1245
1246 if (!fullpath)
1247 goto error_exit;
1248
1249 filename = fullpath;
1250 file_size = (long) fileinfo.st_size;
1251
1252 file = open (filename, O_RDONLY);
1253 if (file < 0)
1254 goto error_exit;
1255
d275726b
JL
1256 /* Load the file, with enough room for a newline and a null. */
1257 result = xmalloc (file_size + 2);
6599da04
JM
1258
1259 /* VMS stat lies about the st_size value. The actual number of
1260 readable bytes is always less than this value. The arcane
1261 mysteries of VMS/RMS are too much to probe, so this hack
1262 suffices to make things work. */
f8b2ac1e
JL
1263#if defined (VMS) || defined (WIN32)
1264#ifdef VMS
6599da04 1265 while ((n = read (file, result + count, file_size)) > 0)
f8b2ac1e
JL
1266#else /* WIN32 */
1267 while ((n = read (file, result + count, 1)) > 0)
1268#endif /* WIN32 */
6599da04
JM
1269 count += n;
1270 if (n == -1)
f8b2ac1e 1271#else /* !VMS && !WIN32 */
6599da04
JM
1272 count = file_size;
1273 if (read (file, result, file_size) != file_size)
f8b2ac1e 1274#endif /* !VMS && !WIN32 */
6599da04
JM
1275 error_exit:
1276 {
1277 if (result)
f8b2ac1e 1278 free (result);
6599da04
JM
1279
1280 if (fullpath)
f8b2ac1e 1281 free (fullpath);
6599da04
JM
1282
1283 if (file != -1)
f8b2ac1e 1284 close (file);
6599da04
JM
1285
1286 return ((char *) NULL);
1287 }
1288 close (file);
1289
1290 /* Set the globals to the new file. */
1291 input_text = result;
1292 size_of_input_text = count;
1293 input_filename = fullpath;
f8b2ac1e 1294 node_filename = xstrdup (fullpath);
6599da04
JM
1295 input_text_offset = 0;
1296 line_number = 1;
1297 /* Not strictly necessary. This magic prevents read_token () from doing
1298 extra unnecessary work each time it is called (that is a lot of times).
d275726b 1299 SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
6599da04 1300 input_text[size_of_input_text] = '\n';
d275726b
JL
1301 /* This, on the other hand, is always necessary. */
1302 input_text[size_of_input_text+1] = 0;
6599da04
JM
1303 return (result);
1304}
1305
1306/* Save the state of the current input file. */
1307void
1308pushfile ()
1309{
1310 FSTACK *newstack = (FSTACK *) xmalloc (sizeof (FSTACK));
1311 newstack->filename = input_filename;
1312 newstack->text = input_text;
1313 newstack->size = size_of_input_text;
1314 newstack->offset = input_text_offset;
1315 newstack->line_number = line_number;
1316 newstack->next = filestack;
1317
1318 filestack = newstack;
1319 push_node_filename ();
1320}
1321
1322/* Make the current file globals be what is on top of the file stack. */
1323void
1324popfile ()
1325{
1326 FSTACK *tos = filestack;
1327
1328 if (!tos)
f8b2ac1e 1329 abort (); /* My fault. I wonder what I did? */
6599da04
JM
1330
1331#if defined (HAVE_MACROS)
1332 if (macro_expansion_output_stream)
1333 {
1334 maybe_write_itext (input_text, input_text_offset);
1335 forget_itext (input_text);
1336 }
1337#endif /* HAVE_MACROS */
1338
1339 /* Pop the stack. */
1340 filestack = filestack->next;
1341
1342 /* Make sure that commands with braces have been satisfied. */
d275726b 1343 if (!executing_string && !me_executing_string)
6599da04
JM
1344 discard_braces ();
1345
1346 /* Get the top of the stack into the globals. */
1347 input_filename = tos->filename;
1348 input_text = tos->text;
1349 size_of_input_text = tos->size;
1350 input_text_offset = tos->offset;
1351 line_number = tos->line_number;
1352 free (tos);
1353
1354 /* Go back to the (now) current node. */
1355 pop_node_filename ();
1356}
1357
1358/* Flush all open files on the file stack. */
1359void
1360flush_file_stack ()
1361{
1362 while (filestack)
1363 {
1364 char *fname = input_filename;
1365 char *text = input_text;
1366 popfile ();
1367 free (fname);
1368 free (text);
1369 }
1370}
1371
1372int node_filename_stack_index = 0;
1373int node_filename_stack_size = 0;
1374char **node_filename_stack = (char **)NULL;
1375
1376void
1377push_node_filename ()
1378{
1379 if (node_filename_stack_index + 1 > node_filename_stack_size)
1380 node_filename_stack = (char **)xrealloc
1381 (node_filename_stack, (node_filename_stack_size += 10) * sizeof (char *));
1382
1383 node_filename_stack[node_filename_stack_index] = node_filename;
1384 node_filename_stack_index++;
1385}
1386
1387void
1388pop_node_filename ()
1389{
1390 node_filename = node_filename_stack[--node_filename_stack_index];
1391}
1392
1393/* Return just the simple part of the filename; i.e. the
1394 filename without the path information, or extensions.
1395 This conses up a new string. */
1396char *
1397filename_part (filename)
1398 char *filename;
1399{
1400 char *basename;
1401
1402 basename = strrchr (filename, '/');
1403 if (!basename)
1404 basename = filename;
1405 else
1406 basename++;
1407
f8b2ac1e 1408 basename = xstrdup (basename);
6599da04
JM
1409#if defined (REMOVE_OUTPUT_EXTENSIONS)
1410
1411 /* See if there is an extension to remove. If so, remove it. */
1412 {
1413 char *temp;
1414
1415 temp = strrchr (basename, '.');
1416 if (temp)
f8b2ac1e 1417 *temp = 0;
6599da04
JM
1418 }
1419#endif /* REMOVE_OUTPUT_EXTENSIONS */
1420 return (basename);
1421}
1422
1423/* Return the pathname part of filename. This can be NULL. */
1424char *
1425pathname_part (filename)
1426 char *filename;
1427{
1428 char *expand_filename ();
1429 char *result = (char *) NULL;
1430 register int i;
1431
1432 filename = expand_filename (filename, "");
1433
1434 i = strlen (filename) - 1;
1435
1436 while (i && filename[i] != '/')
1437 i--;
1438 if (filename[i] == '/')
1439 i++;
1440
1441 if (i)
1442 {
1443 result = (char *)xmalloc (1 + i);
1444 strncpy (result, filename, i);
f8b2ac1e 1445 result[i] = 0;
6599da04
JM
1446 }
1447 free (filename);
1448 return (result);
1449}
1450
1451char *
1452filename_non_directory (name)
1453 char *name;
1454{
1455 register int i;
1456
1457 for (i = strlen (name) - 1; i; i--)
1458 if (name[i] == '/')
f8b2ac1e 1459 return (xstrdup (name + i + 1));
6599da04 1460
f8b2ac1e 1461 return (xstrdup (name));
6599da04
JM
1462}
1463
1464/* Return the expansion of FILENAME. */
1465char *
1466expand_filename (filename, input_name)
1467 char *filename, *input_name;
1468{
1469 register int i;
1470 char *full_pathname ();
1471
1472 if (filename)
1473 filename = full_pathname (filename);
1474 else
1475 {
1476 filename = filename_non_directory (input_name);
1477
1478 if (!*filename)
f8b2ac1e
JL
1479 {
1480 free (filename);
1481 filename = xstrdup ("noname.texi");
1482 }
6599da04
JM
1483
1484 for (i = strlen (filename) - 1; i; i--)
f8b2ac1e
JL
1485 if (filename[i] == '.')
1486 break;
6599da04
JM
1487
1488 if (!i)
f8b2ac1e 1489 i = strlen (filename);
6599da04
JM
1490
1491 if (i + 6 > (strlen (filename)))
f8b2ac1e 1492 filename = (char *)xrealloc (filename, i + 6);
6599da04
JM
1493 strcpy (filename + i, ".info");
1494 return (filename);
1495 }
f8b2ac1e 1496
6599da04
JM
1497 if (filename[0] == '.' || filename[0] == '/')
1498 return (filename);
1499
1500 if (filename[0] != '/' && input_name[0] == '/')
1501 {
1502 /* Make it so that relative names work. */
1503 char *result;
1504
1505 i = strlen (input_name) - 1;
1506
1507 result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
1508 strcpy (result, input_name);
1509
1510 while (result[i] != '/' && i)
f8b2ac1e 1511 i--;
6599da04
JM
1512
1513 if (result[i] == '/')
f8b2ac1e 1514 i++;
6599da04
JM
1515
1516 strcpy (&result[i], filename);
1517 free (filename);
1518 return (result);
1519 }
1520 return (filename);
1521}
1522
1523/* Return the full path to FILENAME. */
1524char *
1525full_pathname (filename)
1526 char *filename;
1527{
1528 int initial_character;
1529 char *result;
1530
1531 /* No filename given? */
1532 if (!filename || !(initial_character = *filename))
f8b2ac1e 1533 return (xstrdup (""));
6599da04
JM
1534
1535 /* Already absolute? */
1536 if ((initial_character == '/') ||
1537 ((strncmp (filename, "./", 2) == 0) ||
1538 (strncmp (filename, "../", 3) == 0)))
f8b2ac1e 1539 return (xstrdup (filename));
6599da04
JM
1540
1541 if (initial_character != '~')
1542 {
1543 char *localdir;
1544
1545 localdir = (char *)xmalloc (1025);
1546#if defined (HAVE_GETCWD)
1547 if (!getcwd (localdir, 1024))
1548#else /* !HAVE_GETCWD */
f8b2ac1e 1549 if (!getwd (localdir))
6599da04 1550#endif /* !HAVE_GETCWD */
f8b2ac1e
JL
1551 {
1552 fprintf (stderr, _("%s: getwd: %s, %s\n"),
1553 progname, filename, localdir);
1554 exit (1);
1555 }
6599da04
JM
1556
1557 strcat (localdir, "/");
1558 strcat (localdir, filename);
f8b2ac1e 1559 result = xstrdup (localdir);
6599da04
JM
1560 free (localdir);
1561 }
1562 else
1563 {
f8b2ac1e 1564#ifndef WIN32
6599da04 1565 if (filename[1] == '/')
f8b2ac1e
JL
1566 {
1567 /* Return the concatenation of the environment variable HOME
1568 and the rest of the string. */
1569 char *temp_home;
1570
1571 temp_home = (char *) getenv ("HOME");
1572 result = (char *)xmalloc (strlen (&filename[1])
1573 + 1
1574 + temp_home ? strlen (temp_home)
1575 : 0);
1576 *result = 0;
1577
1578 if (temp_home)
1579 strcpy (result, temp_home);
1580
1581 strcat (result, &filename[1]);
1582 }
6599da04 1583 else
f8b2ac1e
JL
1584 {
1585 struct passwd *user_entry;
1586 int i, c;
1587 char *username = (char *)xmalloc (257);
1588
1589 for (i = 1; (c = filename[i]); i++)
1590 {
1591 if (c == '/')
1592 break;
1593 else
1594 username[i - 1] = c;
1595 }
1596 if (c)
1597 username[i - 1] = 0;
1598
1599 user_entry = getpwnam (username);
1600
1601 if (!user_entry)
1602 return (xstrdup (filename));
1603
1604 result = (char *)xmalloc (1 + strlen (user_entry->pw_dir)
1605 + strlen (&filename[i]));
1606 strcpy (result, user_entry->pw_dir);
1607 strcat (result, &filename[i]);
1608 }
6599da04 1609 }
f8b2ac1e 1610#endif /* not WIN32 */
6599da04
JM
1611 return (result);
1612}
1613
1614char *
1615output_name_from_input_name (name)
1616 char *name;
1617{
1618 return (expand_filename ((char *)NULL, name));
1619}
1620\f
1621/* **************************************************************** */
f8b2ac1e
JL
1622/* */
1623/* Hacking Tokens and Strings */
1624/* */
6599da04
JM
1625/* **************************************************************** */
1626
1627/* Return the next token as a string pointer. We cons the string. */
1628char *
1629read_token ()
1630{
1631 int i, character;
1632 char *result;
1633
1634 /* If the first character to be read is self-delimiting, then that
1635 is the command itself. */
1636 character = curchar ();
1637 if (self_delimiting (character))
1638 {
1639 input_text_offset++;
1640
1641 if (character == '\n')
f8b2ac1e 1642 line_number++;
6599da04 1643
f8b2ac1e 1644 result = xstrdup (" ");
6599da04
JM
1645 *result = character;
1646 return (result);
1647 }
1648
1649 for (i = 0; ((input_text_offset != size_of_input_text)
f8b2ac1e
JL
1650 && (character = curchar ())
1651 && command_char (character));
6599da04
JM
1652 i++, input_text_offset++);
1653 result = (char *)xmalloc (i + 1);
1654 memcpy (result, &input_text[input_text_offset - i], i);
f8b2ac1e 1655 result[i] = 0;
6599da04
JM
1656 return (result);
1657}
1658
f8b2ac1e 1659/* Return nonzero if CHARACTER is self-delimiting. */
6599da04
JM
1660int
1661self_delimiting (character)
1662 int character;
1663{
1664 /* @; and @\ are not Texinfo commands, but they are listed here
1665 anyway. I don't know why. --karl, 10aug96. */
1666 return member (character, "~{|}`^\\@?=;:.-,*\'\" !\n\t");
1667}
1668
1669/* Clear whitespace from the front and end of string. */
1670void
1671canon_white (string)
1672 char *string;
1673{
1674 int len = strlen (string);
1675 int x;
1676
1677 if (!len)
1678 return;
1679
1680 for (x = 0; x < len; x++)
1681 {
1682 if (!cr_or_whitespace (string[x]))
f8b2ac1e
JL
1683 {
1684 strcpy (string, string + x);
1685 break;
1686 }
6599da04
JM
1687 }
1688 len = strlen (string);
1689 if (len)
1690 len--;
1691 while (len > -1 && cr_or_whitespace (string[len]))
1692 len--;
f8b2ac1e 1693 string[len + 1] = 0;
6599da04
JM
1694}
1695
1696/* Bash STRING, replacing all whitespace with just one space. */
1697void
1698fix_whitespace (string)
1699 char *string;
1700{
1701 char *temp = (char *)xmalloc (strlen (string) + 1);
1702 int string_index = 0;
1703 int temp_index = 0;
1704 int c;
1705
1706 canon_white (string);
1707
1708 while (string[string_index])
1709 {
1710 c = temp[temp_index++] = string[string_index++];
1711
1712 if (c == ' ' || c == '\n' || c == '\t')
f8b2ac1e
JL
1713 {
1714 temp[temp_index - 1] = ' ';
1715 while ((c = string[string_index]) && (c == ' ' ||
1716 c == '\t' ||
1717 c == '\n'))
1718 string_index++;
1719 }
1720 }
1721 temp[temp_index] = 0;
6599da04
JM
1722 strcpy (string, temp);
1723 free (temp);
1724}
1725
1726/* Discard text until the desired string is found. The string is
1727 included in the discarded text. */
1728void
1729discard_until (string)
1730 char *string;
1731{
1732 int temp = search_forward (string, input_text_offset);
1733
1734 int tt = (temp < 0) ? size_of_input_text : temp + strlen (string);
1735 int from = input_text_offset;
1736
1737 /* Find out what line we are on. */
1738 while (from != tt)
1739 if (input_text[from++] == '\n')
1740 line_number++;
1741
1742 if (temp < 0)
1743 {
1744 input_text_offset = size_of_input_text - strlen (string);
1745
1746 if (strcmp (string, "\n") != 0)
f8b2ac1e
JL
1747 {
1748 line_error (_("Expected `%s'"), string);
1749 return;
1750 }
6599da04
JM
1751 }
1752 else
1753 input_text_offset = temp;
1754
1755 input_text_offset += strlen (string);
1756}
1757
1758/* Read characters from the file until we are at MATCH.
1759 Place the characters read into STRING.
1760 On exit input_text_offset is after the match string.
1761 Return the offset where the string starts. */
1762int
1763get_until (match, string)
1764 char *match, **string;
1765{
1766 int len, current_point, x, new_point, tem;
1767
1768 current_point = x = input_text_offset;
1769 new_point = search_forward (match, input_text_offset);
1770
1771 if (new_point < 0)
1772 new_point = size_of_input_text;
1773 len = new_point - current_point;
1774
1775 /* Keep track of which line number we are at. */
1776 tem = new_point + (strlen (match) - 1);
1777 while (x != tem)
1778 if (input_text[x++] == '\n')
1779 line_number++;
1780
1781 *string = (char *)xmalloc (len + 1);
1782
1783 memcpy (*string, &input_text[current_point], len);
f8b2ac1e 1784 (*string)[len] = 0;
6599da04
JM
1785
1786 /* Now leave input_text_offset in a consistent state. */
1787 input_text_offset = tem;
1788
1789 if (input_text_offset > size_of_input_text)
1790 input_text_offset = size_of_input_text;
1791
1792 return (new_point);
1793}
1794
1795/* Read characters from the file until we are at MATCH or end of line.
1796 Place the characters read into STRING. */
1797void
f8b2ac1e
JL
1798get_until_in_line (expand, match, string)
1799 int expand;
6599da04
JM
1800 char *match, **string;
1801{
f8b2ac1e
JL
1802 int real_bottom = size_of_input_text;
1803 int limit = search_forward ("\n", input_text_offset);
1804 if (limit < 0)
1805 limit = size_of_input_text;
1806
1807 /* Replace input_text[input_text_offset .. limit-1] with its macro
1808 expansion (actually, we expand all commands). This allows the node
1809 names themselves to be constructed via a macro, as in:
1810 @macro foo{p, q}
1811 Together: \p\ & \q\.
1812 @end macro
1813
1814 @node @foo{A,B}, next, prev, top
1815
1816 Otherwise, the `,' separating the macro args A and B is taken as
1817 the node argument separator, so the node name is `@foo{A'. This
1818 expansion is only necessary on the first call, since we expand the
1819 whole line then.
1820
1821 Furthermore, if we're executing a string, don't do it -- we'll end
1822 up shrinking the execution string which is currently aliased to
1823 `input_text', so it might get moved, and not updated in the
1824 `execution_strings' array. This happens when processing the
1825 (synthetic) Overview-Footnotes node in the Texinfo manual. */
1826
d275726b 1827 if (expand && !executing_string && !me_executing_string)
f8b2ac1e
JL
1828 {
1829 char *xp;
1830 unsigned xp_len, new_len;
1831
1832 /* Get original string from input. */
1833 unsigned raw_len = limit - input_text_offset;
1834 char *str = xmalloc (raw_len + 1);
1835 strncpy (str, input_text + input_text_offset, raw_len);
1836 str[raw_len] = 0;
1837
1838 /* Expand it. */
1839 xp = expansion (str, 0);
1840 xp_len = strlen (xp);
1841 free (str);
1842
d275726b
JL
1843 /* Plunk the expansion into the middle of `input_text' --
1844 which is terminated by a newline, not a null. */
1845 str = xmalloc (real_bottom - limit + 1);
1846 strncpy (str, input_text + limit, real_bottom - limit + 1);
1847 new_len = input_text_offset + xp_len + real_bottom - limit + 1;
f8b2ac1e
JL
1848 input_text = xrealloc (input_text, new_len);
1849 strcpy (input_text + input_text_offset, xp);
d275726b
JL
1850 strncpy (input_text + input_text_offset + xp_len, str,
1851 real_bottom - limit + 1);
f8b2ac1e
JL
1852 free (str);
1853 free (xp);
1854
1855 limit += xp_len - raw_len;
1856 real_bottom += xp_len - raw_len;
1857 }
6599da04 1858
f8b2ac1e 1859 size_of_input_text = limit;
6599da04
JM
1860 get_until (match, string);
1861 size_of_input_text = real_bottom;
1862}
1863
1864void
1865get_rest_of_line (string)
1866 char **string;
1867{
1868 get_until ("\n", string);
1869 canon_white (*string);
1870
f8b2ac1e 1871 if (curchar () == '\n') /* as opposed to the end of the file... */
6599da04
JM
1872 {
1873 line_number++;
1874 input_text_offset++;
1875 }
1876}
1877
1878/* Backup the input pointer to the previous character, keeping track
1879 of the current line number. */
1880void
1881backup_input_pointer ()
1882{
1883 if (input_text_offset)
1884 {
1885 input_text_offset--;
1886 if (curchar () == '\n')
f8b2ac1e 1887 line_number--;
6599da04
JM
1888 }
1889}
1890
1891/* Read characters from the file until we are at MATCH or closing brace.
1892 Place the characters read into STRING. */
1893void
1894get_until_in_braces (match, string)
1895 char *match, **string;
1896{
f8b2ac1e 1897 char *temp;
6599da04
JM
1898 int i, brace = 0;
1899 int match_len = strlen (match);
6599da04
JM
1900
1901 for (i = input_text_offset; i < size_of_input_text; i++)
1902 {
1903 if (input_text[i] == '{')
f8b2ac1e 1904 brace++;
6599da04 1905 else if (input_text[i] == '}')
f8b2ac1e 1906 brace--;
6599da04 1907 else if (input_text[i] == '\n')
f8b2ac1e 1908 line_number++;
6599da04
JM
1909
1910 if (brace < 0 ||
f8b2ac1e
JL
1911 (brace == 0 && strncmp (input_text + i, match, match_len) == 0))
1912 break;
6599da04
JM
1913 }
1914
1915 match_len = i - input_text_offset;
1916 temp = (char *)xmalloc (2 + match_len);
1917 strncpy (temp, input_text + input_text_offset, match_len);
f8b2ac1e 1918 temp[match_len] = 0;
6599da04
JM
1919 input_text_offset = i;
1920 *string = temp;
1921}
1922\f
1923/* **************************************************************** */
f8b2ac1e
JL
1924/* */
1925/* Converting the File */
1926/* */
6599da04
JM
1927/* **************************************************************** */
1928
1929/* Convert the file named by NAME. The output is saved on the file
1930 named as the argument to the @setfilename command. */
1931static char *suffixes[] = {
1932 ".texinfo",
1933 ".texi",
1934 ".txinfo",
1935 "",
1936 (char *)NULL
1937};
1938
1939void
1940initialize_conversion ()
1941{
1942 init_tag_table ();
1943 init_indices ();
1944 init_internals ();
1945 init_paragraph ();
1946
1947 /* This is used for splitting the output file and for doing section
1948 headings. It was previously initialized in `init_paragraph', but its
1949 use there loses with the `init_paragraph' calls done by the
1950 multitable code; the tag indices get reset to zero. */
1951 output_position = 0;
1952}
1953
1954/* We read in multiples of 4k, simply because it is a typical pipe size
1955 on unix systems. */
1956#define READ_BUFFER_GROWTH (4 * 4096)
1957
f8b2ac1e 1958/* Convert the Texinfo file coming from the open stream STREAM. Assume the
6599da04
JM
1959 source of the stream is named NAME. */
1960void
1961convert_from_stream (stream, name)
1962 FILE *stream;
1963 char *name;
1964{
34b6478b
JL
1965 char *buffer = (char *)NULL;
1966 int buffer_offset = 0, buffer_size = 0;
6599da04
JM
1967
1968 initialize_conversion ();
1969
1970 /* Read until the end of the stream. This isn't strictly correct, since
1971 the texinfo input may end before the stream ends, but it is a quick
34b6478b 1972 working hueristic. */
6599da04
JM
1973 while (!feof (stream))
1974 {
1975 int count;
1976
f8b2ac1e
JL
1977 if (buffer_offset + (READ_BUFFER_GROWTH + 1) >= buffer_size)
1978 buffer = (char *)
1979 xrealloc (buffer, (buffer_size += READ_BUFFER_GROWTH));
6599da04
JM
1980
1981 count = fread (buffer + buffer_offset, 1, READ_BUFFER_GROWTH, stream);
1982
1983 if (count < 0)
f8b2ac1e
JL
1984 {
1985 perror (name);
1986 exit (FATAL);
1987 }
6599da04
JM
1988
1989 buffer_offset += count;
1990 if (count == 0)
f8b2ac1e 1991 break;
6599da04
JM
1992 }
1993
1994 /* Set the globals to the new file. */
1995 input_text = buffer;
1996 size_of_input_text = buffer_offset;
f8b2ac1e
JL
1997 input_filename = xstrdup (name);
1998 node_filename = xstrdup (name);
6599da04
JM
1999 input_text_offset = 0;
2000 line_number = 1;
2001
2002 /* Not strictly necessary. This magic prevents read_token () from doing
2003 extra unnecessary work each time it is called (that is a lot of times).
2004 The SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
2005 input_text[size_of_input_text] = '\n';
2006
2007 convert_from_loaded_file (name);
2008}
2009
2010void
2011convert_from_file (name)
2012 char *name;
2013{
2014 register int i;
2015 char *filename = (char *)xmalloc (strlen (name) + 50);
2016
2017 initialize_conversion ();
2018
2019 /* Try to load the file specified by NAME, concatenated with our
2020 various suffixes. Prefer files like `makeinfo.texi' to
2021 `makeinfo'. */
2022 for (i = 0; suffixes[i]; i++)
2023 {
2024 strcpy (filename, name);
2025 strcat (filename, suffixes[i]);
2026
2027 if (find_and_load (filename))
f8b2ac1e 2028 break;
6599da04
JM
2029
2030 if (!suffixes[i][0] && strrchr (filename, '.'))
f8b2ac1e
JL
2031 {
2032 fs_error (filename);
2033 free (filename);
2034 return;
2035 }
6599da04
JM
2036 }
2037
2038 if (!suffixes[i])
2039 {
2040 fs_error (name);
2041 free (filename);
2042 return;
2043 }
2044
2045 input_filename = filename;
2046
2047 convert_from_loaded_file (name);
2048}
2049
2050void
2051convert_from_loaded_file (name)
2052 char *name;
2053{
2054 char *expand_filename (), *filename_part ();
2055 char *real_output_filename = (char *)NULL;
2056
2057#if defined (HAVE_MACROS)
2058 remember_itext (input_text, 0);
2059#endif /* HAVE_MACROS */
2060
2061 /* Search this file looking for the special string which starts conversion.
2062 Once found, we may truly begin. */
2063 input_text_offset = 0;
2064 while (input_text_offset >= 0)
2065 {
2066 input_text_offset =
f8b2ac1e 2067 search_forward (setfilename_search, input_text_offset);
6599da04
JM
2068
2069 if ((input_text_offset == 0) ||
f8b2ac1e
JL
2070 ((input_text_offset > 0) &&
2071 (input_text[input_text_offset -1] == '\n')))
2072 break;
6599da04 2073 else if (input_text_offset > 0)
f8b2ac1e 2074 input_text_offset++;
6599da04
JM
2075 }
2076
2077 if (input_text_offset < 0)
2078 {
2079 if (!command_output_filename)
f8b2ac1e 2080 {
6599da04 2081#if defined (REQUIRE_SETFILENAME)
f8b2ac1e
JL
2082 error (_("No `%s' found in `%s'"), setfilename_search, name);
2083 goto finished;
6599da04 2084#else
f8b2ac1e
JL
2085 register int i, end_of_first_line;
2086
2087 /* Find the end of the first line in the file. */
2088 for (i = 0; i < size_of_input_text - 1; i++)
2089 if (input_text[i] == '\n')
2090 break;
2091
2092 end_of_first_line = i + 1;
2093
2094 input_text_offset = 0;
2095
2096 for (i = 0; i < end_of_first_line; i++)
2097 {
2098 if ((input_text[i] == '\\') &&
2099 (strncmp (input_text + i + 1, "include", 7) == 0))
2100 {
2101 input_text_offset = end_of_first_line;
2102 break;
2103 }
2104 }
2105 command_output_filename = output_name_from_input_name (name);
6599da04 2106#endif /* !REQUIRE_SETFILENAME */
f8b2ac1e 2107 }
6599da04
JM
2108 }
2109 else
2110 input_text_offset += strlen (setfilename_search);
2111
2112 if (!command_output_filename)
2113 get_until ("\n", &output_filename);
2114 else
2115 {
2116 if (input_text_offset != -1)
f8b2ac1e 2117 discard_until ("\n");
6599da04 2118 else
f8b2ac1e 2119 input_text_offset = 0;
6599da04
JM
2120
2121 real_output_filename = output_filename = command_output_filename;
2122 command_output_filename = (char *)NULL;
2123 }
2124
2125 canon_white (output_filename);
2126
f8b2ac1e 2127 if (real_output_filename && strcmp (real_output_filename, "-") == 0)
6599da04 2128 {
f8b2ac1e
JL
2129 if (macro_expansion_filename
2130 && strcmp (macro_expansion_filename, "-") == 0)
2131 {
2132 fprintf (stderr, _("%s: Skipping macro expansion to stdout as Info output is going there.\n"),
2133 progname);
2134 macro_expansion_output_stream = NULL;
2135 }
2136 real_output_filename = xstrdup (real_output_filename);
6599da04 2137 output_stream = stdout;
f8b2ac1e 2138 splitting = 0; /* Cannot split when writing to stdout. */
6599da04
JM
2139 }
2140 else
2141 {
2142 if (!real_output_filename)
f8b2ac1e 2143 real_output_filename = expand_filename (output_filename, name);
6599da04 2144 else
f8b2ac1e 2145 real_output_filename = xstrdup (real_output_filename);
6599da04
JM
2146
2147 output_stream = fopen (real_output_filename, "w");
2148 }
2149
2150 if (output_stream != stdout)
f8b2ac1e 2151 printf (_("Making %s file `%s' from `%s'.\n"),
6599da04
JM
2152 no_headers ? "text" : "info", output_filename, input_filename);
2153
2154 if (output_stream == NULL)
2155 {
2156 fs_error (real_output_filename);
2157 goto finished;
2158 }
2159
2160 /* Make the displayable filename from output_filename. Only the base
2161 portion of the filename need be displayed. */
2162 if (output_stream != stdout)
2163 pretty_output_filename = filename_part (output_filename);
2164 else
f8b2ac1e 2165 pretty_output_filename = xstrdup ("stdout");
6599da04
JM
2166
2167 /* For this file only, count the number of newlines from the top of
2168 the file to here. This way, we keep track of line numbers for
2169 error reporting. Line_number starts at 1, since the user isn't
2170 zero-based. */
2171 {
2172 int temp = 0;
2173 line_number = 1;
2174 while (temp != input_text_offset)
2175 if (input_text[temp++] == '\n')
f8b2ac1e 2176 line_number++;
6599da04
JM
2177 }
2178
2179 if (!no_headers)
2180 {
f8b2ac1e
JL
2181 add_word_args (_("This is Info file %s, produced by Makeinfo version %d.%d"),
2182 output_filename, major_version, minor_version);
2183 add_word_args (_(" from the input file %s.\n"), input_filename);
6599da04
JM
2184 }
2185
2186 close_paragraph ();
2187 reader_loop ();
2188
2189finished:
f8b2ac1e 2190 discard_insertions (0);
6599da04
JM
2191 close_paragraph ();
2192 flush_file_stack ();
2193
2194#if defined (HAVE_MACROS)
2195 if (macro_expansion_output_stream)
f8b2ac1e
JL
2196 {
2197 fclose (macro_expansion_output_stream);
2198 if (errors_printed && !force
2199 && strcmp (macro_expansion_filename, "-") != 0
2200 && strcmp (macro_expansion_filename, "/dev/null") != 0)
2201 {
2202 fprintf (stderr, _("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
2203 progname, macro_expansion_filename);
2204 if (unlink (macro_expansion_filename) < 0)
2205 perror (macro_expansion_filename);
2206 }
2207 }
6599da04
JM
2208#endif /* HAVE_MACROS */
2209
f8b2ac1e 2210 if (output_stream)
6599da04
JM
2211 {
2212 output_pending_notes ();
2213 free_pending_notes ();
2214 if (tag_table != NULL)
f8b2ac1e
JL
2215 {
2216 tag_table = (TAG_ENTRY *) reverse_list (tag_table);
2217 if (!no_headers)
2218 write_tag_table ();
2219 }
6599da04
JM
2220
2221 if (output_stream != stdout)
f8b2ac1e 2222 fclose (output_stream);
6599da04
JM
2223
2224 /* If validating, then validate the entire file right now. */
2225 if (validating)
f8b2ac1e
JL
2226 validate_file (tag_table);
2227
2228 if (splitting && (!errors_printed || force))
2229 split_file (real_output_filename, 0);
2230 else if (errors_printed && !force
2231 && strcmp (real_output_filename, "-") != 0
2232 && strcmp (real_output_filename, "/dev/null") != 0)
2233 { /* If there were errors, and no --force, remove the output. */
2234 fprintf (stderr, _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
2235 progname, real_output_filename);
2236 if (unlink (real_output_filename) < 0)
2237 perror (real_output_filename);
2238 }
6599da04
JM
2239 }
2240 free (real_output_filename);
2241}
2242
2243void
2244free_and_clear (pointer)
2245 char **pointer;
2246{
f8b2ac1e 2247 if (*pointer)
6599da04
JM
2248 {
2249 free (*pointer);
2250 *pointer = (char *) NULL;
2251 }
2252}
2253
2254 /* Initialize some state. */
2255void
2256init_internals ()
2257{
6599da04
JM
2258 free_and_clear (&output_filename);
2259 free_and_clear (&command);
2260 free_and_clear (&input_filename);
2261 free_node_references ();
2262 init_insertion_stack ();
2263 init_brace_stack ();
f8b2ac1e 2264 current_node = NULL; /* sometimes already freed */
6599da04
JM
2265 command_index = 0;
2266 in_menu = 0;
2267 in_detailmenu = 0;
2268 top_node_seen = 0;
2269 non_top_node_seen = 0;
2270}
2271
2272void
2273init_paragraph ()
2274{
2275 free_and_clear (&output_paragraph);
2276 output_paragraph = (unsigned char *)xmalloc (paragraph_buffer_len);
f8b2ac1e 2277 output_paragraph[0] = 0;
6599da04
JM
2278 output_paragraph_offset = 0;
2279 output_column = 0;
2280 paragraph_is_open = 0;
2281 current_indent = 0;
2282}
2283
2284/* Okay, we are ready to start the conversion. Call the reader on
2285 some text, and fill the text as it is output. Handle commands by
2286 remembering things like open braces and the current file position on a
2287 stack, and when the corresponding close brace is found, you can call
2288 the function with the proper arguments. */
2289void
2290reader_loop ()
2291{
2292 int character;
2293 int done = 0;
2294 int dash_count = 0;
2295
2296 while (!done)
2297 {
2298 if (input_text_offset >= size_of_input_text)
f8b2ac1e 2299 break;
6599da04
JM
2300
2301 character = curchar ();
2302
2303 if (!in_fixed_width_font &&
f8b2ac1e
JL
2304 (character == '\'' || character == '`') &&
2305 input_text[input_text_offset + 1] == character)
2306 {
2307 input_text_offset++;
2308 character = '"';
2309 }
6599da04
JM
2310
2311 if (character == '-')
f8b2ac1e
JL
2312 {
2313 dash_count++;
2314 if (dash_count == 2 && !in_fixed_width_font)
2315 {
2316 input_text_offset++;
2317 continue;
2318 }
2319 }
6599da04 2320 else
f8b2ac1e
JL
2321 {
2322 dash_count = 0;
2323 }
6599da04
JM
2324
2325 /* If this is a whitespace character, then check to see if the line
f8b2ac1e 2326 is blank. If so, advance to the carriage return. */
6599da04 2327 if (whitespace (character))
f8b2ac1e
JL
2328 {
2329 register int i = input_text_offset + 1;
6599da04 2330
f8b2ac1e
JL
2331 while (i < size_of_input_text && whitespace (input_text[i]))
2332 i++;
6599da04 2333
f8b2ac1e
JL
2334 if (i == size_of_input_text || input_text[i] == '\n')
2335 {
2336 if (i == size_of_input_text)
2337 i--;
6599da04 2338
f8b2ac1e
JL
2339 input_text_offset = i;
2340 character = curchar ();
2341 }
2342 }
6599da04
JM
2343
2344 if (character == '\n')
f8b2ac1e
JL
2345 {
2346 line_number++;
2347
2348 /* Check for a menu entry here, since the "escape sequence"
2349 that begins menu entries is "\n* ". */
2350 if (in_menu && input_text_offset + 1 < size_of_input_text)
2351 {
2352 char *glean_node_from_menu (), *tem;
2353
2354 /* Note that the value of TEM is discarded, since it is
2355 gauranteed to be NULL when glean_node_from_menu () is
2356 called with a Nonzero argument. */
2357 if (!in_detailmenu)
2358 tem = glean_node_from_menu (1);
2359 }
2360 }
6599da04
JM
2361
2362 switch (character)
f8b2ac1e
JL
2363 {
2364 case COMMAND_PREFIX:
2365 read_command ();
2366 break;
2367
2368 case '{':
2369 /* Special case. I'm not supposed to see this character by itself.
2370 If I do, it means there is a syntax error in the input text.
2371 Report the error here, but remember this brace on the stack so
2372 you can ignore its partner. */
2373
2374 line_error (_("Misplaced %c"), '{');
2375 remember_brace (misplaced_brace);
2376
2377 /* Don't advance input_text_offset since this happens in
2378 remember_brace ().
2379 input_text_offset++;
6599da04 2380 */
f8b2ac1e 2381 break;
6599da04 2382
f8b2ac1e
JL
2383 case '}':
2384 pop_and_call_brace ();
2385 input_text_offset++;
2386 break;
6599da04 2387
f8b2ac1e
JL
2388 default:
2389 add_char (character);
2390 input_text_offset++;
2391 }
6599da04
JM
2392 }
2393#if defined (HAVE_MACROS)
2394 if (macro_expansion_output_stream)
2395 maybe_write_itext (input_text, input_text_offset);
2396#endif /* HAVE_MACROS */
2397}
2398
2399/* Find the command corresponding to STRING. If the command
2400 is found, return a pointer to the data structure. Otherwise
2401 return (-1). */
2402COMMAND *
2403get_command_entry (string)
2404 char *string;
2405{
2406 register int i;
2407
f8b2ac1e
JL
2408 for (i = 0; command_table[i].name; i++)
2409 if (strcmp (command_table[i].name, string) == 0)
2410 return (&command_table[i]);
6599da04
JM
2411
2412 /* This command is not in our predefined command table. Perhaps
2413 it is a user defined command. */
2414 for (i = 0; i < user_command_array_len; i++)
2415 if (user_command_array[i] &&
f8b2ac1e 2416 (strcmp (user_command_array[i]->name, string) == 0))
6599da04
JM
2417 return (user_command_array[i]);
2418
f8b2ac1e 2419 /* We never heard of this command. */
6599da04
JM
2420 return ((COMMAND *) -1);
2421}
2422
2423/* input_text_offset is right at the command prefix character.
2424 Read the next token to determine what to do. */
2425void
2426read_command ()
2427{
2428 COMMAND *entry;
2429
2430 input_text_offset++;
2431 free_and_clear (&command);
2432 command = read_token ();
2433
2434#if defined (HAVE_MACROS)
2435 /* Check to see if this command is a macro. If so, execute it here. */
2436 {
2437 MACRO_DEF *def;
2438
2439 def = find_macro (command);
2440
2441 if (def)
2442 {
f8b2ac1e
JL
2443 /* We disallow recursive use of a macro call. Inhibit the expansion
2444 of this macro during the life of its execution. */
2445 if (!(def->flags & ME_RECURSE))
2446 def->inhibited = 1;
6599da04 2447
f8b2ac1e 2448 execute_macro (def);
6599da04 2449
f8b2ac1e
JL
2450 if (!(def->flags & ME_RECURSE))
2451 def->inhibited = 0;
6599da04 2452
f8b2ac1e 2453 return;
6599da04
JM
2454 }
2455 }
2456#endif /* HAVE_MACROS */
2457
2458 entry = get_command_entry (command);
6599da04
JM
2459 if (entry == (COMMAND *)-1)
2460 {
f8b2ac1e 2461 line_error (_("Unknown command `%s'"), command);
6599da04
JM
2462 return;
2463 }
2464
2465 if (entry->argument_in_braces)
2466 remember_brace (entry->proc);
2467
2468 (*(entry->proc)) (START, output_paragraph_offset, 0);
2469}
2470
2471/* Return the string which invokes PROC; a pointer to a function. */
2472char *
2473find_proc_name (proc)
2474 COMMAND_FUNCTION *proc;
2475{
2476 register int i;
2477
f8b2ac1e
JL
2478 for (i = 0; command_table[i].name; i++)
2479 if (proc == command_table[i].proc)
2480 return command_table[i].name;
2481 return _("NO_NAME!");
6599da04
JM
2482}
2483
2484void
2485init_brace_stack ()
2486{
2487 brace_stack = (BRACE_ELEMENT *) NULL;
2488}
2489
2490void
2491remember_brace (proc)
2492 COMMAND_FUNCTION *proc;
2493{
2494 if (curchar () != '{')
f8b2ac1e 2495 line_error (_("%c%s expected `{...}'"), COMMAND_PREFIX, command);
6599da04
JM
2496 else
2497 input_text_offset++;
2498 remember_brace_1 (proc, output_paragraph_offset);
2499}
2500
2501/* Remember the current output position here. Save PROC
2502 along with it so you can call it later. */
2503void
2504remember_brace_1 (proc, position)
2505 COMMAND_FUNCTION *proc;
2506 int position;
2507{
2508 BRACE_ELEMENT *new = (BRACE_ELEMENT *) xmalloc (sizeof (BRACE_ELEMENT));
2509 new->next = brace_stack;
2510 new->proc = proc;
2511 new->pos = position;
2512 new->line = line_number;
2513 new->in_fixed_width_font = in_fixed_width_font;
2514 brace_stack = new;
2515}
2516
2517/* Pop the top of the brace stack, and call the associated function
2518 with the args END and POS. */
2519void
2520pop_and_call_brace ()
2521{
2522 BRACE_ELEMENT *temp;
2523 COMMAND_FUNCTION *proc;
2524 int pos;
2525
2526 if (brace_stack == (BRACE_ELEMENT *) NULL)
2527 {
f8b2ac1e 2528 line_error (_("Unmatched }"));
6599da04
JM
2529 return;
2530 }
2531
2532 pos = brace_stack->pos;
2533 proc = brace_stack->proc;
2534 in_fixed_width_font = brace_stack->in_fixed_width_font;
2535 temp = brace_stack->next;
2536 free (brace_stack);
2537 brace_stack = temp;
2538
2539 (*proc) (END, pos, output_paragraph_offset);
2540}
2541
2542/* Shift all of the markers in `brace_stack' by AMOUNT. */
2543void
2544adjust_braces_following (here, amount)
2545 int here, amount;
2546{
2547 register BRACE_ELEMENT *stack = brace_stack;
2548
2549 while (stack)
2550 {
2551 if (stack->pos >= here)
f8b2ac1e 2552 stack->pos += amount;
6599da04
JM
2553 stack = stack->next;
2554 }
2555}
2556
2557/* You call discard_braces () when you shouldn't have any braces on the stack.
2558 I used to think that this happens for commands that don't take arguments
2559 in braces, but that was wrong because of things like @code{foo @@}. So now
2560 I only detect it at the beginning of nodes. */
2561void
2562discard_braces ()
2563{
2564 if (!brace_stack)
2565 return;
2566
2567 while (brace_stack)
2568 {
2569 if (brace_stack->proc != misplaced_brace)
f8b2ac1e
JL
2570 {
2571 char *proc_name;
2572 int temp_line_number = line_number;
2573
2574 line_number = brace_stack->line;
2575 proc_name = find_proc_name (brace_stack->proc);
2576 line_error (_("%c%s missing close brace"), COMMAND_PREFIX, proc_name);
2577 line_number = temp_line_number;
2578 pop_and_call_brace ();
2579 }
6599da04 2580 else
f8b2ac1e
JL
2581 {
2582 BRACE_ELEMENT *temp;
2583 temp = brace_stack->next;
2584 free (brace_stack);
2585 brace_stack = temp;
2586 }
6599da04
JM
2587 }
2588}
2589
2590int
2591get_char_len (character)
2592 int character;
2593{
2594 /* Return the printed length of the character. */
2595 int len;
2596
2597 switch (character)
2598 {
2599 case '\t':
2600 len = (output_column + 8) & 0xf7;
2601 if (len > fill_column)
f8b2ac1e 2602 len = fill_column - output_column;
6599da04 2603 else
f8b2ac1e 2604 len = len - output_column;
6599da04
JM
2605 break;
2606
2607 case '\n':
2608 len = fill_column - output_column;
2609 break;
2610
2611 default:
f8b2ac1e
JL
2612 /* ASCII control characters appear as two characters in the output
2613 (e.g., ^A). But characters with the high bit set are just one
2614 on suitable terminals, so don't count them as two for line
2615 breaking purposes. */
2616 if (0 <= character && character < ' ')
2617 len = 2;
6599da04 2618 else
f8b2ac1e 2619 len = 1;
6599da04 2620 }
f8b2ac1e 2621 return (len);
6599da04
JM
2622}
2623
6599da04 2624void
f8b2ac1e
JL
2625#if defined (VA_FPRINTF) && __STDC__
2626add_word_args (char *format, ...)
2627#else
2628add_word_args (format, va_alist)
2629 char *format;
2630 va_dcl
2631#endif
6599da04
JM
2632{
2633 char buffer[1000];
f8b2ac1e
JL
2634#ifdef VA_FPRINTF
2635 va_list ap;
2636#endif
2637
2638 VA_START (ap, format);
2639#ifdef VA_SPRINTF
2640 VA_SPRINTF (buffer, format, ap);
2641#else
2642 sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
2643#endif /* not VA_SPRINTF */
2644 va_end (ap);
6599da04
JM
2645 add_word (buffer);
2646}
2647
6599da04
JM
2648/* Add STRING to output_paragraph. */
2649void
2650add_word (string)
2651 char *string;
2652{
2653 while (*string)
2654 add_char (*string++);
2655}
2656
f8b2ac1e 2657/* Nonzero if the last character inserted has the syntax class of NEWLINE. */
6599da04
JM
2658int last_char_was_newline = 1;
2659
2660/* The actual last inserted character. Note that this may be something
2661 other than NEWLINE even if last_char_was_newline is 1. */
2662int last_inserted_character = 0;
2663
f8b2ac1e 2664/* Nonzero means that a newline character has already been
6599da04
JM
2665 inserted, so close_paragraph () should insert one less. */
2666int line_already_broken = 0;
2667
f8b2ac1e 2668/* When nonzero we have finished an insertion (see `end_insertion') and we
6599da04
JM
2669 want to ignore false continued paragraph closings. */
2670int insertion_paragraph_closed = 0;
2671
f8b2ac1e 2672/* Nonzero means attempt to make all of the lines have fill_column width. */
6599da04
JM
2673int do_justification = 0;
2674
2675/* Add the character to the current paragraph. If filling_enabled is
f8b2ac1e 2676 nonzero, then do filling as well. */
6599da04
JM
2677void
2678add_char (character)
2679 int character;
2680{
2681 /* If we are avoiding outputting headers, and we are currently
2682 in a menu, then simply return. */
2683 if (no_headers && (in_menu || in_detailmenu))
2684 return;
2685
2686 /* If we are adding a character now, then we don't have to
2687 ignore close_paragraph () calls any more. */
2688 if (must_start_paragraph && character != '\n')
2689 {
2690 must_start_paragraph = 0;
f8b2ac1e 2691 line_already_broken = 0; /* The line is no longer broken. */
6599da04 2692 if (current_indent > output_column)
f8b2ac1e
JL
2693 {
2694 indent (current_indent - output_column);
2695 output_column = current_indent;
2696 }
6599da04
JM
2697 }
2698
2699 if (non_splitting_words && member (character, " \t\n"))
2700 character = ' ' | 0x80;
2701
2702 insertion_paragraph_closed = 0;
2703
2704 switch (character)
2705 {
2706 case '\n':
2707 if (!filling_enabled)
f8b2ac1e
JL
2708 {
2709 insert ('\n');
2710
2711 if (force_flush_right)
2712 {
2713 close_paragraph ();
2714 /* Hack to force single blank lines out in this mode. */
2715 flush_output ();
2716 }
2717
2718 output_column = 0;
2719
2720 if (!no_indent && paragraph_is_open)
2721 indent (output_column = current_indent);
2722 break;
2723 }
6599da04 2724 else /* CHARACTER is newline, and filling is enabled. */
f8b2ac1e
JL
2725 {
2726 if (end_of_sentence_p ())
2727 {
2728 insert (' ');
2729 output_column++;
2730 last_inserted_character = character;
2731 }
2732 }
6599da04
JM
2733
2734 if (last_char_was_newline)
f8b2ac1e
JL
2735 {
2736 close_paragraph ();
2737 pending_indent = 0;
2738 }
6599da04 2739 else
f8b2ac1e
JL
2740 {
2741 last_char_was_newline = 1;
2742 insert (' ');
2743 output_column++;
2744 }
6599da04
JM
2745 break;
2746
2747 default:
2748 {
f8b2ac1e
JL
2749 int len = get_char_len (character);
2750 int suppress_insert = 0;
2751
2752 if ((character == ' ') && (last_char_was_newline))
2753 {
2754 if (!paragraph_is_open)
2755 {
2756 pending_indent++;
2757 return;
2758 }
2759 }
2760
2761 if (!paragraph_is_open)
2762 {
2763 start_paragraph ();
2764
2765 /* If the paragraph is supposed to be indented a certain way,
2766 then discard all of the pending whitespace. Otherwise, we
2767 let the whitespace stay. */
2768 if (!paragraph_start_indent)
2769 indent (pending_indent);
2770 pending_indent = 0;
2771 }
2772
2773 if ((output_column += len) > fill_column)
2774 {
2775 if (filling_enabled)
2776 {
2777 int temp = output_paragraph_offset;
2778 while (--temp > 0 && output_paragraph[temp] != '\n')
2779 {
2780 /* If we have found a space, we have the place to break
2781 the line. */
2782 if (output_paragraph[temp] == ' ')
2783 {
2784 /* Remove trailing whitespace from output. */
2785 while (temp && whitespace (output_paragraph[temp - 1]))
2786 temp--;
2787
2788 output_paragraph[temp++] = '\n';
2789
2790 /* We have correctly broken the line where we want
2791 to. What we don't want is spaces following where
2792 we have decided to break the line. We get rid of
2793 them. */
2794 {
2795 int t1 = temp;
2796
2797 for (;; t1++)
2798 {
2799 if (t1 == output_paragraph_offset)
2800 {
2801 if (whitespace (character))
2802 suppress_insert = 1;
2803 break;
2804 }
2805 if (!whitespace (output_paragraph[t1]))
2806 break;
2807 }
2808
2809 if (t1 != temp)
2810 {
2811 adjust_braces_following (temp, (- (t1 - temp)));
2812 strncpy ((char *) &output_paragraph[temp],
2813 (char *) &output_paragraph[t1],
2814 (output_paragraph_offset - t1));
2815 output_paragraph_offset -= (t1 - temp);
2816 }
2817 }
2818
2819 /* Filled, but now indent if that is right. */
2820 if (indented_fill && current_indent)
2821 {
2822 int buffer_len = ((output_paragraph_offset - temp)
2823 + current_indent);
2824 char *temp_buffer = (char *)xmalloc (buffer_len);
2825 int indentation = 0;
2826
2827 /* We have to shift any markers that are in
2828 front of the wrap point. */
2829 adjust_braces_following (temp, current_indent);
2830
2831 while (current_indent > 0 &&
2832 indentation != current_indent)
2833 temp_buffer[indentation++] = ' ';
2834
2835 strncpy ((char *) &temp_buffer[current_indent],
2836 (char *) &output_paragraph[temp],
2837 buffer_len - current_indent);
2838
2839 if (output_paragraph_offset + buffer_len
2840 >= paragraph_buffer_len)
2841 {
2842 unsigned char *tt = xrealloc
2843 (output_paragraph,
2844 (paragraph_buffer_len += buffer_len));
2845 output_paragraph = tt;
2846 }
2847 strncpy ((char *) &output_paragraph[temp],
2848 temp_buffer, buffer_len);
2849 output_paragraph_offset += current_indent;
2850 free (temp_buffer);
2851 }
2852 output_column = 0;
2853 while (temp < output_paragraph_offset)
2854 output_column +=
2855 get_char_len (output_paragraph[temp++]);
2856 output_column += len;
2857 break;
2858 }
2859 }
2860 }
2861 }
2862
2863 if (!suppress_insert)
2864 {
2865 insert (character);
2866 last_inserted_character = character;
2867 }
2868 last_char_was_newline = 0;
2869 line_already_broken = 0;
6599da04
JM
2870 }
2871 }
2872}
2873
2874/* Insert CHARACTER into `output_paragraph'. */
2875void
2876insert (character)
2877 int character;
2878{
2879 output_paragraph[output_paragraph_offset++] = character;
2880 if (output_paragraph_offset == paragraph_buffer_len)
2881 {
2882 output_paragraph =
f8b2ac1e 2883 xrealloc (output_paragraph, (paragraph_buffer_len += 100));
6599da04
JM
2884 }
2885}
2886
2887/* Insert the null-terminated string STRING into `output_paragraph'. */
2888void
2889insert_string (string)
2890 char *string;
2891{
2892 while (*string)
2893 insert (*string++);
2894}
2895
f8b2ac1e
JL
2896
2897/* Sentences might have these characters after the period (or whatever). */
2898#define post_sentence(c) ((c) == ')' || (c) == '\'' || (c) == '"' \
2899 || (c) == ']')
2900
2901/* Return true if at an end-of-sentence character, possibly followed by
2902 post-sentence punctuation to ignore. */
2903static int
2904end_of_sentence_p ()
2905{
2906 int loc = output_paragraph_offset - 1;
2907 while (loc > 0 && post_sentence (output_paragraph[loc]))
2908 loc--;
2909 return sentence_ender (output_paragraph[loc]);
2910}
2911
2912
38e01259
JL
2913/* Remove up to COUNT characters of whitespace from the
2914 current output line. If COUNT is less than zero,
6599da04
JM
2915 then remove until none left. */
2916void
2917kill_self_indent (count)
2918 int count;
2919{
2920 /* Handle infinite case first. */
2921 if (count < 0)
2922 {
2923 output_column = 0;
2924 while (output_paragraph_offset)
f8b2ac1e
JL
2925 {
2926 if (whitespace (output_paragraph[output_paragraph_offset - 1]))
2927 output_paragraph_offset--;
2928 else
2929 break;
2930 }
6599da04
JM
2931 }
2932 else
2933 {
2934 while (output_paragraph_offset && count--)
f8b2ac1e
JL
2935 if (whitespace (output_paragraph[output_paragraph_offset - 1]))
2936 output_paragraph_offset--;
2937 else
2938 break;
6599da04
JM
2939 }
2940}
2941
f8b2ac1e 2942/* Nonzero means do not honor calls to flush_output (). */
6599da04
JM
2943static int flushing_ignored = 0;
2944
2945/* Prevent calls to flush_output () from having any effect. */
2946void
2947inhibit_output_flushing ()
2948{
2949 flushing_ignored++;
2950}
2951
2952/* Allow calls to flush_output () to write the paragraph data. */
2953void
2954uninhibit_output_flushing ()
2955{
2956 flushing_ignored--;
2957}
2958
2959void
2960flush_output ()
2961{
2962 register int i;
2963
2964 if (!output_paragraph_offset || flushing_ignored)
2965 return;
2966
2967 for (i = 0; i < output_paragraph_offset; i++)
2968 {
2969 /* If we turned on the 8th bit for a space
2970 inside @w, turn it back off for output. */
2971 if (output_paragraph[i] & meta_character_bit)
2972 {
2973 int temp = UNMETA (output_paragraph[i]);
2974 if (temp == ' ')
f8b2ac1e 2975 output_paragraph[i] &= 0x7f;
6599da04
JM
2976 }
2977 }
2978
2979 fwrite (output_paragraph, 1, output_paragraph_offset, output_stream);
2980
2981 output_position += output_paragraph_offset;
2982 output_paragraph_offset = 0;
2983}
2984
2985/* How to close a paragraph controlling the number of lines between
2986 this one and the last one. */
2987
2988/* Paragraph spacing is controlled by this variable. It is the number of
2989 blank lines that you wish to appear between paragraphs. A value of
2990 1 creates a single blank line between paragraphs. */
2991int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING;
2992
2993/* Close the current paragraph, leaving no blank lines between them. */
2994void
2995close_single_paragraph ()
2996{
2997 close_paragraph_with_lines (0);
2998}
2999
3000/* Close a paragraph after an insertion has ended. */
3001void
3002close_insertion_paragraph ()
3003{
3004 if (!insertion_paragraph_closed)
3005 {
3006 /* Close the current paragraph, breaking the line. */
3007 close_single_paragraph ();
3008
f8b2ac1e
JL
3009 /* Start a new paragraph, with the correct indentation for the now
3010 current insertion level (one above the one that we are ending). */
6599da04
JM
3011 start_paragraph ();
3012
f8b2ac1e
JL
3013 /* Tell `close_paragraph' that the previous line has already been
3014 broken, so it should insert one less newline. */
6599da04
JM
3015 line_already_broken = 1;
3016
f8b2ac1e 3017 /* Tell functions such as `add_char' we've already found a newline. */
6599da04
JM
3018 ignore_blank_line ();
3019 }
3020 else
3021 {
3022 /* If the insertion paragraph is closed already, then we are seeing
f8b2ac1e
JL
3023 two `@end' commands in a row. Note that the first one we saw was
3024 handled in the first part of this if-then-else clause, and at that
3025 time `start_paragraph' was called, partially to handle the proper
3026 indentation of the current line. However, the indentation level
3027 may have just changed again, so we may have to outdent the current
3028 line to the new indentation level. */
6599da04 3029 if (current_indent < output_column)
f8b2ac1e 3030 kill_self_indent (output_column - current_indent);
6599da04
JM
3031 }
3032
3033 insertion_paragraph_closed = 1;
3034}
3035
3036void
3037close_paragraph_with_lines (lines)
3038 int lines;
3039{
3040 int old_spacing = paragraph_spacing;
3041 paragraph_spacing = lines;
3042 close_paragraph ();
3043 paragraph_spacing = old_spacing;
3044}
3045
3046/* Close the currently open paragraph. */
3047void
3048close_paragraph ()
3049{
3050 register int i;
3051
3052 /* The insertion paragraph is no longer closed. */
3053 insertion_paragraph_closed = 0;
3054
3055 if (paragraph_is_open && !must_start_paragraph)
3056 {
3057 register int tindex, c;
3058
3059 tindex = output_paragraph_offset;
3060
3061 /* Back up to last non-newline/space character, forcing all such
f8b2ac1e
JL
3062 subsequent characters to be newlines. This isn't strictly
3063 necessary, but a couple of functions use the presence of a newline
3064 to make decisions. */
6599da04 3065 for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex)
f8b2ac1e
JL
3066 {
3067 c = output_paragraph[tindex];
6599da04 3068
f8b2ac1e
JL
3069 if (c == ' '|| c == '\n')
3070 output_paragraph[tindex] = '\n';
3071 else
3072 break;
3073 }
6599da04
JM
3074
3075 /* All trailing whitespace is ignored. */
3076 output_paragraph_offset = ++tindex;
3077
3078 /* Break the line if that is appropriate. */
3079 if (paragraph_spacing >= 0)
f8b2ac1e 3080 insert ('\n');
6599da04 3081
f8b2ac1e 3082 /* Add as many blank lines as is specified in `paragraph_spacing'. */
6599da04 3083 if (!force_flush_right)
f8b2ac1e
JL
3084 {
3085 for (i = 0; i < (paragraph_spacing - line_already_broken); i++)
3086 insert ('\n');
3087 }
6599da04
JM
3088
3089 /* If we are doing flush right indentation, then do it now
f8b2ac1e 3090 on the paragraph (really a single line). */
6599da04 3091 if (force_flush_right)
f8b2ac1e 3092 do_flush_right_indentation ();
6599da04
JM
3093
3094 flush_output ();
3095 paragraph_is_open = 0;
3096 no_indent = 0;
3097 output_column = 0;
3098 }
3099 ignore_blank_line ();
3100}
3101
3102/* Make the last line just read look as if it were only a newline. */
3103void
3104ignore_blank_line ()
3105{
3106 last_inserted_character = '\n';
3107 last_char_was_newline = 1;
3108}
3109
3110/* Align the end of the text in output_paragraph with fill_column. */
3111void
3112do_flush_right_indentation ()
3113{
3114 char *temp;
3115 int temp_len;
3116
3117 kill_self_indent (-1);
3118
3119 if (output_paragraph[0] != '\n')
3120 {
f8b2ac1e 3121 output_paragraph[output_paragraph_offset] = 0;
6599da04
JM
3122
3123 if (output_paragraph_offset < fill_column)
f8b2ac1e
JL
3124 {
3125 register int i;
6599da04 3126
f8b2ac1e
JL
3127 if (fill_column >= paragraph_buffer_len)
3128 output_paragraph =
3129 xrealloc (output_paragraph,
3130 (paragraph_buffer_len += fill_column));
6599da04 3131
f8b2ac1e
JL
3132 temp_len = strlen ((char *)output_paragraph);
3133 temp = (char *)xmalloc (temp_len + 1);
3134 memcpy (temp, (char *)output_paragraph, temp_len);
6599da04 3135
f8b2ac1e
JL
3136 for (i = 0; i < fill_column - output_paragraph_offset; i++)
3137 output_paragraph[i] = ' ';
6599da04 3138
f8b2ac1e
JL
3139 memcpy ((char *)output_paragraph + i, temp, temp_len);
3140 free (temp);
3141 output_paragraph_offset = fill_column;
3142 }
6599da04
JM
3143 }
3144}
3145
3146/* Begin a new paragraph. */
3147void
3148start_paragraph ()
3149{
3150 /* First close existing one. */
3151 if (paragraph_is_open)
3152 close_paragraph ();
3153
3154 /* In either case, the insertion paragraph is no longer closed. */
3155 insertion_paragraph_closed = 0;
3156
3157 /* However, the paragraph is open! */
3158 paragraph_is_open = 1;
3159
3160 /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph ()
3161 had to be called before we would allow any other paragraph operations
3162 to have an effect. */
3163 if (!must_start_paragraph)
3164 {
3165 int amount_to_indent = 0;
3166
3167 /* If doing indentation, then insert the appropriate amount. */
3168 if (!no_indent)
f8b2ac1e
JL
3169 {
3170 if (inhibit_paragraph_indentation)
3171 {
3172 amount_to_indent = current_indent;
3173 if (inhibit_paragraph_indentation < 0)
3174 inhibit_paragraph_indentation++;
3175 }
3176 else if (paragraph_start_indent < 0)
3177 amount_to_indent = current_indent;
3178 else
3179 amount_to_indent = current_indent + paragraph_start_indent;
3180
3181 if (amount_to_indent >= output_column)
3182 {
3183 amount_to_indent -= output_column;
3184 indent (amount_to_indent);
3185 output_column += amount_to_indent;
3186 }
3187 }
6599da04
JM
3188 }
3189 else
3190 must_start_paragraph = 0;
3191}
3192
3193/* Insert the indentation specified by AMOUNT. */
3194void
3195indent (amount)
3196 int amount;
3197{
3198 register BRACE_ELEMENT *elt = brace_stack;
3199
3200 /* For every START_POS saved within the brace stack which will be affected
3201 by this indentation, bump that start pos forward. */
3202 while (elt)
3203 {
3204 if (elt->pos >= output_paragraph_offset)
f8b2ac1e 3205 elt->pos += amount;
6599da04
JM
3206 elt = elt->next;
3207 }
3208
3209 while (--amount >= 0)
3210 insert (' ');
3211}
3212
3213/* Search forward for STRING in input_text.
38e01259 3214 FROM says where to start. */
6599da04
JM
3215int
3216search_forward (string, from)
3217 char *string;
3218 int from;
3219{
3220 int len = strlen (string);
3221
3222 while (from < size_of_input_text)
3223 {
3224 if (strncmp (input_text + from, string, len) == 0)
f8b2ac1e 3225 return (from);
6599da04
JM
3226 from++;
3227 }
3228 return (-1);
3229}
3230
3231/* Whoops, Unix doesn't have strcasecmp. */
3232
3233/* Case independent string compare. */
3234#if !defined (HAVE_STRCASECMP)
3235int
3236strcasecmp (string1, string2)
3237 char *string1, *string2;
3238{
3239 char ch1, ch2;
3240
3241 for (;;)
3242 {
3243 ch1 = *string1++;
3244 ch2 = *string2++;
3245
3246 if (!(ch1 | ch2))
f8b2ac1e 3247 return (0);
6599da04
JM
3248
3249 ch1 = coerce_to_upper (ch1);
3250 ch2 = coerce_to_upper (ch2);
3251
3252 if (ch1 != ch2)
f8b2ac1e 3253 return (ch1 - ch2);
6599da04
JM
3254 }
3255}
3256#endif /* !HAVE_STRCASECMP */
3257
3258void
3259init_insertion_stack ()
3260{
3261 insertion_stack = (INSERTION_ELT *) NULL;
3262}
3263
3264/* Return the type of the current insertion. */
3265enum insertion_type
3266current_insertion_type ()
3267{
3268 if (!insertion_level)
3269 return (bad_type);
3270 else
3271 return (insertion_stack->insertion);
3272}
3273
3274/* Return a pointer to the string which is the function to wrap around
3275 items. */
3276char *
3277current_item_function ()
3278{
3279 register int level, done;
3280 register INSERTION_ELT *elt;
3281
3282 level = insertion_level;
3283 elt = insertion_stack;
3284 done = 0;
3285
3286 /* Skip down through the stack until we find a non-conditional insertion. */
3287 while (!done && (elt != NULL))
3288 {
3289 switch (elt->insertion)
f8b2ac1e
JL
3290 {
3291 case ifinfo:
3292 case ifnothtml:
3293 case ifnottex:
3294 case ifset:
3295 case ifclear:
3296 case cartouche:
3297 elt = elt->next;
3298 level--;
3299 break;
3300
3301 default:
3302 done = 1;
3303 }
6599da04
JM
3304 }
3305
3306 if (!level)
3307 return ((char *) NULL);
3308 else
3309 return (elt->item_function);
3310}
3311
3312char *
3313get_item_function ()
3314{
3315 char *item_function;
3316 get_rest_of_line (&item_function);
3317 backup_input_pointer ();
6599da04
JM
3318 return (item_function);
3319}
3320
3321 /* Push the state of the current insertion on the stack. */
3322void
3323push_insertion (type, item_function)
3324 enum insertion_type type;
3325 char *item_function;
3326{
3327 INSERTION_ELT *new = (INSERTION_ELT *) xmalloc (sizeof (INSERTION_ELT));
3328
3329 new->item_function = item_function;
3330 new->filling_enabled = filling_enabled;
3331 new->indented_fill = indented_fill;
3332 new->insertion = type;
3333 new->line_number = line_number;
f8b2ac1e 3334 new->filename = xstrdup (input_filename);
6599da04
JM
3335 new->inhibited = inhibit_paragraph_indentation;
3336 new->in_fixed_width_font = in_fixed_width_font;
3337 new->next = insertion_stack;
3338 insertion_stack = new;
3339 insertion_level++;
3340}
3341
3342 /* Pop the value on top of the insertion stack into the
3343 global variables. */
3344void
3345pop_insertion ()
3346{
3347 INSERTION_ELT *temp = insertion_stack;
3348
3349 if (temp == (INSERTION_ELT *) NULL)
3350 return;
3351
3352 in_fixed_width_font = temp->in_fixed_width_font;
3353 inhibit_paragraph_indentation = temp->inhibited;
3354 filling_enabled = temp->filling_enabled;
3355 indented_fill = temp->indented_fill;
3356 free_and_clear (&(temp->item_function));
3357 free_and_clear (&(temp->filename));
3358 insertion_stack = insertion_stack->next;
3359 free (temp);
3360 insertion_level--;
3361}
3362
3363 /* Return a pointer to the print name of this
3364 enumerated type. */
3365char *
3366insertion_type_pname (type)
3367 enum insertion_type type;
3368{
3369 if ((int) type < (int) bad_type)
3370 return (insertion_type_names[(int) type]);
3371 else
f8b2ac1e 3372 return (_("Broken-Type in insertion_type_pname"));
6599da04
JM
3373}
3374
3375/* Return the insertion_type associated with NAME.
3376 If the type is not one of the known ones, return BAD_TYPE. */
3377enum insertion_type
3378find_type_from_name (name)
3379 char *name;
3380{
3381 int index = 0;
3382 while (index < (int) bad_type)
3383 {
3384 if (strcmp (name, insertion_type_names[index]) == 0)
f8b2ac1e 3385 return (enum insertion_type) index;
6599da04
JM
3386 index++;
3387 }
3388 return (bad_type);
3389}
3390
3391int
3392defun_insertion (type)
3393 enum insertion_type type;
3394{
3395 return
3396 ((type == deffn)
3397 || (type == defun)
3398 || (type == defmac)
3399 || (type == defspec)
3400 || (type == defvr)
3401 || (type == defvar)
3402 || (type == defopt)
3403 || (type == deftypefn)
3404 || (type == deftypefun)
3405 || (type == deftypevr)
3406 || (type == deftypevar)
3407 || (type == defcv)
3408 || (type == defivar)
3409 || (type == defop)
3410 || (type == defmethod)
3411 || (type == deftypemethod)
3412 || (type == deftp));
3413}
3414
3415/* MAX_NS is the maximum nesting level for enumerations. I picked 100
3416 which seemed reasonable. This doesn't control the number of items,
3417 just the number of nested lists. */
3418#define max_stack_depth 100
3419#define ENUM_DIGITS 1
3420#define ENUM_ALPHA 2
3421typedef struct {
3422 int enumtype;
3423 int enumval;
3424} DIGIT_ALPHA;
3425
3426DIGIT_ALPHA enumstack[max_stack_depth];
3427int enumstack_offset = 0;
3428int current_enumval = 1;
3429int current_enumtype = ENUM_DIGITS;
3430char *enumeration_arg = (char *)NULL;
3431
3432void
3433start_enumerating (at, type)
3434 int at, type;
3435{
3436 if ((enumstack_offset + 1) == max_stack_depth)
3437 {
f8b2ac1e 3438 line_error (_("Enumeration stack overflow"));
6599da04
JM
3439 return;
3440 }
3441 enumstack[enumstack_offset].enumtype = current_enumtype;
3442 enumstack[enumstack_offset].enumval = current_enumval;
3443 enumstack_offset++;
3444 current_enumval = at;
3445 current_enumtype = type;
3446}
3447
3448void
3449stop_enumerating ()
3450{
3451 --enumstack_offset;
3452 if (enumstack_offset < 0)
3453 enumstack_offset = 0;
3454
3455 current_enumval = enumstack[enumstack_offset].enumval;
3456 current_enumtype = enumstack[enumstack_offset].enumtype;
3457}
3458
3459/* Place a letter or digits into the output stream. */
3460void
3461enumerate_item ()
3462{
3463 char temp[10];
3464
3465 if (current_enumtype == ENUM_ALPHA)
3466 {
3467 if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
f8b2ac1e
JL
3468 {
3469 current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
3470 warning (_("lettering overflow, restarting at %c"), current_enumval);
3471 }
6599da04
JM
3472 sprintf (temp, "%c. ", current_enumval);
3473 }
3474 else
3475 sprintf (temp, "%d. ", current_enumval);
3476
3477 indent (output_column += (current_indent - strlen (temp)));
3478 add_word (temp);
3479 current_enumval++;
3480}
3481
3482/* This is where the work for all the "insertion" style
3483 commands is done. A huge switch statement handles the
3484 various setups, and generic code is on both sides. */
3485void
3486begin_insertion (type)
3487 enum insertion_type type;
3488{
3489 int no_discard = 0;
3490
3491 if (defun_insertion (type))
3492 {
f8b2ac1e 3493 push_insertion (type, xstrdup (""));
6599da04
JM
3494 no_discard++;
3495 }
3496 else
3497 push_insertion (type, get_item_function ());
3498
3499 switch (type)
3500 {
3501 case menu:
3502 if (!no_headers)
f8b2ac1e 3503 close_paragraph ();
6599da04
JM
3504
3505 filling_enabled = no_indent = 0;
3506 inhibit_paragraph_indentation = 1;
3507
3508 if (!no_headers)
f8b2ac1e 3509 add_word (_("* Menu:\n"));
6599da04
JM
3510
3511 in_menu++;
3512 no_discard++;
3513 break;
3514
3515 case detailmenu:
6599da04 3516 if (!in_menu)
f8b2ac1e
JL
3517 {
3518 if (!no_headers)
3519 close_paragraph ();
6599da04 3520
f8b2ac1e
JL
3521 filling_enabled = no_indent = 0;
3522 inhibit_paragraph_indentation = 1;
6599da04 3523
f8b2ac1e
JL
3524 no_discard++;
3525 }
6599da04
JM
3526
3527 in_detailmenu++;
3528 break;
3529
3530 case direntry:
3531 close_single_paragraph ();
3532 filling_enabled = no_indent = 0;
3533 inhibit_paragraph_indentation = 1;
3534 insert_string ("START-INFO-DIR-ENTRY\n");
3535 break;
3536
3537 /* I think @quotation is meant to do filling.
f8b2ac1e 3538 If you don't want filling, then use @display. */
6599da04
JM
3539 case quotation:
3540 close_single_paragraph ();
3541 last_char_was_newline = no_indent = 0;
3542 indented_fill = filling_enabled = 1;
3543 inhibit_paragraph_indentation = 1;
3544 current_indent += default_indentation_increment;
3545 break;
3546
3547 case display:
3548 case example:
3549 case smallexample:
3550 case lisp:
3551 case smalllisp:
3552 /* Just like @example, but no indentation. */
3553 case format:
6599da04
JM
3554 close_single_paragraph ();
3555 inhibit_paragraph_indentation = 1;
3556 in_fixed_width_font++;
3557 filling_enabled = 0;
3558 last_char_was_newline = 0;
6599da04 3559 if (type != format)
f8b2ac1e 3560 current_indent += default_indentation_increment;
6599da04
JM
3561 break;
3562
3563 case multitable:
3564 do_multitable ();
3565 break;
3566
3567 case table:
3568 case ftable:
3569 case vtable:
3570 case itemize:
3571 close_single_paragraph ();
3572 current_indent += default_indentation_increment;
3573 filling_enabled = indented_fill = 1;
3574#if defined (INDENT_PARAGRAPHS_IN_TABLE)
3575 inhibit_paragraph_indentation = 0;
3576#else
3577 inhibit_paragraph_indentation = 1;
3578#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
3579
3580 /* Make things work for losers who forget the itemize syntax. */
3581 if (allow_lax_format && (type == itemize))
f8b2ac1e
JL
3582 {
3583 if (!(*insertion_stack->item_function))
3584 {
3585 free (insertion_stack->item_function);
3586 insertion_stack->item_function = xstrdup ("@bullet");
3587 insertion_stack->item_function[0] = COMMAND_PREFIX;
3588 }
3589 }
6599da04
JM
3590
3591 if (!*insertion_stack->item_function)
f8b2ac1e
JL
3592 {
3593 line_error (_("%s requires an argument: the formatter for %citem"),
3594 insertion_type_pname (type), COMMAND_PREFIX);
3595 }
6599da04
JM
3596 break;
3597
3598 case enumerate:
3599 close_single_paragraph ();
3600 no_indent = 0;
3601#if defined (INDENT_PARAGRAPHS_IN_TABLE)
3602 inhibit_paragraph_indentation = 0;
3603#else
3604 inhibit_paragraph_indentation = 1;
3605#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
3606
3607 current_indent += default_indentation_increment;
3608 filling_enabled = indented_fill = 1;
3609
3610 if (isdigit (*enumeration_arg))
f8b2ac1e 3611 start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
6599da04 3612 else
f8b2ac1e 3613 start_enumerating (*enumeration_arg, ENUM_ALPHA);
6599da04
JM
3614 break;
3615
3616 /* Does nothing special in makeinfo. */
3617 case group:
3618 /* Only close the paragraph if we are not inside of an @example. */
3619 if (!insertion_stack->next ||
f8b2ac1e
JL
3620 insertion_stack->next->insertion != example)
3621 close_single_paragraph ();
6599da04
JM
3622 break;
3623
3624 /* Insertions that are no-ops in info, but do something in TeX. */
3625 case ifinfo:
f8b2ac1e
JL
3626 case ifnothtml:
3627 case ifnottex:
6599da04
JM
3628 case ifset:
3629 case ifclear:
3630 case cartouche:
3631 if (in_menu)
f8b2ac1e 3632 no_discard++;
6599da04
JM
3633 break;
3634
3635 case deffn:
3636 case defun:
3637 case defmac:
3638 case defspec:
3639 case defvr:
3640 case defvar:
3641 case defopt:
3642 case deftypefn:
3643 case deftypefun:
3644 case deftypevr:
3645 case deftypevar:
3646 case defcv:
3647 case defivar:
3648 case defop:
3649 case defmethod:
3650 case deftypemethod:
3651 case deftp:
3652 inhibit_paragraph_indentation = 1;
3653 filling_enabled = indented_fill = 1;
3654 current_indent += default_indentation_increment;
3655 no_indent = 0;
3656 break;
3657
3658 case flushleft:
3659 close_single_paragraph ();
3660 inhibit_paragraph_indentation = 1;
3661 filling_enabled = indented_fill = no_indent = 0;
3662 break;
3663
3664 case flushright:
3665 close_single_paragraph ();
3666 filling_enabled = indented_fill = no_indent = 0;
3667 inhibit_paragraph_indentation = 1;
3668 force_flush_right++;
3669 break;
3670 }
3671
3672 if (!no_discard)
3673 discard_until ("\n");
3674}
3675
f8b2ac1e
JL
3676/* Try to end the insertion with the specified TYPE. With a value of
3677 `bad_type', TYPE gets translated to match the value currently on top
3678 of the stack. Otherwise, if TYPE doesn't match the top of the
3679 insertion stack, give error. */
6599da04
JM
3680void
3681end_insertion (type)
3682 enum insertion_type type;
3683{
3684 enum insertion_type temp_type;
3685
3686 if (!insertion_level)
3687 return;
3688
3689 temp_type = current_insertion_type ();
3690
3691 if (type == bad_type)
3692 type = temp_type;
3693
3694 if (type != temp_type)
3695 {
3696 line_error
f8b2ac1e
JL
3697 (_("`%cend' expected `%s', but saw `%s'"), COMMAND_PREFIX,
3698 insertion_type_pname (temp_type), insertion_type_pname (type));
6599da04
JM
3699 return;
3700 }
3701
3702 pop_insertion ();
3703
3704 switch (type)
3705 {
3706 /* Insertions which have no effect on paragraph formatting. */
f8b2ac1e
JL
3707 case ifnothtml:
3708 case ifnottex:
6599da04
JM
3709 case ifinfo:
3710 case ifset:
3711 case ifclear:
3712 break;
3713
3714 case direntry:
3715 insert_string ("END-INFO-DIR-ENTRY\n\n");
3716 close_insertion_paragraph ();
3717 break;
3718
3719 case detailmenu:
f8b2ac1e 3720 in_detailmenu--; /* No longer hacking menus. */
6599da04 3721 if (!in_menu)
f8b2ac1e
JL
3722 {
3723 if (!no_headers)
3724 close_insertion_paragraph ();
3725 }
6599da04
JM
3726 break;
3727
3728 case menu:
f8b2ac1e 3729 in_menu--; /* No longer hacking menus. */
6599da04 3730 if (!no_headers)
f8b2ac1e 3731 close_insertion_paragraph ();
6599da04
JM
3732 break;
3733
3734 case multitable:
3735 end_multitable ();
3736 break;
3737
3738 case enumerate:
3739 stop_enumerating ();
3740 close_insertion_paragraph ();
3741 current_indent -= default_indentation_increment;
3742 break;
3743
3744 case flushleft:
3745 case group:
3746 case cartouche:
3747 close_insertion_paragraph ();
3748 break;
3749
3750 case format:
3751 case display:
3752 case example:
3753 case smallexample:
3754 case lisp:
3755 case smalllisp:
3756 case quotation:
6599da04 3757 /* @format is the only fixed_width insertion without a change
f8b2ac1e 3758 in indentation. */
6599da04 3759 if (type != format)
f8b2ac1e 3760 current_indent -= default_indentation_increment;
6599da04
JM
3761
3762 /* The ending of one of these insertions always marks the
f8b2ac1e 3763 start of a new paragraph. */
6599da04
JM
3764 close_insertion_paragraph ();
3765 break;
3766
3767 case table:
3768 case ftable:
3769 case vtable:
3770 case itemize:
3771 current_indent -= default_indentation_increment;
3772 break;
3773
3774 case flushright:
3775 force_flush_right--;
3776 close_insertion_paragraph ();
3777 break;
3778
3779 /* Handle the @defun style insertions with a default clause. */
3780 default:
3781 current_indent -= default_indentation_increment;
3782 close_insertion_paragraph ();
3783 break;
3784 }
3785}
3786
3787/* Insertions cannot cross certain boundaries, such as node beginnings. In
f8b2ac1e 3788 code that creates such boundaries, you should call `discard_insertions'
6599da04 3789 before doing anything else. It prints the errors for you, and cleans up
f8b2ac1e
JL
3790 the insertion stack. With nonzero SPECIALS_OK, allows unmatched
3791 ifinfo, ifset, ifclear, otherwise not. */
6599da04 3792void
f8b2ac1e
JL
3793discard_insertions (specials_ok)
3794 int specials_ok;
6599da04
JM
3795{
3796 int real_line_number = line_number;
3797 while (insertion_stack)
3798 {
f8b2ac1e
JL
3799 if (specials_ok && (insertion_stack->insertion == ifinfo
3800 || insertion_stack->insertion == ifset
3801 || insertion_stack->insertion == ifclear))
3802 break;
6599da04 3803 else
f8b2ac1e
JL
3804 {
3805 char *offender = insertion_type_pname (insertion_stack->insertion);
3806 char *current_filename = input_filename;
3807
3808 input_filename = insertion_stack->filename;
3809 line_number = insertion_stack->line_number;
3810 line_error (_("No matching `%cend %s'"), COMMAND_PREFIX, offender);
3811 input_filename = current_filename;
3812 pop_insertion ();
3813 }
6599da04
JM
3814 }
3815 line_number = real_line_number;
3816}
3817\f
3818/* The Texinfo commands. */
3819
3820/* Commands which insert their own names. */
3821void
3822insert_self (arg)
3823 int arg;
3824{
3825 if (arg == START)
3826 add_word (command);
3827}
3828
3829void
3830insert_space (arg)
3831 int arg;
3832{
3833 if (arg == START)
3834 add_char (' ');
3835}
3836
3837/* Force a line break in the output. */
3838void
3839cm_asterisk ()
3840{
3841 close_single_paragraph ();
6599da04 3842 cm_noindent ();
6599da04
JM
3843}
3844
3845/* Insert ellipsis. */
3846void
3847cm_dots (arg)
3848 int arg;
3849{
3850 if (arg == START)
3851 add_word ("...");
3852}
3853
3854/* Insert ellipsis for sentence end. */
3855void
3856cm_enddots (arg)
3857 int arg;
3858{
3859 if (arg == START)
3860 add_word ("....");
3861}
3862
3863void
3864cm_bullet (arg)
3865 int arg;
3866{
3867 if (arg == START)
3868 add_char ('*');
3869}
3870
3871void
3872cm_minus (arg)
3873 int arg;
3874{
3875 if (arg == START)
3876 add_char ('-');
3877}
3878
3879/* Insert "TeX". */
3880void
3881cm_TeX (arg)
3882 int arg;
3883{
3884 if (arg == START)
3885 add_word ("TeX");
3886}
3887
3888/* Copyright symbol. */
3889void
3890cm_copyright (arg)
3891 int arg;
3892{
3893 if (arg == START)
3894 add_word ("(C)");
3895}
3896
3897/* Accent commands that take explicit arguments. */
3898void
3899cm_accent (arg)
3900 int arg;
3901{
3902 if (arg == START)
3903 {
3904 if (strcmp (command, "dotaccent") == 0) /* overdot */
3905 add_char ('.');
3906 else if (strcmp (command, "H") == 0) /* Hungarian umlaut */
3907 add_word ("''");
3908 else if (strcmp (command, "ringaccent") == 0)
3909 add_char ('*');
3910 else if (strcmp (command, "tieaccent") == 0)
3911 add_char ('[');
3912 else if (strcmp (command, "u") == 0) /* breve */
3913 add_char ('(');
3914 else if (strcmp (command, "v") == 0) /* hacek/check */
3915 add_char ('<');
3916 }
3917 else if (arg == END)
3918 {
3919 if (strcmp (command, "ubaraccent") == 0) /* underbar */
3920 add_char ('_');
3921 else if (strcmp (command, "udotaccent") == 0) /* underdot */
3922 add_word ("-.");
3923 else if (strcmp (command, ",") == 0) /* cedilla */
3924 add_word (",");
3925 }
3926}
3927
3928/* Non-English letters/characters that don't insert themselves. */
3929void
3930cm_special_char (arg)
3931{
3932 if (arg == START)
3933 {
3934 if ((*command == 'L' || *command == 'l'
3935 || *command == 'O' || *command == 'o')
3936 && command[1] == 0)
3937 {
3938 /* Lslash lslash Oslash oslash */
3939 add_char (*command);
3940 add_char ('/');
3941 }
3942 else if (strcmp (command, "exclamdown") == 0)
3943 add_char ('!');
3944 else if (strcmp (command, "pounds") == 0)
3945 add_char ('#');
3946 else if (strcmp (command, "questiondown") == 0)
3947 add_char ('?');
3948 else
f8b2ac1e 3949 fprintf (stderr, _("How did @%s end up in cm_special_char?\n"), command);
6599da04
JM
3950 }
3951}
3952
3953/* Dotless i or j. */
3954void
3955cm_dotless (arg, start, end)
3956 int arg, start, end;
3957{
3958 if (arg == END)
3959 {
3960 if (output_paragraph[start] != 'i' && output_paragraph[start] != 'j')
3961 /* This error message isn't perfect if the argument is multiple
3962 characters, but it doesn't seem worth getting right. */
f8b2ac1e 3963 line_error (_("%c%s expects `i' or `j' as argument, not `%c'"),
6599da04
JM
3964 COMMAND_PREFIX, command, output_paragraph[start]);
3965
3966 else if (end - start != 1)
f8b2ac1e
JL
3967 line_error (_("%c%s expects a single character `i' or `j' as argument"),
3968 COMMAND_PREFIX, command);
6599da04
JM
3969
3970 /* We've already inserted the `i' or `j', so nothing to do. */
3971 }
3972}
3973
6599da04
JM
3974void
3975cm_today (arg)
3976 int arg;
3977{
f8b2ac1e
JL
3978 static char *months [12] =
3979 { N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
3980 N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
3981 N_("November"), N_("December") };
6599da04
JM
3982 if (arg == START)
3983 {
f8b2ac1e
JL
3984 time_t timer = time (0);
3985 struct tm *ts = localtime (&timer);
d275726b 3986 add_word_args ("%d %s %d", ts->tm_mday, _(months[ts->tm_mon]),
f8b2ac1e 3987 ts->tm_year + 1900);
6599da04
JM
3988 }
3989}
3990
3991void
3992cm_code (arg)
3993 int arg;
3994{
3995 extern int printing_index;
3996
3997 if (arg == START)
3998 {
3999 in_fixed_width_font++;
4000
4001 if (!printing_index)
f8b2ac1e 4002 add_char ('`');
6599da04
JM
4003 }
4004 else
4005 {
4006 if (!printing_index)
f8b2ac1e 4007 add_char ('\'');
6599da04
JM
4008 }
4009}
4010
4011void
4012cm_kbd (arg)
4013 int arg;
4014{
4015 /* People use @kbd in an example to get the "user input" font.
4016 We don't want quotes in that case. */
4017 if (!in_fixed_width_font)
4018 cm_code (arg);
4019}
4020
4021void
f8b2ac1e 4022cm_key (arg)
6599da04
JM
4023 int arg;
4024{
4025 add_char (arg == START ? '<' : '>');
4026}
4027
4028/* Convert the character at position into a true control character. */
4029void
4030cm_ctrl (arg, start, end)
4031 int arg, start, end;
4032{
4033 /* Should we allow multiple character arguments? I think yes. */
4034 if (arg == END)
4035 {
4036 register int i, character;
4037#if defined (NO_MULTIPLE_CTRL)
4038 if ((end - start) != 1)
f8b2ac1e
JL
4039 line_error (_("%c%s expects a single character as an argument"),
4040 COMMAND_PREFIX, command);
6599da04
JM
4041 else
4042#endif
f8b2ac1e
JL
4043 for (i = start; i < end; i++)
4044 {
4045 character = output_paragraph[i];
6599da04 4046
f8b2ac1e
JL
4047 if (isletter (character))
4048 output_paragraph[i] = CTL (coerce_to_upper (character));
4049 }
6599da04
JM
4050 }
4051}
4052
4053/* Handle a command that switches to a non-fixed-width font. */
4054void
4055not_fixed_width (arg)
4056 int arg;
4057{
4058 if (arg == START)
4059 in_fixed_width_font = 0;
4060}
4061
f8b2ac1e 4062/* Small caps and @var in makeinfo just uppercase the text. */
6599da04 4063void
f8b2ac1e 4064cm_var_sc (arg, start_pos, end_pos)
6599da04
JM
4065 int arg, start_pos, end_pos;
4066{
4067 not_fixed_width (arg);
4068
4069 if (arg == END)
4070 {
4071 while (start_pos < end_pos)
f8b2ac1e
JL
4072 {
4073 output_paragraph[start_pos] =
4074 coerce_to_upper (output_paragraph[start_pos]);
4075 start_pos++;
4076 }
6599da04
JM
4077 }
4078}
4079
4080void
4081cm_dfn (arg, position)
4082 int arg, position;
4083{
4084 add_char ('"');
4085}
4086
4087void
4088cm_emph (arg)
4089 int arg;
4090{
4091 add_char ('*');
4092}
4093
4094void
4095cm_strong (arg, position)
4096 int arg, position;
4097{
4098 cm_emph (arg);
4099}
4100
4101void
4102cm_cite (arg, position)
4103 int arg, position;
4104{
4105 if (arg == START)
4106 add_word ("`");
4107 else
4108 add_word ("'");
4109}
4110
4111/* No highlighting, but argument switches fonts. */
4112void
4113cm_not_fixed_width (arg, start, end)
4114 int arg, start, end;
4115{
4116 not_fixed_width (arg);
4117}
4118
f8b2ac1e 4119/* Various commands are no-op's. */
6599da04
JM
4120void
4121cm_no_op ()
4122{
4123}
4124
f8b2ac1e
JL
4125/* No-op that eats its argument on same line. */
4126void
4127cm_no_op_line_arg ()
4128{
4129 char *temp;
4130 get_rest_of_line (&temp);
4131 free (temp);
4132}
4133
6599da04
JM
4134/* Prevent the argument from being split across two lines. */
4135void
4136cm_w (arg, start, end)
4137 int arg, start, end;
4138{
4139 if (arg == START)
4140 non_splitting_words++;
4141 else
4142 non_splitting_words--;
4143}
4144
4145
4146/* Explain that this command is obsolete, thus the user shouldn't
4147 do anything with it. */
4148void
4149cm_obsolete (arg, start, end)
4150 int arg, start, end;
4151{
4152 if (arg == START)
f8b2ac1e 4153 warning (_("%c%s is obsolete"), COMMAND_PREFIX, command);
6599da04
JM
4154}
4155
4156/* Insert the text following input_text_offset up to the end of the line
4157 in a new, separate paragraph. Directly underneath it, insert a
4158 line of WITH_CHAR, the same length of the inserted text. */
4159void
4160insert_and_underscore (with_char)
4161 int with_char;
4162{
4163 register int i, len;
4164 int old_no_indent, starting_pos, ending_pos;
4165 char *temp;
4166
4167 close_paragraph ();
4168 filling_enabled = indented_fill = 0;
4169 old_no_indent = no_indent;
4170 no_indent = 1;
4171
4172#if defined (HAVE_MACROS)
d275726b 4173 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
4174 append_to_expansion_output (input_text_offset + 1);
4175#endif /* HAVE_MACROS */
4176
4177 get_rest_of_line (&temp);
4178
4179 starting_pos = output_position + output_paragraph_offset;
4180#if defined (HAVE_MACROS)
d275726b 4181 if (macro_expansion_output_stream && !executing_string)
6599da04 4182 {
f8b2ac1e 4183 char *temp1 = (char *) xmalloc (2 + strlen (temp));
6599da04
JM
4184 sprintf (temp1, "%s\n", temp);
4185 remember_itext (input_text, input_text_offset);
4186 me_execute_string (temp1);
4187 free (temp1);
4188 }
4189 else
4190#endif /* HAVE_MACROS */
f8b2ac1e 4191 execute_string ("%s\n", temp);
6599da04
JM
4192
4193 ending_pos = output_position + output_paragraph_offset;
4194 free (temp);
4195
4196 len = (ending_pos - starting_pos) - 1;
4197 for (i = 0; i < len; i++)
4198 add_char (with_char);
4199 insert ('\n');
4200 close_paragraph ();
4201 filling_enabled = 1;
4202 no_indent = old_no_indent;
4203}
4204
4205/* Here is a structure which associates sectioning commands with
4206 an integer, hopefully to reflect the `depth' of the current
4207 section. */
4208struct {
4209 char *name;
4210 int level;
4211} section_alist[] = {
4212 { "unnumberedsubsubsec", 5 },
4213 { "unnumberedsubsec", 4 },
4214 { "unnumberedsec", 3 },
4215 { "unnumbered", 2 },
4216 { "appendixsubsubsec", 5 },
4217 { "appendixsubsec", 4 },
4218 { "appendixsec", 3 },
4219 { "appendixsection", 3 },
4220 { "appendix", 2 },
4221 { "subsubsec", 5 },
4222 { "subsubsection", 5 },
4223 { "subsection", 4 },
4224 { "section", 3 },
4225 { "chapter", 2 },
4226 { "top", 1 },
4227
4228 { (char *)NULL, 0 }
4229};
4230
4231/* Amount to offset the name of sectioning commands to levels by. */
4232int section_alist_offset = 0;
4233
4234/* Shift the meaning of @section to @chapter. */
4235void
4236cm_raisesections ()
4237{
4238 discard_until ("\n");
4239 section_alist_offset--;
4240}
4241
4242/* Shift the meaning of @chapter to @section. */
4243void
4244cm_lowersections ()
4245{
4246 discard_until ("\n");
4247 section_alist_offset++;
4248}
4249
4250/* Return an integer which identifies the type section present in TEXT. */
4251int
4252what_section (text)
4253 char *text;
4254{
4255 register int i, j;
4256 char *t;
4257
4258 find_section_command:
4259 for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
4260 if (text[j] != COMMAND_PREFIX)
4261 return (-1);
4262
4263 text = text + j + 1;
4264
4265 /* We skip @c, @comment, and @?index commands. */
4266 if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
4267 (text[0] == 'c' && cr_or_whitespace (text[1])) ||
4268 (strcmp (text + 1, "index") == 0))
4269 {
4270 while (*text++ != '\n');
4271 goto find_section_command;
4272 }
4273
4274 /* Handle italicized sectioning commands. */
4275 if (*text == 'i')
4276 text++;
4277
4278 for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
4279
f8b2ac1e 4280 for (i = 0; (t = section_alist[i].name); i++)
6599da04
JM
4281 {
4282 if (j == strlen (t) && strncmp (t, text, j) == 0)
f8b2ac1e
JL
4283 {
4284 int return_val;
6599da04 4285
f8b2ac1e 4286 return_val = (section_alist[i].level + section_alist_offset);
6599da04 4287
f8b2ac1e
JL
4288 if (return_val < 0)
4289 return_val = 0;
4290 else if (return_val > 5)
4291 return_val = 5;
4292 return (return_val);
4293 }
6599da04
JM
4294 }
4295 return (-1);
4296}
4297
4298/* Set the level of @top to LEVEL. Return the old level of @top. */
4299int
4300set_top_section_level (level)
4301 int level;
4302{
4303 register int i, result = -1;
4304
4305 for (i = 0; section_alist[i].name; i++)
4306 if (strcmp (section_alist[i].name, "top") == 0)
4307 {
f8b2ac1e
JL
4308 result = section_alist[i].level;
4309 section_alist[i].level = level;
4310 break;
6599da04
JM
4311 }
4312 return (result);
4313}
4314
4315/* Treat this just like @unnumbered. The only difference is
4316 in node defaulting. */
4317void
4318cm_top ()
4319{
4320 /* It is an error to have more than one @top. */
4321 if (top_node_seen)
4322 {
4323 TAG_ENTRY *tag = tag_table;
4324
d275726b 4325 line_error (_("Node with %ctop as a section already exists"),
f8b2ac1e 4326 COMMAND_PREFIX);
6599da04
JM
4327
4328 while (tag != (TAG_ENTRY *)NULL)
f8b2ac1e
JL
4329 {
4330 if ((tag->flags & IS_TOP))
4331 {
4332 int old_line_number = line_number;
4333 char *old_input_filename = input_filename;
4334
4335 line_number = tag->line_no;
4336 input_filename = tag->filename;
4337 line_error (_("Here is the %ctop node"), COMMAND_PREFIX);
4338 input_filename = old_input_filename;
4339 line_number = old_line_number;
4340 return;
4341 }
4342 tag = tag->next_ent;
4343 }
6599da04
JM
4344 }
4345 else
4346 {
4347 top_node_seen = 1;
4348
4349 /* It is an error to use @top before you have used @node. */
4350 if (!tag_table)
f8b2ac1e
JL
4351 {
4352 char *top_name;
4353
4354 get_rest_of_line (&top_name);
4355 free (top_name);
4356 line_error (_("%ctop used before %cnode, defaulting to %s"),
4357 COMMAND_PREFIX, COMMAND_PREFIX, top_name);
4358 execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
4359 return;
4360 }
6599da04
JM
4361
4362 cm_unnumbered ();
4363
4364 /* The most recently defined node is the top node. */
4365 tag_table->flags |= IS_TOP;
4366
4367 /* Now set the logical hierarchical level of the Top node. */
4368 {
f8b2ac1e 4369 int orig_offset = input_text_offset;
6599da04 4370
f8b2ac1e 4371 input_text_offset = search_forward (node_search_string, orig_offset);
6599da04 4372
f8b2ac1e
JL
4373 if (input_text_offset > 0)
4374 {
4375 int this_section;
6599da04 4376
f8b2ac1e
JL
4377 /* We have encountered a non-top node, so mark that one exists. */
4378 non_top_node_seen = 1;
6599da04 4379
f8b2ac1e
JL
4380 /* Move to the end of this line, and find out what the
4381 sectioning command is here. */
4382 while (input_text[input_text_offset] != '\n')
4383 input_text_offset++;
6599da04 4384
f8b2ac1e
JL
4385 if (input_text_offset < size_of_input_text)
4386 input_text_offset++;
6599da04 4387
f8b2ac1e 4388 this_section = what_section (input_text + input_text_offset);
6599da04 4389
f8b2ac1e
JL
4390 /* If we found a sectioning command, then give the top section
4391 a level of this section - 1. */
4392 if (this_section != -1)
4393 set_top_section_level (this_section - 1);
4394 }
4395 input_text_offset = orig_offset;
6599da04
JM
4396 }
4397 }
4398}
4399
4400/* Organized by level commands. That is, "*" == chapter, "=" == section. */
4401char *scoring_characters = "*=-.";
4402
4403void
4404sectioning_underscore (command)
4405 char *command;
4406{
4407 char character;
4408 char *temp;
4409 int level;
4410
4411 temp = (char *)xmalloc (2 + strlen (command));
4412 temp[0] = COMMAND_PREFIX;
4413 strcpy (&temp[1], command);
4414 level = what_section (temp);
4415 free (temp);
4416 level -= 2;
4417
4418 if (level < 0)
4419 level = 0;
4420
4421 character = scoring_characters[level];
4422
4423 insert_and_underscore (character);
4424}
4425
4426/* The command still works, but prints a warning message in addition. */
4427void
4428cm_ideprecated (arg, start, end)
4429 int arg, start, end;
4430{
f8b2ac1e
JL
4431 warning (_("%c%s is obsolete; use %c%s instead"),
4432 COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
6599da04
JM
4433 sectioning_underscore (command + 1);
4434}
4435
4436/* The remainder of the text on this line is a chapter heading. */
4437void
4438cm_chapter ()
4439{
4440 sectioning_underscore ("chapter");
4441}
4442
4443/* The remainder of the text on this line is a section heading. */
4444void
4445cm_section ()
4446{
4447 sectioning_underscore ("section");
4448}
4449
4450/* The remainder of the text on this line is a subsection heading. */
4451void
4452cm_subsection ()
4453{
4454 sectioning_underscore ("subsection");
4455}
4456
4457/* The remainder of the text on this line is a subsubsection heading. */
4458void
4459cm_subsubsection ()
4460{
4461 sectioning_underscore ("subsubsection");
4462}
4463
4464/* The remainder of the text on this line is an unnumbered heading. */
4465void
4466cm_unnumbered ()
4467{
4468 cm_chapter ();
4469}
4470
4471/* The remainder of the text on this line is an unnumbered section heading. */
4472void
4473cm_unnumberedsec ()
4474{
4475 cm_section ();
4476}
4477
4478/* The remainder of the text on this line is an unnumbered
4479 subsection heading. */
4480void
4481cm_unnumberedsubsec ()
4482{
4483 cm_subsection ();
4484}
4485
4486/* The remainder of the text on this line is an unnumbered
4487 subsubsection heading. */
4488void
4489cm_unnumberedsubsubsec ()
4490{
4491 cm_subsubsection ();
4492}
4493
4494/* The remainder of the text on this line is an appendix heading. */
4495void
4496cm_appendix ()
4497{
4498 cm_chapter ();
4499}
4500
4501/* The remainder of the text on this line is an appendix section heading. */
4502void
4503cm_appendixsec ()
4504{
4505 cm_section ();
4506}
4507
4508/* The remainder of the text on this line is an appendix subsection heading. */
4509void
4510cm_appendixsubsec ()
4511{
4512 cm_subsection ();
4513}
4514
4515/* The remainder of the text on this line is an appendix
4516 subsubsection heading. */
4517void
4518cm_appendixsubsubsec ()
4519{
4520 cm_subsubsection ();
4521}
4522
4523/* Compatibility functions substitute for chapter, section, etc. */
4524void
4525cm_majorheading ()
4526{
4527 cm_chapheading ();
4528}
4529
4530void
4531cm_chapheading ()
4532{
4533 cm_chapter ();
4534}
4535
4536void
4537cm_heading ()
4538{
4539 cm_section ();
4540}
4541
4542void
4543cm_subheading ()
4544{
4545 cm_subsection ();
4546}
4547
4548void
4549cm_subsubheading ()
4550{
4551 cm_subsubsection ();
4552}
4553\f
4554/* **************************************************************** */
f8b2ac1e
JL
4555/* */
4556/* Adding nodes, and making tags */
4557/* */
6599da04
JM
4558/* **************************************************************** */
4559
4560/* Start a new tag table. */
4561void
4562init_tag_table ()
4563{
4564 while (tag_table != (TAG_ENTRY *) NULL)
4565 {
4566 TAG_ENTRY *temp = tag_table;
4567 free (temp->node);
4568 free (temp->prev);
4569 free (temp->next);
4570 free (temp->up);
4571 tag_table = tag_table->next_ent;
4572 free (temp);
4573 }
4574}
4575
4576void
4577write_tag_table ()
4578{
f8b2ac1e 4579 write_tag_table_internal (0); /* Not indirect. */
6599da04
JM
4580}
4581
4582void
4583write_tag_table_indirect ()
4584{
4585 write_tag_table_internal (1);
4586}
4587
4588/* Write out the contents of the existing tag table.
4589 INDIRECT_P says how to format the output. */
4590void
4591write_tag_table_internal (indirect_p)
4592 int indirect_p;
4593{
4594 TAG_ENTRY *node = tag_table;
4595 int old_indent = no_indent;
4596
4597 no_indent = 1;
4598 filling_enabled = 0;
4599 must_start_paragraph = 0;
4600 close_paragraph ();
4601
4602 if (!indirect_p)
4603 {
4604 no_indent = 1;
4605 insert ('\n');
4606 }
4607
4608 add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
4609
4610 while (node != (TAG_ENTRY *) NULL)
4611 {
4612 execute_string ("Node: %s", node->node);
4613 add_word_args ("\177%d\n", node->position);
4614 node = node->next_ent;
4615 }
4616
4617 add_word ("\037\nEnd Tag Table\n");
4618 flush_output ();
4619 no_indent = old_indent;
4620}
4621
4622char *
f8b2ac1e
JL
4623get_node_token (expand)
4624 int expand;
6599da04
JM
4625{
4626 char *string;
4627
f8b2ac1e 4628 get_until_in_line (expand, ",", &string);
6599da04
JM
4629
4630 if (curchar () == ',')
4631 input_text_offset++;
4632
4633 canon_white (string);
4634
4635 /* Force all versions of "top" to be "Top". */
4636 normalize_node_name (string);
4637
4638 return (string);
4639}
4640
4641/* Convert "top" and friends into "Top". */
4642void
4643normalize_node_name (string)
4644 char *string;
4645{
4646 if (strcasecmp (string, "Top") == 0)
4647 strcpy (string, "Top");
4648}
4649
4650/* Look up NAME in the tag table, and return the associated
4651 tag_entry. If the node is not in the table return NULL. */
4652TAG_ENTRY *
4653find_node (name)
4654 char *name;
4655{
4656 TAG_ENTRY *tag = tag_table;
4657
4658 while (tag != (TAG_ENTRY *) NULL)
4659 {
4660 if (strcmp (tag->node, name) == 0)
f8b2ac1e 4661 return (tag);
6599da04
JM
4662 tag = tag->next_ent;
4663 }
4664 return ((TAG_ENTRY *) NULL);
4665}
4666
4667/* Remember NODE and associates. */
4668void
4669remember_node (node, prev, next, up, position, line_no, no_warn)
4670 char *node, *prev, *next, *up;
4671 int position, line_no, no_warn;
4672{
4673 /* Check for existence of this tag already. */
4674 if (validating)
4675 {
4676 register TAG_ENTRY *tag = find_node (node);
4677 if (tag)
f8b2ac1e
JL
4678 {
4679 line_error (
4680 _("Node `%s' multiply defined (line %d is first definition at)"),
4681 node, tag->line_no);
4682 return;
4683 }
6599da04
JM
4684 }
4685
4686 /* First, make this the current node. */
4687 current_node = node;
4688
4689 /* Now add it to the list. */
4690 {
4691 TAG_ENTRY *new = (TAG_ENTRY *) xmalloc (sizeof (TAG_ENTRY));
4692 new->node = node;
4693 new->prev = prev;
4694 new->next = next;
4695 new->up = up;
4696 new->position = position;
4697 new->line_no = line_no;
4698 new->filename = node_filename;
f8b2ac1e 4699 new->touched = 0; /* not yet referenced. */
6599da04
JM
4700 new->flags = 0;
4701 if (no_warn)
4702 new->flags |= NO_WARN;
4703 new->next_ent = tag_table;
4704 tag_table = new;
4705 }
4706}
4707
4708/* The order is: nodename, nextnode, prevnode, upnode.
4709 If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
4710 You must follow a node command which has those fields defaulted
4711 with a sectioning command (e.g. @chapter) giving the "level" of that node.
4712 It is an error not to do so.
4713 The defaults come from the menu in this node's parent. */
4714void
4715cm_node ()
4716{
4717 char *node, *prev, *next, *up;
4718 int new_node_pos, defaulting, this_section, no_warn = 0;
4719 extern int already_outputting_pending_notes;
4720
4721 if (strcmp (command, "nwnode") == 0)
4722 no_warn = 1;
4723
4724 /* Get rid of unmatched brace arguments from previous commands. */
4725 discard_braces ();
4726
4727 /* There also might be insertions left lying around that haven't been
4728 ended yet. Do that also. */
f8b2ac1e 4729 discard_insertions (1);
6599da04
JM
4730
4731 if (!already_outputting_pending_notes)
4732 {
4733 close_paragraph ();
4734 output_pending_notes ();
4735 free_pending_notes ();
4736 }
4737
4738 filling_enabled = indented_fill = 0;
4739 new_node_pos = output_position;
4740 current_footnote_number = 1;
4741
4742#if defined (HAVE_MACROS)
d275726b 4743 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
4744 append_to_expansion_output (input_text_offset + 1);
4745#endif /* HAVE_MACROS */
4746
f8b2ac1e
JL
4747 node = get_node_token (1);
4748 next = get_node_token (0);
4749 prev = get_node_token (0);
4750 up = get_node_token (0);
6599da04 4751
f8b2ac1e
JL
4752 if (verbose_mode)
4753 printf (_("Formatting node %s...\n"), node);
4754
6599da04 4755#if defined (HAVE_MACROS)
d275726b 4756 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
4757 remember_itext (input_text, input_text_offset);
4758#endif /* HAVE_MACROS */
4759
4760 no_indent = 1;
4761 if (!no_headers)
4762 {
4763 add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
4764
4765#if defined (HAVE_MACROS)
d275726b 4766 if (macro_expansion_output_stream && !executing_string)
f8b2ac1e 4767 me_execute_string (node);
6599da04
JM
4768 else
4769#endif /* HAVE_MACROS */
f8b2ac1e 4770 execute_string ("%s", node);
6599da04
JM
4771 filling_enabled = indented_fill = 0;
4772 }
4773
4774 /* Check for defaulting of this node's next, prev, and up fields. */
f8b2ac1e 4775 defaulting = (*next == 0 && *prev == 0 && *up == 0);
6599da04
JM
4776
4777 this_section = what_section (input_text + input_text_offset);
4778
4779 /* If we are defaulting, then look at the immediately following
4780 sectioning command (error if none) to determine the node's
4781 level. Find the node that contains the menu mentioning this node
4782 that is one level up (error if not found). That node is the "Up"
4783 of this node. Default the "Next" and "Prev" from the menu. */
4784 if (defaulting)
4785 {
4786 NODE_REF *last_ref = (NODE_REF *)NULL;
4787 NODE_REF *ref = node_references;
4788
4789 if ((this_section < 0) && (strcmp (node, "Top") != 0))
f8b2ac1e
JL
4790 {
4791 char *polite_section_name = "top";
4792 int i;
4793
4794 for (i = 0; section_alist[i].name; i++)
4795 if (section_alist[i].level == current_section + 1)
4796 {
4797 polite_section_name = section_alist[i].name;
4798 break;
4799 }
4800
4801 line_error
4802 (_("Node `%s' requires a sectioning command (e.g. %c%s)"),
4803 node, COMMAND_PREFIX, polite_section_name);
4804 }
6599da04 4805 else
f8b2ac1e
JL
4806 {
4807 if (strcmp (node, "Top") == 0)
4808 {
4809 /* Default the NEXT pointer to be the first menu item in
4810 this node, if there is a menu in this node. We have to
4811 try very hard to find the menu, as it may be obscured
4812 by execution_strings which are on the filestack. For
4813 every member of the filestack which has a FILENAME
4814 member which is identical to the current INPUT_FILENAME,
4815 search forward from that offset. */
4816 int saved_input_text_offset = input_text_offset;
4817 int saved_size_of_input_text = size_of_input_text;
4818 char *saved_input_text = input_text;
4819 FSTACK *next_file = filestack;
4820
4821 int orig_offset, orig_size;
4822 char *glean_node_from_menu ();
4823
4824 /* No matter what, make this file point back at `(dir)'. */
4825 free (up); up = xstrdup ("(dir)");
4826
4827 while (1)
4828 {
4829 orig_offset = input_text_offset;
4830 orig_size =
4831 search_forward (node_search_string, orig_offset);
4832
4833 if (orig_size < 0)
4834 orig_size = size_of_input_text;
4835
4836 input_text_offset =
4837 search_forward (menu_search_string, orig_offset);
4838
4839 if (input_text_offset > -1)
4840 {
4841 char *nodename_from_menu = (char *)NULL;
4842
4843 input_text_offset =
4844 search_forward ("\n* ", input_text_offset);
4845
4846 if (input_text_offset != -1)
4847 nodename_from_menu = glean_node_from_menu (0);
4848
4849 if (nodename_from_menu)
4850 {
4851 free (next); next = nodename_from_menu;
4852 break;
4853 }
4854 }
4855
4856 /* We got here, so it hasn't been found yet. Try
4857 the next file on the filestack if there is one. */
4858 if (next_file &&
4859 (strcmp (next_file->filename, input_filename) == 0))
4860 {
4861 input_text = next_file->text;
4862 input_text_offset = next_file->offset;
4863 size_of_input_text = next_file->size;
4864 next_file = next_file->next;
4865 }
4866 else
4867 {
4868 /* No more input files to check. */
4869 break;
4870 }
4871 }
4872
4873 input_text = saved_input_text;
4874 input_text_offset = saved_input_text_offset;
4875 size_of_input_text = saved_size_of_input_text;
4876 }
4877 }
6599da04
JM
4878
4879 /* Fix the level of the menu references in the Top node, iff it
f8b2ac1e 4880 was declared with @top, and no subsequent reference was found. */
6599da04 4881 if (top_node_seen && !non_top_node_seen)
f8b2ac1e
JL
4882 {
4883 /* Then this is the first non-@top node seen. */
4884 int level;
6599da04 4885
f8b2ac1e
JL
4886 level = set_top_section_level (this_section - 1);
4887 non_top_node_seen = 1;
6599da04 4888
f8b2ac1e
JL
4889 while (ref)
4890 {
4891 if (ref->section == level)
4892 ref->section = this_section - 1;
4893 ref = ref->next;
4894 }
6599da04 4895
f8b2ac1e
JL
4896 ref = node_references;
4897 }
6599da04
JM
4898
4899 while (ref)
f8b2ac1e
JL
4900 {
4901 if (ref->section == (this_section - 1) &&
4902 ref->type == menu_reference &&
4903 strcmp (ref->node, node) == 0)
4904 {
4905 char *containing_node = ref->containing_node;
4906
4907 free (up);
4908 up = xstrdup (containing_node);
4909
4910 if (last_ref &&
4911 last_ref->type == menu_reference &&
4912 (strcmp (last_ref->containing_node,
4913 containing_node) == 0))
4914 {
4915 free (next);
4916 next = xstrdup (last_ref->node);
4917 }
4918
4919 while ((ref->section == this_section - 1) &&
4920 (ref->next) &&
4921 (ref->next->type != menu_reference))
4922 ref = ref->next;
4923
4924 if (ref->next && ref->type == menu_reference &&
4925 (strcmp (ref->next->containing_node,
4926 containing_node) == 0))
4927 {
4928 free (prev);
4929 prev = xstrdup (ref->next->node);
4930 }
4931 else if (!ref->next &&
4932 strcasecmp (ref->containing_node, "Top") == 0)
4933 {
4934 free (prev);
4935 prev = xstrdup (ref->containing_node);
4936 }
4937 break;
4938 }
4939 last_ref = ref;
4940 ref = ref->next;
4941 }
6599da04
JM
4942 }
4943
4944#if defined (HAVE_MACROS)
4945 /* Insert the correct args if we are expanding macros, and the node's
4946 pointers weren't defaulted. */
d275726b 4947 if (macro_expansion_output_stream && !executing_string && !defaulting)
6599da04
JM
4948 {
4949 char *temp;
4950 int op_orig = output_paragraph_offset;
4951
4952 temp = (char *)xmalloc (3 + strlen (next));
4953 sprintf (temp, ", %s", next);
4954 me_execute_string (temp);
4955 free (temp);
4956
4957 temp = (char *)xmalloc (3 + strlen (prev));
4958 sprintf (temp, ", %s", prev);
4959 me_execute_string (temp);
4960 free (temp);
4961
4962 temp = (char *)xmalloc (4 + strlen (up));
4963 sprintf (temp, ", %s", up);
4964 me_execute_string (temp);
4965 free (temp);
4966
4967 output_paragraph_offset = op_orig;
4968 }
4969#endif /* HAVE_MACROS */
4970
4971 if (!no_headers)
4972 {
4973#if defined (HAVE_MACROS)
4974 if (macro_expansion_output_stream)
f8b2ac1e 4975 me_inhibit_expansion++;
6599da04
JM
4976#endif /* HAVE_MACROS */
4977
4978 if (*next)
f8b2ac1e
JL
4979 {
4980 execute_string (", Next: %s", next);
4981 filling_enabled = indented_fill = 0;
4982 }
6599da04
JM
4983
4984 if (*prev)
f8b2ac1e
JL
4985 {
4986 execute_string (", Prev: %s", prev);
4987 filling_enabled = indented_fill = 0;
4988 }
6599da04
JM
4989
4990 if (*up)
f8b2ac1e
JL
4991 {
4992 execute_string (", Up: %s", up);
4993 filling_enabled = indented_fill = 0;
4994 }
6599da04
JM
4995#if defined (HAVE_MACROS)
4996 if (macro_expansion_output_stream)
f8b2ac1e 4997 me_inhibit_expansion--;
6599da04
JM
4998#endif /* HAVE_MACROS */
4999 }
5000
5001 close_paragraph ();
5002 no_indent = 0;
5003
5004 if (!*node)
5005 {
5006 line_error ("No node name specified for `%c%s' command",
f8b2ac1e 5007 COMMAND_PREFIX, command);
6599da04
JM
5008 free (node);
5009 free (next);
5010 free (prev);
5011 free (up);
5012 }
5013 else
5014 {
5015 if (!*next) { free (next); next = (char *)NULL; }
5016 if (!*prev) { free (prev); prev = (char *)NULL; }
5017 if (!*up) { free (up); up = (char *)NULL; }
5018 remember_node (node, prev, next, up, new_node_pos, line_number, no_warn);
5019 }
5020
5021 /* Change the section only if there was a sectioning command. */
5022 if (this_section >= 0)
5023 current_section = this_section;
5024
5025 filling_enabled = 1;
5026}
5027
5028/* Validation of an info file.
5029 Scan through the list of tag entries touching the Prev, Next, and Up
5030 elements of each. It is an error not to be able to touch one of them,
5031 except in the case of external node references, such as "(DIR)".
5032
5033 If the Prev is different from the Up,
5034 then the Prev node must have a Next pointing at this node.
5035
5036 Every node except Top must have an Up.
5037 The Up node must contain some sort of reference, other than a Next,
5038 to this node.
5039
5040 If the Next is different from the Next of the Up,
5041 then the Next node must have a Prev pointing at this node. */
5042void
5043validate_file (tag_table)
5044 TAG_ENTRY *tag_table;
5045{
5046 char *old_input_filename = input_filename;
5047 TAG_ENTRY *tags = tag_table;
5048
5049 while (tags != (TAG_ENTRY *) NULL)
5050 {
5051 register TAG_ENTRY *temp_tag;
5052
5053 input_filename = tags->filename;
5054 line_number = tags->line_no;
5055
5056 /* If this is a "no warn" node, don't validate it in any way. */
5057 if (tags->flags & NO_WARN)
f8b2ac1e
JL
5058 {
5059 tags = tags->next_ent;
5060 continue;
5061 }
6599da04
JM
5062
5063 /* If this node has a Next, then make sure that the Next exists. */
5064 if (tags->next)
f8b2ac1e
JL
5065 {
5066 validate (tags->next, tags->line_no, "Next");
5067
5068 /* If the Next node exists, and there is no Up, then make
5069 sure that the Prev of the Next points back. */
5070 temp_tag = find_node (tags->next);
5071 if (temp_tag)
5072 {
5073 char *prev;
5074
5075 if (temp_tag->flags & NO_WARN)
5076 {
5077 /* Do nothing if we aren't supposed to issue warnings
5078 about this node. */
5079 }
5080 else
5081 {
5082 prev = temp_tag->prev;
5083 if (!prev || (strcmp (prev, tags->node) != 0))
5084 {
5085 line_error (_("Node `%s''s Next field not pointed back to"),
5086 tags->node);
5087 line_number = temp_tag->line_no;
5088 input_filename = temp_tag->filename;
5089 line_error
5090 (_("This node (`%s') is the one with the bad `Prev'"),
5091 temp_tag->node);
5092 input_filename = tags->filename;
5093 line_number = tags->line_no;
5094 temp_tag->flags |= PREV_ERROR;
5095 }
5096 }
5097 }
5098 }
6599da04
JM
5099
5100 /* Validate the Prev field if there is one, and we haven't already
f8b2ac1e
JL
5101 complained about it in some way. You don't have to have a Prev
5102 field at this stage. */
6599da04 5103 if (!(tags->flags & PREV_ERROR) && tags->prev)
f8b2ac1e
JL
5104 {
5105 int valid_p = validate (tags->prev, tags->line_no, "Prev");
5106
5107 if (!valid_p)
5108 tags->flags |= PREV_ERROR;
5109 else
5110 {
5111 /* If the Prev field is not the same as the Up field,
5112 then the node pointed to by the Prev field must have
5113 a Next field which points to this node. */
5114 if (tags->up && (strcmp (tags->prev, tags->up) != 0))
5115 {
5116 temp_tag = find_node (tags->prev);
5117
5118 /* If we aren't supposed to issue warnings about the
5119 target node, do nothing. */
5120 if (!temp_tag || (temp_tag->flags & NO_WARN))
5121 {
5122 /* Do nothing. */
5123 }
5124 else
5125 {
5126 if (!temp_tag->next ||
5127 (strcmp (temp_tag->next, tags->node) != 0))
5128 {
5129 line_error
5130 (_("Node `%s's Prev field not pointed back to"),
5131 tags->node);
5132 line_number = temp_tag->line_no;
5133 input_filename = temp_tag->filename;
5134 line_error (_("This node (`%s') has the bad Next"),
5135 temp_tag->node);
5136 input_filename = tags->filename;
5137 line_number = tags->line_no;
5138 temp_tag->flags |= NEXT_ERROR;
5139 }
5140 }
5141 }
5142 }
5143 }
5144
5145 if (!tags->up && (strcasecmp (tags->node, _("Top")) != 0))
5146 line_error (_("Node `%s' missing Up field"), tags->node);
6599da04 5147 else if (tags->up)
f8b2ac1e
JL
5148 {
5149 int valid_p = validate (tags->up, tags->line_no, "Up");
5150
5151 /* If node X has Up: Y, then warn if Y fails to have a menu item
5152 or note pointing at X, if Y isn't of the form "(Y)". */
5153 if (valid_p && *tags->up != '(')
5154 {
5155 NODE_REF *nref, *tref, *list;
5156 NODE_REF *find_node_reference ();
5157
5158 tref = (NODE_REF *) NULL;
5159 list = node_references;
5160
5161 for (;;)
5162 {
5163 if (!(nref = find_node_reference (tags->node, list)))
5164 break;
5165
5166 if (strcmp (nref->containing_node, tags->up) == 0)
5167 {
5168 if (nref->type != menu_reference)
5169 {
5170 tref = nref;
5171 list = nref->next;
5172 }
5173 else
5174 break;
5175 }
5176 list = nref->next;
5177 }
5178
5179 if (!nref)
5180 {
5181 temp_tag = find_node (tags->up);
5182 line_number = temp_tag->line_no;
5183 input_filename = temp_tag->filename;
5184 if (!tref)
5185 line_error (
5186_("`%s' has an Up field of `%s', but `%s' has no menu item for `%s'"),
5187 tags->node, tags->up, tags->up, tags->node);
5188 line_number = tags->line_no;
5189 input_filename = tags->filename;
5190 }
5191 }
5192 }
6599da04
JM
5193 tags = tags->next_ent;
5194 }
5195
5196 validate_other_references (node_references);
5197 /* We have told the user about the references which didn't exist.
5198 Now tell him about the nodes which aren't referenced. */
5199
5200 tags = tag_table;
5201 while (tags != (TAG_ENTRY *) NULL)
5202 {
5203 /* If this node is a "no warn" node, do nothing. */
5204 if (tags->flags & NO_WARN)
f8b2ac1e
JL
5205 {
5206 tags = tags->next_ent;
5207 continue;
5208 }
6599da04
JM
5209
5210 /* Special hack. If the node in question appears to have
5211 been referenced more than REFERENCE_WARNING_LIMIT times,
5212 give a warning. */
5213 if (tags->touched > reference_warning_limit)
f8b2ac1e
JL
5214 {
5215 input_filename = tags->filename;
5216 line_number = tags->line_no;
5217 warning (_("node `%s' has been referenced %d times"),
5218 tags->node, tags->touched);
5219 }
6599da04
JM
5220
5221 if (tags->touched == 0)
f8b2ac1e
JL
5222 {
5223 input_filename = tags->filename;
5224 line_number = tags->line_no;
5225
5226 /* Notice that the node "Top" is special, and doesn't have to
5227 be referenced. */
5228 if (strcasecmp (tags->node, _("Top")) != 0)
5229 warning (_("unreferenced node `%s'"), tags->node);
5230 }
6599da04
JM
5231 tags = tags->next_ent;
5232 }
5233 input_filename = old_input_filename;
5234}
5235
5236/* Return 1 if tag correctly validated, or 0 if not. */
5237int
5238validate (tag, line, label)
5239 char *tag;
5240 int line;
5241 char *label;
5242{
5243 TAG_ENTRY *result;
5244
5245 /* If there isn't a tag to verify, or if the tag is in another file,
5246 then it must be okay. */
5247 if (!tag || !*tag || *tag == '(')
5248 return (1);
5249
5250 /* Otherwise, the tag must exist. */
5251 result = find_node (tag);
5252
5253 if (!result)
5254 {
5255 line_number = line;
f8b2ac1e 5256 line_error (_("%s reference to nonexistent node `%s'"), label, tag);
6599da04
JM
5257 return (0);
5258 }
5259 result->touched++;
5260 return (1);
5261}
5262
5263/* Split large output files into a series of smaller files. Each file
5264 is pointed to in the tag table, which then gets written out as the
5265 original file. The new files have the same name as the original file
5266 with a "-num" attached. SIZE is the largest number of bytes to allow
5267 in any single split file. */
5268void
5269split_file (filename, size)
5270 char *filename;
5271 int size;
5272{
5273 char *root_filename, *root_pathname;
5274 char *the_file, *filename_part ();
5275 struct stat fileinfo;
5276 long file_size;
5277 char *the_header;
5278 int header_size;
5279
5280 /* Can only do this to files with tag tables. */
5281 if (!tag_table)
5282 return;
5283
5284 if (size == 0)
5285 size = DEFAULT_SPLIT_SIZE;
5286
5287 if ((stat (filename, &fileinfo) != 0) ||
5288 (((long) fileinfo.st_size) < SPLIT_SIZE_THRESHOLD))
5289 return;
5290 file_size = (long) fileinfo.st_size;
5291
5292 the_file = find_and_load (filename);
5293 if (!the_file)
5294 return;
5295
5296 root_filename = filename_part (filename);
5297 root_pathname = pathname_part (filename);
5298
5299 if (!root_pathname)
f8b2ac1e 5300 root_pathname = xstrdup ("");
6599da04
JM
5301
5302 /* Start splitting the file. Walk along the tag table
5303 outputting sections of the file. When we have written
5304 all of the nodes in the tag table, make the top-level
5305 pointer file, which contains indirect pointers and
5306 tags for the nodes. */
5307 {
5308 int which_file = 1;
5309 TAG_ENTRY *tags = tag_table;
5310 char *indirect_info = (char *)NULL;
5311
5312 /* Remember the `header' of this file. The first tag in the file is
5313 the bottom of the header; the top of the file is the start. */
5314 the_header = (char *)xmalloc (1 + (header_size = tags->position));
5315 memcpy (the_header, the_file, header_size);
5316
5317 while (tags)
5318 {
f8b2ac1e
JL
5319 int file_top, file_bot, limit;
5320
5321 /* Have to include the Control-_. */
5322 file_top = file_bot = tags->position;
5323 limit = file_top + size;
5324
5325 /* If the rest of this file is only one node, then
5326 that is the entire subfile. */
5327 if (!tags->next_ent)
5328 {
5329 int i = tags->position + 1;
5330 char last_char = the_file[i];
5331
5332 while (i < file_size)
5333 {
5334 if ((the_file[i] == '\037') &&
5335 ((last_char == '\n') ||
5336 (last_char == '\014')))
5337 break;
5338 else
5339 last_char = the_file[i];
5340 i++;
5341 }
5342 file_bot = i;
5343 tags = tags->next_ent;
5344 goto write_region;
5345 }
5346
5347 /* Otherwise, find the largest number of nodes that can fit in
5348 this subfile. */
5349 for (; tags; tags = tags->next_ent)
5350 {
5351 if (!tags->next_ent)
5352 {
5353 /* This entry is the last node. Search forward for the end
5354 of this node, and that is the end of this file. */
5355 int i = tags->position + 1;
5356 char last_char = the_file[i];
5357
5358 while (i < file_size)
5359 {
5360 if ((the_file[i] == '\037') &&
5361 ((last_char == '\n') ||
5362 (last_char == '\014')))
5363 break;
5364 else
5365 last_char = the_file[i];
5366 i++;
5367 }
5368 file_bot = i;
5369
5370 if (file_bot < limit)
5371 {
5372 tags = tags->next_ent;
5373 goto write_region;
5374 }
5375 else
5376 {
5377 /* Here we want to write out everything before the last
5378 node, and then write the last node out in a file
5379 by itself. */
5380 file_bot = tags->position;
5381 goto write_region;
5382 }
5383 }
5384
5385 if (tags->next_ent->position > limit)
5386 {
5387 if (tags->position == file_top)
5388 tags = tags->next_ent;
5389
5390 file_bot = tags->position;
5391
5392 write_region:
5393 {
5394 int fd;
5395 char *split_filename;
5396
5397 split_filename = (char *) xmalloc
5398 (10 + strlen (root_pathname) + strlen (root_filename));
5399 sprintf
5400 (split_filename,
5401 "%s%s-%d", root_pathname, root_filename, which_file);
5402
5403 fd = open
5404 (split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
5405
5406 if ((fd < 0) ||
5407 (write (fd, the_header, header_size) != header_size) ||
5408 (write (fd, the_file + file_top, file_bot - file_top)
5409 != (file_bot - file_top)) ||
5410 ((close (fd)) < 0))
5411 {
5412 perror (split_filename);
5413 if (fd != -1)
5414 close (fd);
5415 exit (FATAL);
5416 }
5417
5418 if (!indirect_info)
5419 {
5420 indirect_info = the_file + file_top;
5421 sprintf (indirect_info, "\037\nIndirect:\n");
5422 indirect_info += strlen (indirect_info);
5423 }
5424
5425 sprintf (indirect_info, "%s-%d: %d\n",
5426 root_filename, which_file, file_top);
5427
5428 free (split_filename);
5429 indirect_info += strlen (indirect_info);
5430 which_file++;
5431 break;
5432 }
5433 }
5434 }
6599da04
JM
5435 }
5436
5437 /* We have sucessfully created the subfiles. Now write out the
5438 original again. We must use `output_stream', or
5439 write_tag_table_indirect () won't know where to place the output. */
5440 output_stream = fopen (filename, "w");
5441 if (!output_stream)
5442 {
f8b2ac1e
JL
5443 perror (filename);
5444 exit (FATAL);
6599da04
JM
5445 }
5446
5447 {
5448 int distance = indirect_info - the_file;
5449 fwrite (the_file, 1, distance, output_stream);
5450
5451 /* Inhibit newlines. */
5452 paragraph_is_open = 0;
5453
5454 write_tag_table_indirect ();
5455 fclose (output_stream);
5456 free (the_header);
5457 free (the_file);
5458 return;
5459 }
5460 }
5461}
5462
f8b2ac1e
JL
5463/* The strings here are followed in the message by `reference to...' in
5464 the `validate' routine. */
6599da04
JM
5465char *
5466reftype_type_string (type)
5467 enum reftype type;
5468{
5469 switch (type)
5470 {
5471 case menu_reference:
5472 return ("Menu");
5473 case followed_reference:
f8b2ac1e 5474 return ("Cross");
6599da04
JM
5475 default:
5476 return ("Internal-bad-reference-type");
5477 }
5478}
5479
f8b2ac1e
JL
5480/* Remember this node name for later validation use. This is used to
5481 remember menu references while reading the input file. After the
5482 output file has been written, if validation is on, then we use the
5483 contents of `node_references' as a list of nodes to validate. */
6599da04
JM
5484void
5485remember_node_reference (node, line, type)
5486 char *node;
5487 int line;
5488 enum reftype type;
5489{
5490 NODE_REF *temp = (NODE_REF *) xmalloc (sizeof (NODE_REF));
5491
5492 temp->next = node_references;
f8b2ac1e 5493 temp->node = xstrdup (node);
6599da04
JM
5494 temp->line_no = line;
5495 temp->section = current_section;
5496 temp->type = type;
f8b2ac1e 5497 temp->containing_node = xstrdup (current_node ? current_node : "");
6599da04
JM
5498 temp->filename = node_filename;
5499
5500 node_references = temp;
5501}
5502
5503void
5504validate_other_references (ref_list)
5505 register NODE_REF *ref_list;
5506{
5507 char *old_input_filename = input_filename;
5508
5509 while (ref_list != (NODE_REF *) NULL)
5510 {
5511 input_filename = ref_list->filename;
5512 validate (ref_list->node, ref_list->line_no,
f8b2ac1e 5513 reftype_type_string (ref_list->type));
6599da04
JM
5514 ref_list = ref_list->next;
5515 }
5516 input_filename = old_input_filename;
5517}
5518
5519/* Find NODE in REF_LIST. */
5520NODE_REF *
5521find_node_reference (node, ref_list)
5522 char *node;
5523 register NODE_REF *ref_list;
5524{
5525 while (ref_list)
5526 {
5527 if (strcmp (node, ref_list->node) == 0)
f8b2ac1e 5528 break;
6599da04
JM
5529 ref_list = ref_list->next;
5530 }
5531 return (ref_list);
5532}
5533
5534void
5535free_node_references ()
5536{
5537 register NODE_REF *list, *temp;
5538
5539 list = node_references;
5540
5541 while (list)
5542 {
5543 temp = list;
5544 free (list->node);
5545 free (list->containing_node);
5546 list = list->next;
5547 free (temp);
5548 }
5549 node_references = (NODE_REF *) NULL;
5550}
5551
5552 /* This function gets called at the start of every line while inside of
5553 a menu. It checks to see if the line starts with "* ", and if so,
5554 remembers the node reference that this menu refers to.
5555 input_text_offset is at the \n just before the line start. */
5556#define menu_starter "* "
5557char *
5558glean_node_from_menu (remember_reference)
5559 int remember_reference;
5560{
5561 int i, orig_offset = input_text_offset;
5562 char *nodename;
5563
5564 if (strncmp (&input_text[input_text_offset + 1],
f8b2ac1e
JL
5565 menu_starter,
5566 strlen (menu_starter)) != 0)
6599da04
JM
5567 return ((char *)NULL);
5568 else
5569 input_text_offset += strlen (menu_starter) + 1;
5570
f8b2ac1e 5571 get_until_in_line (0, ":", &nodename);
6599da04
JM
5572 if (curchar () == ':')
5573 input_text_offset++;
5574 canon_white (nodename);
5575
5576 if (curchar () == ':')
5577 goto save_node;
5578
5579 free (nodename);
5580 get_rest_of_line (&nodename);
5581
5582 /* Special hack: If the nodename follows the menu item name,
5583 then we have to read the rest of the line in order to find
5584 out what the nodename is. But we still have to read the
5585 line later, in order to process any formatting commands that
5586 might be present. So un-count the carriage return that has just
5587 been counted. */
5588 line_number--;
5589
5590 isolate_nodename (nodename);
5591
5592save_node:
5593 input_text_offset = orig_offset;
5594 normalize_node_name (nodename);
5595 i = strlen (nodename);
5596 if (i && nodename[i - 1] == ':')
f8b2ac1e 5597 nodename[i - 1] = 0;
6599da04
JM
5598
5599 if (remember_reference)
5600 {
5601 remember_node_reference (nodename, line_number, menu_reference);
5602 free (nodename);
5603 return ((char *)NULL);
5604 }
5605 else
5606 return (nodename);
5607}
5608
5609static void
5610isolate_nodename (nodename)
5611 char *nodename;
5612{
5613 register int i, c;
5614 int paren_seen, paren;
5615
5616 if (!nodename)
5617 return;
5618
5619 canon_white (nodename);
5620 paren_seen = paren = i = 0;
5621
5622 if (*nodename == '.' || !*nodename)
5623 {
f8b2ac1e 5624 *nodename = 0;
6599da04
JM
5625 return;
5626 }
5627
5628 if (*nodename == '(')
5629 {
5630 paren++;
5631 paren_seen++;
5632 i++;
5633 }
5634
f8b2ac1e 5635 for (; (c = nodename[i]); i++)
6599da04
JM
5636 {
5637 if (paren)
f8b2ac1e
JL
5638 {
5639 if (c == '(')
5640 paren++;
5641 else if (c == ')')
5642 paren--;
6599da04 5643
f8b2ac1e
JL
5644 continue;
5645 }
6599da04
JM
5646
5647 /* If the character following the close paren is a space, then this
f8b2ac1e 5648 node has no more characters associated with it. */
6599da04 5649 if (c == '\t' ||
f8b2ac1e
JL
5650 c == '\n' ||
5651 c == ',' ||
5652 ((paren_seen && nodename[i - 1] == ')') &&
5653 (c == ' ' || c == '.')) ||
5654 (c == '.' &&
5655 ((!nodename[i + 1] ||
5656 (cr_or_whitespace (nodename[i + 1])) ||
5657 (nodename[i + 1] == ')')))))
5658 break;
6599da04 5659 }
f8b2ac1e 5660 nodename[i] = 0;
6599da04
JM
5661}
5662
5663void
5664cm_menu ()
5665{
5666 if (current_node == (char *)NULL)
5667 {
f8b2ac1e
JL
5668 warning (_("%cmenu seen before first node"), COMMAND_PREFIX);
5669 warning (_("creating `Top' node"));
6599da04
JM
5670 execute_string ("@node Top");
5671 }
5672 begin_insertion (menu);
5673}
5674
5675void
5676cm_detailmenu ()
5677{
5678 if (current_node == (char *)NULL)
5679 {
f8b2ac1e
JL
5680 warning (_("%cmenu seen before first node"), COMMAND_PREFIX);
5681 warning (_("creating `Top' node"));
6599da04
JM
5682 execute_string ("@node Top");
5683 }
5684 begin_insertion (detailmenu);
5685}
5686\f
5687/* **************************************************************** */
f8b2ac1e
JL
5688/* */
5689/* Cross Reference Hacking */
5690/* */
6599da04
JM
5691/* **************************************************************** */
5692
f8b2ac1e
JL
5693/* Return next comma-delimited argument, but do not cross a close-brace
5694 boundary. Clean up whitespace, too. */
6599da04
JM
5695char *
5696get_xref_token ()
5697{
5698 char *string;
5699
5700 get_until_in_braces (",", &string);
5701 if (curchar () == ',')
5702 input_text_offset++;
5703 fix_whitespace (string);
5704 return (string);
5705}
5706
f8b2ac1e 5707int px_ref_flag = 0; /* Controls initial output string. */
6599da04
JM
5708
5709/* Make a cross reference. */
5710void
5711cm_xref (arg)
5712{
5713 if (arg == START)
5714 {
5715 char *arg1, *arg2, *arg3, *arg4, *arg5;
5716
5717 arg1 = get_xref_token ();
5718 arg2 = get_xref_token ();
5719 arg3 = get_xref_token ();
5720 arg4 = get_xref_token ();
5721 arg5 = get_xref_token ();
5722
5723 add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
5724
5725 if (*arg5 || *arg4)
f8b2ac1e
JL
5726 {
5727 char *node_name;
5728
5729 if (!*arg2)
5730 {
5731 if (*arg3)
5732 node_name = arg3;
5733 else
5734 node_name = arg1;
5735 }
5736 else
5737 node_name = arg2;
5738
5739 execute_string ("%s: (%s)%s", node_name, arg4, arg1);
5740 /* Free all of the arguments found. */
5741 if (arg1) free (arg1);
5742 if (arg2) free (arg2);
5743 if (arg3) free (arg3);
5744 if (arg4) free (arg4);
5745 if (arg5) free (arg5);
5746 return;
5747 }
6599da04 5748 else
f8b2ac1e 5749 remember_node_reference (arg1, line_number, followed_reference);
6599da04
JM
5750
5751 if (*arg3)
f8b2ac1e
JL
5752 {
5753 if (!*arg2)
5754 execute_string ("%s: %s", arg3, arg1);
5755 else
5756 execute_string ("%s: %s", arg2, arg1);
5757 }
6599da04 5758 else
f8b2ac1e
JL
5759 {
5760 if (*arg2)
5761 execute_string ("%s: %s", arg2, arg1);
5762 else
5763 execute_string ("%s::", arg1);
5764 }
6599da04
JM
5765
5766 /* Free all of the arguments found. */
5767 if (arg1) free (arg1);
5768 if (arg2) free (arg2);
5769 if (arg3) free (arg3);
5770 if (arg4) free (arg4);
5771 if (arg5) free (arg5);
5772 }
5773 else
5774 {
5775 /* Check to make sure that the next non-whitespace character is either
5776 a period or a comma. input_text_offset is pointing at the "}" which
5777 ended the xref or pxref command. */
5778 int temp = input_text_offset + 1;
5779
5780 if (output_paragraph[output_paragraph_offset - 2] == ':' &&
f8b2ac1e
JL
5781 output_paragraph[output_paragraph_offset - 1] == ':')
5782 return;
6599da04 5783 while (temp < size_of_input_text)
f8b2ac1e
JL
5784 {
5785 if (cr_or_whitespace (input_text[temp]))
5786 temp++;
5787 else
5788 {
5789 if (input_text[temp] != '.'
5790 && input_text[temp] != ','
5791 && input_text[temp] != '\t')
5792 {
5793 line_error (
5794 _("`.' or `,' must follow cross reference, not %c"),
5795 input_text[temp]);
5796 }
5797 break;
5798 }
5799 }
6599da04
JM
5800 }
5801}
5802
5803void
5804cm_pxref (arg)
5805 int arg;
5806{
5807 if (arg == START)
5808 {
5809 px_ref_flag++;
5810 cm_xref (arg);
5811 px_ref_flag--;
5812 }
5813 else
5814 add_char ('.');
5815}
5816
5817void
5818cm_inforef (arg)
5819 int arg;
5820{
5821 if (arg == START)
5822 {
f8b2ac1e
JL
5823 char *node = get_xref_token ();
5824 char *pname = get_xref_token ();
5825 char *file = get_xref_token ();
5826
5827 if (*pname)
5828 execute_string ("*note %s: (%s)%s", pname, file, node);
5829 else
5830 execute_string ("*note (%s)%s::", file, node);
5831
5832 free (node);
5833 free (pname);
5834 free (file);
5835 }
5836}
5837
5838/* A URL reference. */
5839void
5840cm_uref (arg, start_pos, end_pos)
5841 int arg, start_pos, end_pos;
5842{
5843 if (arg == END)
5844 {
5845 char *comma;
d275726b 5846 char *arg = (char *) &output_paragraph[start_pos];
f8b2ac1e
JL
5847
5848 output_paragraph[end_pos] = 0;
5849 output_column -= end_pos - start_pos;
5850 output_paragraph_offset = start_pos;
5851
5852 arg = xstrdup (arg);
5853 comma = strchr (arg, ','); /* let's hope for no commas in the url */
5854 if (comma)
5855 {
5856 *comma = 0;
5857 /* Ignore spaces at beginning of second arg. */
5858 for (comma++; isspace (*comma); comma++)
5859 ;
5860 add_word (comma);
5861 add_char (' ');
5862 add_char ('(');
5863 add_word (arg);
5864 add_char (')');
5865 }
5866 else
5867 {
5868 extern int printing_index;
5869
5870 if (!printing_index)
5871 add_char ('`');
5872
5873 add_word (arg);
5874
5875 if (!printing_index)
5876 add_char ('\'');
5877 }
5878 free (arg);
5879 }
5880}
5881
5882/* An email reference. */
5883void
5884cm_email (arg, start_pos, end_pos)
5885 int arg, start_pos, end_pos;
5886{
5887 if (arg == END)
5888 {
5889 char *comma;
d275726b 5890 char *arg = (char *) &output_paragraph[start_pos];
f8b2ac1e
JL
5891
5892 output_paragraph[end_pos] = 0;
5893 output_column -= end_pos - start_pos;
5894 output_paragraph_offset = start_pos;
5895
5896 arg = xstrdup (arg);
5897 comma = strchr (arg, ',');
5898 if (comma)
5899 {
5900 *comma = 0;
5901 for (comma++; isspace (*comma); comma++)
5902 ;
5903 add_word (comma);
5904 add_char (' ');
5905 }
5906 add_char ('<');
5907 add_word (arg);
5908 add_char ('>');
5909 free (arg);
5910 }
5911}
6599da04 5912
f8b2ac1e
JL
5913/* An external image is a reference, kind of. The parsing is (not
5914 coincidentally) similar, anyway. */
5915void
5916cm_image (arg)
5917 int arg;
5918{
5919 if (arg == START)
5920 {
5921 char *name_arg = get_xref_token ();
5922 /* We don't yet care about any other args, but read them so they
5923 don't end up in the text. */
5924 char *arg = get_xref_token ();
5925 if (arg) free (arg);
5926 arg = get_xref_token ();
5927 if (arg) free (arg);
5928
5929 if (*name_arg)
5930 {
5931 /* Try to open foo.txt. */
5932 FILE *image_file;
5933 char *name = xmalloc (strlen (name_arg) + 4);
5934 strcpy (name, name_arg);
5935 strcat (name, ".txt");
5936 image_file = fopen (name, "r");
5937 if (image_file)
5938 {
5939 int ch;
5940 int save_inhibit_indentation = inhibit_paragraph_indentation;
5941 int save_filling_enabled = filling_enabled;
5942
5943 inhibit_paragraph_indentation = 1;
5944 filling_enabled = 0;
5945 last_char_was_newline = 0;
5946
5947 /* Maybe we need to remove the final newline if the image
5948 file is only one line to allow in-line images. On the
5949 other hand, they could just make the file without a
5950 final newline. */
5951 while ((ch = getc (image_file)) != EOF)
5952 add_char (ch);
5953
5954 inhibit_paragraph_indentation = save_inhibit_indentation;
5955 filling_enabled = save_filling_enabled;
5956
5957 if (fclose (image_file) != 0) {
5958 perror (name);
5959 }
5960 }
5961 else
5962 warning (_("@image file `%s' unreadable: %s"), name,
5963 strerror (errno));
5964 }
5965 else
5966 line_error (_("@image missing filename argument"));
6599da04 5967
f8b2ac1e 5968 if (name_arg) free (name_arg);
6599da04
JM
5969 }
5970}
5971\f
5972/* **************************************************************** */
f8b2ac1e
JL
5973/* */
5974/* Insertion Command Stubs */
5975/* */
6599da04
JM
5976/* **************************************************************** */
5977
5978void
5979cm_quotation ()
5980{
5981 begin_insertion (quotation);
5982}
5983
5984void
5985cm_example ()
5986{
5987 begin_insertion (example);
5988}
5989
5990void
5991cm_smallexample ()
5992{
5993 begin_insertion (smallexample);
5994}
5995
5996void
5997cm_lisp ()
5998{
5999 begin_insertion (lisp);
6000}
6001
6002void
6003cm_smalllisp ()
6004{
6005 begin_insertion (smalllisp);
6006}
6007
6008/* @cartouche/@end cartouche draws box with rounded corners in
f8b2ac1e 6009 TeX output. Right now, just a no-op insertion. */
6599da04
JM
6010void
6011cm_cartouche ()
6012{
6013 begin_insertion (cartouche);
6014}
6015
6016void
6017cm_format ()
6018{
6019 begin_insertion (format);
6020}
6021
6022void
6023cm_display ()
6024{
6025 begin_insertion (display);
6026}
6027
6028void
6029cm_direntry ()
6030{
6031 if (no_headers)
6032 command_name_condition ();
6033 else
6034 begin_insertion (direntry);
6035}
6036
6037void
6038cm_itemize ()
6039{
6040 begin_insertion (itemize);
6041}
6042
6043void
6044cm_enumerate ()
6045{
6046 do_enumeration (enumerate, "1");
6047}
6048
6049/* Start an enumeration insertion of type TYPE. If the user supplied
6050 no argument on the line, then use DEFAULT_STRING as the initial string. */
6051void
6052do_enumeration (type, default_string)
6053 int type;
6054 char *default_string;
6055{
f8b2ac1e 6056 get_until_in_line (0, ".", &enumeration_arg);
6599da04
JM
6057 canon_white (enumeration_arg);
6058
6059 if (!*enumeration_arg)
6060 {
6061 free (enumeration_arg);
f8b2ac1e 6062 enumeration_arg = xstrdup (default_string);
6599da04
JM
6063 }
6064
6065 if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
6066 {
f8b2ac1e 6067 warning (_("%s requires letter or digit"), insertion_type_pname (type));
6599da04
JM
6068
6069 switch (type)
f8b2ac1e
JL
6070 {
6071 case enumerate:
6072 default_string = "1";
6073 break;
6074 }
6075 enumeration_arg = xstrdup (default_string);
6599da04
JM
6076 }
6077 begin_insertion (type);
6078}
6079
6080void
6081cm_table ()
6082{
6083 begin_insertion (table);
6084}
6085
6086void
6087cm_multitable ()
6088{
f8b2ac1e 6089 begin_insertion (multitable); /* @@ */
6599da04
JM
6090}
6091
6092void
6093cm_ftable ()
6094{
6095 begin_insertion (ftable);
6096}
6097
6098void
6099cm_vtable ()
6100{
6101 begin_insertion (vtable);
6102}
6103
6104void
6105cm_group ()
6106{
6107 begin_insertion (group);
6108}
6109
6110void
6111cm_ifinfo ()
6112{
6113 begin_insertion (ifinfo);
6114}
6115
f8b2ac1e
JL
6116void
6117cm_ifnothtml ()
6118{
6119 begin_insertion (ifnothtml);
6120}
6121
6122void
6123cm_ifnottex ()
6124{
6125 begin_insertion (ifnottex);
6126}
6127
6599da04
JM
6128/* Begin an insertion where the lines are not filled or indented. */
6129void
6130cm_flushleft ()
6131{
6132 begin_insertion (flushleft);
6133}
6134
6135/* Begin an insertion where the lines are not filled, and each line is
6136 forced to the right-hand side of the page. */
6137void
6138cm_flushright ()
6139{
6140 begin_insertion (flushright);
6141}
f8b2ac1e
JL
6142
6143/* End existing insertion block. */
6144void
6145cm_end ()
6146{
6147 char *temp;
6148 enum insertion_type type;
6149
6150 if (!insertion_level)
6151 {
6152 line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
6153 return;
6154 }
6155
6156 get_rest_of_line (&temp);
6157
6158 if (temp[0] == 0)
6159 line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
6160
6161 type = find_type_from_name (temp);
6162
6163 if (type == bad_type)
6164 {
6165 line_error (_("Bad argument to `%s', `%s', using `%s'"),
6166 command, temp, insertion_type_pname (current_insertion_type ()));
6167 }
6168 end_insertion (type);
6169 free (temp);
6170}
6599da04
JM
6171\f
6172/* **************************************************************** */
f8b2ac1e
JL
6173/* */
6174/* Conditional Handling */
6175/* */
6599da04
JM
6176/* **************************************************************** */
6177
6178/* A structure which contains `defined' variables. */
6179typedef struct defines {
6180 struct defines *next;
6181 char *name;
6182 char *value;
6183} DEFINE;
6184
6185/* The linked list of `set' defines. */
6186DEFINE *defines = (DEFINE *)NULL;
6187
6188/* Add NAME to the list of `set' defines. */
6189void
6190set (name, value)
6191 char *name;
6192 char *value;
6193{
6194 DEFINE *temp;
6195
6196 for (temp = defines; temp; temp = temp->next)
6197 if (strcmp (name, temp->name) == 0)
6198 {
f8b2ac1e
JL
6199 free (temp->value);
6200 temp->value = xstrdup (value);
6201 return;
6599da04
JM
6202 }
6203
6204 temp = (DEFINE *)xmalloc (sizeof (DEFINE));
6205 temp->next = defines;
f8b2ac1e
JL
6206 temp->name = xstrdup (name);
6207 temp->value = xstrdup (value);
6599da04
JM
6208 defines = temp;
6209}
6210
6211/* Remove NAME from the list of `set' defines. */
6212void
6213clear (name)
6214 char *name;
6215{
6216 register DEFINE *temp, *last;
6217
6218 last = (DEFINE *)NULL;
6219 temp = defines;
6220
6221 while (temp)
6222 {
6223 if (strcmp (temp->name, name) == 0)
f8b2ac1e
JL
6224 {
6225 if (last)
6226 last->next = temp->next;
6227 else
6228 defines = temp->next;
6229
6230 free (temp->name);
6231 free (temp->value);
6232 free (temp);
6233 break;
6234 }
6599da04
JM
6235 last = temp;
6236 temp = temp->next;
6237 }
6238}
6239
6240/* Return the value of NAME. The return value is NULL if NAME is unset. */
6241char *
6242set_p (name)
6243 char *name;
6244{
6245 register DEFINE *temp;
6246
6247 for (temp = defines; temp; temp = temp->next)
6248 if (strcmp (temp->name, name) == 0)
6249 return (temp->value);
6250
6251 return ((char *)NULL);
6252}
6253
6254/* Conditionally parse based on the current command name. */
6255void
6256command_name_condition ()
6257{
6258 char *discarder;
6259
6260 discarder = (char *)xmalloc (8 + strlen (command));
6261
6262 sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
6263 discard_until (discarder);
6264 discard_until ("\n");
6265
6266 free (discarder);
6267}
6268
6269/* Create a variable whose name appears as the first word on this line. */
6270void
6271cm_set ()
6272{
6273 handle_variable (SET);
6274}
6275
6276/* Remove a variable whose name appears as the first word on this line. */
6277void
6278cm_clear ()
6279{
6280 handle_variable (CLEAR);
6281}
6282
6283void
6284cm_ifset ()
6285{
6286 handle_variable (IFSET);
6287}
6288
6289void
6290cm_ifclear ()
6291{
6292 handle_variable (IFCLEAR);
6293}
6294
6295/* This command takes braces, but we parse the contents specially, so we
6296 don't use the standard brace popping code.
6297
6298 The syntax @ifeq{arg1, arg2, texinfo-commands} performs texinfo-commands
6299 if ARG1 and ARG2 caselessly string compare to the same string, otherwise,
6300 it produces no output. */
6301void
6302cm_ifeq ()
6303{
6599da04
JM
6304 char **arglist;
6305
6306 arglist = get_brace_args (0);
6307
6308 if (arglist)
6309 {
6310 if (array_len (arglist) > 1)
f8b2ac1e
JL
6311 {
6312 if ((strcasecmp (arglist[0], arglist[1]) == 0) &&
6313 (arglist[2] != (char *)NULL))
6314 execute_string ("%s\n", arglist[2]);
6315 }
6599da04
JM
6316
6317 free_array (arglist);
6318 }
6319}
6320
6321void
6322cm_value (arg, start_pos, end_pos)
6323 int arg, start_pos, end_pos;
6324{
6325 if (arg == END)
6326 {
d275726b
JL
6327 char *name = (char *) &output_paragraph[start_pos];
6328 char *value;
f8b2ac1e
JL
6329 output_paragraph[end_pos] = 0;
6330 name = xstrdup (name);
6599da04
JM
6331 value = set_p (name);
6332 output_column -= end_pos - start_pos;
6333 output_paragraph_offset = start_pos;
6334
6335 if (value)
6336 execute_string ("%s", value);
6337 else
f8b2ac1e 6338 add_word_args (_("{No Value For \"%s\"}"), name);
6599da04
JM
6339
6340 free (name);
6341 }
6342}
6343
6344/* Set, clear, or conditionalize based on ACTION. */
6345void
6346handle_variable (action)
6347 int action;
6348{
6349 char *name;
6350
6351 get_rest_of_line (&name);
6352 backup_input_pointer ();
6599da04
JM
6353 handle_variable_internal (action, name);
6354 free (name);
6355}
6356
6357void
6358handle_variable_internal (action, name)
6359 int action;
6360 char *name;
6361{
6362 char *temp;
6363 int delimiter, additional_text_present = 0;
6364
6365 /* Only the first word of NAME is a valid tag. */
6366 temp = name;
6367 delimiter = 0;
6368 while (*temp && (delimiter || !whitespace (*temp)))
6369 {
6370/* #if defined (SET_WITH_EQUAL) */
6371 if (*temp == '"' || *temp == '\'')
f8b2ac1e
JL
6372 {
6373 if (*temp == delimiter)
6374 delimiter = 0;
6375 else
6376 delimiter = *temp;
6377 }
6599da04
JM
6378/* #endif SET_WITH_EQUAL */
6379 temp++;
6380 }
6381
6382 if (*temp)
6383 additional_text_present++;
6384
f8b2ac1e 6385 *temp = 0;
6599da04
JM
6386
6387 if (!*name)
f8b2ac1e 6388 line_error (_("%c%s requires a name"), COMMAND_PREFIX, command);
6599da04
JM
6389 else
6390 {
6391 switch (action)
f8b2ac1e
JL
6392 {
6393 case SET:
6394 {
6395 char *value;
6599da04
JM
6396
6397#if defined (SET_WITH_EQUAL)
f8b2ac1e
JL
6398 /* Allow a value to be saved along with a variable. The value is
6399 the text following an `=' sign in NAME, if any is present. */
6599da04 6400
f8b2ac1e 6401 for (value = name; *value && *value != '='; value++);
6599da04 6402
f8b2ac1e
JL
6403 if (*value)
6404 *value++ = 0;
6599da04 6405
f8b2ac1e
JL
6406 if (*value == '"' || *value == '\'')
6407 {
6408 value++;
6409 value[strlen (value) - 1] = 0;
6410 }
6599da04
JM
6411
6412#else /* !SET_WITH_EQUAL */
f8b2ac1e
JL
6413 /* The VALUE of NAME is the remainder of the line sans
6414 whitespace. */
6415 if (additional_text_present)
6416 {
6417 value = temp + 1;
6418 canon_white (value);
6419 }
6420 else
6421 value = "";
6599da04
JM
6422#endif /* !SET_WITH_VALUE */
6423
f8b2ac1e
JL
6424 set (name, value);
6425 }
6426 break;
6427
6428 case CLEAR:
6429 clear (name);
6430 break;
6431
6432 case IFSET:
6433 case IFCLEAR:
6434 /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set,
38e01259 6435 read lines from the file until we reach a matching
f8b2ac1e
JL
6436 "@end CONDITION". This means that we only take note of
6437 "@ifset/clear" and "@end" commands. */
6438 {
6439 char condition[8];
6440 int condition_len;
6441 int orig_line_number = line_number;
6442
6443 if (action == IFSET)
6444 strcpy (condition, "ifset");
6445 else
6446 strcpy (condition, "ifclear");
6447
6448 condition_len = strlen (condition);
6449
6450 if ((action == IFSET && !set_p (name))
6451 || (action == IFCLEAR && set_p (name)))
6452 {
6453 int level = 0, done = 0;
6454
6455 while (!done && input_text_offset < size_of_input_text)
6456 {
6457 char *freeable_line, *line;
6458
6459 get_rest_of_line (&freeable_line);
6460
6461 for (line = freeable_line; whitespace (*line); line++);
6462
6463 if (*line == COMMAND_PREFIX &&
6464 (strncmp (line + 1, condition, condition_len) == 0))
6465 level++;
6466 else if (strncmp (line, "@end", 4) == 0)
6467 {
6468 char *cname = line + 4;
6469 char *temp;
6470
6471 while (*cname && whitespace (*cname))
6472 cname++;
6473 temp = cname;
6474
6475 while (*temp && !whitespace (*temp))
6476 temp++;
6477 *temp = 0;
6478
6479 if (strcmp (cname, condition) == 0)
6480 {
6481 if (!level)
6482 {
6483 done = 1;
6484 }
6485 else
6486 level--;
6487 }
6488 }
6489 free (freeable_line);
6490 }
6491
6492 if (!done)
6493 {
6494 int save = line_number;
6495 line_number = orig_line_number;
6496 line_error (_("Reached eof before matching @end %s"),
6497 condition);
6498 line_number = save;
6499 }
6500
6501 /* We found the end of a false @ifset/ifclear. If we are
6502 in a menu, back up over the newline that ends the ifset,
6503 since that newline may also begin the next menu entry. */
6504 break;
6505 }
6506 else
6507 {
6508 if (action == IFSET)
6509 begin_insertion (ifset);
6510 else
6511 begin_insertion (ifclear);
6512 }
6513 }
6514 break;
6515 }
6599da04
JM
6516 }
6517}
6518\f
6519/* Execution of random text not in file. */
6520
6521typedef struct {
f8b2ac1e
JL
6522 char *string; /* The string buffer. */
6523 int size; /* The size of the buffer. */
6524 int in_use; /* Nonzero means string currently in use. */
6599da04
JM
6525} EXECUTION_STRING;
6526
6527static EXECUTION_STRING **execution_strings = (EXECUTION_STRING **)NULL;
6528static int execution_strings_index = 0;
6529static int execution_strings_slots = 0;
6530
6531EXECUTION_STRING *
6532get_execution_string (initial_size)
6533 int initial_size;
6534{
6535 register int i = 0;
6536 EXECUTION_STRING *es = (EXECUTION_STRING *)NULL;
6537
6538 if (execution_strings)
6539 {
6540 for (i = 0; i < execution_strings_index; i++)
f8b2ac1e
JL
6541 if (execution_strings[i] && (execution_strings[i]->in_use == 0))
6542 {
6543 es = execution_strings[i];
6544 break;
6545 }
6599da04
JM
6546 }
6547
6548 if (!es)
6549 {
6550 if (execution_strings_index + 1 >= execution_strings_slots)
f8b2ac1e
JL
6551 {
6552 execution_strings = (EXECUTION_STRING **)xrealloc
6553 (execution_strings,
6554 (execution_strings_slots += 3) * sizeof (EXECUTION_STRING *));
6555 for (; i < execution_strings_slots; i++)
6556 execution_strings[i] = (EXECUTION_STRING *)NULL;
6557 }
6599da04
JM
6558
6559 execution_strings[execution_strings_index] =
f8b2ac1e 6560 (EXECUTION_STRING *)xmalloc (sizeof (EXECUTION_STRING));
6599da04
JM
6561 es = execution_strings[execution_strings_index];
6562 execution_strings_index++;
6563
6564 es->size = 0;
6565 es->string = (char *)NULL;
6566 es->in_use = 0;
6567 }
6568
6569 if (initial_size > es->size)
f8b2ac1e
JL
6570 {
6571 es->string = (char *) xrealloc (es->string, initial_size);
6572 es->size = initial_size;
6573 }
6574 return (es);
6575}
6599da04 6576
f8b2ac1e
JL
6577/* Execute the string produced by formatting the ARGs with FORMAT. This
6578 is like submitting a new file with @include. */
6599da04 6579void
f8b2ac1e
JL
6580#if defined (VA_FPRINTF) && __STDC__
6581execute_string (char *format, ...)
6582#else
6583execute_string (format, va_alist)
6584 char *format;
6585 va_dcl
6586#endif
6599da04
JM
6587{
6588 EXECUTION_STRING *es;
6589 char *temp_string;
f8b2ac1e
JL
6590#ifdef VA_FPRINTF
6591 va_list ap;
6592#endif
6599da04
JM
6593
6594 es = get_execution_string (4000);
6595 temp_string = es->string;
6596 es->in_use = 1;
6597
f8b2ac1e
JL
6598 VA_START (ap, format);
6599#ifdef VA_SPRINTF
6600 VA_SPRINTF (temp_string, format, ap);
6601#else
6602 sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
6603#endif /* not VA_SPRINTF */
6604 va_end (ap);
6599da04
JM
6605
6606 pushfile ();
6607 input_text_offset = 0;
6608 input_text = temp_string;
f8b2ac1e 6609 input_filename = xstrdup (input_filename);
6599da04
JM
6610 size_of_input_text = strlen (temp_string);
6611
6612 executing_string++;
6613 reader_loop ();
6614 free (input_filename);
6615
6616 popfile ();
6617 executing_string--;
6618 es->in_use = 0;
6619}
6620
6621
6622/* Return what would be output for STR, i.e., expand Texinfo commands.
6623 If IMPLICIT_CODE is set, expand @code{STR}. */
6624
6625char *
6626expansion (str, implicit_code)
6627 char *str;
6628 int implicit_code;
6629{
6630 int length;
6631 char *result;
6632
6633 /* Inhibit any real output. */
6634 int start = output_paragraph_offset;
6635 int saved_paragraph_is_open = paragraph_is_open;
6636
6637 inhibit_output_flushing ();
f8b2ac1e 6638 paragraph_is_open = 1;
6599da04
JM
6639 execute_string (implicit_code ? "@code{%s}" : "%s", str);
6640 uninhibit_output_flushing ();
6641
6642 /* Copy the expansion from the buffer. */
6643 length = output_paragraph_offset - start;
6644 result = xmalloc (1 + length);
6645 memcpy (result, (char *) (output_paragraph + start), length);
6646 result[length] = 0;
6647
6648 /* Pretend it never happened. */
6649 output_paragraph_offset = start;
6650 paragraph_is_open = saved_paragraph_is_open;
6651
6652 return result;
6653}
6654\f
6655/* @itemx, @item. */
6656
6657static int itemx_flag = 0;
6658
6659void
6660cm_itemx ()
6661{
6662 itemx_flag++;
6663 cm_item ();
6664 itemx_flag--;
6665}
6666
6667void
6668cm_item ()
6669{
6670 char *rest_of_line, *item_func;
6671
6672 /* Can only hack "@item" while inside of an insertion. */
6673 if (insertion_level)
6674 {
6675 INSERTION_ELT *stack = insertion_stack;
6676 int original_input_text_offset;
6677
6678 skip_whitespace ();
6679 original_input_text_offset = input_text_offset;
6680
6681 get_rest_of_line (&rest_of_line);
6599da04
JM
6682 item_func = current_item_function ();
6683
6684 /* Okay, do the right thing depending on which insertion function
f8b2ac1e 6685 is active. */
6599da04
JM
6686
6687 switch_top:
6688 switch (stack->insertion)
f8b2ac1e
JL
6689 {
6690 case multitable:
6691 multitable_item ();
6692 /* Ultra special hack. It appears that some people incorrectly
6693 place text directly after the @item, instead of on a new line
6694 by itself. This happens to work in TeX, so I make it work
6695 here. */
6696 if (*rest_of_line)
6697 {
6698 line_number--;
6699 input_text_offset = original_input_text_offset;
6700 }
6701 break;
6702
6703 case ifinfo:
6704 case ifset:
6705 case ifclear:
6706 case cartouche:
6707 stack = stack->next;
6708 if (!stack)
6709 goto no_insertion;
6710 else
6711 goto switch_top;
6712 break;
6713
6714 case menu:
6715 case quotation:
6716 case example:
6717 case smallexample:
6718 case lisp:
6719 case format:
6720 case display:
6721 case group:
6722 line_error (_("The `%c%s' command is meaningless within a `@%s' block"),
6723 COMMAND_PREFIX, command,
6724 insertion_type_pname (current_insertion_type ()));
6725 break;
6726
6727 case itemize:
6728 case enumerate:
6729 if (itemx_flag)
6730 {
6731 line_error (_("%citemx is not meaningful inside of a `%s' block"),
6732 COMMAND_PREFIX,
6733 insertion_type_pname (current_insertion_type ()));
6734 }
6735 else
6736 {
6737 start_paragraph ();
6738 kill_self_indent (-1);
6739 filling_enabled = indented_fill = 1;
6740
6741 if (current_insertion_type () == itemize)
6742 {
6743 indent (output_column = current_indent - 2);
6744
6745 /* I need some way to determine whether this command
6746 takes braces or not. I believe the user can type
6747 either "@bullet" or "@bullet{}". Of course, they
6748 can also type "o" or "#" or whatever else they want. */
6749 if (item_func && *item_func)
6750 {
6751 if (*item_func == COMMAND_PREFIX)
6752 if (item_func[strlen (item_func) - 1] != '}')
6753 execute_string ("%s{}", item_func);
6754 else
6755 execute_string ("%s", item_func);
6756 else
6757 execute_string ("%s", item_func);
6758 }
6759 insert (' ');
6760 output_column++;
6761 }
6762 else
6763 enumerate_item ();
6764
6765 /* Special hack. This makes `close_paragraph' a no-op until
6766 `start_paragraph' has been called. */
6767 must_start_paragraph = 1;
6768
6769 /* Handle text directly after the @item. */
6770 if (*rest_of_line)
6771 {
6772 line_number--;
6773 input_text_offset = original_input_text_offset;
6774 }
6775 }
6776 break;
6777
6778 case table:
6779 case ftable:
6780 case vtable:
6781 {
6782 /* We need this to determine if we have two @item's in a row
6783 (see test just below). */
6784 static int last_item_output_position = 0;
6785
6786 /* Get rid of extra characters. */
6787 kill_self_indent (-1);
6788
6789 /* If we have one @item followed directly by another @item,
6790 we need to insert a blank line. This is not true for
6791 @itemx, though. */
6792 if (!itemx_flag && last_item_output_position == output_position)
6793 insert ('\n');
6794
6795 /* `close_paragraph' almost does what we want. The problem
6796 is when paragraph_is_open, and last_char_was_newline, and
6797 the last newline has been turned into a space, because
6798 filling_enabled. I handle it here. */
6799 if (last_char_was_newline && filling_enabled && paragraph_is_open)
6800 insert ('\n');
6801 close_paragraph ();
6599da04
JM
6802
6803#if defined (INDENT_PARAGRAPHS_IN_TABLE)
f8b2ac1e
JL
6804 /* Indent on a new line, but back up one indentation level. */
6805 {
6806 int save = inhibit_paragraph_indentation;
6807 inhibit_paragraph_indentation = 1;
6808 /* At this point, inserting any non-whitespace character will
6809 force the existing indentation to be output. */
6810 add_char ('i');
6811 inhibit_paragraph_indentation = save;
6812 }
6599da04 6813#else /* !INDENT_PARAGRAPHS_IN_TABLE */
f8b2ac1e 6814 add_char ('i');
6599da04
JM
6815#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
6816
f8b2ac1e
JL
6817 output_paragraph_offset--;
6818 kill_self_indent (default_indentation_increment + 1);
6819
6820 /* Add item's argument to the line. */
6821 filling_enabled = 0;
6822 if (item_func && *item_func)
6823 execute_string ("%s{%s}", item_func, rest_of_line);
6824 else
6825 execute_string ("%s", rest_of_line);
6826
6827 if (current_insertion_type () == ftable)
6828 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
6829 else if (current_insertion_type () == vtable)
6830 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
6831
6832 /* Start a new line, and let start_paragraph ()
6833 do the indenting of it for you. */
6834 close_single_paragraph ();
6835 indented_fill = filling_enabled = 1;
6836 last_item_output_position = output_position;
6837 }
6838 }
6599da04
JM
6839 free (rest_of_line);
6840 }
6841 else
6842 {
6843 no_insertion:
f8b2ac1e
JL
6844 line_error (_("%c%s found outside of an insertion block"),
6845 COMMAND_PREFIX, command);
6599da04
JM
6846 }
6847}
6848\f
6849/* **************************************************************** */
f8b2ac1e
JL
6850/* */
6851/* Defun and Friends */
6852/* */
6599da04
JM
6853/* **************************************************************** */
6854
f8b2ac1e
JL
6855#define DEFUN_SELF_DELIMITING(c) \
6856 (((c) == '(') \
6857 || ((c) == ')') \
6858 || ((c) == '[') \
6599da04
JM
6859 || ((c) == ']'))
6860
6861struct token_accumulator
6862{
6863 unsigned int length;
6864 unsigned int index;
6865 char **tokens;
6866};
6867
6868void
6869initialize_token_accumulator (accumulator)
6870 struct token_accumulator *accumulator;
6871{
6872 (accumulator->length) = 0;
6873 (accumulator->index) = 0;
6874 (accumulator->tokens) = NULL;
6875}
6876
6877void
6878accumulate_token (accumulator, token)
6879 struct token_accumulator *accumulator;
6880 char *token;
6881{
6882 if ((accumulator->index) >= (accumulator->length))
6883 {
6884 (accumulator->length) += 10;
6885 (accumulator->tokens) = (char **) xrealloc
f8b2ac1e 6886 (accumulator->tokens, (accumulator->length * sizeof (char *)));
6599da04
JM
6887 }
6888 accumulator->tokens[accumulator->index] = token;
6889 accumulator->index += 1;
6890}
6891
6892char *
6893copy_substring (start, end)
6894 char *start;
6895 char *end;
6896{
6897 char *result, *scan, *scan_result;
6898
6899 result = (char *) xmalloc ((end - start) + 1);
6900 scan_result = result;
6901 scan = start;
6902
6903 while (scan < end)
6904 *scan_result++ = *scan++;
6905
f8b2ac1e 6906 *scan_result = 0;
6599da04
JM
6907 return (result);
6908}
6909
6910/* Given `string' pointing at an open brace, skip forward and return a
6911 pointer to just past the matching close brace. */
6912int
6913scan_group_in_string (string_pointer)
6914 char **string_pointer;
6915{
6916 register int c;
6917 register char *scan_string;
6918 register unsigned int level = 1;
6919
6920 scan_string = (*string_pointer) + 1;
6921
6922 while (1)
6923 {
6924 if (level == 0)
f8b2ac1e
JL
6925 {
6926 (*string_pointer) = scan_string;
6927 return (1);
6928 }
6599da04 6929 c = (*scan_string++);
f8b2ac1e
JL
6930 if (c == 0)
6931 {
6932 /* Tweak line_number to compensate for fact that
6933 we gobbled the whole line before coming here. */
6934 line_number -= 1;
6935 line_error (_("Missing `}' in %cdef arg"), COMMAND_PREFIX);
6936 line_number += 1;
6937 (*string_pointer) = (scan_string - 1);
6938 return (0);
6939 }
6599da04 6940 if (c == '{')
f8b2ac1e 6941 level += 1;
6599da04 6942 if (c == '}')
f8b2ac1e 6943 level -= 1;
6599da04
JM
6944 }
6945}
6946
6947/* Return a list of tokens from the contents of `string'.
6948 Commands and brace-delimited groups count as single tokens.
6949 Contiguous whitespace characters are converted to a token
6950 consisting of a single space. */
6951char **
6952args_from_string (string)
6953 char *string;
6954{
6955 struct token_accumulator accumulator;
6956 register char *scan_string = string;
6957 char *token_start, *token_end;
6958
6959 initialize_token_accumulator (&accumulator);
6960
f8b2ac1e 6961 while ((*scan_string) != 0)
6599da04
JM
6962 {
6963 /* Replace arbitrary whitespace by a single space. */
6964 if (whitespace (*scan_string))
f8b2ac1e
JL
6965 {
6966 scan_string += 1;
6967 while (whitespace (*scan_string))
6968 scan_string += 1;
6969 accumulate_token ((&accumulator), (xstrdup (" ")));
6970 continue;
6971 }
6599da04
JM
6972
6973 /* Commands count as single tokens. */
6974 if ((*scan_string) == COMMAND_PREFIX)
f8b2ac1e
JL
6975 {
6976 token_start = scan_string;
6977 scan_string += 1;
6978 if (self_delimiting (*scan_string))
6979 scan_string += 1;
6980 else
6981 {
6982 register int c;
6983 while (1)
6984 {
6985 c = *scan_string++;
6986
6987 if ((c == 0) || (c == '{') || (whitespace (c)))
6988 {
6989 scan_string -= 1;
6990 break;
6991 }
6992 }
6993
6994 if (*scan_string == '{')
6995 {
6996 char *s = scan_string;
6997 (void) scan_group_in_string (&s);
6998 scan_string = s;
6999 }
7000 }
7001 token_end = scan_string;
7002 }
6599da04
JM
7003
7004 /* Parentheses and brackets are self-delimiting. */
7005 else if (DEFUN_SELF_DELIMITING (*scan_string))
f8b2ac1e
JL
7006 {
7007 token_start = scan_string;
7008 scan_string += 1;
7009 token_end = scan_string;
7010 }
6599da04
JM
7011
7012 /* Open brace introduces a group that is a single token. */
7013 else if (*scan_string == '{')
f8b2ac1e
JL
7014 {
7015 char *s = scan_string;
7016 int balanced = scan_group_in_string (&s);
6599da04 7017
f8b2ac1e
JL
7018 token_start = scan_string + 1;
7019 scan_string = s;
7020 token_end = balanced ? (scan_string - 1) : scan_string;
7021 }
6599da04
JM
7022
7023 /* Otherwise a token is delimited by whitespace, parentheses,
f8b2ac1e 7024 brackets, or braces. A token is also ended by a command. */
6599da04 7025 else
f8b2ac1e
JL
7026 {
7027 token_start = scan_string;
6599da04 7028
f8b2ac1e
JL
7029 while (1)
7030 {
7031 register int c;
6599da04 7032
f8b2ac1e 7033 c = *scan_string++;
6599da04
JM
7034
7035 /* Do not back up if we're looking at a }; since the only
7036 valid }'s are those matched with {'s, we want to give
7037 an error. If we back up, we go into an infinite loop. */
f8b2ac1e
JL
7038 if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c)
7039 || c == '{')
7040 {
7041 scan_string--;
7042 break;
7043 }
7044
7045 /* If we encounter a command embedded within a token,
7046 then end the token. */
7047 if (c == COMMAND_PREFIX)
7048 {
7049 scan_string--;
7050 break;
7051 }
7052 }
7053 token_end = scan_string;
7054 }
6599da04
JM
7055
7056 accumulate_token
f8b2ac1e 7057 (&accumulator, copy_substring (token_start, token_end));
6599da04
JM
7058 }
7059 accumulate_token (&accumulator, NULL);
7060 return (accumulator.tokens);
7061}
7062
7063void
7064process_defun_args (defun_args, auto_var_p)
7065 char **defun_args;
7066 int auto_var_p;
7067{
7068 int pending_space = 0;
7069
7070 while (1)
7071 {
7072 char *defun_arg = *defun_args++;
7073
7074 if (defun_arg == NULL)
f8b2ac1e 7075 break;
6599da04
JM
7076
7077 if (defun_arg[0] == ' ')
f8b2ac1e
JL
7078 {
7079 pending_space = 1;
7080 continue;
7081 }
6599da04
JM
7082
7083 if (pending_space)
f8b2ac1e
JL
7084 {
7085 add_char (' ');
7086 pending_space = 0;
7087 }
6599da04
JM
7088
7089 if (DEFUN_SELF_DELIMITING (defun_arg[0]))
f8b2ac1e 7090 add_char (defun_arg[0]);
6599da04 7091 else if (defun_arg[0] == '&')
f8b2ac1e 7092 add_word (defun_arg);
6599da04 7093 else if (defun_arg[0] == COMMAND_PREFIX)
f8b2ac1e 7094 execute_string ("%s", defun_arg);
6599da04 7095 else if (auto_var_p)
f8b2ac1e 7096 execute_string ("%cvar{%s}", COMMAND_PREFIX, defun_arg);
6599da04 7097 else
f8b2ac1e 7098 add_word (defun_arg);
6599da04
JM
7099 }
7100}
7101
7102char *
7103next_nonwhite_defun_arg (arg_pointer)
7104 char ***arg_pointer;
7105{
7106 char **scan = (*arg_pointer);
7107 char *arg = (*scan++);
7108
7109 if ((arg != 0) && (*arg == ' '))
7110 arg = *scan++;
7111
7112 if (arg == 0)
7113 scan -= 1;
7114
7115 *arg_pointer = scan;
7116
7117 return ((arg == 0) ? "" : arg);
7118}
7119
7120/* Make the defun type insertion.
7121 TYPE says which insertion this is.
f8b2ac1e 7122 X_P, if nonzero, says not to start a new insertion. */
6599da04
JM
7123void
7124defun_internal (type, x_p)
7125 enum insertion_type type;
7126 int x_p;
7127{
7128 enum insertion_type base_type;
7129 char **defun_args, **scan_args;
7130 char *category, *defined_name, *type_name, *type_name2;
7131
7132 {
7133 char *line;
7134 get_rest_of_line (&line);
7135 defun_args = (args_from_string (line));
7136 free (line);
7137 }
7138
7139 scan_args = defun_args;
7140
7141 switch (type)
7142 {
7143 case defun:
f8b2ac1e 7144 category = _("Function");
6599da04
JM
7145 base_type = deffn;
7146 break;
7147 case defmac:
f8b2ac1e 7148 category = _("Macro");
6599da04
JM
7149 base_type = deffn;
7150 break;
7151 case defspec:
f8b2ac1e 7152 category = _("Special Form");
6599da04
JM
7153 base_type = deffn;
7154 break;
7155 case defvar:
f8b2ac1e 7156 category = _("Variable");
6599da04
JM
7157 base_type = defvr;
7158 break;
7159 case defopt:
f8b2ac1e 7160 category = _("User Option");
6599da04
JM
7161 base_type = defvr;
7162 break;
7163 case deftypefun:
f8b2ac1e 7164 category = _("Function");
6599da04
JM
7165 base_type = deftypefn;
7166 break;
7167 case deftypevar:
f8b2ac1e 7168 category = _("Variable");
6599da04
JM
7169 base_type = deftypevr;
7170 break;
7171 case defivar:
f8b2ac1e 7172 category = _("Instance Variable");
6599da04
JM
7173 base_type = defcv;
7174 break;
7175 case defmethod:
f8b2ac1e 7176 category = _("Method");
6599da04
JM
7177 base_type = defop;
7178 break;
7179 case deftypemethod:
f8b2ac1e 7180 category = _("Method");
6599da04
JM
7181 base_type = deftypemethod;
7182 break;
7183 default:
7184 category = next_nonwhite_defun_arg (&scan_args);
7185 base_type = type;
7186 break;
7187 }
7188
7189 if ((base_type == deftypefn)
7190 || (base_type == deftypevr)
7191 || (base_type == defcv)
7192 || (base_type == defop)
7193 || (base_type == deftypemethod))
7194 type_name = next_nonwhite_defun_arg (&scan_args);
7195
7196 if (base_type == deftypemethod)
7197 type_name2 = next_nonwhite_defun_arg (&scan_args);
7198
7199 defined_name = next_nonwhite_defun_arg (&scan_args);
7200
7201 /* This hack exists solely for the purposes of formatting the texinfo
7202 manual. I couldn't think of a better way. The token might be
7203 a simple @@ followed immediately by more text. If this is the case,
7204 then the next defun arg is part of this one, and we should concatenate
7205 them. */
7206 if (*scan_args && **scan_args && !whitespace (**scan_args) &&
7207 (strcmp (defined_name, "@@") == 0))
7208 {
7209 char *tem = (char *)xmalloc (3 + strlen (scan_args[0]));
7210
7211 sprintf (tem, "@@%s", scan_args[0]);
7212
7213 free (scan_args[0]);
7214 scan_args[0] = tem;
7215 scan_args++;
7216 defined_name = tem;
7217 }
7218
7219 if (!x_p)
7220 begin_insertion (type);
7221
7222 /* Write the definition header line.
7223 This should start at the normal indentation. */
7224 current_indent -= default_indentation_increment;
7225 start_paragraph ();
7226
7227 switch (base_type)
7228 {
7229 case deffn:
7230 case defvr:
7231 case deftp:
7232 execute_string (" -- %s: %s", category, defined_name);
7233 break;
7234 case deftypefn:
7235 case deftypevr:
7236 execute_string (" -- %s: %s %s", category, type_name, defined_name);
7237 break;
7238 case defcv:
7239 execute_string (" -- %s of %s: %s", category, type_name, defined_name);
7240 break;
7241 case defop:
7242 execute_string (" -- %s on %s: %s", category, type_name, defined_name);
7243 break;
7244 case deftypemethod:
7245 execute_string (" -- %s on %s: %s %s", category, type_name, type_name2,
f8b2ac1e 7246 defined_name);
6599da04
JM
7247 break;
7248 }
7249 current_indent += default_indentation_increment;
7250
7251 /* Now process the function arguments, if any.
7252 If these carry onto the next line, they should be indented by two
7253 increments to distinguish them from the body of the definition,
7254 which is indented by one increment. */
7255 current_indent += default_indentation_increment;
7256
7257 switch (base_type)
7258 {
7259 case deffn:
7260 case defop:
7261 process_defun_args (scan_args, 1);
7262 break;
f8b2ac1e
JL
7263
7264 /* Through Makeinfo 1.67 we processed remaining args only for deftp,
7265 deftypefn, and deftypemethod. But the libc manual, for example,
7266 needs to say:
7267 @deftypevar {char *} tzname[2]
7268 And simply allowing the extra text seems far simpler than trying
7269 to invent yet more defn commands. In any case, we should either
7270 output it or give an error, not silently ignore it. */
7271 default:
6599da04
JM
7272 process_defun_args (scan_args, 0);
7273 break;
7274 }
7275 current_indent -= default_indentation_increment;
7276 close_single_paragraph ();
7277
d275726b
JL
7278 /* Make an entry in the appropriate index. */
7279 switch (base_type)
7280 {
7281 case deffn:
7282 case deftypefn:
7283 execute_string ("%cfindex %s\n", COMMAND_PREFIX, defined_name);
7284 break;
7285 case defvr:
7286 case deftypevr:
7287 case defcv:
7288 execute_string ("%cvindex %s\n", COMMAND_PREFIX, defined_name);
7289 break;
7290 case defop:
7291 case deftypemethod:
7292 execute_string ("%cfindex %s on %s\n",
7293 COMMAND_PREFIX, defined_name, type_name);
7294 break;
7295 case deftp:
7296 execute_string ("%ctindex %s\n", COMMAND_PREFIX, defined_name);
7297 break;
7298 }
6599da04
JM
7299
7300 /* Deallocate the token list. */
7301 scan_args = defun_args;
7302 while (1)
7303 {
7304 char * arg = (*scan_args++);
7305 if (arg == NULL)
f8b2ac1e 7306 break;
6599da04
JM
7307 free (arg);
7308 }
7309 free (defun_args);
7310}
7311
7312/* Add an entry for a function, macro, special form, variable, or option.
7313 If the name of the calling command ends in `x', then this is an extra
7314 entry included in the body of an insertion of the same type. */
7315void
7316cm_defun ()
7317{
7318 int x_p;
7319 enum insertion_type type;
f8b2ac1e 7320 char *temp = xstrdup (command);
6599da04
JM
7321
7322 x_p = (command[strlen (command) - 1] == 'x');
7323
7324 if (x_p)
f8b2ac1e 7325 temp[strlen (temp) - 1] = 0;
6599da04
JM
7326
7327 type = find_type_from_name (temp);
7328 free (temp);
7329
7330 /* If we are adding to an already existing insertion, then make sure
7331 that we are already in an insertion of type TYPE. */
7332 if (x_p &&
7333 (!insertion_level || insertion_stack->insertion != type))
7334 {
f8b2ac1e
JL
7335 line_error (_("Must be in a `%s' insertion in order to use `%s'x"),
7336 command, command);
6599da04
JM
7337 discard_until ("\n");
7338 return;
7339 }
7340
7341 defun_internal (type, x_p);
7342}
7343\f
6599da04 7344/* **************************************************************** */
f8b2ac1e
JL
7345/* */
7346/* Other Random Commands */
7347/* */
6599da04
JM
7348/* **************************************************************** */
7349
7350/* This says to inhibit the indentation of the next paragraph, but
7351 not of following paragraphs. */
7352void
7353cm_noindent ()
7354{
7355 if (!inhibit_paragraph_indentation)
7356 inhibit_paragraph_indentation = -1;
7357}
7358
7359/* I don't know exactly what to do with this. Should I allow
7360 someone to switch filenames in the middle of output? Since the
7361 file could be partially written, this doesn't seem to make sense.
7362 Another option: ignore it, since they don't *really* want to
7363 switch files. Finally, complain, or at least warn. */
7364void
7365cm_setfilename ()
7366{
7367 char *filename;
7368 get_rest_of_line (&filename);
7369 /* warning ("`@%s %s' encountered and ignored", command, filename); */
7370 free (filename);
7371}
7372
7373void
7374cm_ignore_line ()
7375{
7376 discard_until ("\n");
7377}
7378
7379/* @br can be immediately followed by `{}', so we have to read those here.
7380 It should simply close the paragraph. */
7381void
7382cm_br ()
7383{
7384 if (looking_at ("{}"))
7385 input_text_offset += 2;
7386
7387 if (curchar () == '\n')
7388 {
7389 input_text_offset++;
7390 line_number++;
7391 }
7392
7393 close_paragraph ();
7394}
7395
7396 /* Insert the number of blank lines passed as argument. */
7397void
7398cm_sp ()
7399{
7400 int lines;
7401 char *line;
7402
7403 get_rest_of_line (&line);
7404
7405 if (sscanf (line, "%d", &lines) != 1)
7406 {
f8b2ac1e 7407 line_error (_("%csp requires a positive numeric argument"), COMMAND_PREFIX);
6599da04
JM
7408 }
7409 else
7410 {
7411 if (lines < 0)
f8b2ac1e 7412 lines = 0;
6599da04
JM
7413
7414 while (lines--)
f8b2ac1e 7415 add_char ('\n');
6599da04
JM
7416 }
7417 free (line);
7418}
7419
7420/* @dircategory LINE outputs INFO-DIR-SECTION LINE,
7421 but not if --no-headers. */
7422
7423void
7424cm_dircategory ()
7425{
f8b2ac1e 7426 char *line;
6599da04
JM
7427
7428 get_rest_of_line (&line);;
7429
f8b2ac1e 7430 if (!no_headers)
6599da04
JM
7431 {
7432 insert_string ("INFO-DIR-SECTION ");
7433 insert_string (line);
7434 insert ('\n');
7435 }
7436
7437 free (line);
7438}
7439
7440/* Start a new line with just this text on it.
7441 Then center the line of text.
7442 This always ends the current paragraph. */
7443void
7444cm_center ()
7445{
7446 register int i, start, length;
7447 int fudge_factor = 1;
7448 unsigned char *line;
7449
7450 close_paragraph ();
7451 filling_enabled = indented_fill = 0;
7452 cm_noindent ();
7453 start = output_paragraph_offset;
7454 inhibit_output_flushing ();
7455 get_rest_of_line ((char **)&line);
7456 execute_string ("%s", (char *)line);
7457 free (line);
7458 uninhibit_output_flushing ();
7459
7460 i = output_paragraph_offset - 1;
7461 while (i > (start - 1) && output_paragraph[i] == '\n')
f8b2ac1e 7462 i--;
6599da04
JM
7463
7464 output_paragraph_offset = ++i;
7465 length = output_paragraph_offset - start;
7466
7467 if (length < (fill_column - fudge_factor))
7468 {
7469 line = (unsigned char *)xmalloc (1 + length);
7470 memcpy (line, (char *)(output_paragraph + start), length);
7471
7472 i = (fill_column - fudge_factor - length) / 2;
7473 output_paragraph_offset = start;
7474
7475 while (i--)
f8b2ac1e 7476 insert (' ');
6599da04
JM
7477
7478 for (i = 0; i < length; i++)
f8b2ac1e 7479 insert (line[i]);
6599da04
JM
7480
7481 free (line);
7482 }
7483
7484 insert ('\n');
7485 close_paragraph ();
7486 filling_enabled = 1;
7487}
7488
7489/* Show what an expression returns. */
7490void
7491cm_result (arg)
7492 int arg;
7493{
7494 if (arg == END)
7495 add_word ("=>");
7496}
7497
7498/* What an expression expands to. */
7499void
7500cm_expansion (arg)
7501 int arg;
7502{
7503 if (arg == END)
7504 add_word ("==>");
7505}
7506
7507/* Indicates two expressions are equivalent. */
7508void
7509cm_equiv (arg)
7510 int arg;
7511{
7512 if (arg == END)
7513 add_word ("==");
7514}
7515
7516/* What an expression may print. */
7517void
7518cm_print (arg)
7519 int arg;
7520{
7521 if (arg == END)
7522 add_word ("-|");
7523}
7524
7525/* An error signaled. */
7526void
7527cm_error (arg)
7528 int arg;
7529{
7530 if (arg == END)
7531 add_word ("error-->");
7532}
7533
7534/* The location of point in an example of a buffer. */
7535void
7536cm_point (arg)
7537 int arg;
7538{
7539 if (arg == END)
7540 add_word ("-!-");
7541}
7542
7543/* Start a new line with just this text on it.
7544 The text is outdented one level if possible. */
7545void
7546cm_exdent ()
7547{
7548 char *line;
7549 int i = current_indent;
7550
7551 if (current_indent)
7552 current_indent -= default_indentation_increment;
7553
7554 get_rest_of_line (&line);
7555 close_single_paragraph ();
7556 execute_string ("%s", line);
7557 current_indent = i;
7558 free (line);
7559 close_single_paragraph ();
7560}
7561
6599da04
JM
7562
7563/* Remember this file, and move onto the next. */
7564void
7565cm_include ()
7566{
7567 char *filename;
7568
7569#if defined (HAVE_MACROS)
d275726b 7570 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
7571 me_append_before_this_command ();
7572#endif /* HAVE_MACROS */
7573
7574 close_paragraph ();
7575 get_rest_of_line (&filename);
7576
7577#if defined (HAVE_MACROS)
d275726b 7578 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
7579 remember_itext (input_text, input_text_offset);
7580#endif /* HAVE_MACROS */
7581
7582 pushfile ();
7583
7584 /* In verbose mode we print info about including another file. */
7585 if (verbose_mode)
7586 {
7587 register int i = 0;
7588 register FSTACK *stack = filestack;
7589
7590 for (i = 0, stack = filestack; stack; stack = stack->next, i++);
7591
7592 i *= 2;
7593
7594 printf ("%*s", i, "");
7595 printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
7596 fflush (stdout);
7597 }
7598
7599 if (!find_and_load (filename))
7600 {
7601 extern int errno;
7602
7603 popfile ();
7604 line_number--;
7605
7606 /* Cannot "@include foo", in line 5 of "/wh/bar". */
f8b2ac1e
JL
7607 line_error ("%c%s %s: %s", COMMAND_PREFIX, command, filename,
7608 strerror (errno));
6599da04
JM
7609
7610 free (filename);
7611 return;
7612 }
7613 else
7614 {
7615#if defined (HAVE_MACROS)
d275726b 7616 if (macro_expansion_output_stream && !executing_string)
f8b2ac1e 7617 remember_itext (input_text, input_text_offset);
6599da04
JM
7618#endif /* HAVE_MACROS */
7619 reader_loop ();
7620 }
7621 free (filename);
7622 popfile ();
7623}
7624
7625/* The other side of a malformed expression. */
7626void
7627misplaced_brace ()
7628{
f8b2ac1e 7629 line_error (_("Misplaced %c"), '}');
6599da04
JM
7630}
7631
7632/* Signals end of processing. Easy to make this happen. */
7633void
7634cm_bye ()
7635{
7636 input_text_offset = size_of_input_text;
7637}
f8b2ac1e
JL
7638
7639/* Set the paragraph indentation variable to the value specified in STRING.
7640 Values can be:
7641 `asis': Don't change existing indentation.
7642 `none': Remove existing indentation.
7643 NUM: Indent NUM spaces at the starts of paragraphs.
7644 If NUM is zero, we assume `none'.
7645 Returns 0 if successful, or nonzero if STRING isn't one of the above. */
7646int
7647set_paragraph_indent (string)
7648 char *string;
7649{
7650 if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
7651 paragraph_start_indent = 0;
7652 else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
7653 paragraph_start_indent = -1;
7654 else
7655 {
7656 if (sscanf (string, "%d", &paragraph_start_indent) != 1)
7657 return (-1);
7658 else
7659 {
7660 if (paragraph_start_indent == 0)
7661 paragraph_start_indent = -1;
7662 }
7663 }
7664 return (0);
7665}
7666
7667void
7668cm_paragraphindent ()
7669{
7670 char *arg;
7671
7672 get_rest_of_line (&arg);
7673 if (set_paragraph_indent (arg) != 0)
7674 line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
7675
7676 free (arg);
7677}
6599da04
JM
7678\f
7679/* **************************************************************** */
f8b2ac1e
JL
7680/* */
7681/* Indexing Stuff */
7682/* */
6599da04
JM
7683/* **************************************************************** */
7684
7685
7686/* An index element... */
7687typedef struct index_elt
7688{
7689 struct index_elt *next;
f8b2ac1e
JL
7690 char *entry; /* The index entry itself. */
7691 char *node; /* The node from whence it came. */
7692 int code; /* Nonzero means add `@code{...}' when
7693 printing this element. */
7694 int defining_line; /* Line number where this entry was written. */
7695 char *defining_file; /* Source file for defining_line. */
6599da04
JM
7696} INDEX_ELT;
7697
f8b2ac1e
JL
7698/* A list of short-names for each index.
7699
7700 There are two indices into the the_indices array.
7701
7702 * read_index is the index that points to the list of index
7703 entries that we will find if we ask for the list of entries for
7704 this name.
7705
7706 * write_index is the index that points to the list of index entries
7707 that we will add new entries to.
7708
7709 Initially, read_index and write index are the same, but the
7710 @syncodeindex and @synindex commands can change the list we add
7711 entries to.
7712
7713 For example, after the commands
7714
7715 @cindex foo
7716 @defindex ii
7717 @synindex cp ii
7718 @cindex bar
7719
7720 the cp index will contain the entry `foo', and the new ii
7721 index will contain the entry `bar'. This is consistent with the
7722 way texinfo.tex handles the same situation.
7723
7724 In addition, for each index, it is remembered whether that index is
7725 a code index or not. Code indices have @code{} inserted around the
7726 first word when they are printed with printindex. */
6599da04
JM
7727typedef struct
7728{
7729 char *name;
f8b2ac1e
JL
7730 int read_index; /* index entries for `name' */
7731 int write_index; /* store index entries here, @synindex can change it */
6599da04
JM
7732 int code;
7733} INDEX_ALIST;
7734
7735INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL;
7736
7737/* An array of pointers. Each one is for a different index. The
7738 "synindex" command changes which array slot is pointed to by a
7739 given "index". */
7740INDEX_ELT **the_indices = (INDEX_ELT **) NULL;
7741
7742/* The number of defined indices. */
7743int defined_indices = 0;
7744
6599da04
JM
7745void
7746init_indices ()
7747{
7748 int i;
7749
7750 /* Create the default data structures. */
7751
7752 /* Initialize data space. */
7753 if (!the_indices)
7754 {
7755 the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) *
f8b2ac1e 7756 sizeof (INDEX_ELT *));
6599da04
JM
7757 the_indices[defined_indices] = (INDEX_ELT *) NULL;
7758
7759 name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) *
f8b2ac1e 7760 sizeof (INDEX_ALIST *));
6599da04
JM
7761 name_index_alist[defined_indices] = (INDEX_ALIST *) NULL;
7762 }
7763
7764 /* If there were existing indices, get rid of them now. */
7765 for (i = 0; i < defined_indices; i++)
f8b2ac1e
JL
7766 {
7767 undefindex (name_index_alist[i]->name);
7768 if (name_index_alist[i])
7769 { /* Suppose we're called with two input files, and the first
7770 does a @synindex pg cp. Then, when we get here to start
7771 the second file, the "pg" element won't get freed by
7772 undefindex (because it's pointing to "cp"). So free it
7773 here; otherwise, when we try to define the pg index again
7774 just below, it will still point to cp. */
7775 free (name_index_alist[i]->name);
7776 free (name_index_alist[i]);
7777 name_index_alist[i] = (INDEX_ALIST *) NULL;
7778 }
7779 }
6599da04
JM
7780
7781 /* Add the default indices. */
f8b2ac1e
JL
7782 top_defindex ("cp", 0); /* cp is the only non-code index. */
7783 top_defindex ("fn", 1);
7784 top_defindex ("ky", 1);
7785 top_defindex ("pg", 1);
7786 top_defindex ("tp", 1);
7787 top_defindex ("vr", 1);
6599da04
JM
7788}
7789
7790/* Find which element in the known list of indices has this name.
7791 Returns -1 if NAME isn't found. */
7792int
7793find_index_offset (name)
7794 char *name;
7795{
7796 register int i;
7797 for (i = 0; i < defined_indices; i++)
7798 if (name_index_alist[i] &&
f8b2ac1e
JL
7799 strcmp (name, name_index_alist[i]->name) == 0)
7800 return (i);
6599da04
JM
7801 return (-1);
7802}
7803
7804/* Return a pointer to the entry of (name . index) for this name.
7805 Return NULL if the index doesn't exist. */
7806INDEX_ALIST *
7807find_index (name)
7808 char *name;
7809{
7810 int offset = find_index_offset (name);
7811 if (offset > -1)
7812 return (name_index_alist[offset]);
7813 else
7814 return ((INDEX_ALIST *) NULL);
7815}
7816
7817/* Given an index name, return the offset in the_indices of this index,
7818 or -1 if there is no such index. */
7819int
7820translate_index (name)
7821 char *name;
7822{
7823 INDEX_ALIST *which = find_index (name);
7824
7825 if (which)
f8b2ac1e 7826 return (which->read_index);
6599da04
JM
7827 else
7828 return (-1);
7829}
7830
7831/* Return the index list which belongs to NAME. */
7832INDEX_ELT *
7833index_list (name)
7834 char *name;
7835{
7836 int which = translate_index (name);
7837 if (which < 0)
7838 return ((INDEX_ELT *) -1);
7839 else
7840 return (the_indices[which]);
7841}
7842
7843/* Please release me, let me go... */
7844void
7845free_index (index)
7846 INDEX_ELT *index;
7847{
7848 INDEX_ELT *temp;
7849
7850 while ((temp = index) != (INDEX_ELT *) NULL)
7851 {
7852 free (temp->entry);
f8b2ac1e
JL
7853 /* Do not free the node, because we already freed the tag table,
7854 which freed all the node names. */
7855 /* free (temp->node); */
6599da04
JM
7856 index = index->next;
7857 free (temp);
7858 }
7859}
7860
f8b2ac1e
JL
7861/* Flush an index by name. This will delete the list of entries that
7862 would be written by a @printindex command for this index. */
6599da04
JM
7863void
7864undefindex (name)
7865 char *name;
7866{
7867 int i;
7868 int which = find_index_offset (name);
7869
f8b2ac1e
JL
7870 /* The index might have already been freed if this was the target of
7871 an @synindex. */
7872 if (which < 0 || !name_index_alist[which])
6599da04
JM
7873 return;
7874
f8b2ac1e 7875 i = name_index_alist[which]->read_index;
6599da04
JM
7876
7877 free_index (the_indices[i]);
7878 the_indices[i] = (INDEX_ELT *) NULL;
7879
7880 free (name_index_alist[which]->name);
7881 free (name_index_alist[which]);
7882 name_index_alist[which] = (INDEX_ALIST *) NULL;
7883}
7884
7885/* Define an index known as NAME. We assign the slot number.
f8b2ac1e 7886 CODE if Nonzero says to make this a code index. */
6599da04
JM
7887void
7888defindex (name, code)
7889 char *name;
7890 int code;
7891{
7892 register int i, slot;
7893
7894 /* If it already exists, flush it. */
7895 undefindex (name);
7896
7897 /* Try to find an empty slot. */
7898 slot = -1;
7899 for (i = 0; i < defined_indices; i++)
7900 if (!name_index_alist[i])
7901 {
f8b2ac1e
JL
7902 slot = i;
7903 break;
6599da04
JM
7904 }
7905
7906 if (slot < 0)
7907 {
7908 /* No such luck. Make space for another index. */
7909 slot = defined_indices;
7910 defined_indices++;
7911
7912 name_index_alist = (INDEX_ALIST **)
f8b2ac1e
JL
7913 xrealloc ((char *)name_index_alist,
7914 (1 + defined_indices) * sizeof (INDEX_ALIST *));
6599da04 7915 the_indices = (INDEX_ELT **)
f8b2ac1e
JL
7916 xrealloc ((char *)the_indices,
7917 (1 + defined_indices) * sizeof (INDEX_ELT *));
6599da04
JM
7918 }
7919
7920 /* We have a slot. Start assigning. */
7921 name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST));
f8b2ac1e
JL
7922 name_index_alist[slot]->name = xstrdup (name);
7923 name_index_alist[slot]->read_index = slot;
7924 name_index_alist[slot]->write_index = slot;
6599da04
JM
7925 name_index_alist[slot]->code = code;
7926
7927 the_indices[slot] = (INDEX_ELT *) NULL;
7928}
7929
7930/* Add the arguments to the current index command to the index NAME. */
7931void
7932index_add_arg (name)
7933 char *name;
7934{
7935 int which;
7936 char *index_entry;
7937 INDEX_ALIST *tem;
7938
7939 tem = find_index (name);
7940
f8b2ac1e 7941 which = tem ? tem->write_index : -1;
6599da04
JM
7942
7943#if defined (HAVE_MACROS)
d275726b 7944 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
7945 append_to_expansion_output (input_text_offset + 1);
7946#endif /* HAVE_MACROS */
7947
7948 get_rest_of_line (&index_entry);
7949 ignore_blank_line ();
7950
7951#if defined (HAVE_MACROS)
d275726b 7952 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
7953 {
7954 int op_orig;
7955
7956 remember_itext (input_text, input_text_offset);
7957 op_orig = output_paragraph_offset;
7958 me_execute_string (index_entry);
7959 me_execute_string ("\n");
7960 output_paragraph_offset = op_orig;
7961 }
7962#endif /* HAVE_MACROS */
7963
7964 if (which < 0)
7965 {
f8b2ac1e 7966 line_error (_("Unknown index `%s'"), name);
6599da04
JM
7967 free (index_entry);
7968 }
7969 else
7970 {
7971 INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT));
7972 new->next = the_indices[which];
7973 new->entry = index_entry;
7974 new->node = current_node;
7975 new->code = tem->code;
7976 new->defining_line = line_number - 1;
f8b2ac1e 7977 new->defining_file = input_filename;
6599da04
JM
7978 the_indices[which] = new;
7979 }
7980}
7981
7982#define INDEX_COMMAND_SUFFIX "index"
7983
7984/* The function which user defined index commands call. */
7985void
7986gen_index ()
7987{
f8b2ac1e 7988 char *name = xstrdup (command);
6599da04 7989 if (strlen (name) >= strlen ("index"))
f8b2ac1e 7990 name[strlen (name) - strlen ("index")] = 0;
6599da04
JM
7991 index_add_arg (name);
7992 free (name);
7993}
7994
7995void
7996top_defindex (name, code)
7997 char *name;
7998 int code;
7999{
8000 char *temp;
8001
8002 temp = (char *) xmalloc (1 + strlen (name) + strlen ("index"));
8003 sprintf (temp, "%sindex", name);
8004 define_user_command (temp, gen_index, 0);
8005 defindex (name, code);
8006 free (temp);
8007}
8008
8009/* Define a new index command. Arg is name of index. */
8010void
8011cm_defindex ()
8012{
8013 gen_defindex (0);
8014}
8015
8016void
8017cm_defcodeindex ()
8018{
8019 gen_defindex (1);
8020}
8021
8022void
8023gen_defindex (code)
8024 int code;
8025{
8026 char *name;
8027 get_rest_of_line (&name);
8028
8029 if (find_index (name))
8030 {
f8b2ac1e 8031 line_error (_("Index `%s' already exists"), name);
6599da04
JM
8032 free (name);
8033 return;
8034 }
8035 else
8036 {
8037 char *temp = (char *) alloca (1 + strlen (name) + strlen ("index"));
8038 sprintf (temp, "%sindex", name);
8039 define_user_command (temp, gen_index, 0);
8040 defindex (name, code);
8041 free (name);
8042 }
8043}
8044
6599da04
JM
8045/* Expects 2 args, on the same line. Both are index abbreviations.
8046 Make the first one be a synonym for the second one, i.e. make the
8047 first one have the same index as the second one. */
8048void
8049cm_synindex ()
8050{
f8b2ac1e
JL
8051 int source, target;
8052 char *abbrev1, *abbrev2;
6599da04
JM
8053
8054 skip_whitespace ();
f8b2ac1e
JL
8055 get_until_in_line (0, " ", &abbrev1);
8056 target = find_index_offset (abbrev1);
6599da04 8057 skip_whitespace ();
f8b2ac1e
JL
8058 get_until_in_line (0, " ", &abbrev2);
8059 source = find_index_offset (abbrev2);
8060 if (source < 0 || target < 0)
6599da04 8061 {
f8b2ac1e
JL
8062 line_error (_("Unknown index `%s' and/or `%s' in @synindex"),
8063 abbrev1, abbrev2);
6599da04
JM
8064 }
8065 else
8066 {
f8b2ac1e
JL
8067 name_index_alist[target]->write_index
8068 = name_index_alist[source]->write_index;
6599da04 8069 }
f8b2ac1e
JL
8070
8071 free (abbrev1);
8072 free (abbrev2);
6599da04
JM
8073}
8074
8075void
f8b2ac1e 8076cm_pindex () /* Pinhead index. */
6599da04
JM
8077{
8078 index_add_arg ("pg");
8079}
8080
8081void
f8b2ac1e 8082cm_vindex () /* Variable index. */
6599da04
JM
8083{
8084 index_add_arg ("vr");
8085}
8086
8087void
f8b2ac1e 8088cm_kindex () /* Key index. */
6599da04
JM
8089{
8090 index_add_arg ("ky");
8091}
8092
8093void
f8b2ac1e 8094cm_cindex () /* Concept index. */
6599da04
JM
8095{
8096 index_add_arg ("cp");
8097}
8098
8099void
f8b2ac1e 8100cm_findex () /* Function index. */
6599da04
JM
8101{
8102 index_add_arg ("fn");
8103}
8104
8105void
f8b2ac1e 8106cm_tindex () /* Data Type index. */
6599da04
JM
8107{
8108 index_add_arg ("tp");
8109}
8110
8111/* Sorting the index. */
8112int
8113index_element_compare (element1, element2)
8114 INDEX_ELT **element1, **element2;
8115{
8116 return (strcasecmp ((*element1)->entry, (*element2)->entry));
8117}
8118
8119/* Force all index entries to be unique. */
8120void
8121make_index_entries_unique (array, count)
8122 INDEX_ELT **array;
8123 int count;
8124{
8125 register int i, j;
8126 INDEX_ELT **copy;
8127 int counter = 1;
8128
8129 copy = (INDEX_ELT **)xmalloc ((1 + count) * sizeof (INDEX_ELT *));
8130
8131 for (i = 0, j = 0; i < count; i++)
8132 {
8133 if ((i == (count - 1)) ||
f8b2ac1e
JL
8134 (array[i]->node != array[i + 1]->node) ||
8135 (strcmp (array[i]->entry, array[i + 1]->entry) != 0))
8136 copy[j++] = array[i];
6599da04 8137 else
f8b2ac1e
JL
8138 {
8139 free (array[i]->entry);
8140 free (array[i]);
8141 }
6599da04
JM
8142 }
8143 copy[j] = (INDEX_ELT *)NULL;
8144
8145 /* Now COPY contains only unique entries. Duplicated entries in the
8146 original array have been freed. Replace the current array with
8147 the copy, fixing the NEXT pointers. */
8148 for (i = 0; copy[i] != (INDEX_ELT *)NULL; i++)
8149 {
8150
8151 copy[i]->next = copy[i + 1];
8152
8153 /* Fix entry names which are the same. They point to different nodes,
f8b2ac1e 8154 so we make the entry name unique. */
6599da04 8155 if ((copy[i + 1] != (INDEX_ELT *)NULL) &&
f8b2ac1e
JL
8156 (strcmp (copy[i]->entry, copy[i + 1]->entry) == 0))
8157 {
8158 char *new_entry_name;
8159
8160 new_entry_name = (char *)xmalloc (10 + strlen (copy[i]->entry));
8161 sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
8162 free (copy[i]->entry);
8163 copy[i]->entry = new_entry_name;
8164 counter++;
8165 }
6599da04 8166 else
f8b2ac1e 8167 counter = 1;
6599da04
JM
8168
8169 array[i] = copy[i];
8170 }
8171 array[i] = (INDEX_ELT *)NULL;
8172
8173 /* Free the storage used only by COPY. */
8174 free (copy);
8175}
8176
8177/* Sort the index passed in INDEX, returning an array of
8178 pointers to elements. The array is terminated with a NULL
8179 pointer. We call qsort because it's supposed to be fast.
8180 I think this looks bad. */
8181INDEX_ELT **
8182sort_index (index)
8183 INDEX_ELT *index;
8184{
6599da04 8185 INDEX_ELT **array;
f8b2ac1e 8186 INDEX_ELT *temp = index;
6599da04 8187 int count = 0;
f8b2ac1e
JL
8188 int save_line_number = line_number;
8189 char *save_input_filename = input_filename;
6599da04
JM
8190
8191 while (temp != (INDEX_ELT *) NULL)
8192 {
8193 count++;
8194 temp = temp->next;
8195 }
8196
8197 /* We have the length. Make an array. */
8198
8199 array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *));
8200 count = 0;
8201 temp = index;
8202
8203 while (temp != (INDEX_ELT *) NULL)
8204 {
8205 array[count++] = temp;
8206
f8b2ac1e
JL
8207 /* Set line number and input filename to the source line for this
8208 index entry, as this expansion finds any errors. */
8209 line_number = array[count - 1]->defining_line;
8210 input_filename = array[count - 1]->defining_file;
6599da04
JM
8211
8212 /* If this particular entry should be printed as a "code" index,
f8b2ac1e 8213 then wrap the entry with "@code{...}". */
6599da04
JM
8214 array[count - 1]->entry = expansion (temp->entry, index->code);
8215
8216 temp = temp->next;
8217 }
f8b2ac1e
JL
8218 array[count] = (INDEX_ELT *) NULL; /* terminate the array. */
8219 line_number = save_line_number;
8220 input_filename = save_input_filename;
6599da04
JM
8221
8222 /* Sort the array. */
8223 qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
8224 make_index_entries_unique (array, count);
8225 return (array);
8226}
8227
f8b2ac1e 8228/* Nonzero means that we are in the middle of printing an index. */
6599da04
JM
8229int printing_index = 0;
8230
8231/* Takes one arg, a short name of an index to print.
8232 Outputs a menu of the sorted elements of the index. */
8233void
8234cm_printindex ()
8235{
8236 int item;
8237 INDEX_ELT *index;
8238 INDEX_ELT **array;
8239 char *index_name;
8240 unsigned line_length;
8241 char *line;
8242 int saved_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
8243 int saved_filling_enabled = filling_enabled;
8244
8245 close_paragraph ();
8246 get_rest_of_line (&index_name);
8247
8248 index = index_list (index_name);
8249 if (index == (INDEX_ELT *)-1)
8250 {
f8b2ac1e 8251 line_error (_("Unknown index `%s' in @printindex"), index_name);
6599da04
JM
8252 free (index_name);
8253 return;
8254 }
8255 else
8256 free (index_name);
8257
8258 /* Do this before sorting, so execute_string in index_element_compare
8259 will give the same results as when we actually print. */
8260 printing_index = 1;
8261 filling_enabled = 0;
8262 inhibit_paragraph_indentation = 1;
8263 array = sort_index (index);
8264
8265 close_paragraph ();
f8b2ac1e 8266 add_word (_("* Menu:\n\n"));
6599da04
JM
8267
8268#if defined (HAVE_MACROS)
8269 me_inhibit_expansion++;
8270#endif /* HAVE_MACROS */
8271
8272 /* This will probably be enough. */
8273 line_length = 100;
8274 line = xmalloc (line_length);
8275
8276 for (item = 0; (index = array[item]); item++)
8277 {
8278 /* A pathological document might have an index entry outside of any
8279 node. Don't crash. Perhaps should warn. */
8280 char *index_node = index->node ? index->node : "(none)";
f8b2ac1e
JL
8281 unsigned new_length = strlen (index->entry);
8282
8283 if (new_length < 37) /* minimum length used below */
8284 new_length = 37;
8285 new_length += strlen (index_node) + 7; /* * : .\n\0 */
6599da04
JM
8286
8287 if (new_length > line_length)
8288 {
f8b2ac1e 8289 line_length = new_length;
6599da04
JM
8290 line = xrealloc (line, line_length);
8291 }
8292
8293 /* Print the entry, nicely formatted. We've already expanded any
8294 commands, including any implicit @code. Thus, can't call
8295 execute_string, since @@ has turned into @. */
8296 sprintf (line, "* %-37s %s.\n", index->entry, index_node);
8297 line[2 + strlen (index->entry)] = ':';
8298 insert_string (line);
8299
8300 /* Previous `output_paragraph' from growing to the size of the
8301 whole index. */
8302 flush_output ();
8303 }
8304
8305 free (line);
8306
8307#if defined (HAVE_MACROS)
8308 me_inhibit_expansion--;
8309#endif /* HAVE_MACROS */
8310
8311 printing_index = 0;
8312 free (array);
8313 close_single_paragraph ();
8314 filling_enabled = saved_filling_enabled;
8315 inhibit_paragraph_indentation = saved_inhibit_paragraph_indentation;
8316}
f8b2ac1e
JL
8317
8318/* User-defined commands, which happens only from user-defined indexes. */
6599da04
JM
8319
8320void
8321define_user_command (name, proc, needs_braces_p)
8322 char *name;
8323 COMMAND_FUNCTION *proc;
8324 int needs_braces_p;
8325{
8326 int slot = user_command_array_len;
8327 user_command_array_len++;
8328
8329 if (!user_command_array)
8330 user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *));
8331
8332 user_command_array = (COMMAND **) xrealloc (user_command_array,
f8b2ac1e
JL
8333 (1 + user_command_array_len) *
8334 sizeof (COMMAND *));
6599da04
JM
8335
8336 user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND));
f8b2ac1e 8337 user_command_array[slot]->name = xstrdup (name);
6599da04
JM
8338 user_command_array[slot]->proc = proc;
8339 user_command_array[slot]->argument_in_braces = needs_braces_p;
8340}
f8b2ac1e 8341\f
6599da04
JM
8342/* Some support for footnotes. */
8343
8344/* Footnotes are a new construct in Info. We don't know the best method
8345 of implementing them for sure, so we present two possiblities.
8346
8347 SeparateNode:
f8b2ac1e
JL
8348 Make them look like followed references, with the reference
8349 destinations in a makeinfo manufactured node or,
6599da04
JM
8350
8351 EndNode:
f8b2ac1e
JL
8352 Make them appear at the bottom of the node that they originally
8353 appeared in. */
6599da04
JM
8354#define SeparateNode 0
8355#define EndNode 1
8356
8357int footnote_style = EndNode;
8358int first_footnote_this_node = 1;
8359int footnote_count = 0;
8360
8361/* Set the footnote style based on he style identifier in STRING. */
8362int
8363set_footnote_style (string)
8364 char *string;
8365{
8366 if ((strcasecmp (string, "separate") == 0) ||
8367 (strcasecmp (string, "MN") == 0))
8368 footnote_style = SeparateNode;
8369 else if ((strcasecmp (string, "end") == 0) ||
f8b2ac1e 8370 (strcasecmp (string, "EN") == 0))
6599da04
JM
8371 footnote_style = EndNode;
8372 else
8373 return (-1);
8374
8375 return (0);
8376}
8377
8378void
8379cm_footnotestyle ()
8380{
8381 char *arg;
8382
8383 get_rest_of_line (&arg);
8384
8385 /* If set on command line, do not change the footnote style. */
8386 if (!footnote_style_preset && set_footnote_style (arg) != 0)
8387 line_error ("Bad argument to %c%s", COMMAND_PREFIX, command);
8388
8389 free (arg);
8390}
8391
8392typedef struct fn
8393{
8394 struct fn *next;
8395 char *marker;
8396 char *note;
8397} FN;
8398
8399FN *pending_notes = (FN *) NULL;
8400
8401/* A method for remembering footnotes. Note that this list gets output
8402 at the end of the current node. */
8403void
8404remember_note (marker, note)
8405 char *marker, *note;
8406{
8407 FN *temp = (FN *) xmalloc (sizeof (FN));
8408
f8b2ac1e
JL
8409 temp->marker = xstrdup (marker);
8410 temp->note = xstrdup (note);
6599da04
JM
8411 temp->next = pending_notes;
8412 pending_notes = temp;
8413 footnote_count++;
8414}
8415
8416/* How to get rid of existing footnotes. */
8417void
8418free_pending_notes ()
8419{
8420 FN *temp;
8421
8422 while ((temp = pending_notes) != (FN *) NULL)
8423 {
8424 free (temp->marker);
8425 free (temp->note);
8426 pending_notes = pending_notes->next;
8427 free (temp);
8428 }
8429 first_footnote_this_node = 1;
8430 footnote_count = 0;
8431}
8432
8433/* What to do when you see a @footnote construct. */
8434
8435 /* Handle a "footnote".
8436 footnote *{this is a footnote}
f8b2ac1e 8437 where "*" is the (optional) marker character for this note. */
6599da04
JM
8438void
8439cm_footnote ()
8440{
8441 char *marker;
8442 char *note;
8443
8444 get_until ("{", &marker);
8445 canon_white (marker);
8446
d275726b
JL
8447 if (macro_expansion_output_stream && !executing_string)
8448 append_to_expansion_output (input_text_offset + 1); /* include the { */
8449
6599da04
JM
8450 /* Read the argument in braces. */
8451 if (curchar () != '{')
8452 {
f8b2ac1e
JL
8453 line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
8454 COMMAND_PREFIX, command, marker);
6599da04
JM
8455 free (marker);
8456 return;
8457 }
8458 else
8459 {
6599da04 8460 int len;
f8b2ac1e
JL
8461 int braces = 1;
8462 int loc = ++input_text_offset;
6599da04
JM
8463
8464 while (braces)
f8b2ac1e
JL
8465 {
8466 if (loc == size_of_input_text)
8467 {
8468 line_error (_("No closing brace for footnote `%s'"), marker);
8469 return;
8470 }
8471
8472 if (input_text[loc] == '{')
8473 braces++;
8474 else if (input_text[loc] == '}')
8475 braces--;
8476 else if (input_text[loc] == '\n')
8477 line_number++;
8478
8479 loc++;
8480 }
8481
8482 len = (loc - input_text_offset) - 1;
6599da04
JM
8483 note = (char *)xmalloc (len + 1);
8484 strncpy (note, &input_text[input_text_offset], len);
f8b2ac1e
JL
8485 note[len] = 0;
8486 input_text_offset = loc;
8487 }
8488
8489 /* Must write the macro-expanded argument to the macro expansion
8490 output stream. This is like the case in index_add_arg. */
d275726b 8491 if (macro_expansion_output_stream && !executing_string)
f8b2ac1e
JL
8492 {
8493 int op_orig;
8494
8495 remember_itext (input_text, input_text_offset);
8496 op_orig = output_paragraph_offset;
8497 me_execute_string (note);
8498 /* Calling me_execute_string on a lone } provokes an error, since
8499 as far as the reader knows there is no matching {. We wrote
8500 the { above in the call to append_to_expansion_output. */
8501 write_region_to_macro_output ("}", 0, 1);
8502 output_paragraph_offset = op_orig;
6599da04
JM
8503 }
8504
8505 if (!current_node || !*current_node)
8506 {
f8b2ac1e 8507 line_error (_("Footnote defined without parent node"));
6599da04
JM
8508 free (marker);
8509 free (note);
8510 return;
8511 }
8512
8513 if (!*marker)
8514 {
8515 free (marker);
8516
8517 if (number_footnotes)
f8b2ac1e
JL
8518 {
8519 marker = (char *)xmalloc (10);
8520 sprintf (marker, "%d", current_footnote_number);
8521 current_footnote_number++;
8522 }
6599da04 8523 else
f8b2ac1e 8524 marker = xstrdup ("*");
6599da04
JM
8525 }
8526
8527 remember_note (marker, note);
8528
8529 /* Your method should at least insert MARKER. */
8530 switch (footnote_style)
8531 {
8532 case SeparateNode:
8533 add_word_args ("(%s)", marker);
8534 if (first_footnote_this_node)
f8b2ac1e
JL
8535 {
8536 char *temp_string;
8537
8538 temp_string = (char *)
8539 xmalloc ((strlen (current_node)) + (strlen (_("-Footnotes"))) + 1);
8540
8541 add_word_args (" (*note %s-Footnotes::)", current_node);
8542 strcpy (temp_string, current_node);
8543 strcat (temp_string, "-Footnotes");
8544 remember_node_reference (temp_string, line_number, followed_reference);
8545 free (temp_string);
8546 first_footnote_this_node = 0;
8547 }
6599da04
JM
8548 break;
8549
8550 case EndNode:
8551 add_word_args ("(%s)", marker);
8552 break;
8553
8554 default:
8555 break;
8556 }
8557 free (marker);
8558 free (note);
8559}
8560
f8b2ac1e 8561/* Nonzero means that we are currently in the process of outputting
6599da04
JM
8562 footnotes. */
8563int already_outputting_pending_notes = 0;
8564
8565/* Output the footnotes. We are at the end of the current node. */
8566void
8567output_pending_notes ()
8568{
8569 FN *footnote = pending_notes;
8570
8571 if (!pending_notes)
8572 return;
8573
8574 switch (footnote_style)
8575 {
8576 case SeparateNode:
8577 {
f8b2ac1e
JL
8578 char *old_current_node = current_node;
8579 char *old_command = xstrdup (command);
8580
8581 already_outputting_pending_notes++;
8582 execute_string ("%cnode %s-Footnotes,,,%s\n",
8583 COMMAND_PREFIX, current_node, current_node);
8584 already_outputting_pending_notes--;
8585 current_node = old_current_node;
8586 free (command);
8587 command = old_command;
6599da04
JM
8588 }
8589 break;
8590
8591 case EndNode:
8592 close_paragraph ();
8593 in_fixed_width_font++;
f8b2ac1e 8594 execute_string (_("---------- Footnotes ----------\n\n"));
6599da04
JM
8595 in_fixed_width_font--;
8596 break;
8597 }
8598
8599 /* Handle the footnotes in reverse order. */
8600 {
8601 FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *));
8602
8603 array[footnote_count] = (FN *) NULL;
8604
8605 while (--footnote_count > -1)
8606 {
f8b2ac1e
JL
8607 array[footnote_count] = footnote;
8608 footnote = footnote->next;
6599da04
JM
8609 }
8610
8611 filling_enabled = 1;
8612 indented_fill = 1;
8613
f8b2ac1e 8614 while ((footnote = array[++footnote_count]))
6599da04 8615 {
f8b2ac1e
JL
8616 execute_string ("(%s) %s", footnote->marker, footnote->note);
8617 close_paragraph ();
6599da04
JM
8618 }
8619 close_paragraph ();
8620 free (array);
8621 }
8622}
8623\f
8624/* **************************************************************** */
8625/* */
f8b2ac1e 8626/* User definable Macros (text substitution) */
6599da04
JM
8627/* */
8628/* **************************************************************** */
8629
8630#if defined (HAVE_MACROS)
8631
8632/* Array of macros and definitions. */
8633MACRO_DEF **macro_list = (MACRO_DEF **)NULL;
8634
f8b2ac1e
JL
8635int macro_list_len = 0; /* Number of elements. */
8636int macro_list_size = 0; /* Number of slots in total. */
6599da04
JM
8637
8638/* Return the macro definition of NAME or NULL if NAME is not defined. */
8639MACRO_DEF *
8640find_macro (name)
8641 char *name;
8642{
8643 register int i;
8644 register MACRO_DEF *def;
8645
8646 def = (MACRO_DEF *)NULL;
8647 for (i = 0; macro_list && (def = macro_list[i]); i++)
8648 {
8649 if ((!def->inhibited) && (strcmp (def->name, name) == 0))
f8b2ac1e 8650 break;
6599da04
JM
8651 }
8652 return (def);
8653}
8654
8655/* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
8656 SOURCE_FILE is the name of the file where this definition can be found,
8657 and SOURCE_LINENO is the line number within that file. If a macro already
8658 exists with NAME, then a warning is produced, and that previous
8659 definition is overwritten. */
8660void
8661add_macro (name, arglist, body, source_file, source_lineno, flags)
8662 char *name;
8663 char **arglist;
8664 char *body;
8665 char *source_file;
8666 int source_lineno, flags;
8667{
8668 register MACRO_DEF *def;
8669
8670 def = find_macro (name);
8671
8672 if (!def)
8673 {
8674 if (macro_list_len + 2 >= macro_list_size)
f8b2ac1e
JL
8675 macro_list = (MACRO_DEF **)xrealloc
8676 (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
6599da04
JM
8677
8678 macro_list[macro_list_len] = (MACRO_DEF *)xmalloc (sizeof (MACRO_DEF));
8679 macro_list[macro_list_len + 1] = (MACRO_DEF *)NULL;
8680
8681 def = macro_list[macro_list_len];
8682 macro_list_len += 1;
8683 def->name = name;
8684 }
8685 else
8686 {
8687 char *temp_filename = input_filename;
8688 int temp_line = line_number;
8689
f8b2ac1e 8690 warning (_("macro `%s' previously defined"), name);
6599da04
JM
8691
8692 input_filename = def->source_file;
8693 line_number = def->source_lineno;
f8b2ac1e 8694 warning (_("here is the previous definition of `%s'"), name);
6599da04
JM
8695
8696 input_filename = temp_filename;
8697 line_number = temp_line;
8698
8699 if (def->arglist)
f8b2ac1e
JL
8700 {
8701 register int i;
6599da04 8702
f8b2ac1e
JL
8703 for (i = 0; def->arglist[i]; i++)
8704 free (def->arglist[i]);
6599da04 8705
f8b2ac1e
JL
8706 free (def->arglist);
8707 }
6599da04
JM
8708 free (def->source_file);
8709 free (def->body);
8710 }
8711
f8b2ac1e 8712 def->source_file = xstrdup (source_file);
6599da04
JM
8713 def->source_lineno = source_lineno;
8714 def->body = body;
8715 def->arglist = arglist;
8716 def->inhibited = 0;
8717 def->flags = flags;
8718}
8719
8720/* Delete the macro with name NAME. The macro is deleted from the list,
8721 but it is also returned. If there was no macro defined, NULL is
8722 returned. */
8723MACRO_DEF *
8724delete_macro (name)
8725 char *name;
8726{
8727 register int i;
8728 register MACRO_DEF *def;
8729
8730 def = (MACRO_DEF *)NULL;
8731
8732 for (i = 0; macro_list && (def = macro_list[i]); i++)
8733 if (strcmp (def->name, name) == 0)
8734 {
f8b2ac1e
JL
8735 memmove (macro_list + i, macro_list + i + 1,
8736 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
8737 macro_list_len--;
8738 break;
6599da04
JM
8739 }
8740 return (def);
8741}
8742
8743/* Return the arglist on the current line. This can behave in two different
8744 ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
8745int braces_required_for_macro_args = 0;
8746
8747char **
8748get_macro_args (def)
f8b2ac1e 8749 MACRO_DEF *def;
6599da04
JM
8750{
8751 register int i;
8752 char *word;
8753
8754 /* Quickly check to see if this macro has been invoked with any arguments.
8755 If not, then don't skip any of the following whitespace. */
8756 for (i = input_text_offset; i < size_of_input_text; i++)
8757 if (!cr_or_whitespace (input_text[i]))
8758 break;
8759
8760 if (input_text[i] != '{')
8761 {
8762 if (braces_required_for_macro_args)
f8b2ac1e
JL
8763 {
8764 return ((char **)NULL);
8765 }
6599da04 8766 else
f8b2ac1e
JL
8767 {
8768 /* Braces are not required to fill out the macro arguments. If
8769 this macro takes one argument, it is considered to be the
8770 remainder of the line, sans whitespace. */
8771 if (def->arglist && def->arglist[0] && !def->arglist[1])
8772 {
8773 char **arglist;
8774
8775 get_rest_of_line (&word);
8776 if (input_text[input_text_offset - 1] == '\n')
8777 {
8778 input_text_offset--;
8779 line_number--;
8780 }
8781 /* canon_white (word); */
8782 arglist = (char **)xmalloc (2 * sizeof (char *));
8783 arglist[0] = word;
8784 arglist[1] = (char *)NULL;
8785 return (arglist);
8786 }
8787 else
8788 {
8789 /* The macro either took no arguments, or took more than
8790 one argument. In that case, it must be invoked with
8791 arguments surrounded by braces. */
8792 return ((char **)NULL);
8793 }
8794 }
6599da04
JM
8795 }
8796 return (get_brace_args (def->flags & ME_QUOTE_ARG));
8797}
8798
8799/* Substitute actual parameters for named parameters in body.
8800 The named parameters which appear in BODY must by surrounded
8801 reverse slashes, as in \foo\. */
8802char *
8803apply (named, actuals, body)
8804 char **named, **actuals, *body;
8805{
8806 register int i;
8807 int new_body_index, new_body_size;
8808 char *new_body, *text;
8809 int length_of_actuals;
8810
8811 length_of_actuals = array_len (actuals);
8812 new_body_size = strlen (body);
8813 new_body = (char *)xmalloc (1 + new_body_size);
8814
8815 /* Copy chars from BODY into NEW_BODY. */
8816 i = 0; new_body_index = 0;
8817
8818 while (1)
8819 {
8820 if (!body[i])
f8b2ac1e 8821 break;
6599da04
JM
8822
8823 if (body[i] != '\\')
f8b2ac1e 8824 new_body[new_body_index++] = body[i++];
6599da04 8825 else
f8b2ac1e
JL
8826 {
8827 /* Snarf parameter name, check against named parameters. */
8828 char *param;
8829 int param_start, which, len;
8830
8831 param_start = ++i;
8832 while ((body[i]) && (body[i] != '\\'))
8833 i++;
8834
8835 len = i - param_start;
8836 param = (char *)xmalloc (1 + len);
8837 memcpy (param, body + param_start, len);
8838 param[len] = 0;
8839
8840 if (body[i]) /* move past \ */
8841 i++;
8842
8843 /* Now check against named parameters. */
8844 for (which = 0; named && named[which]; which++)
8845 if (strcmp (named[which], param) == 0)
8846 break;
8847
8848 if (named && named[which])
8849 {
8850 if (which < length_of_actuals)
8851 text = actuals[which];
8852 else
8853 text = (char *)NULL;
8854
8855 if (!text)
8856 text = "";
8857
8858 len = strlen (text);
8859 }
8860 else
8861 { /* not a parameter, restore \'s */
d275726b
JL
8862 i = body[i] ? (i - 1) : i;
8863 len++;
8864 text = xmalloc (1 + len);
8865 sprintf (text, "\\%s", param);
f8b2ac1e
JL
8866 }
8867
8868 if ((2 + strlen (param)) < len)
8869 {
8870 new_body_size += len + 1;
8871 new_body = xrealloc (new_body, new_body_size);
8872 }
8873
8874 free (param);
8875
8876 strcpy (new_body + new_body_index, text);
8877 new_body_index += len;
8878
8879 if (!named || !named[which])
8880 free (text);
8881 }
8882 }
8883 new_body[new_body_index] = 0;
6599da04
JM
8884 return (new_body);
8885}
8886
8887/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
8888void
8889execute_macro (def)
8890 MACRO_DEF *def;
8891{
6599da04
JM
8892 char **arglist;
8893 int num_args;
8894 char *execution_string = (char *)NULL;
8895
d275726b 8896 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
6599da04
JM
8897 me_append_before_this_command ();
8898
8899 /* Find out how many arguments this macro definition takes. */
8900 num_args = array_len (def->arglist);
8901
8902 /* Gather the arguments present on the line if there are any. */
8903 arglist = get_macro_args (def);
8904
8905 if (num_args < array_len (arglist))
8906 {
8907 free_array (arglist);
f8b2ac1e 8908 line_error (_("Macro `%s' called with too many args"), def->name);
6599da04
JM
8909 return;
8910 }
8911
8912 if (def->body)
8913 execution_string = apply (def->arglist, arglist, def->body);
8914
8915 free_array (arglist);
8916
8917 if (def->body)
8918 {
d275726b 8919 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
f8b2ac1e
JL
8920 {
8921 remember_itext (input_text, input_text_offset);
8922 me_execute_string (execution_string);
8923 }
6599da04 8924 else
f8b2ac1e 8925 execute_string ("%s", execution_string);
6599da04
JM
8926
8927 free (execution_string);
8928 }
8929}
8930
8931/* Read and remember the definition of a macro. */
8932void
8933cm_macro ()
8934{
8935 register int i;
8936 char *name, **arglist, *body, *line;
8937 int body_size, body_index;
8938 int depth = 1;
8939 int defining_line = line_number;
8940 int flags = 0;
8941
8942 arglist = (char **)NULL;
8943 body = (char *)NULL;
8944 body_size = 0;
8945 body_index = 0;
8946
d275726b 8947 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
8948 me_append_before_this_command ();
8949
8950 skip_whitespace ();
8951
8952 /* Get the name of the macro. This is the set of characters which are
8953 not whitespace and are not `{' immediately following the @macro. */
8954 {
8955 int start = input_text_offset;
8956 int len;
8957
8958 for (i = start;
f8b2ac1e
JL
8959 (i < size_of_input_text) &&
8960 (input_text[i] != '{') &&
8961 (!cr_or_whitespace (input_text[i]));
8962 i++);
6599da04
JM
8963
8964 len = i - start;
8965 name = (char *)xmalloc (1 + len);
8966 strncpy (name, input_text + start, len);
f8b2ac1e 8967 name[len] = 0;
6599da04
JM
8968 input_text_offset = i;
8969 }
8970
8971 skip_whitespace ();
8972
8973 /* It is not required that the definition of a macro includes an arglist.
8974 If not, don't try to get the named parameters, just use a null list. */
8975 if (curchar () == '{')
8976 {
8977 int arglist_index = 0, arglist_size = 0;
8978 int gathering_words = 1;
8979 char *word = (char *)NULL;
8980 int character;
8981
8982 /* Read the words inside of the braces which determine the arglist.
f8b2ac1e
JL
8983 These words will be replaced within the body of the macro at
8984 execution time. */
6599da04
JM
8985
8986 input_text_offset++;
8987 skip_whitespace_and_newlines ();
8988
8989 while (gathering_words)
f8b2ac1e
JL
8990 {
8991 int len;
8992
8993 for (i = input_text_offset;
8994 (character = input_text[i]);
8995 i++)
8996 {
8997 switch (character)
8998 {
8999 case '\n':
9000 line_number++;
9001 case ' ':
9002 case '\t':
9003 case ',':
9004 case '}':
9005 /* Found the end of the current arglist word. Save it. */
9006 len = i - input_text_offset;
9007 word = (char *)xmalloc (1 + len);
9008 strncpy (word, input_text + input_text_offset, len);
9009 word[len] = 0;
9010 input_text_offset = i;
9011
9012 /* Advance to the comma or close-brace that signified
9013 the end of the argument. */
9014 while ((character = curchar ())
9015 && character != ','
9016 && character != '}')
9017 {
9018 input_text_offset++;
9019 if (character == '\n')
9020 line_number++;
9021 }
9022
9023 /* Add the word to our list of words. */
9024 if ((arglist_index + 2) >= arglist_size)
9025 arglist = (char **)xrealloc
9026 (arglist, (arglist_size += 10) * sizeof (char *));
9027
9028 arglist[arglist_index++] = word;
9029 arglist[arglist_index] = (char *)NULL;
9030 break;
9031 }
9032
9033 if (character == '}')
9034 {
9035 input_text_offset++;
9036 gathering_words = 0;
9037 break;
9038 }
9039
9040 if (character == ',')
9041 {
9042 input_text_offset++;
9043 skip_whitespace_and_newlines ();
9044 i = input_text_offset - 1;
9045 }
9046 }
9047 }
6599da04
JM
9048 }
9049
9050 /* Read the text carefully until we find an "@end macro" which
9051 matches this one. The text in between is the body of the macro. */
9052 skip_whitespace_and_newlines ();
9053
9054 while (depth)
9055 {
9056 if ((input_text_offset + 9) > size_of_input_text)
f8b2ac1e
JL
9057 {
9058 int temp_line = line_number;
9059 line_number = defining_line;
9060 line_error (_("%cend macro not found"), COMMAND_PREFIX);
9061 line_number = temp_line;
9062 return;
9063 }
6599da04
JM
9064
9065 get_rest_of_line (&line);
9066
9067 /* Handle commands only meaningful within a macro. */
9068 if ((*line == COMMAND_PREFIX) && (depth == 1) &&
f8b2ac1e
JL
9069 (strncmp (line + 1, "allow-recursion", 15) == 0) &&
9070 (line[16] == 0 || whitespace (line[16])))
9071 {
9072 for (i = 16; whitespace (line[i]); i++);
9073 strcpy (line, line + i);
9074 flags |= ME_RECURSE;
9075 if (!*line)
9076 {
9077 free (line);
9078 continue;
9079 }
9080 }
6599da04
JM
9081
9082 if ((*line == COMMAND_PREFIX) && (depth == 1) &&
f8b2ac1e
JL
9083 (strncmp (line + 1, "quote-arg", 9) == 0) &&
9084 (line[10] == 0 || whitespace (line[10])))
9085 {
9086 for (i = 10; whitespace (line[i]); i++);
9087 strcpy (line, line + i);
9088
9089 if (arglist && arglist[0] && !arglist[1])
9090 {
9091 flags |= ME_QUOTE_ARG;
9092 if (!*line)
9093 {
9094 free (line);
9095 continue;
9096 }
9097 }
9098 else
9099 {
9100 line_error (_("%cquote-arg only useful when the macro takes a single argument"),
9101 COMMAND_PREFIX);
9102 }
9103 }
6599da04
JM
9104
9105 if ((*line == COMMAND_PREFIX) &&
f8b2ac1e
JL
9106 (strncmp (line + 1, "macro ", 6) == 0))
9107 depth++;
6599da04
JM
9108
9109 if ((*line == COMMAND_PREFIX) &&
f8b2ac1e
JL
9110 (strncmp (line + 1, "end macro", 9) == 0))
9111 depth--;
6599da04
JM
9112
9113 if (depth)
f8b2ac1e
JL
9114 {
9115 if ((body_index + strlen (line) + 3) >= body_size)
9116 body = (char *)xrealloc
9117 (body, body_size += 3 + strlen (line));
9118 strcpy (body + body_index, line);
9119 body_index += strlen (line);
9120 body[body_index++] = '\n';
9121 body[body_index] = 0;
9122 }
6599da04
JM
9123 free (line);
9124 }
9125
f8b2ac1e
JL
9126 /* If it was an empty macro like
9127 @macro foo
9128 @end macro
9129 create an empty body. (Otherwise, the macro is not expanded.) */
9130 if (!body)
9131 {
9132 body = (char *)malloc(1);
9133 *body = 0;
9134 }
9135
6599da04
JM
9136 /* We now have the name, the arglist, and the body. However, BODY
9137 includes the final newline which preceded the `@end macro' text.
9138 Delete it. */
9139 if (body && strlen (body))
f8b2ac1e 9140 body[strlen (body) - 1] = 0;
6599da04
JM
9141
9142 add_macro (name, arglist, body, input_filename, defining_line, flags);
9143
d275726b 9144 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
9145 remember_itext (input_text, input_text_offset);
9146}
9147
9148void
9149cm_unmacro ()
9150{
9151 register int i;
9152 char *line, *name;
9153 MACRO_DEF *def;
9154
d275726b 9155 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
9156 me_append_before_this_command ();
9157
9158 get_rest_of_line (&line);
6599da04
JM
9159
9160 for (i = 0; line[i] && !whitespace (line[i]); i++);
f8b2ac1e 9161 name = (char *)xmalloc (i + 1);
6599da04 9162 strncpy (name, line, i);
f8b2ac1e 9163 name[i] = 0;
6599da04
JM
9164
9165 def = delete_macro (name);
9166
9167 if (def)
9168 {
9169 free (def->source_file);
9170 free (def->name);
9171 free (def->body);
9172
9173 if (def->arglist)
f8b2ac1e
JL
9174 {
9175 register int i;
6599da04 9176
f8b2ac1e
JL
9177 for (i = 0; def->arglist[i]; i++)
9178 free (def->arglist[i]);
6599da04 9179
f8b2ac1e
JL
9180 free (def->arglist);
9181 }
6599da04
JM
9182
9183 free (def);
9184 }
9185
9186 free (line);
9187 free (name);
9188
d275726b 9189 if (macro_expansion_output_stream && !executing_string)
6599da04
JM
9190 remember_itext (input_text, input_text_offset);
9191}
9192
9193/* How to output sections of the input file verbatim. */
9194
9195/* Set the value of POINTER's offset to OFFSET. */
9196ITEXT *
9197remember_itext (pointer, offset)
9198 char *pointer;
9199 int offset;
9200{
9201 register int i;
9202 ITEXT *itext = (ITEXT *)NULL;
9203
9204 /* If we have no info, initialize a blank list. */
9205 if (!itext_info)
9206 {
9207 itext_info = (ITEXT **)xmalloc ((itext_size = 10) * sizeof (ITEXT *));
9208 for (i = 0; i < itext_size; i++)
f8b2ac1e 9209 itext_info[i] = (ITEXT *)NULL;
6599da04
JM
9210 }
9211
9212 /* If the pointer is already present in the list, then set the offset. */
9213 for (i = 0; i < itext_size; i++)
9214 if ((itext_info[i] != (ITEXT *)NULL) &&
f8b2ac1e 9215 (itext_info[i]->pointer == pointer))
6599da04 9216 {
f8b2ac1e
JL
9217 itext = itext_info[i];
9218 itext_info[i]->offset = offset;
9219 break;
6599da04
JM
9220 }
9221
9222 if (i == itext_size)
9223 {
f8b2ac1e
JL
9224 /* Find a blank slot (or create a new one), and remember the
9225 pointer and offset. */
6599da04 9226 for (i = 0; i < itext_size; i++)
f8b2ac1e
JL
9227 if (itext_info[i] == (ITEXT *)NULL)
9228 break;
6599da04
JM
9229
9230 /* If not found, then add some slots. */
9231 if (i == itext_size)
f8b2ac1e
JL
9232 {
9233 register int j;
6599da04 9234
f8b2ac1e
JL
9235 itext_info = (ITEXT **)xrealloc
9236 (itext_info, (itext_size += 10) * sizeof (ITEXT *));
6599da04 9237
f8b2ac1e
JL
9238 for (j = i; j < itext_size; j++)
9239 itext_info[j] = (ITEXT *)NULL;
9240 }
6599da04
JM
9241
9242 /* Now add the pointer and the offset. */
9243 itext_info[i] = (ITEXT *)xmalloc (sizeof (ITEXT));
9244 itext_info[i]->pointer = pointer;
9245 itext_info[i]->offset = offset;
9246 itext = itext_info[i];
9247 }
9248 return (itext);
9249}
9250
9251/* Forget the input text associated with POINTER. */
9252void
9253forget_itext (pointer)
9254 char *pointer;
9255{
9256 register int i;
9257
9258 for (i = 0; i < itext_size; i++)
9259 if (itext_info[i] && (itext_info[i]->pointer == pointer))
9260 {
f8b2ac1e
JL
9261 free (itext_info[i]);
9262 itext_info[i] = (ITEXT *)NULL;
9263 break;
6599da04
JM
9264 }
9265}
9266
9267/* Append the text which appeared in input_text from the last offset to
9268 the character just before the command that we are currently executing. */
9269void
9270me_append_before_this_command ()
9271{
9272 register int i;
9273
9274 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--);
9275 maybe_write_itext (input_text, i);
9276}
9277
9278/* Similar to execute_string (), but only takes a single string argument,
9279 and remembers the input text location, etc. */
9280void
9281me_execute_string (execution_string)
9282 char *execution_string;
9283{
9284 pushfile ();
9285 input_text_offset = 0;
9286 input_text = execution_string;
f8b2ac1e 9287 input_filename = xstrdup (input_filename);
6599da04
JM
9288 size_of_input_text = strlen (execution_string);
9289
9290 remember_itext (execution_string, 0);
9291
d275726b 9292 me_executing_string++;
6599da04
JM
9293 reader_loop ();
9294 popfile ();
d275726b 9295 me_executing_string--;
6599da04
JM
9296}
9297
9298/* Append the text which appears in input_text from the last offset to
9299 the current OFFSET. */
9300void
9301append_to_expansion_output (offset)
9302 int offset;
9303{
9304 register int i;
9305 ITEXT *itext = (ITEXT *)NULL;
9306
9307 for (i = 0; i < itext_size; i++)
9308 if (itext_info[i] && itext_info[i]->pointer == input_text)
9309 {
f8b2ac1e
JL
9310 itext = itext_info[i];
9311 break;
6599da04
JM
9312 }
9313
9314 if (!itext)
d275726b 9315 return;
6599da04
JM
9316
9317 if (offset > itext->offset)
9318 {
9319 write_region_to_macro_output
f8b2ac1e 9320 (input_text, itext->offset, offset);
6599da04
JM
9321 remember_itext (input_text, offset);
9322 }
9323}
9324
9325/* Only write this input text iff it appears in our itext list. */
9326void
9327maybe_write_itext (pointer, offset)
9328 char *pointer;
9329 int offset;
9330{
9331 register int i;
9332 ITEXT *itext = (ITEXT *)NULL;
9333
9334 for (i = 0; i < itext_size; i++)
9335 if (itext_info[i] && (itext_info[i]->pointer == pointer))
9336 {
f8b2ac1e
JL
9337 itext = itext_info[i];
9338 break;
6599da04
JM
9339 }
9340
9341 if (itext && (itext->offset < offset))
9342 {
9343 write_region_to_macro_output (itext->pointer, itext->offset, offset);
9344 remember_itext (pointer, offset);
9345 }
9346}
9347
9348void
9349write_region_to_macro_output (string, start, end)
9350 char *string;
9351 int start, end;
9352{
9353 if (macro_expansion_output_stream)
9354 fwrite (string + start, 1, end - start, macro_expansion_output_stream);
9355}
9356
9357#endif /* HAVE_MACROS */
9358
9359/* Return the length of the array in ARRAY. */
9360int
9361array_len (array)
9362 char **array;
9363{
9364 register int i = 0;
9365
9366 if (array)
9367 for (i = 0; array[i] != (char *)NULL; i++);
9368
9369 return (i);
9370}
9371
9372void
9373free_array (array)
9374 char **array;
9375{
9376 if (array)
9377 {
9378 register int i;
9379
9380 for (i = 0; array[i] != (char *)NULL; i++)
f8b2ac1e 9381 free (array[i]);
6599da04
JM
9382
9383 free (array);
9384 }
9385}
9386
9387/* Function is used even when we don't have macros. Although, I have
9388 to admit, it is unlikely that you would have a use for it if you
9389 aren't using macros. */
9390char **
9391get_brace_args (quote_single)
9392 int quote_single;
9393{
9394 char **arglist, *word;
9395 int arglist_index, arglist_size;
9396 int character, escape_seen, start;
9397 int depth = 1;
9398
9399 /* There is an arglist in braces here, so gather the args inside of it. */
9400 skip_whitespace_and_newlines ();
9401 input_text_offset++;
9402 arglist = (char **)NULL;
9403 arglist_index = arglist_size = 0;
9404
9405 get_arg:
9406 skip_whitespace_and_newlines ();
9407 start = input_text_offset;
9408 escape_seen = 0;
9409
f8b2ac1e 9410 while ((character = curchar ()))
6599da04
JM
9411 {
9412 if (character == '\\')
f8b2ac1e
JL
9413 {
9414 input_text_offset += 2;
9415 escape_seen = 1;
9416 }
6599da04 9417 else if (character == '{')
f8b2ac1e
JL
9418 {
9419 depth++;
9420 input_text_offset++;
9421 }
6599da04 9422 else if ((character == ',' && !quote_single) ||
f8b2ac1e
JL
9423 ((character == '}') && depth == 1))
9424 {
9425 int len = input_text_offset - start;
9426
9427 if (len || (character != '}'))
9428 {
9429 word = (char *)xmalloc (1 + len);
9430 strncpy (word, input_text + start, len);
9431 word[len] = 0;
9432
9433 /* Clean up escaped characters. */
9434 if (escape_seen)
9435 {
9436 register int i;
9437
9438 for (i = 0; word[i]; i++)
9439 if (word[i] == '\\')
9440 memmove (word + i, word + i + 1,
9441 1 + strlen (word + i + 1));
9442 }
9443
9444 if (arglist_index + 2 >= arglist_size)
9445 arglist = (char **)xrealloc
9446 (arglist, (arglist_size += 10) * sizeof (char *));
9447
9448 arglist[arglist_index++] = word;
9449 arglist[arglist_index] = (char *)NULL;
9450 }
9451
9452 input_text_offset++;
9453 if (character == '}')
9454 break;
9455 else
9456 goto get_arg;
9457 }
6599da04 9458 else if (character == '}')
f8b2ac1e
JL
9459 {
9460 depth--;
9461 input_text_offset++;
9462 }
6599da04 9463 else
f8b2ac1e
JL
9464 {
9465 input_text_offset++;
9466 if (character == '\n') line_number++;
9467 }
6599da04
JM
9468 }
9469 return (arglist);
9470}
9471\f
9472/* **************************************************************** */
9473/* */
9474/* Looking For Include Files */
9475/* */
9476/* **************************************************************** */
9477
9478/* Given a string containing units of information separated by colons,
9479 return the next one pointed to by INDEX, or NULL if there are no more.
9480 Advance INDEX to the character after the colon. */
9481char *
9482extract_colon_unit (string, index)
9483 char *string;
9484 int *index;
9485{
9486 int i, start;
9487
9488 i = *index;
9489
9490 if (!string || (i >= strlen (string)))
9491 return ((char *)NULL);
9492
9493 /* Each call to this routine leaves the index pointing at a colon if
9494 there is more to the path. If I is > 0, then increment past the
9495 `:'. If I is 0, then the path has a leading colon. Trailing colons
9496 are handled OK by the `else' part of the if statement; an empty
9497 string is returned in that case. */
9498 if (i && string[i] == ':')
9499 i++;
9500
9501 start = i;
9502
9503 while (string[i] && string[i] != ':') i++;
9504
9505 *index = i;
9506
9507 if (i == start)
9508 {
9509 if (string[i])
f8b2ac1e 9510 (*index)++;
6599da04
JM
9511
9512 /* Return "" in the case of a trailing `:'. */
f8b2ac1e 9513 return (xstrdup (""));
6599da04
JM
9514 }
9515 else
9516 {
9517 char *value;
9518
9519 value = (char *)xmalloc (1 + (i - start));
9520 strncpy (value, &string[start], (i - start));
f8b2ac1e 9521 value [i - start] = 0;
6599da04
JM
9522
9523 return (value);
9524 }
9525}
9526
9527/* Return the full pathname for FILENAME by searching along PATH.
9528 When found, return the stat () info for FILENAME in FINFO.
9529 If PATH is NULL, only the current directory is searched.
9530 If the file could not be found, return a NULL pointer. */
9531char *
9532get_file_info_in_path (filename, path, finfo)
9533 char *filename, *path;
9534 struct stat *finfo;
9535{
9536 char *dir;
9537 int result, index = 0;
9538
9539 if (path == (char *)NULL)
9540 path = ".";
9541
9542 /* Handle absolute pathnames. "./foo", "/foo", "../foo". */
9543 if (*filename == '/' ||
9544 (*filename == '.' &&
9545 (filename[1] == '/' ||
f8b2ac1e
JL
9546 (filename[1] == '.' && filename[2] == '/')))
9547#ifdef WIN32
9548 /* Handle names that look like "d:/foo/bar" */
9549 || (isalpha (*filename) && filename [1] == ':'
9550 && (filename [2] == '/' || filename [2] == '\\'))
9551#endif
9552 )
6599da04
JM
9553 {
9554 if (stat (filename, finfo) == 0)
f8b2ac1e 9555 return (xstrdup (filename));
6599da04 9556 else
f8b2ac1e 9557 return ((char *)NULL);
6599da04
JM
9558 }
9559
f8b2ac1e 9560 while ((dir = extract_colon_unit (path, &index)))
6599da04
JM
9561 {
9562 char *fullpath;
9563
9564 if (!*dir)
f8b2ac1e
JL
9565 {
9566 free (dir);
9567 dir = xstrdup (".");
9568 }
6599da04
JM
9569
9570 fullpath = (char *)xmalloc (2 + strlen (dir) + strlen (filename));
9571 sprintf (fullpath, "%s/%s", dir, filename);
9572 free (dir);
9573
9574 result = stat (fullpath, finfo);
9575
9576 if (result == 0)
f8b2ac1e 9577 return (fullpath);
6599da04 9578 else
f8b2ac1e 9579 free (fullpath);
6599da04 9580 }
f8b2ac1e 9581 return NULL;
6599da04 9582}