cmds.c revision 100513
1/* cmds.c -- Texinfo commands.
2   $Id: cmds.c,v 1.79 2002/03/28 16:35:29 karl Exp $
3
4   Copyright (C) 1998, 99, 2000, 01, 02 Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software Foundation,
18   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#include "system.h"
21#include "cmds.h"
22#include "defun.h"
23#include "files.h"
24#include "footnote.h"
25#include "insertion.h"
26#include "lang.h"
27#include "macro.h"
28#include "makeinfo.h"
29#include "node.h"
30#include "sectioning.h"
31#include "toc.h"
32#include "xml.h"
33
34#ifdef TM_IN_SYS_TIME
35#include <sys/time.h>
36#else
37#include <time.h>
38#endif
39
40
41void insert_self (), insert_space (), cm_ignore_line (), cm_ignore_arg ();
42
43void
44  cm_TeX (), cm_acronym (), cm_asterisk (), cm_b (), cm_bullet (), cm_cite (),
45  cm_code (), cm_copyright (), cm_ctrl (), cm_dfn (), cm_dircategory (),
46  cm_direntry (), cm_dmn (), cm_dots (), cm_emph (), cm_enddots (), cm_i (),
47  cm_image (), cm_kbd (), cm_key (), cm_no_op (),
48  cm_novalidate (), cm_not_fixed_width (), cm_r (),
49  cm_strong (), cm_var (), cm_sc (), cm_w (), cm_email (), cm_url (),
50  cm_verb (), cm_copying (), cm_insert_copying (),
51  cm_documentdescription ();
52
53void
54  cm_anchor (), cm_node (), cm_menu (), cm_xref (), cm_ftable (),
55  cm_vtable (), cm_pxref (), cm_inforef (), cm_uref (), cm_email (),
56  cm_quotation (), cm_display (), cm_smalldisplay (), cm_itemize (),
57  cm_enumerate (), cm_tab (), cm_table (), cm_itemx (), cm_noindent (),
58  cm_setfilename (), cm_br (), cm_sp (), cm_page (), cm_group (),
59  cm_center (), cm_ref (), cm_include (), cm_bye (), cm_item (), cm_end (),
60  cm_kindex (), cm_cindex (), cm_findex (), cm_pindex (), cm_vindex (),
61  cm_tindex (), cm_synindex (), cm_printindex (), cm_minus (),
62  cm_example (), cm_smallexample (), cm_smalllisp (), cm_lisp (),
63  cm_format (), cm_smallformat (), cm_exdent (), cm_defindex (),
64  cm_defcodeindex (), cm_result (), cm_expansion (), cm_equiv (),
65  cm_print (), cm_error (), cm_point (), cm_today (), cm_flushleft (),
66  cm_flushright (), cm_finalout (), cm_cartouche (), cm_detailmenu (),
67  cm_multitable (), cm_settitle (), cm_titlefont (), cm_tt (),
68  cm_verbatim (), cm_verbatiminclude ();
69
70/* Conditionals. */
71void cm_set (), cm_clear (), cm_ifset (), cm_ifclear ();
72void cm_value (), cm_ifeq ();
73
74/* Options. */
75static void cm_paragraphindent (), cm_exampleindent ();
76
77/* Internals. */
78static void cm_obsolete ();
79
80/* A random string.  */
81static const char small_tag[] = "small";
82
83/* The dispatch table.  */
84COMMAND command_table[] = {
85  { "\t", insert_space, NO_BRACE_ARGS },
86  { "\n", insert_space, NO_BRACE_ARGS },
87  { " ", insert_space, NO_BRACE_ARGS },
88  { "!", insert_self, NO_BRACE_ARGS },
89  { "\"", cm_accent_umlaut, MAYBE_BRACE_ARGS },
90  { "'", cm_accent_acute, MAYBE_BRACE_ARGS },
91  { "*", cm_asterisk, NO_BRACE_ARGS },
92  { ",", cm_accent_cedilla, MAYBE_BRACE_ARGS },
93  { "-", cm_no_op, NO_BRACE_ARGS },
94  { ".", insert_self, NO_BRACE_ARGS },
95  { ":", cm_no_op, NO_BRACE_ARGS },
96  { "=", cm_accent, MAYBE_BRACE_ARGS },
97  { "?", insert_self, NO_BRACE_ARGS },
98  { "@", insert_self, NO_BRACE_ARGS },
99  { "\\", insert_self, NO_BRACE_ARGS },
100  { "^", cm_accent_hat, MAYBE_BRACE_ARGS },
101  { "`", cm_accent_grave, MAYBE_BRACE_ARGS },
102  { "{", insert_self, NO_BRACE_ARGS },
103  { "|", cm_no_op, NO_BRACE_ARGS },
104  { "}", insert_self, NO_BRACE_ARGS },
105  { "~", cm_accent_tilde, MAYBE_BRACE_ARGS },
106  { "AA", cm_special_char, BRACE_ARGS },
107  { "AE", cm_special_char, BRACE_ARGS },
108  { "H", cm_accent, MAYBE_BRACE_ARGS },
109  { "L", cm_special_char, BRACE_ARGS },
110  { "O", cm_special_char, BRACE_ARGS },
111  { "OE", cm_special_char, BRACE_ARGS },
112  { "TeX", cm_TeX, BRACE_ARGS },
113  { "aa", cm_special_char, BRACE_ARGS },
114  { "acronym", cm_acronym, BRACE_ARGS },
115  { "ae", cm_special_char, BRACE_ARGS },
116  { "afivepaper", cm_ignore_line, NO_BRACE_ARGS },
117  { "afourlatex", cm_ignore_line, NO_BRACE_ARGS },
118  { "afourpaper", cm_ignore_line, NO_BRACE_ARGS },
119  { "afourwide", cm_ignore_line, NO_BRACE_ARGS },
120  { "alias", cm_alias, NO_BRACE_ARGS },
121  { "anchor", cm_anchor, BRACE_ARGS },
122  { "appendix", cm_appendix, NO_BRACE_ARGS },
123  { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
124  { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
125  { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
126  { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
127  { "asis", cm_no_op, BRACE_ARGS },
128  { "b", cm_b, BRACE_ARGS },
129  { "bullet", cm_bullet, BRACE_ARGS },
130  { "bye", cm_bye, NO_BRACE_ARGS },
131  { "c", cm_ignore_line, NO_BRACE_ARGS },
132  { "cartouche", cm_cartouche, NO_BRACE_ARGS },
133  { "center", cm_center, NO_BRACE_ARGS },
134  { "centerchap", cm_unnumbered, NO_BRACE_ARGS },
135  { "chapheading", cm_chapheading, NO_BRACE_ARGS },
136  { "chapter", cm_chapter, NO_BRACE_ARGS },
137  { "cindex", cm_cindex, NO_BRACE_ARGS },
138  { "cite", cm_cite, BRACE_ARGS },
139  { "clear", cm_clear, NO_BRACE_ARGS },
140  { "code", cm_code, BRACE_ARGS },
141  { "command", cm_code, BRACE_ARGS },
142  { "comment", cm_ignore_line, NO_BRACE_ARGS },
143  { "contents", cm_contents, NO_BRACE_ARGS },
144  { "copying", cm_copying, NO_BRACE_ARGS },
145  { "copyright", cm_copyright, BRACE_ARGS },
146  { "ctrl", cm_obsolete, BRACE_ARGS },
147  { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
148  { "defcv", cm_defun, NO_BRACE_ARGS },
149  { "defcvx", cm_defun, NO_BRACE_ARGS },
150  { "deffn", cm_defun, NO_BRACE_ARGS },
151  { "deffnx", cm_defun, NO_BRACE_ARGS },
152  { "defindex", cm_defindex, NO_BRACE_ARGS },
153  { "definfoenclose", cm_definfoenclose, NO_BRACE_ARGS },
154  { "defivar", cm_defun, NO_BRACE_ARGS },
155  { "defivarx", cm_defun, NO_BRACE_ARGS },
156  { "defmac", cm_defun, NO_BRACE_ARGS },
157  { "defmacx", cm_defun, NO_BRACE_ARGS },
158  { "defmethod", cm_defun, NO_BRACE_ARGS },
159  { "defmethodx", cm_defun, NO_BRACE_ARGS },
160  { "defop", cm_defun, NO_BRACE_ARGS },
161  { "defopt", cm_defun, NO_BRACE_ARGS },
162  { "defoptx", cm_defun, NO_BRACE_ARGS },
163  { "defopx", cm_defun, NO_BRACE_ARGS },
164  { "defspec", cm_defun, NO_BRACE_ARGS },
165  { "defspecx", cm_defun, NO_BRACE_ARGS },
166  { "deftp", cm_defun, NO_BRACE_ARGS },
167  { "deftpx", cm_defun, NO_BRACE_ARGS },
168  { "deftypefn", cm_defun, NO_BRACE_ARGS },
169  { "deftypefnx", cm_defun, NO_BRACE_ARGS },
170  { "deftypefun", cm_defun, NO_BRACE_ARGS },
171  { "deftypefunx", cm_defun, NO_BRACE_ARGS },
172  { "deftypeivar", cm_defun, NO_BRACE_ARGS },
173  { "deftypeivarx", cm_defun, NO_BRACE_ARGS },
174  { "deftypemethod", cm_defun, NO_BRACE_ARGS },
175  { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
176  { "deftypeop", cm_defun, NO_BRACE_ARGS },
177  { "deftypeopx", cm_defun, NO_BRACE_ARGS },
178  { "deftypevar", cm_defun, NO_BRACE_ARGS },
179  { "deftypevarx", cm_defun, NO_BRACE_ARGS },
180  { "deftypevr", cm_defun, NO_BRACE_ARGS },
181  { "deftypevrx", cm_defun, NO_BRACE_ARGS },
182  { "defun", cm_defun, NO_BRACE_ARGS },
183  { "defunx", cm_defun, NO_BRACE_ARGS },
184  { "defvar", cm_defun, NO_BRACE_ARGS },
185  { "defvarx", cm_defun, NO_BRACE_ARGS },
186  { "defvr", cm_defun, NO_BRACE_ARGS },
187  { "defvrx", cm_defun, NO_BRACE_ARGS },
188  { "detailmenu", cm_detailmenu, NO_BRACE_ARGS },
189  { "dfn", cm_dfn, BRACE_ARGS },
190  { "dircategory", cm_dircategory, NO_BRACE_ARGS },
191  { "direntry", cm_direntry, NO_BRACE_ARGS },
192  { "display", cm_display, NO_BRACE_ARGS },
193  { "dmn", cm_no_op, BRACE_ARGS },
194  { "documentdescription", cm_documentdescription, NO_BRACE_ARGS },
195  { "documentencoding", cm_documentencoding, NO_BRACE_ARGS },
196  { "documentlanguage", cm_documentlanguage, NO_BRACE_ARGS },
197  { "dotaccent", cm_accent, MAYBE_BRACE_ARGS },
198  { "dotless", cm_dotless, BRACE_ARGS },
199  { "dots", cm_dots, BRACE_ARGS },
200  { "email", cm_email, BRACE_ARGS },
201  { "emph", cm_emph, BRACE_ARGS },
202  { "end", cm_end, NO_BRACE_ARGS },
203  { "enddots", cm_enddots, BRACE_ARGS },
204  { "enumerate", cm_enumerate, NO_BRACE_ARGS },
205  { "env", cm_code, BRACE_ARGS },
206  { "equiv", cm_equiv, BRACE_ARGS },
207  { "error", cm_error, BRACE_ARGS },
208  { "evenfooting", cm_ignore_line, NO_BRACE_ARGS },
209  { "evenheading", cm_ignore_line, NO_BRACE_ARGS },
210  { "everyfooting", cm_ignore_line, NO_BRACE_ARGS },
211  { "everyheading", cm_ignore_line, NO_BRACE_ARGS },
212  { "example", cm_example, NO_BRACE_ARGS },
213  { "exampleindent", cm_exampleindent, NO_BRACE_ARGS },
214  { "exclamdown", cm_special_char, BRACE_ARGS },
215  { "exdent", cm_exdent, NO_BRACE_ARGS },
216  { "expansion", cm_expansion, BRACE_ARGS },
217  { "file", cm_code, BRACE_ARGS },
218  { "finalout", cm_no_op, NO_BRACE_ARGS },
219  { "findex", cm_findex, NO_BRACE_ARGS },
220  { "flushleft", cm_flushleft, NO_BRACE_ARGS },
221  { "flushright", cm_flushright, NO_BRACE_ARGS },
222  { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
223  { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
224  { "format", cm_format, NO_BRACE_ARGS },
225  { "ftable", cm_ftable, NO_BRACE_ARGS },
226  { "group", cm_group, NO_BRACE_ARGS },
227  { "heading", cm_heading, NO_BRACE_ARGS },
228  { "headings", cm_ignore_line, NO_BRACE_ARGS },
229  { "html", cm_html, NO_BRACE_ARGS },
230  { "hyphenation", cm_ignore_arg, BRACE_ARGS },
231  { "i", cm_i, BRACE_ARGS },
232  { "ifclear", cm_ifclear, NO_BRACE_ARGS },
233  { "ifeq", cm_ifeq, NO_BRACE_ARGS },
234  { "ifhtml", cm_ifhtml, NO_BRACE_ARGS },
235  { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
236  { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS },
237  { "ifnotinfo", cm_ifnotinfo, NO_BRACE_ARGS },
238  { "ifnotplaintext", cm_ifnotplaintext, NO_BRACE_ARGS },
239  { "ifnottex", cm_ifnottex, NO_BRACE_ARGS },
240  { "ifplaintext", cm_ifplaintext, NO_BRACE_ARGS },
241  { "ifset", cm_ifset, NO_BRACE_ARGS },
242  { "iftex", cm_iftex, NO_BRACE_ARGS },
243  { "ignore", command_name_condition, NO_BRACE_ARGS },
244  { "image", cm_image, BRACE_ARGS },
245  { "include", cm_include, NO_BRACE_ARGS },
246  { "inforef", cm_inforef, BRACE_ARGS },
247  { "insertcopying", cm_insert_copying, NO_BRACE_ARGS },
248  { "item", cm_item, NO_BRACE_ARGS },
249  { "itemize", cm_itemize, NO_BRACE_ARGS },
250  { "itemx", cm_itemx, NO_BRACE_ARGS },
251  { "kbd", cm_kbd, BRACE_ARGS },
252  { "kbdinputstyle", cm_ignore_line, NO_BRACE_ARGS },
253  { "key", cm_key, BRACE_ARGS },
254  { "kindex", cm_kindex, NO_BRACE_ARGS },
255  { "l", cm_special_char, BRACE_ARGS },
256  { "lisp", cm_lisp, NO_BRACE_ARGS },
257  { "lowersections", cm_lowersections, NO_BRACE_ARGS },
258  { "macro", cm_macro, NO_BRACE_ARGS },
259  { "majorheading", cm_majorheading, NO_BRACE_ARGS },
260  { "math", cm_no_op, BRACE_ARGS },
261  { "menu", cm_menu, NO_BRACE_ARGS },
262  { "minus", cm_minus, BRACE_ARGS },
263  { "multitable", cm_multitable, NO_BRACE_ARGS },
264  { "need", cm_ignore_line, NO_BRACE_ARGS },
265  { "node", cm_node, NO_BRACE_ARGS },
266  { "noindent", cm_noindent, NO_BRACE_ARGS },
267  { "noindent", cm_novalidate, NO_BRACE_ARGS },
268  { "nwnode", cm_node, NO_BRACE_ARGS },
269  { "o", cm_special_char, BRACE_ARGS },
270  { "oddfooting", cm_ignore_line, NO_BRACE_ARGS },
271  { "oddheading", cm_ignore_line, NO_BRACE_ARGS },
272  { "oe", cm_special_char, BRACE_ARGS },
273  { "option", cm_code, BRACE_ARGS },
274  { "page", cm_no_op, NO_BRACE_ARGS },
275  { "pagesizes", cm_ignore_line, NO_BRACE_ARGS },
276  { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
277  { "pindex", cm_pindex, NO_BRACE_ARGS },
278  { "point", cm_point, BRACE_ARGS },
279  { "pounds", cm_special_char, BRACE_ARGS },
280  { "print", cm_print, BRACE_ARGS },
281  { "printindex", cm_printindex, NO_BRACE_ARGS },
282  { "pxref", cm_pxref, BRACE_ARGS },
283  { "questiondown", cm_special_char, BRACE_ARGS },
284  { "quotation", cm_quotation, NO_BRACE_ARGS },
285  { "r", cm_r, BRACE_ARGS },
286  { "raisesections", cm_raisesections, NO_BRACE_ARGS },
287  { "ref", cm_ref, BRACE_ARGS },
288  { "refill", cm_no_op, NO_BRACE_ARGS },
289  { "result", cm_result, BRACE_ARGS },
290  { "ringaccent", cm_accent, MAYBE_BRACE_ARGS },
291  { "rmacro", cm_rmacro, NO_BRACE_ARGS },
292  { "samp", cm_code, BRACE_ARGS },
293  { "sc", cm_sc, BRACE_ARGS },
294  { "section", cm_section, NO_BRACE_ARGS },
295  { "set", cm_set, NO_BRACE_ARGS },
296  { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
297  { "setchapterstyle", cm_obsolete, NO_BRACE_ARGS },
298  { "setcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
299  { "setfilename", cm_setfilename, NO_BRACE_ARGS },
300  { "setshortcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
301  { "settitle", cm_settitle, NO_BRACE_ARGS },
302  { "shortcontents", cm_shortcontents, NO_BRACE_ARGS },
303  { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
304  { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
305  { "smalldisplay", cm_smalldisplay, NO_BRACE_ARGS },
306  { "smallexample", cm_smallexample, NO_BRACE_ARGS },
307  { "smallformat", cm_smallformat, NO_BRACE_ARGS },
308  { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
309  { "sp", cm_sp, NO_BRACE_ARGS },
310  { "ss", cm_special_char, BRACE_ARGS },
311  { "strong", cm_strong, BRACE_ARGS },
312  { "subheading", cm_subheading, NO_BRACE_ARGS },
313  { "subsection", cm_subsection, NO_BRACE_ARGS },
314  { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
315  { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
316  { "summarycontents", cm_shortcontents, NO_BRACE_ARGS },
317  { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
318  { "synindex", cm_synindex, NO_BRACE_ARGS },
319  { "t", cm_tt, BRACE_ARGS },
320  { "tab", cm_tab, NO_BRACE_ARGS },
321  { "table", cm_table, NO_BRACE_ARGS },
322  { "tex", cm_tex, NO_BRACE_ARGS },
323  { "tieaccent", cm_accent, MAYBE_BRACE_ARGS },
324  { "tindex", cm_tindex, NO_BRACE_ARGS },
325  { "titlefont", cm_titlefont, BRACE_ARGS },
326  { "titlepage", command_name_condition, NO_BRACE_ARGS },
327  { "today", cm_today, BRACE_ARGS },
328  { "top", cm_top, NO_BRACE_ARGS  },
329  { "u", cm_accent, MAYBE_BRACE_ARGS },
330  { "ubaraccent", cm_accent, MAYBE_BRACE_ARGS },
331  { "udotaccent", cm_accent, MAYBE_BRACE_ARGS },
332  { "unmacro", cm_unmacro, NO_BRACE_ARGS },
333  { "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
334  { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
335  { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
336  { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
337  { "uref", cm_uref, BRACE_ARGS },
338  { "url", cm_url, BRACE_ARGS },
339  { "v", cm_accent, MAYBE_BRACE_ARGS },
340  { "value", cm_value, BRACE_ARGS },
341  { "var", cm_var, BRACE_ARGS },
342  { "verb", cm_verb, NO_BRACE_ARGS },
343  { "verbatim", cm_verbatim, NO_BRACE_ARGS },
344  { "verbatiminclude", cm_verbatiminclude, NO_BRACE_ARGS },
345  { "vindex", cm_vindex, NO_BRACE_ARGS },
346  { "vtable", cm_vtable, NO_BRACE_ARGS },
347  { "w", cm_w, BRACE_ARGS },
348  { "xref", cm_xref, BRACE_ARGS },
349
350  /* Deprecated commands.  These used to be for italics.  */
351  { "iappendix", cm_ideprecated, NO_BRACE_ARGS },
352  { "iappendixsec", cm_ideprecated, NO_BRACE_ARGS },
353  { "iappendixsection", cm_ideprecated, NO_BRACE_ARGS },
354  { "iappendixsubsec", cm_ideprecated, NO_BRACE_ARGS },
355  { "iappendixsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
356  { "ichapter", cm_ideprecated, NO_BRACE_ARGS },
357  { "isection", cm_ideprecated, NO_BRACE_ARGS },
358  { "isubsection", cm_ideprecated, NO_BRACE_ARGS },
359  { "isubsubsection", cm_ideprecated, NO_BRACE_ARGS },
360  { "iunnumbered", cm_ideprecated, NO_BRACE_ARGS },
361  { "iunnumberedsec", cm_ideprecated, NO_BRACE_ARGS },
362  { "iunnumberedsubsec", cm_ideprecated, NO_BRACE_ARGS },
363  { "iunnumberedsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
364
365  /* Now @include does what this was used to. */
366  { "infoinclude", cm_obsolete, NO_BRACE_ARGS },
367  { "titlespec", cm_obsolete, NO_BRACE_ARGS },
368
369  { NULL, NULL, NO_BRACE_ARGS }
370};
371
372/* The bulk of the Texinfo commands. */
373
374/* Commands which insert their own names. */
375void
376insert_self (arg)
377    int arg;
378{
379  if (arg == START)
380    add_word (command);
381}
382
383void
384insert_space (arg)
385    int arg;
386{
387  if (arg == START)
388    {
389      if (xml && !docbook)
390	xml_insert_entity ("space");
391      else
392	add_char (' ');
393    }
394}
395
396/* Force a line break in the output. */
397void
398cm_asterisk ()
399{
400  if (html)
401    add_word ("<br>");
402  else if (xml && !docbook)
403    xml_insert_entity ("linebreak");
404  else if (docbook)
405    xml_asterisk ();
406  else
407    {
408      close_single_paragraph ();
409      cm_noindent ();
410    }
411}
412
413/* Insert ellipsis. */
414void
415cm_dots (arg)
416     int arg;
417{
418  if (arg == START)
419    {
420      if (xml && !docbook)
421	xml_insert_entity ("dots");
422      else if (docbook)
423	xml_insert_entity ("hellip");
424      else
425	add_word (html ? "<small>...</small>" : "...");
426    }
427}
428
429/* Insert ellipsis for sentence end. */
430void
431cm_enddots (arg)
432     int arg;
433{
434  if (arg == START)
435    {
436      if (xml && !docbook)
437	xml_insert_entity ("enddots");
438      else if (docbook)
439	{
440	  xml_insert_entity ("hellip");
441	  add_char ('.');
442	}
443      else
444	add_word (html ? "<small>...</small>." : "....");
445    }
446}
447
448void
449cm_bullet (arg)
450     int arg;
451{
452  if (arg == START)
453    {
454      if (html)
455        add_word ("&#149;");
456      else if (xml && !docbook)
457	xml_insert_entity ("bullet");
458      else if (docbook)
459	xml_insert_entity ("bull");
460      else
461        add_char ('*');
462    }
463}
464
465void
466cm_minus (arg)
467     int arg;
468{
469  if (arg == START)
470    {
471      if (xml)
472	xml_insert_entity ("minus");
473      else
474	add_char ('-');
475    }
476}
477
478/* Insert "TeX". */
479void
480cm_TeX (arg)
481     int arg;
482{
483  if (arg == START)
484    {
485      if (xml && ! docbook)
486	xml_insert_entity ("tex");
487      else
488	add_word ("TeX");
489    }
490}
491
492/* Copyright symbol.  */
493void
494cm_copyright (arg)
495    int arg;
496{
497  if (arg == START)
498    {
499    if (html)
500      add_word ("&copy;");
501    else if (xml && !docbook)
502      xml_insert_entity ("copyright");
503    else if (docbook)
504      xml_insert_entity ("copy");
505    else
506      add_word ("(C)");
507    }
508}
509
510void
511cm_today (arg)
512     int arg;
513{
514  static char *months[12] =
515    { N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
516      N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
517      N_("November"), N_("December") };
518  if (arg == START)
519    {
520      time_t timer = time (0);
521      struct tm *ts = localtime (&timer);
522      add_word_args ("%d %s %d", ts->tm_mday, _(months[ts->tm_mon]),
523                     ts->tm_year + 1900);
524    }
525}
526
527void
528cm_acronym (arg)
529     int arg;
530{
531  if (html)
532    insert_html_tag (arg, small_tag);
533  else if (xml)
534    xml_insert_element (ACRONYM, arg);
535}
536
537void
538cm_tt (arg)
539     int arg;
540{
541  /* @t{} is a no-op in Info.  */
542  if (html)
543    insert_html_tag (arg, "tt");
544  else if (xml)
545    xml_insert_element (TT, arg);
546}
547
548void
549cm_code (arg)
550     int arg;
551{
552  if (xml)
553    xml_insert_element (CODE, arg);
554  else
555    {
556  extern int printing_index;
557
558  if (arg == START)
559    {
560      in_fixed_width_font++;
561
562      if (html)
563        insert_html_tag (arg, "code");
564      else if (!printing_index)
565        add_char ('`');
566    }
567  else if (html)
568    insert_html_tag (arg, "code");
569  else
570    {
571      if (!printing_index)
572        add_meta_char ('\'');
573    }
574    }
575}
576
577void
578cm_kbd (arg)
579     int arg;
580{
581  if (xml)
582    xml_insert_element (KBD, arg);
583  else if (html)
584    { /* Seems like we should increment in_fixed_width_font for Info
585         format too, but then the quote-omitting special case gets
586         confused.  Punt.  */
587      if (arg == START)
588        in_fixed_width_font++;
589      insert_html_tag (arg, "kbd");
590    }
591  else
592    { /* People use @kbd in an example to get the "user input" font.
593         We don't want quotes in that case.  */
594      if (!in_fixed_width_font)
595        cm_code (arg);
596    }
597}
598
599void
600cm_url (arg, start, end)
601{
602  if (xml)
603    xml_insert_element (URL, arg);
604  else if (html)
605    {
606      if (arg == START)
607        add_word ("&lt;<code>");
608      else
609	add_word ("</code>&gt;");
610    }
611  else
612    if (arg == START)
613      add_word ("<");
614    else
615      add_word (">");
616}
617
618void
619cm_key (arg)
620     int arg;
621{
622  if (xml)
623    xml_insert_element (KEY, arg);
624  else if (html)
625    add_word (arg == START ? "&lt;" : "&gt;");
626  else
627    add_char (arg == START ? '<' : '>');
628}
629
630/* Handle a command that switches to a non-fixed-width font.  */
631void
632not_fixed_width (arg)
633     int arg;
634{
635  if (arg == START)
636    in_fixed_width_font = 0;
637}
638
639/* @var in makeinfo just uppercases the text. */
640void
641cm_var (arg, start_pos, end_pos)
642     int arg, start_pos, end_pos;
643{
644  if (xml)
645    xml_insert_element (VAR, arg);
646  else
647    {
648  not_fixed_width (arg);
649
650  if (html)
651    insert_html_tag (arg, "var");
652  else if (arg == END)
653    {
654      while (start_pos < end_pos)
655        {
656          unsigned char c = output_paragraph[start_pos];
657          if (strchr ("[](),", c))
658            warning (_("unlikely character %c in @var"), c);
659          output_paragraph[start_pos] = coerce_to_upper (c);
660          start_pos++;
661        }
662    }
663    }
664}
665
666void
667cm_sc (arg, start_pos, end_pos)
668     int arg, start_pos, end_pos;
669{
670  if (xml)
671    xml_insert_element (SC, arg);
672  else
673    {
674  not_fixed_width (arg);
675
676  if (arg == START)
677    {
678      if (html)
679	insert_html_tag (arg, small_tag);
680    }
681  else
682    {
683      int all_upper;
684
685      if (html)
686        start_pos += sizeof (small_tag) + 2 - 1; /* skip <small> */
687
688      /* Avoid the warning below if there's no text inside @sc{}, or
689         when processing menus under --no-headers.  */
690      all_upper = start_pos < end_pos;
691
692      while (start_pos < end_pos)
693        {
694          unsigned char c = output_paragraph[start_pos];
695          if (!isupper (c))
696            all_upper = 0;
697          output_paragraph[start_pos] = coerce_to_upper (c);
698          start_pos++;
699        }
700      if (all_upper)
701        warning (_("@sc argument all uppercase, thus no effect"));
702
703      if (html)
704	insert_html_tag (arg, small_tag);
705    }
706    }
707}
708
709void
710cm_dfn (arg, position)
711     int arg, position;
712{
713  if (xml)
714    xml_insert_element (DFN, arg);
715  else
716    {
717  if (html)
718    insert_html_tag (arg, "dfn");
719  else if (arg == START)
720    add_char ('"');
721  else
722    add_meta_char ('"');
723    }
724}
725
726void
727cm_emph (arg)
728     int arg;
729{
730  if (xml)
731    xml_insert_element (EMPH, arg);
732  else if (html)
733    insert_html_tag (arg, "em");
734  else
735    add_char ('_');
736}
737
738void
739cm_verb (arg)
740     int arg;
741{
742  int character;
743  int delimiter;
744  int seen_end = 0;
745
746  in_fixed_width_font++;
747  /* are these necessary ? */
748  last_char_was_newline = 0;
749
750  if (html)
751    add_word ("<pre>");
752
753  if (input_text_offset < input_text_length)
754    {
755      character = curchar ();
756      if (character == '{')
757	input_text_offset++;
758      else
759	line_error (_("`{' expected, but saw `%c'"), character);
760    }
761
762  if (input_text_offset < input_text_length)
763    {
764      delimiter = curchar ();
765      input_text_offset++;
766    }
767
768  while (input_text_offset < input_text_length)
769    {
770      character = curchar ();
771
772      if (character == '\n')
773        line_number++;
774      /*
775	Assume no newlines in END_VERBATIM
776      */
777      else if (character == delimiter)
778	{
779	  seen_end = 1;
780	  input_text_offset++;
781	  break;
782	}
783
784      add_char (character);
785      input_text_offset++;
786    }
787
788  if (!seen_end)
789    warning (_("end of file inside verb block"));
790
791  if (input_text_offset < input_text_length)
792    {
793      character = curchar ();
794      if (character == '}')
795	input_text_offset++;
796      else
797	line_error (_("`}' expected, but saw `%c'"), character);
798    }
799
800  if (html)
801    add_word ("</pre>");
802}
803
804void
805cm_strong (arg, position)
806     int arg, position;
807{
808  if (xml)
809    xml_insert_element (STRONG, arg);
810  else if (html)
811    insert_html_tag (arg, "strong");
812  else
813    add_char ('*');
814}
815
816void
817cm_cite (arg, position)
818     int arg, position;
819{
820  if (xml)
821    xml_insert_element (CITE, arg);
822  else if (html)
823    insert_html_tag (arg, "cite");
824  else
825    {
826      if (arg == START)
827        add_char ('`');
828      else
829        add_char ('\'');
830    }
831}
832
833/* No highlighting, but argument switches fonts.  */
834void
835cm_not_fixed_width (arg, start, end)
836     int arg, start, end;
837{
838  if (xml)
839    xml_insert_element (NOTFIXEDWIDTH, arg);
840  not_fixed_width (arg);
841}
842
843void
844cm_i (arg)
845     int arg;
846{
847  if (xml)
848    xml_insert_element (I, arg);
849  else if (html)
850    insert_html_tag (arg, "i");
851  else
852    not_fixed_width (arg);
853}
854
855void
856cm_b (arg)
857     int arg;
858{
859  if (xml)
860    xml_insert_element (B, arg);
861  else if (html)
862    insert_html_tag (arg, "b");
863  else
864    not_fixed_width (arg);
865}
866
867void
868cm_r (arg)
869     int arg;
870{
871  if (xml)
872    xml_insert_element (R, arg);
873  else
874    {
875      extern int printing_index;
876
877      /* People use @r{} in index entries like this:
878
879      @findex foo@r{, some text}
880
881      This is supposed to produce output as if the entry were saying
882      "@code{foo}, some text", since the "fn" index is typeset as
883      @code.  The following attempts to do the same in HTML.  Note that
884      this relies on the fact that only @code bumps up the variable
885      in_fixed_width_font while processing index entries in HTML mode.  */
886      if (html && printing_index)
887	{
888	  int level = in_fixed_width_font;
889
890	  while (level--)
891	    insert_html_tag (arg == START ? END : START, "code");
892	}
893
894      not_fixed_width (arg);
895    }
896}
897
898void
899cm_titlefont (arg)
900     int arg;
901{
902  if (xml)
903    xml_insert_element (TITLEFONT, arg);
904  else
905  not_fixed_width (arg);
906}
907
908/* Various commands are no-op's. */
909void
910cm_no_op ()
911{
912}
913
914
915/* For proofing single chapters, etc.  */
916void
917cm_novalidate ()
918{
919  validating = 0;
920}
921
922
923/* Prevent the argument from being split across two lines. */
924void
925cm_w (arg, start, end)
926     int arg, start, end;
927{
928  if (arg == START)
929    non_splitting_words++;
930  else
931    non_splitting_words--;
932}
933
934
935/* Explain that this command is obsolete, thus the user shouldn't
936   do anything with it. */
937static void
938cm_obsolete (arg, start, end)
939     int arg, start, end;
940{
941  if (arg == START)
942    warning (_("%c%s is obsolete"), COMMAND_PREFIX, command);
943}
944
945
946/* This says to inhibit the indentation of the next paragraph, but
947   not of following paragraphs.  */
948void
949cm_noindent ()
950{
951  if (!inhibit_paragraph_indentation)
952    inhibit_paragraph_indentation = -1;
953}
954
955/* I don't know exactly what to do with this.  Should I allow
956   someone to switch filenames in the middle of output?  Since the
957   file could be partially written, this doesn't seem to make sense.
958   Another option: ignore it, since they don't *really* want to
959   switch files.  Finally, complain, or at least warn.  It doesn't
960   really matter, anyway, since this doesn't get executed.  */
961void
962cm_setfilename ()
963{
964  char *filename;
965  get_rest_of_line (1, &filename);
966  /* warning ("`@%s %s' encountered and ignored", command, filename); */
967  if (xml)
968    add_word_args ("<setfilename>%s</setfilename>", filename);
969  free (filename);
970}
971
972void
973cm_settitle ()
974{
975  if (xml)
976    {
977      xml_begin_document (current_output_filename);
978      xml_insert_element (SETTITLE, START);
979      get_rest_of_line (0, &title);
980      execute_string ("%s", title);
981      xml_insert_element (SETTITLE, END);
982    }
983  else
984    get_rest_of_line (0, &title);
985}
986
987
988/* Ignore argument in braces.  */
989void
990cm_ignore_arg (arg, start_pos, end_pos)
991     int arg, start_pos, end_pos;
992{
993  if (arg == END)
994    output_paragraph_offset = start_pos;
995}
996
997/* Ignore argument on rest of line.  */
998void
999cm_ignore_line ()
1000{
1001  discard_until ("\n");
1002}
1003
1004/* Insert the number of blank lines passed as argument. */
1005void
1006cm_sp ()
1007{
1008  int lines;
1009  char *line;
1010
1011  get_rest_of_line (1, &line);
1012
1013  if (sscanf (line, "%d", &lines) != 1 || lines <= 0)
1014    line_error (_("@sp requires a positive numeric argument, not `%s'"), line);
1015  else
1016    {
1017      if (xml)
1018	{
1019	  xml_insert_element_with_attribute (SP, START, "lines=\"%s\"", line);
1020	  /*	  insert_string (line);*/
1021	  xml_insert_element (SP, END);
1022	}
1023      else
1024	{
1025	  /* Must disable filling since otherwise multiple newlines is like
1026         multiple spaces.  Must close paragraph since that's what the
1027         manual says and that's what TeX does.  */
1028      int save_filling_enabled = filling_enabled;
1029      filling_enabled = 0;
1030
1031      /* close_paragraph generates an extra blank line.  */
1032      close_single_paragraph ();
1033
1034      if (lines && html && !executing_string)
1035	html_output_head ();
1036
1037      while (lines--)
1038	{
1039	  if (html)
1040	    insert_string ("<br><p>\n");
1041	  else
1042	    add_char ('\n');
1043	}
1044
1045      filling_enabled = save_filling_enabled;
1046    }
1047    }
1048  free (line);
1049}
1050
1051/* @dircategory LINE outputs INFO-DIR-SECTION LINE, unless --no-headers.  */
1052void
1053cm_dircategory ()
1054{
1055  char *line;
1056
1057  if (html || docbook)
1058    cm_ignore_line ();
1059  else if (xml)
1060    {
1061      xml_insert_element (DIRCATEGORY, START);
1062      get_rest_of_line (1, &line);
1063      insert_string (line);
1064      free (line);
1065      xml_insert_element (DIRCATEGORY, END);
1066    }
1067  else
1068    {
1069      get_rest_of_line (1, &line);
1070
1071      if (!no_headers && !html)
1072        {
1073          kill_self_indent (-1); /* make sure there's no indentation */
1074          insert_string ("INFO-DIR-SECTION ");
1075          insert_string (line);
1076          insert ('\n');
1077        }
1078
1079      free (line);
1080    }
1081}
1082
1083/* Start a new line with just this text on it.
1084   Then center the line of text.
1085   */
1086void
1087cm_center ()
1088{
1089  if (xml)
1090    {
1091      unsigned char *line;
1092      xml_insert_element (CENTER, START);
1093      get_rest_of_line (0, (char **)&line);
1094      execute_string ("%s", (char *)line);
1095      free (line);
1096      xml_insert_element (CENTER, END);
1097    }
1098  else
1099    {
1100  int i, start, length;
1101  unsigned char *line;
1102  int save_indented_fill = indented_fill;
1103  int save_filling_enabled = filling_enabled;
1104  int fudge_factor = 1;
1105
1106  filling_enabled = indented_fill = 0;
1107  cm_noindent ();
1108  start = output_paragraph_offset;
1109
1110  if (html)
1111    add_word ("<div align=\"center\">");
1112
1113  inhibit_output_flushing ();
1114  get_rest_of_line (0, (char **)&line);
1115  execute_string ("%s", (char *)line);
1116  free (line);
1117  uninhibit_output_flushing ();
1118   if (html)
1119    add_word ("</div>");
1120
1121   else
1122     {
1123       i = output_paragraph_offset - 1;
1124       while (i > (start - 1) && output_paragraph[i] == '\n')
1125	 i--;
1126
1127       output_paragraph_offset = ++i;
1128       length = output_paragraph_offset - start;
1129
1130       if (length < (fill_column - fudge_factor))
1131	 {
1132	   line = xmalloc (1 + length);
1133	   memcpy (line, (char *)(output_paragraph + start), length);
1134
1135	   i = (fill_column - fudge_factor - length) / 2;
1136	   output_paragraph_offset = start;
1137
1138	   while (i--)
1139	     insert (' ');
1140
1141	   for (i = 0; i < length; i++)
1142	     insert (line[i]);
1143
1144	   free (line);
1145	 }
1146     }
1147
1148  insert ('\n');
1149  filling_enabled = save_filling_enabled;
1150  indented_fill = save_indented_fill;
1151    }
1152}
1153
1154/* Show what an expression returns. */
1155void
1156cm_result (arg)
1157     int arg;
1158{
1159  if (arg == END)
1160    add_word (html ? "=&gt;" : "=>");
1161}
1162
1163/* What an expression expands to. */
1164void
1165cm_expansion (arg)
1166     int arg;
1167{
1168  if (arg == END)
1169    add_word (html ? "==&gt;" : "==>");
1170}
1171
1172/* Indicates two expressions are equivalent. */
1173void
1174cm_equiv (arg)
1175     int arg;
1176{
1177  if (arg == END)
1178    add_word ("==");
1179}
1180
1181/* What an expression may print. */
1182void
1183cm_print (arg)
1184     int arg;
1185{
1186  if (arg == END)
1187    add_word ("-|");
1188}
1189
1190/* An error signaled. */
1191void
1192cm_error (arg)
1193     int arg;
1194{
1195  if (arg == END)
1196    add_word (html ? "error--&gt;" : "error-->");
1197}
1198
1199/* The location of point in an example of a buffer. */
1200void
1201cm_point (arg)
1202     int arg;
1203{
1204  if (arg == END)
1205    add_word ("-!-");
1206}
1207
1208/* @exdent: Start a new line with just this text on it.
1209   The text is outdented one level if possible. */
1210void
1211cm_exdent ()
1212{
1213  char *line;
1214  int save_indent = current_indent;
1215  int save_in_fixed_width_font = in_fixed_width_font;
1216
1217  /* Read argument  */
1218  get_rest_of_line (0, &line);
1219
1220  /* Exdent the output.  Actually this may be a no-op.   */
1221  if (current_indent)
1222    current_indent -= default_indentation_increment;
1223
1224  /* @exdent arg is supposed to be in roman.  */
1225  in_fixed_width_font = 0;
1226
1227  /* The preceding newline already inserted the `current_indent'.
1228     Remove one level's worth.  */
1229  kill_self_indent (default_indentation_increment);
1230
1231  if (html)
1232    add_word ("<br>");
1233
1234  /* Can't close_single_paragraph, then we lose preceding blank lines.  */
1235  flush_output ();
1236  execute_string ("%s", line);
1237  free (line);
1238
1239  if (html)
1240    add_word ("<br>");
1241  close_single_paragraph ();
1242
1243  current_indent = save_indent;
1244  in_fixed_width_font = save_in_fixed_width_font;
1245}
1246
1247/*
1248  Read include-filename, process the include-file:
1249    verbatim_include == 0: process through reader_loop
1250    verbatim_include != 0: process through handle_verbatim_environment
1251 */
1252static void
1253handle_include (verbatim_include)
1254  int verbatim_include;
1255{
1256  char *filename;
1257
1258  if (macro_expansion_output_stream && !executing_string)
1259    me_append_before_this_command ();
1260
1261  close_paragraph ();
1262  get_rest_of_line (0, &filename);
1263
1264  if (macro_expansion_output_stream && !executing_string)
1265    remember_itext (input_text, input_text_offset);
1266
1267  pushfile ();
1268
1269  /* In verbose mode we print info about including another file. */
1270  if (verbose_mode)
1271    {
1272      int i = 0;
1273      FSTACK *stack = filestack;
1274
1275      for (i = 0, stack = filestack; stack; stack = stack->next, i++);
1276
1277      i *= 2;
1278
1279      printf ("%*s", i, "");
1280      printf ("%c%s `%s'\n", COMMAND_PREFIX, command, filename);
1281      fflush (stdout);
1282    }
1283
1284  if (!find_and_load (filename))
1285    {
1286      extern int errno;
1287
1288      popfile ();
1289      line_number--;
1290
1291      /* /wh/bar:5: @include/@verbatiminclude `foo': No such file or dir */
1292      line_error ("%c%s `%s': %s", COMMAND_PREFIX, command, filename,
1293                  strerror (errno));
1294
1295      free (filename);
1296      return;
1297    }
1298  else
1299    {
1300      if (macro_expansion_output_stream && !executing_string)
1301	remember_itext (input_text, input_text_offset);
1302
1303      if (!verbatim_include)
1304	reader_loop ();
1305      else
1306	handle_verbatim_environment (0);
1307    }
1308  free (filename);
1309  popfile ();
1310}
1311
1312
1313/* Include file as if put in @verbatim environment */
1314void
1315cm_verbatiminclude ()
1316{
1317  handle_include (1);
1318}
1319
1320
1321/* Remember this file, and move onto the next. */
1322void
1323cm_include ()
1324{
1325  handle_include (0);
1326}
1327
1328
1329/* @bye: Signals end of processing.  Easy to make this happen. */
1330
1331void
1332cm_bye ()
1333{
1334  discard_braces (); /* should not have any unclosed braces left */
1335  flush_output ();
1336  input_text_offset = input_text_length;
1337}
1338
1339/* @paragraphindent */
1340
1341static void
1342cm_paragraphindent ()
1343{
1344  char *arg;
1345
1346  get_rest_of_line (1, &arg);
1347  if (set_paragraph_indent (arg) != 0)
1348    line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
1349
1350  free (arg);
1351}
1352
1353/* @exampleindent: change indentation of example-like environments.   */
1354static int
1355set_default_indentation_increment (string)
1356     char *string;
1357{
1358  if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
1359    ;
1360  else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
1361    default_indentation_increment = 0;
1362  else if (sscanf (string, "%d", &default_indentation_increment) != 1)
1363    return -1;
1364  return 0;
1365}
1366
1367static void
1368cm_exampleindent ()
1369{
1370  char *arg;
1371
1372  get_rest_of_line (1, &arg);
1373  if (set_default_indentation_increment (arg) != 0)
1374    line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
1375
1376  free (arg);
1377}
1378