Home | History | Annotate | Line # | Download | only in makeinfo
      1 /*	$NetBSD: cmds.c,v 1.5 2025/12/31 22:18:50 oster Exp $	*/
      2 
      3 /* cmds.c -- Texinfo commands.
      4    Id: cmds.c,v 1.55 2004/12/14 00:15:36 karl Exp
      5 
      6    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
      7    Foundation, Inc.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 2, or (at your option)
     12    any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software Foundation,
     21    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
     22 
     23 #include "system.h"
     24 #include "cmds.h"
     25 #include "defun.h"
     26 #include "files.h"
     27 #include "footnote.h"
     28 #include "html.h"
     29 #include "insertion.h"
     30 #include "lang.h"
     31 #include "macro.h"
     32 #include "makeinfo.h"
     33 #include "node.h"
     34 #include "sectioning.h"
     35 #include "toc.h"
     36 #include "xml.h"
     37 
     38 #ifdef TM_IN_SYS_TIME
     39 #include <sys/time.h>
     40 #else
     41 #include <time.h>
     42 #endif
     43 
     44 /* Options. */
     45 static void cm_exampleindent (int arg, int arg2, int arg3),
     46      cm_firstparagraphindent (int arg, int arg2, int arg3),
     47      cm_paragraphindent (int arg, int arg2, int arg3),
     48      cm_novalidate (int arg, int arg2, int arg3);
     49 
     50 /* Internals. */
     51 static void cm_obsolete (int arg, int start, int end),
     52      not_fixed_width (int arg);
     53 
     54 /* The dispatch table.  */
     55 COMMAND command_table[] = {
     56   { "\t", insert_space, NO_BRACE_ARGS },
     57   { "\n", insert_space, NO_BRACE_ARGS },
     58   { " ", insert_space, NO_BRACE_ARGS },
     59   { "!", cm_punct, NO_BRACE_ARGS },
     60   { "\"", cm_accent_umlaut, MAYBE_BRACE_ARGS },
     61   { "'", cm_accent_acute, MAYBE_BRACE_ARGS },
     62   { "*", cm_asterisk, NO_BRACE_ARGS },
     63   { ",", cm_accent_cedilla, MAYBE_BRACE_ARGS },
     64   { "-", cm_no_op, NO_BRACE_ARGS },
     65   { ".", cm_punct, NO_BRACE_ARGS },
     66   { "/", cm_no_op, NO_BRACE_ARGS },
     67   { ":", cm_colon, NO_BRACE_ARGS },
     68   { "=", cm_accent, MAYBE_BRACE_ARGS },
     69   { "?", cm_punct, NO_BRACE_ARGS },
     70   { "@", insert_self, NO_BRACE_ARGS },
     71   { "\\", insert_self, NO_BRACE_ARGS },
     72   { "^", cm_accent_hat, MAYBE_BRACE_ARGS },
     73   { "`", cm_accent_grave, MAYBE_BRACE_ARGS },
     74   { "{", insert_self, NO_BRACE_ARGS },
     75   { "|", cm_no_op, NO_BRACE_ARGS },
     76   { "}", insert_self, NO_BRACE_ARGS },
     77   { "~", cm_accent_tilde, MAYBE_BRACE_ARGS },
     78   { "AA", cm_special_char, BRACE_ARGS },
     79   { "AE", cm_special_char, BRACE_ARGS },
     80   { "H", cm_accent, MAYBE_BRACE_ARGS },
     81   { "L", cm_special_char, BRACE_ARGS },
     82   { "LaTeX", cm_LaTeX, BRACE_ARGS },
     83   { "O", cm_special_char, BRACE_ARGS },
     84   { "OE", cm_special_char, BRACE_ARGS },
     85   { "TeX", cm_TeX, BRACE_ARGS },
     86   { "aa", cm_special_char, BRACE_ARGS },
     87   { "abbr", cm_abbr, BRACE_ARGS },
     88   { "acronym", cm_acronym, BRACE_ARGS },
     89   { "ae", cm_special_char, BRACE_ARGS },
     90   { "afivepaper", cm_ignore_line, NO_BRACE_ARGS },
     91   { "afourlatex", cm_ignore_line, NO_BRACE_ARGS },
     92   { "afourpaper", cm_ignore_line, NO_BRACE_ARGS },
     93   { "afourwide", cm_ignore_line, NO_BRACE_ARGS },
     94   { "alias", cm_alias, NO_BRACE_ARGS },
     95   { "anchor", cm_anchor, BRACE_ARGS },
     96   { "appendix", cm_appendix, NO_BRACE_ARGS },
     97   { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
     98   { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
     99   { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
    100   { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
    101   { "asis", cm_no_op, BRACE_ARGS },
    102   { "author", cm_author, NO_BRACE_ARGS },
    103   { "b", cm_b, BRACE_ARGS },
    104   { "bullet", cm_bullet, BRACE_ARGS },
    105   { "bye", cm_bye, NO_BRACE_ARGS },
    106   { "c", cm_comment, NO_BRACE_ARGS },
    107   { "caption", cm_caption, BRACE_ARGS },
    108   { "cartouche", cm_cartouche, NO_BRACE_ARGS },
    109   { "center", cm_center, NO_BRACE_ARGS },
    110   { "centerchap", cm_unnumbered, NO_BRACE_ARGS },
    111   { "chapheading", cm_chapheading, NO_BRACE_ARGS },
    112   { "chapter", cm_chapter, NO_BRACE_ARGS },
    113   { "cindex", cm_cindex, NO_BRACE_ARGS },
    114   { "cite", cm_cite, BRACE_ARGS },
    115   { "clear", cm_clear, NO_BRACE_ARGS },
    116   { "code", cm_code, BRACE_ARGS },
    117   { "comma", cm_comma, BRACE_ARGS },
    118   { "command", cm_code, BRACE_ARGS },
    119   { "comment", cm_comment, NO_BRACE_ARGS },
    120   { "contents", cm_contents, NO_BRACE_ARGS },
    121   { "copying", cm_copying, NO_BRACE_ARGS },
    122   { "copyright", cm_copyright, BRACE_ARGS },
    123   { "ctrl", cm_obsolete, BRACE_ARGS },
    124   { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
    125   { "defcv", cm_defun, NO_BRACE_ARGS },
    126   { "defcvx", cm_defun, NO_BRACE_ARGS },
    127   { "deffn", cm_defun, NO_BRACE_ARGS },
    128   { "deffnx", cm_defun, NO_BRACE_ARGS },
    129   { "defindex", cm_defindex, NO_BRACE_ARGS },
    130   { "definfoenclose", cm_definfoenclose, NO_BRACE_ARGS },
    131   { "defivar", cm_defun, NO_BRACE_ARGS },
    132   { "defivarx", cm_defun, NO_BRACE_ARGS },
    133   { "defmac", cm_defun, NO_BRACE_ARGS },
    134   { "defmacx", cm_defun, NO_BRACE_ARGS },
    135   { "defmethod", cm_defun, NO_BRACE_ARGS },
    136   { "defmethodx", cm_defun, NO_BRACE_ARGS },
    137   { "defop", cm_defun, NO_BRACE_ARGS },
    138   { "defopt", cm_defun, NO_BRACE_ARGS },
    139   { "defoptx", cm_defun, NO_BRACE_ARGS },
    140   { "defopx", cm_defun, NO_BRACE_ARGS },
    141   { "defspec", cm_defun, NO_BRACE_ARGS },
    142   { "defspecx", cm_defun, NO_BRACE_ARGS },
    143   { "deftp", cm_defun, NO_BRACE_ARGS },
    144   { "deftpx", cm_defun, NO_BRACE_ARGS },
    145   { "deftypecv", cm_defun, NO_BRACE_ARGS },
    146   { "deftypecvx", cm_defun, NO_BRACE_ARGS },
    147   { "deftypefn", cm_defun, NO_BRACE_ARGS },
    148   { "deftypefnx", cm_defun, NO_BRACE_ARGS },
    149   { "deftypefun", cm_defun, NO_BRACE_ARGS },
    150   { "deftypefunx", cm_defun, NO_BRACE_ARGS },
    151   { "deftypeivar", cm_defun, NO_BRACE_ARGS },
    152   { "deftypeivarx", cm_defun, NO_BRACE_ARGS },
    153   { "deftypemethod", cm_defun, NO_BRACE_ARGS },
    154   { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
    155   { "deftypeop", cm_defun, NO_BRACE_ARGS },
    156   { "deftypeopx", cm_defun, NO_BRACE_ARGS },
    157   { "deftypevar", cm_defun, NO_BRACE_ARGS },
    158   { "deftypevarx", cm_defun, NO_BRACE_ARGS },
    159   { "deftypevr", cm_defun, NO_BRACE_ARGS },
    160   { "deftypevrx", cm_defun, NO_BRACE_ARGS },
    161   { "defun", cm_defun, NO_BRACE_ARGS },
    162   { "defunx", cm_defun, NO_BRACE_ARGS },
    163   { "defvar", cm_defun, NO_BRACE_ARGS },
    164   { "defvarx", cm_defun, NO_BRACE_ARGS },
    165   { "defvr", cm_defun, NO_BRACE_ARGS },
    166   { "defvrx", cm_defun, NO_BRACE_ARGS },
    167   { "detailmenu", cm_detailmenu, NO_BRACE_ARGS },
    168   { "dfn", cm_dfn, BRACE_ARGS },
    169   { "dircategory", cm_dircategory, NO_BRACE_ARGS },
    170   { "direntry", cm_direntry, NO_BRACE_ARGS },
    171   { "display", cm_display, NO_BRACE_ARGS },
    172   { "dmn", cm_dmn, BRACE_ARGS },
    173   { "docbook", cm_docbook, NO_BRACE_ARGS },
    174   { "documentdescription", cm_documentdescription, NO_BRACE_ARGS },
    175   { "documentencoding", cm_documentencoding, NO_BRACE_ARGS },
    176   { "documentlanguage", cm_documentlanguage, NO_BRACE_ARGS },
    177   { "dotaccent", cm_accent, MAYBE_BRACE_ARGS },
    178   { "dotless", cm_dotless, BRACE_ARGS },
    179   { "dots", cm_dots, BRACE_ARGS },
    180   { "email", cm_email, BRACE_ARGS },
    181   { "emph", cm_emph, BRACE_ARGS },
    182   { "end", cm_end, NO_BRACE_ARGS },
    183   { "enddots", cm_enddots, BRACE_ARGS },
    184   { "enumerate", cm_enumerate, NO_BRACE_ARGS },
    185   { "env", cm_code, BRACE_ARGS },
    186   { "equiv", cm_equiv, BRACE_ARGS },
    187   { "error", cm_error, BRACE_ARGS },
    188   { "euro", cm_special_char, BRACE_ARGS },
    189   { "evenfooting", cm_ignore_line, NO_BRACE_ARGS },
    190   { "evenheading", cm_ignore_line, NO_BRACE_ARGS },
    191   { "everyfooting", cm_ignore_line, NO_BRACE_ARGS },
    192   { "everyheading", cm_ignore_line, NO_BRACE_ARGS },
    193   { "example", cm_example, NO_BRACE_ARGS },
    194   { "exampleindent", cm_exampleindent, NO_BRACE_ARGS },
    195   { "exclamdown", cm_special_char, BRACE_ARGS },
    196   { "exdent", cm_exdent, NO_BRACE_ARGS },
    197   { "expansion", cm_expansion, BRACE_ARGS },
    198   { "file", cm_code, BRACE_ARGS },
    199   { "finalout", cm_no_op, NO_BRACE_ARGS },
    200   { "findex", cm_findex, NO_BRACE_ARGS },
    201   { "firstparagraphindent", cm_firstparagraphindent, NO_BRACE_ARGS },
    202   { "float", cm_float, NO_BRACE_ARGS },
    203   { "flushleft", cm_flushleft, NO_BRACE_ARGS },
    204   { "flushright", cm_flushright, NO_BRACE_ARGS },
    205   { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
    206   { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
    207   { "format", cm_format, NO_BRACE_ARGS },
    208   { "ftable", cm_ftable, NO_BRACE_ARGS },
    209   { "group", cm_group, NO_BRACE_ARGS },
    210   { "heading", cm_heading, NO_BRACE_ARGS },
    211   { "headings", cm_ignore_line, NO_BRACE_ARGS },
    212   { "headitem", cm_headitem, NO_BRACE_ARGS },
    213   { "html", cm_html, NO_BRACE_ARGS },
    214   { "hyphenation", cm_ignore_arg, BRACE_ARGS },
    215   { "i", cm_i, BRACE_ARGS },
    216   { "ifclear", cm_ifclear, NO_BRACE_ARGS },
    217   { "ifeq", cm_ifeq, NO_BRACE_ARGS },
    218   { "ifdocbook", cm_ifdocbook, NO_BRACE_ARGS },
    219   { "ifhtml", cm_ifhtml, NO_BRACE_ARGS },
    220   { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
    221   { "ifnotdocbook", cm_ifnotdocbook, NO_BRACE_ARGS },
    222   { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS },
    223   { "ifnotinfo", cm_ifnotinfo, NO_BRACE_ARGS },
    224   { "ifnotplaintext", cm_ifnotplaintext, NO_BRACE_ARGS },
    225   { "ifnottex", cm_ifnottex, NO_BRACE_ARGS },
    226   { "ifnotxml", cm_ifnotxml, NO_BRACE_ARGS },
    227   { "ifplaintext", cm_ifplaintext, NO_BRACE_ARGS },
    228   { "ifset", cm_ifset, NO_BRACE_ARGS },
    229   { "iftex", cm_iftex, NO_BRACE_ARGS },
    230   { "ifxml", cm_ifxml, NO_BRACE_ARGS },
    231   { "ignore", command_name_condition, NO_BRACE_ARGS },
    232   { "image", cm_image, BRACE_ARGS },
    233   { "include", cm_include, NO_BRACE_ARGS },
    234   { "indent", cm_indent, NO_BRACE_ARGS },
    235   { "indicateurl", cm_indicate_url, BRACE_ARGS },
    236   { "inforef", cm_inforef, BRACE_ARGS },
    237   { "insertcopying", cm_insert_copying, NO_BRACE_ARGS },
    238   { "item", cm_item, NO_BRACE_ARGS },
    239   { "itemize", cm_itemize, NO_BRACE_ARGS },
    240   { "itemx", cm_itemx, NO_BRACE_ARGS },
    241   { "kbd", cm_kbd, BRACE_ARGS },
    242   { "kbdinputstyle", cm_ignore_line, NO_BRACE_ARGS },
    243   { "key", cm_key, BRACE_ARGS },
    244   { "kindex", cm_kindex, NO_BRACE_ARGS },
    245   { "l", cm_special_char, BRACE_ARGS },
    246   { "lisp", cm_lisp, NO_BRACE_ARGS },
    247   { "listoffloats", cm_listoffloats, NO_BRACE_ARGS },
    248   { "lowersections", cm_lowersections, NO_BRACE_ARGS },
    249   { "macro", cm_macro, NO_BRACE_ARGS },
    250   { "majorheading", cm_majorheading, NO_BRACE_ARGS },
    251   { "math", cm_math, BRACE_ARGS },
    252   { "menu", cm_menu, NO_BRACE_ARGS },
    253   { "minus", cm_minus, BRACE_ARGS },
    254   { "multitable", cm_multitable, NO_BRACE_ARGS },
    255   { "need", cm_ignore_line, NO_BRACE_ARGS },
    256   { "node", cm_node, NO_BRACE_ARGS },
    257   { "noindent", cm_noindent_cmd, NO_BRACE_ARGS },
    258   { "novalidate", cm_novalidate, NO_BRACE_ARGS },
    259   { "nwnode", cm_node, NO_BRACE_ARGS },
    260   { "o", cm_special_char, BRACE_ARGS },
    261   { "oddfooting", cm_ignore_line, NO_BRACE_ARGS },
    262   { "oddheading", cm_ignore_line, NO_BRACE_ARGS },
    263   { "oe", cm_special_char, BRACE_ARGS },
    264   { "option", cm_code, BRACE_ARGS },
    265   { "ordf", cm_special_char, BRACE_ARGS },
    266   { "ordm", cm_special_char, BRACE_ARGS },
    267   { "page", cm_no_op, NO_BRACE_ARGS },
    268   { "pagesizes", cm_ignore_line, NO_BRACE_ARGS },
    269   { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
    270   { "pindex", cm_pindex, NO_BRACE_ARGS },
    271   { "point", cm_point, BRACE_ARGS },
    272   { "pounds", cm_special_char, BRACE_ARGS },
    273   { "print", cm_print, BRACE_ARGS },
    274   { "printindex", cm_printindex, NO_BRACE_ARGS },
    275   { "pxref", cm_pxref, BRACE_ARGS },
    276   { "questiondown", cm_special_char, BRACE_ARGS },
    277   { "quotation", cm_quotation, NO_BRACE_ARGS },
    278   { "r", cm_r, BRACE_ARGS },
    279   { "raisesections", cm_raisesections, NO_BRACE_ARGS },
    280   { "ref", cm_ref, BRACE_ARGS },
    281   { "refill", cm_no_op, NO_BRACE_ARGS },
    282   { "registeredsymbol", cm_registeredsymbol, BRACE_ARGS },
    283   { "result", cm_result, BRACE_ARGS },
    284   { "ringaccent", cm_accent, MAYBE_BRACE_ARGS },
    285   { "rmacro", cm_rmacro, NO_BRACE_ARGS },
    286   { "samp", cm_code, BRACE_ARGS },
    287   { "sansserif", cm_sansserif, BRACE_ARGS },
    288   { "sc", cm_sc, BRACE_ARGS },
    289   { "section", cm_section, NO_BRACE_ARGS },
    290   { "set", cm_set, NO_BRACE_ARGS },
    291   { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
    292   { "setchapterstyle", cm_obsolete, NO_BRACE_ARGS },
    293   { "setcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
    294   { "setfilename", cm_setfilename, NO_BRACE_ARGS },
    295   { "setshortcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
    296   { "settitle", cm_settitle, NO_BRACE_ARGS },
    297   { "shortcaption", cm_caption, BRACE_ARGS },
    298   { "shortcontents", cm_contents, NO_BRACE_ARGS },
    299   { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
    300   { "slanted", cm_slanted, BRACE_ARGS },
    301   { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
    302   { "smalldisplay", cm_smalldisplay, NO_BRACE_ARGS },
    303   { "smallexample", cm_smallexample, NO_BRACE_ARGS },
    304   { "smallformat", cm_smallformat, NO_BRACE_ARGS },
    305   { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
    306   { "sp", cm_sp, NO_BRACE_ARGS },
    307   { "ss", cm_special_char, BRACE_ARGS },
    308   { "strong", cm_strong, BRACE_ARGS },
    309   { "subheading", cm_subheading, NO_BRACE_ARGS },
    310   { "subsection", cm_subsection, NO_BRACE_ARGS },
    311   { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
    312   { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
    313   { "subtitle", cm_titlepage_cmds, NO_BRACE_ARGS },
    314   { "summarycontents", cm_contents, NO_BRACE_ARGS },
    315   { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
    316   { "synindex", cm_synindex, NO_BRACE_ARGS },
    317   { "t", cm_tt, BRACE_ARGS },
    318   { "tab", cm_tab, NO_BRACE_ARGS },
    319   { "table", cm_table, NO_BRACE_ARGS },
    320   { "tex", cm_tex, NO_BRACE_ARGS },
    321   { "tie", cm_tie, BRACE_ARGS },
    322   { "tieaccent", cm_accent, MAYBE_BRACE_ARGS },
    323   { "tindex", cm_tindex, NO_BRACE_ARGS },
    324   { "title", cm_titlepage_cmds, NO_BRACE_ARGS },
    325   { "titlefont", cm_titlefont, BRACE_ARGS },
    326   { "titlepage", cm_titlepage, 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_uref, 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   { "vskip", cm_ignore_line, NO_BRACE_ARGS },
    348   { "w", cm_w, BRACE_ARGS },
    349   { "xml", cm_xml, NO_BRACE_ARGS },
    350   { "xref", cm_xref, BRACE_ARGS },
    351 
    352   /* Deprecated commands.  These used to be for italics.  */
    353   { "iappendix", cm_ideprecated, NO_BRACE_ARGS },
    354   { "iappendixsec", cm_ideprecated, NO_BRACE_ARGS },
    355   { "iappendixsection", cm_ideprecated, NO_BRACE_ARGS },
    356   { "iappendixsubsec", cm_ideprecated, NO_BRACE_ARGS },
    357   { "iappendixsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
    358   { "ichapter", cm_ideprecated, NO_BRACE_ARGS },
    359   { "isection", cm_ideprecated, NO_BRACE_ARGS },
    360   { "isubsection", cm_ideprecated, NO_BRACE_ARGS },
    361   { "isubsubsection", cm_ideprecated, NO_BRACE_ARGS },
    362   { "iunnumbered", cm_ideprecated, NO_BRACE_ARGS },
    363   { "iunnumberedsec", cm_ideprecated, NO_BRACE_ARGS },
    364   { "iunnumberedsubsec", cm_ideprecated, NO_BRACE_ARGS },
    365   { "iunnumberedsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
    366 
    367   /* Now @include does what this was used to. */
    368   { "infoinclude", cm_obsolete, NO_BRACE_ARGS },
    369   { "titlespec", cm_obsolete, NO_BRACE_ARGS },
    370 
    371   { NULL, NULL, NO_BRACE_ARGS }
    372 };
    373 
    374 /* The bulk of the Texinfo commands. */
    376 
    377 /* Commands which insert their own names. */
    378 void
    379 insert_self (int arg, int arg2, int arg3)
    380 {
    381   if (arg == START)
    382     add_word (command);
    383 }
    384 
    385 void
    386 insert_space (int arg, int arg2, int arg3)
    387 {
    388   if (arg == START)
    389     {
    390       if (xml && !docbook)
    391         xml_insert_entity ("space");
    392       else
    393         add_char (' ');
    394     }
    395 }
    396 
    397 /* Insert a comma.  Useful when a literal , would break our parsing of
    398    multiple arguments.  */
    399 void
    400 cm_comma (int arg, int arg2, int arg3)
    401 {
    402   if (arg == START)
    403     add_char (',');
    404 }
    405 
    406 
    407 /* Force a line break in the output. */
    408 void
    409 cm_asterisk (int arg, int arg2, int arg3)
    410 {
    411   if (html)
    412     add_word ("<br>");
    413   else if (xml && !docbook)
    414     xml_insert_entity ("linebreak");
    415   else if (docbook)
    416     xml_asterisk ();
    417   else
    418     {
    419       close_single_paragraph ();
    420       cm_noindent (0, 0, 0);
    421     }
    422 }
    423 
    424 /* Insert ellipsis. */
    425 void
    426 cm_dots (int arg, int arg2, int arg3)
    427 {
    428   if (arg == START)
    429     {
    430       if (xml && !docbook)
    431         xml_insert_entity ("dots");
    432       else if (docbook)
    433         xml_insert_entity ("hellip");
    434       else
    435 	if (html && !in_fixed_width_font)
    436 	  insert_string ("<small class=\"dots\">...</small>");
    437 	else
    438 	  add_word ("...");
    439     }
    440 }
    441 
    442 /* Insert ellipsis for sentence end. */
    443 void
    444 cm_enddots (int arg, int arg2, int arg3)
    445 {
    446   if (arg == START)
    447     {
    448       if (xml && !docbook)
    449 	xml_insert_entity ("enddots");
    450       else if (docbook)
    451 	{
    452 	  xml_insert_entity ("hellip");
    453 	  add_char ('.');
    454 	}
    455       else
    456 	if (html && !in_fixed_width_font)
    457 	  insert_string ("<small class=\"enddots\">....</small>");
    458 	else
    459 	  add_word ("....");
    460     }
    461 }
    462 
    463 void
    464 cm_bullet (int arg, int arg2, int arg3)
    465 {
    466   if (arg == START)
    467     {
    468       if (html)
    469         add_word ("&bull;");
    470       else if (xml && !docbook)
    471 	xml_insert_entity ("bullet");
    472       else if (docbook)
    473 	xml_insert_entity ("bull");
    474       else
    475         add_char ('*');
    476     }
    477 }
    478 
    479 void
    480 cm_minus (int arg, int arg2, int arg3)
    481 {
    482   if (arg == START)
    483     {
    484       if (xml)
    485 	xml_insert_entity ("minus");
    486       else if (html)
    487         add_word ("&minus;");
    488       else
    489 	add_char ('-');
    490     }
    491 }
    492 
    493 /* Formatting a dimension unit.  */
    494 void
    495 cm_dmn (int arg, int arg2, int arg3)
    496 {
    497   if (html)
    498     insert_html_tag_with_attribute (arg, "span", "class=\"dmn\"");
    499   else if (docbook)
    500     /* No units in docbook yet.  */
    501     ;
    502   else if (xml)
    503     xml_insert_element (DIMENSION, arg);
    504 }
    505 
    506 /* Insert "TeX". */
    507 void
    508 cm_TeX (int arg, int arg2, int arg3)
    509 {
    510   static int last_position;
    511 
    512   if (arg == START)
    513     {
    514       if (xml)
    515 	xml_insert_entity ("tex");
    516       else
    517 	add_word ("TeX");
    518 
    519       last_position = output_paragraph_offset;
    520     }
    521   else if (last_position != output_paragraph_offset)
    522     {
    523       warning (_("arguments to @%s ignored"), command);
    524       output_paragraph_offset = last_position;
    525     }
    526 }
    527 
    528 /* Insert "LaTeX".  */
    529 void
    530 cm_LaTeX (int arg, int arg2, int arg3)
    531 {
    532   static int last_position;
    533 
    534   if (arg == START)
    535     {
    536       if (xml)
    537         xml_insert_entity ("latex");
    538       else
    539         add_word ("LaTeX");
    540 
    541       last_position = output_paragraph_offset;
    542     }
    543   else if (last_position != output_paragraph_offset)
    544     {
    545       warning (_("arguments to @%s ignored"), command);
    546       output_paragraph_offset = last_position;
    547     }
    548 }
    549 
    550 /* Copyright symbol.  */
    551 void
    552 cm_copyright (int arg, int arg2, int arg3)
    553 {
    554   if (arg == START)
    555     {
    556     if (html)
    557       add_word ("&copy;");
    558     else if (xml && !docbook)
    559       xml_insert_entity ("copyright");
    560     else if (docbook)
    561       xml_insert_entity ("copy");
    562     else
    563       add_word ("(C)");
    564     }
    565 }
    566 
    567 /* Registered symbol.  */
    568 void
    569 cm_registeredsymbol (int arg, int arg2, int arg3)
    570 {
    571   if (arg == START)
    572     {
    573       if (html)
    574         add_word ("&reg;");
    575       else if (docbook)
    576         xml_insert_entity ("reg");
    577       else if (xml && !docbook)
    578         xml_insert_entity ("registered");
    579       else
    580         add_word ("(R)");
    581     }
    582 }
    583 
    584 void
    585 cm_today (int arg, int arg2, int arg3)
    586 {
    587   static char *months[12] =
    588     { N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
    589       N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
    590       N_("November"), N_("December") };
    591   if (arg == START)
    592     {
    593       time_t timer = time (0);
    594       struct tm *ts = localtime (&timer);
    595       add_word_args ("%d %s %d", ts->tm_mday, _(months[ts->tm_mon]),
    596                      ts->tm_year + 1900);
    597     }
    598 }
    599 
    600 void
    601 cm_comment (int arg, int arg2, int arg3)
    602 {
    603   /* For HTML, do not output comments before HTML header is written,
    604      otherwise comments before @settitle cause an empty <title> in the
    605      header.  */
    606   if ((html && html_output_head_p) || xml)
    607     {
    608       char *line;
    609       get_rest_of_line (0, &line);
    610 
    611       if (strlen (line) > 0)
    612         {
    613           int save_inhibit_indentation = inhibit_paragraph_indentation;
    614           int save_paragraph_is_open = paragraph_is_open;
    615           int save_escape_html = escape_html;
    616           int save_xml_no_para = xml_no_para;
    617           int i;
    618 
    619           inhibit_paragraph_indentation = 1;
    620           escape_html = 0;
    621           xml_no_para = 1;
    622 
    623           /* @c and @comment can appear between @item and @itemx,
    624              @deffn and @deffnx.  */
    625           xml_dont_touch_items_defs++;
    626 
    627           /* Use insert for HTML, and XML when indentation is enabled.
    628              For Docbook, use add_char.  */
    629           if (xml && xml_indentation_increment > 0
    630               && output_paragraph[output_paragraph_offset-1] != '\n')
    631             insert ('\n');
    632 
    633           /* Crunch double hyphens in comments.  */
    634           add_html_block_elt ("<!-- ");
    635           for (i = 0; i < strlen (line); i++)
    636             if (line[i] != '-' || (i && line[i-1] != '-'))
    637               add_char (line[i]);
    638           add_word (" -->");
    639 
    640           if (html)
    641             add_char ('\n');
    642 
    643           inhibit_paragraph_indentation = save_inhibit_indentation;
    644           paragraph_is_open = save_paragraph_is_open;
    645           escape_html = save_escape_html;
    646           xml_no_para = save_xml_no_para;
    647           xml_dont_touch_items_defs--;
    648         }
    649 
    650       free (line);
    651     }
    652   else
    653     cm_ignore_line (0, 0, 0);
    654 }
    655 
    656 
    657 
    658 /* We keep acronyms with two arguments around, to be able to refer to them
    660    later with only one argument.  */
    661 static ACRONYM_DESC *acronyms_stack = NULL;
    662 
    663 static void
    664 cm_acronym_or_abbr (int arg, int is_abbr)
    665 {
    666   char *aa, *description;
    667   unsigned len;
    668 
    669   /* We do everything at START.  */
    670   if (arg == END)
    671     return;
    672 
    673   get_until_in_braces (",", &aa);
    674   if (input_text[input_text_offset] == ',')
    675     input_text_offset++;
    676   get_until_in_braces ("}", &description);
    677 
    678   canon_white (aa);
    679   canon_white (description);
    680 
    681   /* If not enclosed in braces, strip after comma to be compatible
    682      with texinfo.tex.  */
    683   if (description[0] != '{' && strchr (description, ',') != NULL)
    684     {
    685       int i = 0;
    686       while (description[i] != ',')
    687         i++;
    688       /* For now, just terminate the string at comma.  */
    689       description[i] = 0;
    690     }
    691 
    692   /* Get description out of braces.  */
    693   if (description[0] == '{')
    694     description++;
    695 
    696   len = strlen (description);
    697   if (len && description[len-1] == '}')
    698     description[len-1] = 0;
    699 
    700   /* Save new description.  */
    701   if (strlen (description) > 0)
    702     {
    703       ACRONYM_DESC *new = xmalloc (sizeof (ACRONYM_DESC));
    704 
    705       new->acronym = xstrdup (aa);
    706       new->description = xstrdup (description);
    707       new->next = acronyms_stack;
    708       acronyms_stack = new;
    709     }
    710 
    711   if (html)
    712     {
    713       add_word (is_abbr ? "<abbr" : "<acronym");
    714 
    715       if (strlen (description) > 0)
    716         add_word_args (" title=\"%s\"", text_expansion (description));
    717       else if (acronyms_stack)
    718         {
    719           /* No second argument, get from previous.  Search order is from
    720              last to first defined, so we get the most recent version of
    721              the description.  */
    722           ACRONYM_DESC *temp = acronyms_stack;
    723 
    724           while (temp)
    725             {
    726               if (STREQ (aa, temp->acronym)
    727                   && strlen (temp->description) > 0)
    728                 {
    729                   add_word_args (" title=\"%s\"",
    730                                  text_expansion (temp->description));
    731                   break;
    732                 }
    733               temp = temp->next;
    734             }
    735         }
    736 
    737       add_char ('>');
    738       execute_string ("%s", aa);
    739       add_word (is_abbr ? "</abbr>" : "</acronym>");
    740     }
    741   else if (docbook)
    742     {
    743       xml_insert_element (is_abbr ? ABBREV : ACRONYM, START);
    744       execute_string ("%s", aa);
    745       xml_insert_element (is_abbr ? ABBREV : ACRONYM, END);
    746     }
    747   else if (xml)
    748     {
    749       xml_insert_element (is_abbr ? ABBREV : ACRONYM, START);
    750 
    751       xml_insert_element (is_abbr ? ABBREVWORD : ACRONYMWORD, START);
    752       execute_string ("%s", aa);
    753       xml_insert_element (is_abbr ? ABBREVWORD : ACRONYMWORD, END);
    754 
    755       if (strlen (description) > 0)
    756         {
    757           xml_insert_element (is_abbr ? ABBREVDESC : ACRONYMDESC, START);
    758           execute_string ("%s", description);
    759           xml_insert_element (is_abbr ? ABBREVDESC : ACRONYMDESC, END);
    760         }
    761 
    762       xml_insert_element (is_abbr ? ABBREV : ACRONYM, END);
    763     }
    764   else
    765     execute_string ("%s", aa);
    766 
    767   /* Put description into parenthesis after the acronym for all outputs
    768      except XML.  */
    769   if (strlen (description) > 0 && (!xml || docbook))
    770     add_word_args (" (%s)", description);
    771 }
    772 
    773 void
    774 cm_acronym (int arg, int arg2, int arg3)
    775 {
    776   cm_acronym_or_abbr (arg, 0);
    777 }
    778 
    779 void
    780 cm_abbr (int arg, int arg2, int arg3)
    781 {
    782   cm_acronym_or_abbr (arg, 1);
    783 }
    784 
    785 void
    786 cm_tt (int arg, int arg2, int arg3)
    787 {
    788   /* @t{} is a no-op in Info.  */
    789   if (html)
    790     insert_html_tag (arg, "tt");
    791   else if (xml)
    792     xml_insert_element (TT, arg);
    793 }
    794 
    795 void
    796 cm_code (int arg, int arg2, int arg3)
    797 {
    798   if (arg == START)
    799     in_fixed_width_font++;
    800 
    801   if (xml)
    802     {
    803       if (STREQ (command, "command"))
    804 	xml_insert_element (COMMAND_TAG, arg);
    805       else if (STREQ (command, "env"))
    806 	xml_insert_element (ENV, arg);
    807       else if (STREQ (command, "file"))
    808 	xml_insert_element (FILE_TAG, arg);
    809       else if (STREQ (command, "option"))
    810 	xml_insert_element (OPTION, arg);
    811       else if (STREQ (command, "samp"))
    812         {
    813           if (docbook && arg == START)
    814             {
    815               /* Even though @samp is in_fixed_width_font, it
    816                  should always start a paragraph.  Unfortunately,
    817                  in_fixed_width_font inhibits that.  */
    818               xml_start_para ();
    819               xml_insert_entity ("lsquo");
    820             }
    821           xml_insert_element (SAMP, arg);
    822           if (docbook && arg == END)
    823             xml_insert_entity ("rsquo");
    824         }
    825       else
    826 	xml_insert_element (CODE, arg);
    827     }
    828   else if (html)
    829     {
    830       if (STREQ (command, "code"))
    831         insert_html_tag (arg, "code");
    832       else
    833         { /* Use <samp> tag in general to get typewriter.  */
    834           if (arg == START)
    835             { /* If @samp specifically, add quotes a la TeX output.  */
    836               if (STREQ (command, "samp")) add_char ('`');
    837               add_word ("<samp>");
    838             }
    839           insert_html_tag_with_attribute (arg, "span", "class=\"%s\"",command);
    840           if (arg == END)
    841             {
    842               add_word ("</samp>");
    843               if (STREQ (command, "samp")) add_char ('\'');
    844             }
    845         }
    846     }
    847   else
    848     {
    849       extern int printing_index;
    850 
    851       if (!printing_index)
    852         {
    853           if (arg == START)
    854             add_char ('`');
    855           else
    856             add_meta_char ('\'');
    857         }
    858     }
    859 }
    860 
    861 void
    862 cm_kbd (int arg, int arg2, int arg3)
    863 {
    864   if (xml)
    865     xml_insert_element (KBD, arg);
    866   else if (html)
    867     { /* Seems like we should increment in_fixed_width_font for Info
    868          format too, but then the quote-omitting special case gets
    869          confused.  Punt.  */
    870       if (arg == START)
    871         in_fixed_width_font++;
    872       insert_html_tag (arg, "kbd");
    873     }
    874   else
    875     { /* People use @kbd in an example to get the "user input" font.
    876          We don't want quotes in that case.  */
    877       if (!in_fixed_width_font)
    878         cm_code (arg, 0, 0);
    879     }
    880 }
    881 
    882 /* Just show a url (http://example.org/..., for example), don't link to it.  */
    883 void
    884 cm_indicate_url (int arg, int start, int end)
    885 {
    886   if (xml)
    887     xml_insert_element (URL, arg);
    888   else if (html)
    889     {
    890       if (arg == START)
    891         add_word ("&lt;");
    892       insert_html_tag (arg, "code");
    893       if (arg != START)
    894         add_word ("&gt;");
    895     }
    896   else
    897     if (arg == START)
    898       add_word ("<");
    899     else
    900       add_word (">");
    901 }
    902 
    903 void
    904 cm_key (int arg, int arg2, int arg3)
    905 {
    906   if (xml)
    907     xml_insert_element (KEY, arg);
    908   else if (html)
    909     add_word (arg == START ? "&lt;" : "&gt;");
    910   else
    911     add_char (arg == START ? '<' : '>');
    912 }
    913 
    914 /* Handle a command that switches to a non-fixed-width font.  */
    915 void
    916 not_fixed_width (int arg)
    917 {
    918   if (arg == START)
    919     in_fixed_width_font = 0;
    920 }
    921 
    922 /* @var in makeinfo just uppercases the text. */
    923 void
    924 cm_var (int arg, int start_pos, int end_pos)
    925 {
    926   if (xml)
    927     xml_insert_element (VAR, arg);
    928   else
    929     {
    930   not_fixed_width (arg);
    931 
    932   if (html)
    933     insert_html_tag (arg, "var");
    934   else if (arg == END)
    935     {
    936       while (start_pos < end_pos)
    937         {
    938           unsigned char c = output_paragraph[start_pos];
    939           if (strchr ("[](),", c))
    940             warning (_("unlikely character %c in @var"), c);
    941           output_paragraph[start_pos] = coerce_to_upper (c);
    942           start_pos++;
    943         }
    944     }
    945     }
    946 }
    947 
    948 void
    949 cm_sc (int arg, int start_pos, int end_pos)
    950 {
    951   if (xml)
    952     xml_insert_element (SC, arg);
    953   else
    954     {
    955       not_fixed_width (arg);
    956 
    957       if (arg == START)
    958         {
    959           if (html)
    960             insert_html_tag_with_attribute (arg, "span", "class=\"sc\"");
    961         }
    962       else
    963         {
    964           int all_upper;
    965 
    966           if (html)
    967             start_pos += sizeof ("<span class=\"sc\">") - 1; /* skip <span> */
    968 
    969           /* Avoid the warning below if there's no text inside @sc{}, or
    970              when processing menus under --no-headers.  */
    971           all_upper = start_pos < end_pos;
    972 
    973           while (start_pos < end_pos)
    974             {
    975               unsigned char c = output_paragraph[start_pos];
    976               if (!isupper (c))
    977                 all_upper = 0;
    978               if (!html)
    979                 output_paragraph[start_pos] = coerce_to_upper (c);
    980               start_pos++;
    981             }
    982           if (all_upper)
    983             warning (_("@sc argument all uppercase, thus no effect"));
    984 
    985           if (html)
    986             insert_html_tag (arg, "span");
    987         }
    988     }
    989 }
    990 
    991 void
    992 cm_dfn (int arg, int position, int arg3)
    993 {
    994   if (xml)
    995     xml_insert_element (DFN, arg);
    996   else
    997     {
    998   if (html)
    999     insert_html_tag (arg, "dfn");
   1000   else if (arg == START)
   1001     add_char ('"');
   1002   else
   1003     add_meta_char ('"');
   1004     }
   1005 }
   1006 
   1007 void
   1008 cm_emph (int arg, int arg2, int arg3)
   1009 {
   1010   if (xml)
   1011     xml_insert_element (EMPH, arg);
   1012   else if (html)
   1013     insert_html_tag (arg, "em");
   1014   else
   1015     add_char ('_');
   1016 }
   1017 
   1018 void
   1019 cm_verb (int arg, int arg2, int arg3)
   1020 {
   1021   int character;
   1022   int delimiter = 0; /* avoid warning */
   1023   int seen_end = 0;
   1024 
   1025   in_fixed_width_font++;
   1026   /* are these necessary ? */
   1027   last_char_was_newline = 0;
   1028 
   1029   if (html)
   1030     add_word ("<tt>");
   1031 
   1032   if (input_text_offset < input_text_length)
   1033     {
   1034       character = curchar ();
   1035       if (character == '{')
   1036 	input_text_offset++;
   1037       else
   1038 	line_error (_("`{' expected, but saw `%c'"), character);
   1039     }
   1040 
   1041   if (input_text_offset < input_text_length)
   1042     {
   1043       delimiter = curchar ();
   1044       input_text_offset++;
   1045     }
   1046 
   1047   while (input_text_offset < input_text_length)
   1048     {
   1049       character = curchar ();
   1050 
   1051       if (character == '\n')
   1052         {
   1053           line_number++;
   1054           if (html)
   1055             add_word ("<br>\n");
   1056         }
   1057 
   1058       else if (html && character == '<')
   1059         add_word ("&lt;");
   1060 
   1061       else if (html && character == '&')
   1062         add_word ("&amp;");
   1063 
   1064       else if (character == delimiter && input_text[input_text_offset+1] == '}')
   1065 	{ /* Assume no newlines in END_VERBATIM. */
   1066 	  seen_end = 1;
   1067 	  input_text_offset++;
   1068 	  break;
   1069 	}
   1070 
   1071       else
   1072         add_char (character);
   1073 
   1074       input_text_offset++;
   1075     }
   1076 
   1077   if (!seen_end)
   1078     warning (_("end of file inside verb block"));
   1079 
   1080   if (input_text_offset < input_text_length)
   1081     {
   1082       character = curchar ();
   1083       if (character == '}')
   1084 	input_text_offset++;
   1085       else
   1086 	line_error (_("`}' expected, but saw `%c'"), character);
   1087     }
   1088 
   1089   if (html)
   1090     add_word ("</tt>");
   1091 
   1092   in_fixed_width_font--;
   1093 }
   1094 
   1095 
   1096 void
   1097 cm_strong (int arg, int start_pos, int end_pos)
   1098 {
   1099   if (docbook && arg == START)
   1100     xml_insert_element_with_attribute (B, arg, "role=\"bold\"");
   1101   else if (xml)
   1102     xml_insert_element (STRONG, arg);
   1103   else if (html)
   1104     insert_html_tag (arg, "strong");
   1105   else
   1106     add_char ('*');
   1107 
   1108   if (!xml && !html && !docbook && !no_headers
   1109       && arg == END
   1110       && end_pos - start_pos >= 6
   1111       && (STRNCASEEQ ((char *) output_paragraph + start_pos, "*Note:", 6)
   1112           || STRNCASEEQ ((char *) output_paragraph + start_pos, "*Note ", 6)))
   1113     {
   1114       /* Translators: "Note:" is literal here and should not be
   1115          translated.  @strong{Nota}, say, does not cause the problem.  */
   1116       warning (_("@strong{Note...} produces a spurious cross-reference in Info; reword to avoid that"));
   1117       /* Adjust the output to avoid writing the bad xref.  */
   1118       output_paragraph[start_pos + 5] = '_';
   1119     }
   1120 }
   1121 
   1122 void
   1123 cm_cite (int arg, int position, int arg3)
   1124 {
   1125   if (xml)
   1126     xml_insert_element (CITE, arg);
   1127   else if (html)
   1128     insert_html_tag (arg, "cite");
   1129   else
   1130     {
   1131       if (arg == START)
   1132         add_char ('`');
   1133       else
   1134         add_char ('\'');
   1135     }
   1136 }
   1137 
   1138 /* No highlighting, but argument switches fonts.  */
   1139 void
   1140 cm_not_fixed_width (int arg, int start, int end)
   1141 {
   1142   if (xml)
   1143     xml_insert_element (NOTFIXEDWIDTH, arg);
   1144   not_fixed_width (arg);
   1145 }
   1146 
   1147 void
   1148 cm_i (int arg, int arg2, int arg3)
   1149 {
   1150   /* Make use of <lineannotation> of Docbook, if we are
   1151      inside an @example or similar.  */
   1152   extern int printing_index;
   1153   if (docbook && !filling_enabled && !printing_index)
   1154     xml_insert_element (LINEANNOTATION, arg);
   1155   else if (xml)
   1156     xml_insert_element (I, arg);
   1157   else if (html)
   1158     insert_html_tag (arg, "i");
   1159   else
   1160     not_fixed_width (arg);
   1161 }
   1162 
   1163 void
   1164 cm_slanted (int arg, int arg2, int arg3)
   1165 {
   1166   /* Make use of <lineannotation> of Docbook, if we are
   1167      inside an @example or similar.  */
   1168   extern int printing_index;
   1169   if (docbook && !filling_enabled && !printing_index)
   1170     xml_insert_element (LINEANNOTATION, arg);
   1171   else if (xml)
   1172     xml_insert_element (SLANTED, arg);
   1173   else if (html)
   1174     insert_html_tag (arg, "i");
   1175   else
   1176     not_fixed_width (arg);
   1177 }
   1178 
   1179 void
   1180 cm_b (int arg, int arg2, int arg3)
   1181 {
   1182   /* See cm_i comments.  */
   1183   extern int printing_index;
   1184   if (docbook && !filling_enabled && !printing_index)
   1185     xml_insert_element (LINEANNOTATION, arg);
   1186   else if (docbook && arg == START)
   1187     xml_insert_element_with_attribute (B, arg, "role=\"bold\"");
   1188   else if (xml)
   1189     xml_insert_element (B, arg);
   1190   else if (html)
   1191     insert_html_tag (arg, "b");
   1192   else
   1193     not_fixed_width (arg);
   1194 }
   1195 
   1196 void
   1197 cm_r (int arg, int arg2, int arg3)
   1198 {
   1199   /* See cm_i comments.  */
   1200   extern int printing_index;
   1201   if (docbook && !filling_enabled && !printing_index)
   1202     xml_insert_element (LINEANNOTATION, arg);
   1203   else if (xml)
   1204     xml_insert_element (R, arg);
   1205   else if (html)
   1206     insert_html_tag_with_attribute (arg, "span", "class=\"roman\"");
   1207   else
   1208     not_fixed_width (arg);
   1209 }
   1210 
   1211 void
   1212 cm_sansserif (int arg, int arg2, int arg3)
   1213 {
   1214   /* See cm_i comments.  */
   1215   extern int printing_index;
   1216   if (docbook && !filling_enabled && !printing_index)
   1217     xml_insert_element (LINEANNOTATION, arg);
   1218   else if (xml)
   1219     xml_insert_element (SANSSERIF, arg);
   1220   else if (html)
   1221     insert_html_tag_with_attribute (arg, "span", "class=\"sansserif\"");
   1222   else
   1223     not_fixed_width (arg);
   1224 }
   1225 
   1226 void
   1227 cm_titlefont (int arg, int arg2, int arg3)
   1228 {
   1229   if (xml)
   1230     xml_insert_element (TITLEFONT, arg);
   1231   else
   1232    {
   1233      not_fixed_width (arg);
   1234      if (html)
   1235 	{
   1236 	  html_title_written = 1; /* suppress title from @settitle */
   1237 	  if (arg == START)
   1238 	    add_word ("<h1 class=\"titlefont\">");
   1239 	  else
   1240 	    add_word ("</h1>\n");
   1241 	}
   1242    }
   1243 }
   1244 
   1245 
   1246 /* Unfortunately, we cannot interpret @math{} contents like TeX does.  We just
   1247    pass them through.  */
   1248 void
   1249 cm_math (int arg, int arg2, int arg3)
   1250 {
   1251   if (xml && !docbook)
   1252     xml_insert_element (MATH, arg);
   1253 }
   1254 
   1255 /* Various commands are no-op's. */
   1256 void
   1257 cm_no_op (int arg, int arg2, int arg3)
   1258 {
   1259 }
   1260 
   1261 
   1262 /* For proofing single chapters, etc.  */
   1263 void
   1264 cm_novalidate (int arg, int arg2, int arg3)
   1265 {
   1266   validating = 0;
   1267 }
   1268 
   1269 
   1270 /* Prevent the argument from being split across two lines. */
   1271 void
   1272 cm_w (int arg, int arg2, int arg3)
   1273 {
   1274   if (arg == START)
   1275     non_splitting_words++;
   1276   else
   1277     {
   1278       if (docbook || html || xml)
   1279         /* This is so @w{$}Log$ doesn't end up as <dollar>Log<dollar>
   1280            in the output.  */
   1281         insert_string ("<!-- /@w -->");
   1282 
   1283       non_splitting_words--;
   1284     }
   1285 }
   1286 
   1287 
   1288 /* An unbreakable word space.  Same as @w{ } for makeinfo, but different
   1289    for TeX (the space stretches and stretches, and does not inhibit
   1290    hyphenation).  */
   1291 void
   1292 cm_tie (int arg, int arg2, int arg3)
   1293 {
   1294   if (arg == START)
   1295     {
   1296       cm_w (START, 0, 0);
   1297       add_char (' ');
   1298     }
   1299   else
   1300     cm_w (END, 0, 0);
   1301 }
   1302 
   1303 /* Explain that this command is obsolete, thus the user shouldn't
   1304    do anything with it. */
   1305 static void
   1306 cm_obsolete (int arg, int start, int end)
   1307 {
   1308   if (arg == START)
   1309     warning (_("%c%s is obsolete"), COMMAND_PREFIX, command);
   1310 }
   1311 
   1312 
   1313 /* Inhibit the indentation of the next paragraph, but not of following
   1314    paragraphs.  */
   1315 void
   1316 cm_noindent (int arg, int arg2, int arg3)
   1317 {
   1318   if (!inhibit_paragraph_indentation)
   1319     inhibit_paragraph_indentation = -1;
   1320 }
   1321 
   1322 void
   1323 cm_noindent_cmd (int arg, int arg2, int arg3)
   1324 {
   1325   cm_noindent (0, 0, 0);
   1326   xml_no_indent = 1;
   1327   skip_whitespace_and_newlines();
   1328 
   1329   if (xml)
   1330     xml_start_para ();
   1331   else if (html && !paragraph_is_open)
   1332     add_html_block_elt ("<p class=\"noindent\">");
   1333   else
   1334     {
   1335       paragraph_is_open = 0;
   1336       start_paragraph ();
   1337     }
   1338 }
   1339 
   1340 /* Force indentation of the next paragraph. */
   1341 void
   1342 cm_indent (int arg, int arg2, int arg3)
   1343 {
   1344   inhibit_paragraph_indentation = 0;
   1345   xml_no_indent = 0;
   1346   skip_whitespace_and_newlines();
   1347 
   1348   if (xml)
   1349     xml_start_para ();
   1350   else if (html && !paragraph_is_open)
   1351     add_html_block_elt ("<p class=\"indent\">");
   1352   else
   1353     start_paragraph ();
   1354 }
   1355 
   1356 /* I don't know exactly what to do with this.  Should I allow
   1357    someone to switch filenames in the middle of output?  Since the
   1358    file could be partially written, this doesn't seem to make sense.
   1359    Another option: ignore it, since they don't really want to
   1360    switch files.  Finally, complain, or at least warn.  It doesn't
   1361    really matter, anyway, since this doesn't get executed.  */
   1362 void
   1363 cm_setfilename (int arg, int arg2, int arg3)
   1364 {
   1365   char *filename;
   1366   get_rest_of_line (1, &filename);
   1367   /* warning ("`@%s %s' encountered and ignored", command, filename); */
   1368   if (xml)
   1369     add_word_args ("<setfilename>%s</setfilename>", filename);
   1370   free (filename);
   1371 }
   1372 
   1373 void
   1374 cm_settitle (int arg, int arg2, int arg3)
   1375 {
   1376   if (xml)
   1377     {
   1378       xml_begin_document (current_output_filename);
   1379       xml_insert_element (SETTITLE, START);
   1380       xml_in_book_title = 1;
   1381       get_rest_of_line (0, &title);
   1382       execute_string ("%s", title);
   1383       xml_in_book_title = 0;
   1384       xml_insert_element (SETTITLE, END);
   1385     }
   1386   else
   1387     get_rest_of_line (0, &title);
   1388 }
   1389 
   1390 
   1391 /* Ignore argument in braces.  */
   1392 void
   1393 cm_ignore_arg (int arg, int start_pos, int end_pos)
   1394 {
   1395   if (arg == END)
   1396     output_paragraph_offset = start_pos;
   1397 }
   1398 
   1399 /* Ignore argument on rest of line.  */
   1400 void
   1401 cm_ignore_line (int arg, int arg2, int arg3)
   1402 {
   1403   discard_until ("\n");
   1404 }
   1405 
   1406 /* Insert the number of blank lines passed as argument. */
   1407 void
   1408 cm_sp (int arg, int arg2, int arg3)
   1409 {
   1410   int lines;
   1411   char *line;
   1412 
   1413   /* Due to tricky stuff in execute_string(), @value{} can't be expanded.
   1414      So there is really no reason to enable expansion for @sp parameters.  */
   1415   get_rest_of_line (0, &line);
   1416 
   1417   if (sscanf (line, "%d", &lines) != 1 || lines <= 0)
   1418     line_error (_("@sp requires a positive numeric argument, not `%s'"), line);
   1419   else
   1420     {
   1421       if (xml)
   1422 	{
   1423           /* @sp can appear between @item and @itemx, @deffn and @deffnx.  */
   1424           xml_dont_touch_items_defs++;
   1425 	  xml_insert_element_with_attribute (SP, START, "lines=\"%s\"", line);
   1426 	  /*	  insert_string (line);*/
   1427 	  xml_insert_element (SP, END);
   1428           xml_dont_touch_items_defs--;
   1429 	}
   1430       else
   1431         {
   1432           /* Must disable filling since otherwise multiple newlines is like
   1433              multiple spaces.  Must close paragraph since that's what the
   1434              manual says and that's what TeX does.  */
   1435           int save_filling_enabled = filling_enabled;
   1436           filling_enabled = 0;
   1437 
   1438           /* close_paragraph generates an extra blank line.  */
   1439           close_single_paragraph ();
   1440 
   1441           if (lines && html && !executing_string)
   1442             html_output_head ();
   1443 
   1444           if (html)
   1445             add_html_block_elt ("<pre class=\"sp\">\n");
   1446 
   1447           while (lines--)
   1448             add_char ('\n');
   1449 
   1450           if (html)
   1451             add_html_block_elt ("</pre>\n");
   1452 
   1453           filling_enabled = save_filling_enabled;
   1454         }
   1455     }
   1456   free (line);
   1457 }
   1458 
   1459 /* @dircategory LINE outputs INFO-DIR-SECTION LINE, unless --no-headers.  */
   1460 void
   1461 cm_dircategory (int arg, int arg2, int arg3)
   1462 {
   1463   char *line;
   1464 
   1465   if (html || docbook)
   1466     cm_ignore_line (0, 0, 0);
   1467   else if (xml)
   1468     {
   1469       xml_insert_element (DIRCATEGORY, START);
   1470       get_rest_of_line (1, &line);
   1471       insert_string (line);
   1472       free (line);
   1473       xml_insert_element (DIRCATEGORY, END);
   1474     }
   1475   else
   1476     {
   1477       get_rest_of_line (1, &line);
   1478 
   1479       if (!no_headers && !html)
   1480         {
   1481           kill_self_indent (-1); /* make sure there's no indentation */
   1482           insert_string ("INFO-DIR-SECTION ");
   1483           insert_string (line);
   1484           insert ('\n');
   1485         }
   1486 
   1487       free (line);
   1488     }
   1489 }
   1490 
   1491 /* Start a new line with just this text on it.
   1492    Then center the line of text.
   1493    */
   1494 void
   1495 cm_center (int arg, int arg2, int arg3)
   1496 {
   1497   if (xml)
   1498     {
   1499       char *line;
   1500       xml_insert_element (CENTER, START);
   1501       get_rest_of_line (0, &line);
   1502       execute_string ("%s", line);
   1503       free (line);
   1504       xml_insert_element (CENTER, END);
   1505     }
   1506   else
   1507     {
   1508       int i, start, length;
   1509       char *line;
   1510       int save_indented_fill = indented_fill;
   1511       int save_filling_enabled = filling_enabled;
   1512       int fudge_factor = 1;
   1513 
   1514       filling_enabled = indented_fill = 0;
   1515       cm_noindent (0, 0, 0);
   1516       start = output_paragraph_offset;
   1517 
   1518       if (html)
   1519         add_html_block_elt ("<div align=\"center\">");
   1520 
   1521       inhibit_output_flushing ();
   1522       get_rest_of_line (0, &line);
   1523       execute_string ("%s", line);
   1524       free (line);
   1525       uninhibit_output_flushing ();
   1526       if (html)
   1527         add_html_block_elt ("</div>");
   1528 
   1529        else
   1530          {
   1531            i = output_paragraph_offset - 1;
   1532            while (i > (start - 1) && output_paragraph[i] == '\n')
   1533              i--;
   1534 
   1535            output_paragraph_offset = ++i;
   1536            length = output_paragraph_offset - start;
   1537 
   1538            if (length < (fill_column - fudge_factor))
   1539              {
   1540                line = xmalloc (1 + length);
   1541                memcpy (line, (char *)(output_paragraph + start), length);
   1542 
   1543                i = (fill_column - fudge_factor - length) / 2;
   1544                output_paragraph_offset = start;
   1545 
   1546                while (i--)
   1547                  insert (' ');
   1548 
   1549                for (i = 0; i < length; i++)
   1550                  insert (line[i]);
   1551 
   1552                free (line);
   1553              }
   1554          }
   1555 
   1556       insert ('\n');
   1557       filling_enabled = save_filling_enabled;
   1558       indented_fill = save_indented_fill;
   1559       close_single_paragraph ();
   1560       if (looking_at("\n"))
   1561         insert ('\n');
   1562     }
   1563 }
   1564 
   1565 /* Show what an expression returns. */
   1566 void
   1567 cm_result (int arg, int arg2, int arg3)
   1568 {
   1569   if (arg == END)
   1570     add_word (html ? "=&gt;" : "=>");
   1571 }
   1572 
   1573 /* What an expression expands to. */
   1574 void
   1575 cm_expansion (int arg, int arg2, int arg3)
   1576 {
   1577   if (arg == END)
   1578     add_word (html ? "==&gt;" : "==>");
   1579 }
   1580 
   1581 /* Indicates two expressions are equivalent. */
   1582 void
   1583 cm_equiv (int arg, int arg2, int arg3)
   1584 {
   1585   if (arg == END)
   1586     add_word ("==");
   1587 }
   1588 
   1589 /* What an expression may print. */
   1590 void
   1591 cm_print (int arg, int arg2, int arg3)
   1592 {
   1593   if (arg == END)
   1594     add_word ("-|");
   1595 }
   1596 
   1597 /* An error signaled. */
   1598 void
   1599 cm_error (int arg, int arg2, int arg3)
   1600 {
   1601   if (arg == END)
   1602     add_word (html ? "error--&gt;" : "error-->");
   1603 }
   1604 
   1605 /* The location of point in an example of a buffer. */
   1606 void
   1607 cm_point (int arg, int arg2, int arg3)
   1608 {
   1609   if (arg == END)
   1610     add_word ("-!-");
   1611 }
   1612 
   1613 /* @exdent: Start a new line with just this text on it.
   1614    The text is outdented one level if possible. */
   1615 void
   1616 cm_exdent (int arg, int arg2, int arg3)
   1617 {
   1618   char *line;
   1619   int save_indent = current_indent;
   1620   int save_in_fixed_width_font = in_fixed_width_font;
   1621 
   1622   /* Read argument.  */
   1623   get_rest_of_line (0, &line);
   1624 
   1625   /* Exdent the output.  Actually this may be a no-op.   */
   1626   if (current_indent)
   1627     current_indent -= default_indentation_increment;
   1628 
   1629   /* @exdent arg is supposed to be in roman.  */
   1630   in_fixed_width_font = 0;
   1631 
   1632   /* The preceding newline already inserted the `current_indent'.
   1633      Remove one level's worth.  */
   1634   kill_self_indent (default_indentation_increment);
   1635 
   1636   if (html)
   1637     add_word ("<br>");
   1638   else if (docbook)
   1639     xml_insert_element (LINEANNOTATION, START);
   1640   else if (xml)
   1641     xml_insert_element (EXDENT, START);
   1642 
   1643   /* Can't close_single_paragraph, then we lose preceding blank lines.  */
   1644   flush_output ();
   1645   execute_string ("%s", line);
   1646   free (line);
   1647 
   1648   if (html)
   1649     add_word ("<br>");
   1650   else if (xml)
   1651     {
   1652       xml_insert_element (docbook ? LINEANNOTATION : EXDENT, END);
   1653       insert ('\n');
   1654     }
   1655 
   1656   close_single_paragraph ();
   1657 
   1658   current_indent = save_indent;
   1659   in_fixed_width_font = save_in_fixed_width_font;
   1660   if (!xml)
   1661     start_paragraph ();
   1662 }
   1663 
   1664 /*
   1665   Read include-filename, process the include-file:
   1666     verbatim_include == 0: process through reader_loop
   1667     verbatim_include != 0: process through handle_verbatim_environment
   1668  */
   1669 static void
   1670 handle_include (int verbatim_include)
   1671 {
   1672   char *arg, *filename;
   1673 
   1674   if (macro_expansion_output_stream && !executing_string)
   1675     me_append_before_this_command ();
   1676 
   1677   if (!insertion_stack)
   1678     close_paragraph ();  /* No blank lines etc. if not at outer level.  */
   1679 
   1680   get_rest_of_line (0, &arg);
   1681   /* We really only want to expand @value, but it's easier to just do
   1682      everything.  TeX will only work with @value.  */
   1683   filename = text_expansion (arg);
   1684   free (arg);
   1685 
   1686   if (macro_expansion_output_stream && !executing_string)
   1687     remember_itext (input_text, input_text_offset);
   1688 
   1689   pushfile ();
   1690 
   1691   /* In verbose mode we print info about including another file. */
   1692   if (verbose_mode)
   1693     {
   1694       int i = 0;
   1695       FSTACK *stack = filestack;
   1696 
   1697       for (i = 0, stack = filestack; stack; stack = stack->next, i++);
   1698 
   1699       i *= 2;
   1700 
   1701       printf ("%*s", i, "");
   1702       printf ("%c%s `%s'\n", COMMAND_PREFIX, command, filename);
   1703       fflush (stdout);
   1704     }
   1705 
   1706   if (!find_and_load (filename, 1))
   1707     {
   1708       popfile ();
   1709       line_number--;
   1710 
   1711       /* /wh/bar:5: @include/@verbatiminclude `foo': No such file or dir */
   1712       line_error ("%c%s `%s': %s", COMMAND_PREFIX, command, filename,
   1713                   strerror (errno));
   1714 
   1715       free (filename);
   1716       return;
   1717     }
   1718   else
   1719     {
   1720       if (macro_expansion_output_stream && !executing_string)
   1721 	remember_itext (input_text, input_text_offset);
   1722 
   1723       if (!verbatim_include)
   1724 	reader_loop ();
   1725       else
   1726 	handle_verbatim_environment (0);
   1727     }
   1728   free (filename);
   1729   popfile ();
   1730 }
   1731 
   1732 
   1733 /* Include file as if put in @verbatim environment */
   1734 void
   1735 cm_verbatiminclude (int arg, int arg2, int arg3)
   1736 {
   1737   handle_include (1);
   1738 }
   1739 
   1740 
   1741 /* Remember this file, and move onto the next. */
   1742 void
   1743 cm_include (int arg, int arg2, int arg3)
   1744 {
   1745   handle_include (0);
   1746 }
   1747 
   1748 
   1749 /* @bye: Signals end of processing.  Easy to make this happen. */
   1750 
   1751 void
   1752 cm_bye (int arg, int arg2, int arg3)
   1753 {
   1754   discard_braces (); /* should not have any unclosed braces left */
   1755   input_text_offset = input_text_length;
   1756 }
   1757 
   1758 /* @paragraphindent */
   1760 
   1761 static void
   1762 cm_paragraphindent (int arg1, int arg2, int arg3)
   1763 {
   1764   char *arg;
   1765 
   1766   get_rest_of_line (1, &arg);
   1767   if (set_paragraph_indent (arg) != 0)
   1768     line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
   1769 
   1770   free (arg);
   1771 }
   1772 
   1773 
   1774 /* @exampleindent: change indentation of example-like environments.   */
   1775 static int
   1776 set_example_indentation_increment (char *string)
   1777 {
   1778   if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
   1779     ;
   1780   else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
   1781     example_indentation_increment = 0;
   1782   else if (sscanf (string, "%d", &example_indentation_increment) != 1)
   1783     return -1;
   1784   return 0;
   1785 }
   1786 
   1787 static void
   1788 cm_exampleindent (int arg1, int arg2, int arg3)
   1789 {
   1790   char *arg;
   1791 
   1792   get_rest_of_line (1, &arg);
   1793   if (set_example_indentation_increment (arg) != 0)
   1794     line_error (_("Bad argument to @%s"), command);
   1795 
   1796   if (input_text[input_text_offset] == '\n')
   1797     close_single_paragraph ();
   1798 
   1799   free (arg);
   1800 }
   1801 
   1802 
   1803 /* @firstparagraphindent: suppress indentation in first paragraphs after
   1804    headings. */
   1805 static int
   1806 set_firstparagraphindent (char *string)
   1807 {
   1808   if (STREQ (string, "insert") || STREQ (string, _("insert")))
   1809     do_first_par_indent = 1;
   1810   else if (STREQ (string, "none") || STREQ (string, _("none")))
   1811     do_first_par_indent = 0;
   1812   else
   1813     return -1;
   1814   return 0;
   1815 }
   1816 
   1817 static void
   1818 cm_firstparagraphindent (int arg1, int arg2, int arg3)
   1819 {
   1820   char *arg;
   1821 
   1822   get_rest_of_line (1, &arg);
   1823   if (set_firstparagraphindent (arg) != 0)
   1824     line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
   1825 
   1826   free (arg);
   1827 }
   1828 
   1829 /* For DocBook and XML, produce &period; for `.@:'. This gives the processing
   1830    software a fighting chance to treat it specially by not adding extra space.
   1831 
   1832    Do this also for ?, !, and :.  */
   1833 void
   1834 cm_colon (int arg, int arg2, int arg3)
   1835 {
   1836   if (xml)
   1837     {
   1838       if (strchr (".?!:", input_text[input_text_offset-3]) != NULL)
   1839         {
   1840           /* Erase literal character that's there, except `>', which is
   1841              part of the XML tag.  */
   1842           if (output_paragraph[output_paragraph_offset-1] != '>')
   1843             output_paragraph_offset--;
   1844 
   1845           switch (input_text[input_text_offset-3])
   1846             {
   1847             case '.':
   1848               xml_insert_entity ("period");
   1849               break;
   1850             case '?':
   1851               xml_insert_entity ("quest");
   1852               break;
   1853             case '!':
   1854               xml_insert_entity ("excl");
   1855               break;
   1856             case ':':
   1857               xml_insert_entity ("colon");
   1858               break;
   1859             }
   1860         }
   1861     }
   1862 }
   1863 
   1864 /* Ending sentences explicitly.  Currently, only outputs entities for XML
   1865    output, for other formats it calls insert_self.  */
   1866 void
   1867 cm_punct (int arg, int arg2, int arg3)
   1868 {
   1869   if (xml && !docbook)
   1870     {
   1871       switch (input_text[input_text_offset-1])
   1872         {
   1873         case '.':
   1874           xml_insert_entity ("eosperiod");
   1875           break;
   1876         case '?':
   1877           xml_insert_entity ("eosquest");
   1878           break;
   1879         case '!':
   1880           xml_insert_entity ("eosexcl");
   1881           break;
   1882         }
   1883     }
   1884   else
   1885     {
   1886       insert_self (arg, 0, 0);
   1887     }
   1888 }
   1889