code:
/* xml.c -- xml output, both TexinfoML and Docbook.
   $Id: xml.c,v 1.76 2011-04-06 21:22:03 gray Exp $

   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
   Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   Originally written by Philippe Martin <feloy@free.fr>.  */

#include "system.h"
#include "makeinfo.h"
#include "insertion.h"
#include "files.h"
#include "float.h"
#include "macro.h"
#include "cmds.h"
#include "lang.h"

#include "xml.h"

#include <assert.h>

#if !__OPTIMIZE__
/* To make enum names available to debugger. */
static enum xml_element xml_element_dummy;
#endif

typedef struct _element
{
  char name[32];
  int contains_para;
  int contained_in_para;
  int keep_space;
} element;

element texinfoml_element_list [] = {
  { "texinfo",             1, 0, 0 },
  { "setfilename",         0, 0, 0 },
  { "titlefont",           0, 0, 0 },
  { "settitle",            0, 0, 0 },
  { "documentdescription", 1, 0, 0 },

  { "node",                1, 0, 0 },
  { "nodenext",            0, 0, 0 },
  { "nodeprev",            0, 0, 0 },
  { "nodeup",              0, 0, 0 },

  { "chapter",             1, 0, 0 },
  { "section",             1, 0, 0 },
  { "subsection",          1, 0, 0 },
  { "subsubsection",       1, 0, 0 },

  { "top",                 1, 0, 0 },
  { "unnumbered",          1, 0, 0 },
  { "unnumberedsec",       1, 0, 0 },
  { "unnumberedsubsec",    1, 0, 0 },
  { "unnumberedsubsubsec", 1, 0, 0 },

  { "appendix",            1, 0, 0 },
  { "appendixsec",         1, 0, 0 },
  { "appendixsubsec",      1, 0, 0 },
  { "appendixsubsubsec",   1, 0, 0 },

  { "majorheading",        0, 0, 0 },
  { "chapheading",         0, 0, 0 },
  { "heading",             0, 0, 0 },
  { "subheading",          0, 0, 0 },
  { "subsubheading",       0, 0, 0 },

  { "titlepage",           1, 0, 0 },
  { "author",              0, 0, 0 },
  { "booktitle",           0, 0, 0 },
  { "booksubtitle",        0, 0, 0 },

  { "menu",                1, 0, 0 },
  { "detailmenu",          1, 0, 0 },
  { "menuentry",           0, 0, 0 },
  { "menutitle",           0, 0, 0 },
  { "menucomment",         0, 0, 0 },
  { "menunode",            0, 0, 0 },
  { "nodename",            0, 0, 0 },

  { "acronym",             0, 1, 0 },
  { "acronymword",         0, 1, 0 },
  { "acronymdesc",         0, 1, 0 },

  { "abbrev",              0, 1, 0 },
  { "abbrevword",          0, 1, 0 },
  { "abbrevdesc",          0, 1, 0 },

  { "tt",                  0, 1, 0 },
  { "code",                0, 1, 0 },
  { "command",             0, 1, 0 },
  { "env",                 0, 1, 0 },
  { "file",                0, 1, 0 },
  { "option",              0, 1, 0 },
  { "samp",                0, 1, 0 },
  { "kbd",                 0, 1, 0 },
  { "url",                 0, 1, 0 },
  { "key",                 0, 1, 0 },
  { "var",                 0, 1, 0 },
  { "sc",                  0, 1, 0 },
  { "dfn",                 0, 1, 0 },
  { "emph",                0, 1, 0 },
  { "strong",              0, 1, 0 },
  { "cite",                0, 1, 0 },
  { "notfixedwidth",       0, 1, 0 },
  { "i",                   0, 1, 0 },
  { "b",                   0, 1, 0 },
  { "r",                   0, 1, 0 },
  { "slanted",             0, 1, 0 },
  { "sansserif",           0, 1, 0 },

  { "exdent",              0, 0, 0 },

  { "title",               0, 0, 0 },
  { "ifinfo",              1, 0, 0 },
  { "sp",                  0, 0, 0 },
  { "center",              1, 0, 0 },
  { "dircategory",         0, 0, 0 },
  { "quotation",           1, 0, 0 },
  { "example",             0, 0, 1 },
  { "smallexample",        0, 0, 1 },
  { "lisp",                0, 0, 1 },
  { "smalllisp",           0, 0, 1 },
  { "cartouche",           1, 0, 0 },
  { "copying",             1, 0, 0 },
  { "format",              0, 0, 1 },
  { "smallformat",         0, 0, 1 },
  { "display",             0, 0, 1 },
  { "smalldisplay",        0, 0, 1 },
  { "verbatim",            0, 0, 1 },
  { "footnote",            0, 1, 0 },
  { "",                    0, 1, 0 }, /* LINEANNOTATION (docbook) */

  { "",                    1, 0, 0 }, /* TIP (docbook)       */
  { "",                    1, 0, 0 }, /* NOTE (docbook)      */
  { "",                    1, 0, 0 }, /* IMPORTANT (docbook) */
  { "",                    1, 0, 0 }, /* WARNING (docbook)   */
  { "",                    1, 0, 0 }, /* CAUTION (docbook)   */

  { "itemize",             0, 0, 0 },
  { "itemfunction",        0, 0, 0 },
  { "item",                1, 0, 0 },
  { "enumerate",           0, 0, 0 },
  { "table",               0, 0, 0 },
  { "tableitem",           0, 0, 0 },
  { "tableterm",           0, 0, 0 },

  { "indexterm",           0, 1, 0 },

  { "math",                0, 1, 0 },

  { "dmn",                 0, 1, 0 },

  { "clicksequence",       0, 1, 0 },
  { "click",               0, 1, 0 },

  { "xref",                0, 1, 0 },
  { "xrefnodename",        0, 1, 0 },
  { "xrefinfoname",        0, 1, 0 },
  { "xrefprinteddesc",     0, 1, 0 },
  { "xrefinfofile",        0, 1, 0 },
  { "xrefprintedname",     0, 1, 0 },

  { "inforef",             0, 1, 0 },
  { "inforefnodename",     0, 1, 0 },
  { "inforefrefname",      0, 1, 0 },
  { "inforefinfoname",     0, 1, 0 },

  { "uref",                0, 1, 0 },
  { "urefurl",             0, 1, 0 },
  { "urefdesc",            0, 1, 0 },
  { "urefreplacement",     0, 1, 0 },

  { "email",               0, 1, 0 },
  { "emailaddress",        0, 1, 0 },
  { "emailname",           0, 1, 0 },

  { "group",               0, 0, 0 },
  { "float",               1, 0, 0 },
  { "floattype",           0, 0, 0 },
  { "floatpos",            0, 0, 0 },
  { "caption",             0, 0, 0 },
  { "shortcaption",        0, 0, 0 },

  { "",                    0, 0, 0 }, /* TABLE (docbook) */
  { "",                    0, 0, 0 }, /* FIGURE (docbook) */
  { "",                    0, 0, 0 }, /* EXAMPLE (docbook) */
  { "",                    1, 0, 0 }, /* SIDEBAR (docbook) */

  { "printindex",          0, 0, 0 },
  { "listoffloats",        0, 0, 0 },
  { "anchor",              0, 1, 0 },

  { "image",               0, 0, 0 },
  { "inlineimage",         0, 1, 0 },
  { "alttext",             0, 1, 0 },

  { "",                    0, 1, 0 }, /* PRIMARY (docbook) */
  { "",                    0, 1, 0 }, /* SECONDARY (docbook) */
  { "",                    0, 0, 0 }, /* INFORMALFIGURE (docbook) */
  { "",                    0, 0, 0 }, /* MEDIAOBJECT (docbook) */
  { "",                    0, 0, 0 }, /* IMAGEOBJECT (docbook) */
  { "",                    0, 0, 0 }, /* IMAGEDATA (docbook) */
  { "",                    0, 0, 0 }, /* TEXTOBJECT (docbook) */
  { "",                    0, 0, 0 }, /* INDEXENTRY (docbook) */
  { "",                    0, 0, 0 }, /* PRIMARYIE (docbook) */
  { "",                    0, 0, 0 }, /* SECONDARYIE (docbook) */
  { "",                    0, 0, 0 }, /* INDEXDIV (docbook) */
  { "multitable",          0, 0, 0 },
  { "",                    0, 0, 0 }, /* TGROUP (docbook) */
  { "columnfraction",      0, 0, 0 },
  { "thead",               0, 0, 0 },
  { "tbody",               0, 0, 0 },
  { "entry",               0, 0, 0 },
  { "row",                 0, 0, 0 },
  { "",                    0, 0, 0 }, /* BOOKINFO (docbook) */
  { "",                    0, 0, 0 }, /* ABSTRACT (docbook) */
  { "",                    0, 0, 0 }, /* REPLACEABLE (docbook) */
  { "",                    0, 0, 0 }, /* ENVAR (docbook) */
  { "",                    0, 0, 0 }, /* COMMENT (docbook) */
  { "",                    0, 0, 0 }, /* FUNCTION (docbook) */
  { "",                    0, 0, 0 }, /* LEGALNOTICE (docbook) */

  { "contents",            0, 0, 0 },
  { "shortcontents",       0, 0, 0 },
  { "documentlanguage",    0, 0, 0 },

  { "setvalue",            0, 0, 0 },
  { "clearvalue",          0, 0, 0 },

  { "definition",          0, 0, 0 },
  { "definitionterm",      0, 0, 0 },
  { "definitionitem",      1, 0, 0 },
  { "defcategory",         0, 0, 0 },
  { "deffunction",         0, 0, 0 },
  { "defvariable",         0, 0, 0 },
  { "defparam",            0, 0, 0 },
  { "defdelimiter",        0, 0, 0 },
  { "deftype",             0, 0, 0 },
  { "defparamtype",        0, 0, 0 },
  { "defdatatype",         0, 0, 0 },
  { "defclass",            0, 0, 0 },
  { "defclassvar",         0, 0, 0 },
  { "defoperation",        0, 0, 0 },
  { "frenchspacing",       0, 0, 0 },

  { "para",                0, 0, 0 } /* Must be last */
  /* name / contains para / contained in para / preserve space */
};

element docbook_element_list [] = {
  { "book",                0, 0, 0 }, /* TEXINFO */
  { "",                    0, 0, 0 }, /* SETFILENAME */
  { "",                    0, 0, 0 }, /* TITLEINFO */
  { "title",               0, 0, 0 }, /* SETTITLE */
  { "",                    1, 0, 0 }, /* DOCUMENTDESCRIPTION (?) */

  { "",                    1, 0, 0 }, /* NODE */
  { "",                    0, 0, 0 }, /* NODENEXT */
  { "",                    0, 0, 0 }, /* NODEPREV */
  { "",                    0, 0, 0 }, /* NODEUP */

  { "chapter",             1, 0, 0 },
  { "sect1",               1, 0, 0 }, /* SECTION */
  { "sect2",               1, 0, 0 }, /* SUBSECTION */
  { "sect3",               1, 0, 0 }, /* SUBSUBSECTION */

  { "chapter",             1, 0, 0 }, /* TOP */
  { "chapter",             1, 0, 0 }, /* UNNUMBERED */
  { "sect1",               1, 0, 0 }, /* UNNUMBEREDSEC */
  { "sect2",               1, 0, 0 }, /* UNNUMBEREDSUBSEC */
  { "sect3",               1, 0, 0 }, /* UNNUMBEREDSUBSUBSEC */

  { "appendix",            1, 0, 0 },
  { "sect1",               1, 0, 0 }, /* APPENDIXSEC */
  { "sect2",               1, 0, 0 }, /* APPENDIXSUBSEC */
  { "sect3",               1, 0, 0 }, /* APPENDIXSUBSUBSEC */

  { "bridgehead",          0, 0, 0 }, /* MAJORHEADING */
  { "bridgehead",          0, 0, 0 }, /* CHAPHEADING */
  { "bridgehead",          0, 0, 0 }, /* HEADING */
  { "bridgehead",          0, 0, 0 }, /* SUBHEADING */
  { "bridgehead",          0, 0, 0 }, /* SUBSUBHEADING */

  { "",                    0, 0, 0 }, /* TITLEPAGE */
  { "",                    0, 0, 0 }, /* AUTHOR */
  { "",                    0, 0, 0 }, /* BOOKTITLE */
  { "",                    0, 0, 0 }, /* BOOKSUBTITLE */

  { "",                    1, 0, 0 }, /* MENU */
  { "",                    1, 0, 0 }, /* DETAILMENU */
  { "",                    1, 0, 0 }, /* MENUENTRY */
  { "",                    0, 0, 0 }, /* MENUTITLE */
  { "",                    1, 0, 0 }, /* MENUCOMMENT */
  { "",                    0, 0, 0 }, /* MENUNODE */
  { "anchor",              0, 0, 0 }, /* NODENAME */

  { "acronym",             0, 1, 0 },
  { "",                    0, 1, 0 }, /* ACRONYMWORD */
  { "",                    0, 1, 0 }, /* ACRONYMDESC */

  { "abbrev",              0, 1, 0 },
  { "",                    0, 1, 0 }, /* ABBREVWORD */
  { "",                    0, 1, 0 }, /* ABBREVDESC */

  { "literal",             0, 1, 0 }, /* TT */
  { "literal",             0, 1, 0 }, /* CODE */
  { "command",             0, 1, 0 }, /* COMMAND */
  { "envar",               0, 1, 0 }, /* ENV */
  { "filename",            0, 1, 0 }, /* FILE */
  { "option",              0, 1, 0 }, /* OPTION */
  { "literal",             0, 1, 0 }, /* SAMP */
  { "userinput",           0, 1, 0 }, /* KBD */
  { "wordasword",          0, 1, 0 }, /* URL */
  { "keycap",              0, 1, 0 }, /* KEY */
  { "replaceable",         0, 1, 0 }, /* VAR */
  { "",                    0, 1, 0 }, /* SC */
  { "firstterm",           0, 1, 0 }, /* DFN */
  { "emphasis",            0, 1, 0 }, /* EMPH */
  { "emphasis",            0, 1, 0 }, /* STRONG */
  { "citetitle",           0, 1, 0 }, /* CITE */
  { "",                    0, 1, 0 }, /* NOTFIXEDWIDTH */
  { "wordasword",          0, 1, 0 }, /* I */
  { "emphasis",            0, 1, 0 }, /* B */
  { "",                    0, 1, 0 }, /* R */
  { "",                    0, 1, 0 }, /* SLANTED */
  { "",                    0, 1, 0 }, /* SANSSERIF */

  { "",                    0, 0, 0 }, /* EXDENT */

  { "title",               0, 0, 0 },
  { "",                    1, 0, 0 }, /* IFINFO */
  { "",                    0, 0, 0 }, /* SP */
  { "",                    1, 0, 0 }, /* CENTER */
  { "",                    0, 0, 0 }, /* DIRCATEGORY */
  { "blockquote",          1, 0, 0 }, /* QUOTATION */
  { "screen",              0, 0, 1 }, /* EXAMPLE */
  { "screen",              0, 0, 1 }, /* SMALLEXAMPLE */
  { "programlisting",      0, 0, 1 }, /* LISP */
  { "programlisting",      0, 0, 1 }, /* SMALLLISP */
  { "",                    1, 0, 0 }, /* CARTOUCHE */
  { "",                    1, 0, 0 }, /* COPYING */
  { "screen",              0, 1, 1 }, /* FORMAT */
  { "screen",              0, 1, 1 }, /* SMALLFORMAT */
  { "literallayout",       0, 1, 1 }, /* DISPLAY */
  { "literallayout",       0, 1, 1 }, /* SMALLDISPLAY */
  { "screen",              0, 0, 1 }, /* VERBATIM */
  { "footnote",            0, 1, 0 },
  { "lineannotation",      0, 1, 0 },

  { "tip",                 1, 0, 0 },
  { "note",                1, 0, 0 },
  { "important",           1, 0, 0 },
  { "warning",             1, 0, 0 },
  { "caution",             1, 0, 0 },

  { "itemizedlist",        0, 0, 0 }, /* ITEMIZE */
  { "",                    0, 0, 0 }, /* ITEMFUNCTION */
  { "listitem",            1, 0, 0 }, /* ITEM */
  { "orderedlist",         0, 0, 0 }, /* ENUMERATE */
  { "variablelist",        0, 0, 0 }, /* TABLE */
  { "varlistentry",        0, 0, 0 }, /* TABLEITEM */
  { "term",                0, 0, 0 }, /* TABLETERM */

  { "indexterm",           0, 1, 0 }, /* INDEXTERM */

  { "",                    0, 1, 0 }, /* MATH */

  { "",                    0, 1, 0 }, /* DIMENSION */

  { "",                    0, 1, 0 }, /* CLICKSEQUENCE */
  { "",                    0, 1, 0 }, /* CLICK */

  { "xref",                0, 1, 0 }, /* XREF */
  { "link",                0, 1, 0 }, /* XREFNODENAME */
  { "",                    0, 1, 0 }, /* XREFINFONAME */
  { "",                    0, 1, 0 }, /* XREFPRINTEDDESC */
  { "",                    0, 1, 0 }, /* XREFINFOFILE */
  { "",                    0, 1, 0 }, /* XREFPRINTEDNAME */

  { "",                    0, 1, 0 }, /* INFOREF */
  { "",                    0, 1, 0 }, /* INFOREFNODENAME */
  { "",                    0, 1, 0 }, /* INFOREFREFNAME */
  { "",                    0, 1, 0 }, /* INFOREFINFONAME */

  { "ulink",               0, 1, 0 }, /* UREF */
  { "",                    0, 1, 0 }, /* UREFURL */
  { "",                    0, 1, 0 }, /* UREFDESC */
  { "",                    0, 1, 0 }, /* UREFREPLACEMENT */

  { "ulink",               0, 1, 0 }, /* EMAIL */
  { "email",               0, 1, 0 }, /* EMAILADDRESS */
  { "",                    0, 1, 0 }, /* EMAILNAME */

  { "",                    0, 0, 0 }, /* GROUP */
  { "",                    1, 0, 0 }, /* FLOAT */
  { "",                    0, 0, 0 }, /* FLOATTYPE */
  { "",                    0, 0, 0 }, /* FLOATPOS */
  { "",                    0, 0, 0 }, /* CAPTION */
  { "",                    0, 0, 0 }, /* SHORTCAPTION */

  { "table",               0, 1, 0 },
  { "figure",              0, 1, 0 },
  { "example",             1, 1, 0 },
  { "sidebar",             1, 0, 0 },

  { "index",               0, 0, 0 }, /* PRINTINDEX */
  { "",                    0, 1, 0 }, /* LISTOFFLOATS */
  { "anchor",              0, 1, 0 }, /* ANCHOR */

  { "",                    0, 0, 0 }, /* IMAGE */
  { "inlinemediaobject",   0, 1, 0 }, /* INLINEIMAGE */
  { "",                    0, 0, 0 }, /* IMAGEALTTEXT */

  { "primary",             0, 1, 0 }, /* PRIMARY */
  { "secondary",           0, 1, 0 },
  { "informalfigure",      0, 0, 0 },
  { "mediaobject",         0, 0, 0 },
  { "imageobject",         0, 1, 0 },
  { "imagedata",           0, 1, 0 },
  { "textobject",          0, 1, 0 },
  { "indexentry",          0, 0, 0 },
  { "primaryie",           0, 0, 0 },
  { "secondaryie",         0, 0, 0 },
  { "indexdiv",            0, 0, 0 },
  { "informaltable",       0, 0, 0 },
  { "tgroup",              0, 0, 0 },
  { "colspec",             0, 0, 0 },
  { "thead",               0, 0, 0 },
  { "tbody",               0, 0, 0 },
  { "entry",               0, 0, 0 },
  { "row",                 0, 0, 0 },
  { "bookinfo",            0, 0, 0 },
  { "abstract",            1, 0, 0 },
  { "replaceable",         0, 0, 0 },
  { "envar",               0, 1, 0 },
  { "comment",             0, 0, 0 },
  { "function",            0, 1, 0 },
  { "legalnotice",         1, 0, 0 },

  { "",                    0, 0, 0 }, /* CONTENTS (xml) */
  { "",                    0, 0, 0 }, /* SHORTCONTENTS (xml) */
  { "",                    0, 0, 0 }, /* DOCUMENT LANGUAGE (xml) */

  { "",                    0, 0, 0 }, /* SETVALUE (xml) */
  { "",                    0, 0, 0 }, /* CLEARVALUE (xml) */

  { "informalfigure",      1, 0, 0 }, /* DEFINITION */
  { "synopsis",            0, 0, 1 }, /* DEFINITIONTERM */
  { "blockquote",          1, 0, 0 }, /* DEFINITIONITEM (xml) */
  { "",                    0, 0, 0 }, /* DEFCATEGORY (xml) */
  { "function",            0, 0, 0 }, /* DEFFUNCTION */
  { "varname",             0, 0, 0 }, /* DEFVARIABLE */
  { "replaceable",         0, 0, 0 }, /* DEFPARAM */
  { "",                    0, 0, 0 }, /* DEFDELIMITER (xml) */
  { "returnvalue",         0, 0, 0 }, /* DEFTYPE */
  { "type",                0, 0, 0 }, /* DEFPARAMTYPE */
  { "structname",          0, 0, 0 }, /* DEFDATATYPE */
  { "classname",           0, 0, 0 }, /* DEFCLASS */
  { "property",            0, 0, 0 }, /* DEFCLASSVAR */
  { "methodname",          0, 0, 0 }, /* DEFOPERATION */
  { "",                    0, 0, 0 }, /* FRENCHSPACING */

  { "para",                0, 0, 0 } /* Must be last */
  /* name / contains para / contained in para / preserve space */
};

element *xml_element_list = NULL;

typedef struct _replace_element
{
  int element_to_replace;
  int element_containing;
  int element_replacing;
} replace_element;

/* Elements to replace - Docbook only
   -------------------
   if `element_to_replace' have to be inserted
   as a child of `element_containing,'
   use `element_replacing' instead.

   A value of `-1' for element_replacing means `do not use any element.'
*/

replace_element replace_elements [] = {
  { I, TABLETERM, EMPH },
  { B, TABLETERM, EMPH },
  { TT, CODE, -1 },
  { EXAMPLE, DISPLAY, -1 },
  { CODE, DFN, -1 },
  { CODE, VAR, -1 },
  { EMPH, CODE, REPLACEABLE },
  { VAR, VAR, -1},
  { VAR, B, EMPH},
  { B, CODE, ENVAR},
  { CODE, I, EMPH},
  { SAMP, VAR, -1 },
  { FORMAT, BOOKINFO, ABSTRACT },
  { QUOTATION, ABSTRACT, -1},
  { LINEANNOTATION, LINEANNOTATION, -1 },
  { LEGALNOTICE, ABSTRACT, -1 },
  { QUOTATION, QUOTATION, -1 },
  /* Formal versions of table and image elements.  */
  { MULTITABLE, FLOAT, FLOATTABLE },
  { INFORMALFIGURE, FLOAT, FLOATFIGURE },
  { CARTOUCHE, FLOAT, FLOATCARTOUCHE },
  /* Unnecessary markup in @defun blocks.  */
  { VAR, DEFPARAM, -1 },
  { CODE, DEFTYPE, -1 },
  /* Add your elements to replace here */
  {-1, 0, 0}
};

int xml_in_menu_entry = 0;
int xml_in_menu_entry_comment = 0;
int xml_node_open = 0;
int xml_node_level = -1;
int xml_in_para = 0;
int xml_just_after_element = 0;
int xml_keep_space = 0;

int xml_no_indent = 0;

int xml_no_para = 0;
char *xml_node_id = NULL;

/* Currently sorting the index. */
int xml_sort_index = 0;

int xml_in_xref_token = 0;
int xml_in_bookinfo = 0;
int xml_in_book_title = 0;
int xml_in_abstract = 0;

/* Non-zero if we are handling an element that can appear between
   @item and @itemx, @deffn and @deffnx.  */
int xml_dont_touch_items_defs = 0;

/* We need to keep footnote state, because elements inside footnote may try
   to close the previous parent para.  */
static int xml_in_footnote = 0;

static int xml_after_table_term = 0;
static int book_started = 0;
static int first_section_opened = 0;

static int xml_in_tableitem[256];
static int xml_in_item[256];
static int xml_table_level = 0;

static int xml_in_def_item[256];
static int xml_definition_level = 0;
int xml_after_def_term = 0;

static int in_table_title = 0;

static int in_indexentry = 0;
static int in_secondary = 0;
static int in_indexterm = 0;

/* Technically there are certain Unicode characters which cannot
   appear.  Trying to implement the real rules would lead to deep
   waters.  So essentially just pass along what we are given.  Some
   references:
   http://www.w3.org/TR/xml-id/
   -> http://www.w3.org/TR/xml-names11/#NT-NCName
   -> http://www.w3.org/TR/xml11/#NT-NameChar
*/

char *
xml_id (char *id)
{
  char *tem = xmalloc (strlen (id) + 1);
  char *p = tem;
  strcpy (tem, id);
  while (*p)
    {
      if (strchr (":\" \t\f\r\n", *p))
        *p = '-';
      p++;
    }
  p = tem;

  /* First character cannot be a number.  Clearly we should make this
     dependent on the actual numeral found.  */
  if (strchr ("0123456789", *p))
    *p = 'i';

  return tem;
}

int
xml_element (char *name)
{
  int i;
  for (i = 0; i<=PARA; i++)
    {
      if (mbscasecmp (name, texinfoml_element_list[i].name) == 0)
        return i;
    }
  printf ("Error xml_element\n");
  return -1;
}

void
xml_begin_document (const char *output_basename)
{
  if (book_started)
    return;

  book_started = 1;

  /* Make sure this is the very first string of the output document.  */
  output_paragraph_offset = 0;

  insert_string ("<?xml version=\"1.0\"");

  /* At this point, we register a delayed writing for document encoding,
     so in the end, proper encoding attribute will be inserted here.
     Since the user is unaware that we are implicitly executing this
     command, we should disable warnings temporarily, in order to avoid
     possible confusion.  (ie. if the output is not seekable,
     register_delayed_write issues a warning.)  */
  {
    extern int print_warnings;
    int save_print_warnings = print_warnings;
    print_warnings = 0;
    register_delayed_write ("@documentencoding");
    print_warnings = save_print_warnings;
  }

  insert_string ("?>\n");

  if (docbook)
    {
      insert_string ("<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\" [\n  <!ENTITY tex \"TeX\">\n  <!ENTITY latex \"LaTeX\">\n]>");
      xml_element_list = docbook_element_list;
    }
  else
    {
      insert_string ("<!DOCTYPE texinfo PUBLIC \"-//GNU//DTD TexinfoML V");
      insert_string (VERSION);
      insert_string ("//EN\" \"http://www.gnu.org/software/texinfo/dtd/");
      insert_string (VERSION);
      insert_string ("/texinfo.dtd\">");
      xml_element_list = texinfoml_element_list;
    }

  if (strcmp (xml_element_list[PARA].name, "para"))
    {
      warning ("internal error: xml_element_list table inconsistent");
      xexit (-1);
    }

  if (language_code != last_language_code)
    {
      if (docbook)
	/* The toplevel <book> element needs an id attribute if you want
           to use the chunk.xml feature of the Docbook-XSL stylesheets.
           Might as well use the output filename?  */
        xml_insert_element_with_attribute (TEXINFO, START,
                                           "id=\"%s\" lang=\"%s\"",
                                         output_basename,
                                         language_table[language_code].abbrev);
      else
	xml_insert_element_with_attribute (TEXINFO, START,
                                           "xml:lang=\"%s\"",
                                         language_table[language_code].abbrev);
    }
  if (!docbook)
    {
      xml_insert_element (SETFILENAME, START);
      insert_string (output_basename);
      xml_insert_element (SETFILENAME, END);
    }
}

/*  */
static int element_stack[256];
static int element_stack_index = 0;

static int
xml_current_element (void)
{
  assert (element_stack_index > 0);
  return element_stack[element_stack_index-1];
}

static void
xml_push_current_element (int elt)
{
  element_stack[element_stack_index++] = elt;
  if (element_stack_index > 200)  /* fixxme, no hard limits */
    warning ("internal error: xml stack overflow (%d - %s)",
             element_stack_index, xml_element_list[elt].name);
}

static void
xml_pop_current_element (void)
{
  element_stack_index--;
  if (element_stack_index < 0)
    {
      warning ("internal error: xml stack underflow (index %d)",
               element_stack_index);
      element_stack_index = 0;
    }
}

int
xml_current_stack_index (void)
{
  return element_stack_index;
}

void
xml_end_current_element (void)
{
  xml_insert_element (xml_current_element (), END);
}

static void
xml_indent (void)
{
  if (xml_indentation_increment > 0)
    {
      int i;
      if (output_paragraph[output_paragraph_offset-1] != '\n')
        insert ('\n');
      for (i = 0; i < element_stack_index * xml_indentation_increment; i++)
        insert (' ');
    }
}

void
xml_start_para (void)
{
  if (xml_in_para || xml_in_footnote
      || !xml_element_list[xml_current_element()].contains_para)
    return;

  while (output_paragraph_offset > 0
	 && output_paragraph[output_paragraph_offset-1] == '\n')
    output_paragraph_offset--;
  xml_indent ();

  insert_string ("<para");
  if (xml_no_indent)
    insert_string (" role=\"continues\"");
  insert_string (">");
  xml_no_indent = 0;
  xml_in_para = 1;
}

void
xml_end_para (void)
{
  if (!xml_in_para || xml_in_footnote)
    return;

  while (output_paragraph_offset > 0
	 && cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
    output_paragraph_offset--;

  insert_string ("</para>");
  if (xml_indentation_increment > 0)
    insert ('\n');
  xml_in_para = 0;
}

void
xml_end_document (void)
{
  if (xml_node_open)
    {
      if (xml_node_level != -1)
        {
          xml_close_sections (xml_node_level);
          xml_node_level = -1;
        }
      xml_insert_element (NODE, END);
    }
  else
    xml_close_sections (xml_node_level);

  xml_insert_element (TEXINFO, END);
  if (xml_indentation_increment == 0)
    insert ('\n');
  insert_string ("<!-- Keep this comment at the end of the file\n\
Local variables:\n\
mode: sgml\n\
sgml-indent-step:1\n\
sgml-indent-data:nil\n\
End:\n\
-->\n");
  if (element_stack_index != 0)
    error ("Element stack index : %d\n", element_stack_index);
}

/* MUST be 0 or 1, not true or false values */
static int start_element_inserted = 1;

/* NOTE: We use `elt' rather than `element' in the argument list of
   the next function, since otherwise the Solaris SUNWspro compiler
   barfs because `element' is a typedef declared near the beginning of
   this file.  */
void
xml_insert_element_with_attribute (int elt, int arg, char *format, ...)
{
  /* Look at the replace_elements table to see if we have to change the element */
  if (xml_sort_index)
      return;
  if (docbook && element_stack_index > 0)
    {
      replace_element *element_list = replace_elements;
      while (element_list->element_to_replace >= 0)
        {
          if ( ( (arg == START) &&
                 (element_list->element_containing == xml_current_element ()) &&
                 (element_list->element_to_replace == elt) ) ||
               ( (arg == END) &&
                 (element_list->element_containing == element_stack[element_stack_index-1-start_element_inserted]) &&
                 (element_list->element_to_replace == elt) ) )
            {
              elt = element_list->element_replacing;
              break;
            }
          element_list ++;
        }

      /* Forget the element */
      if (elt < 0)
        {
          if (arg == START)
            start_element_inserted = 0;
          else
            /* Replace the default value, for the next time */
            start_element_inserted = 1;
          return;
        }
    }

  if (!book_started)
    return;

  if (!xml_dont_touch_items_defs && arg == START)
    {
      if (xml_after_table_term && elt != TABLETERM && xml_table_level
          && !xml_in_item[xml_table_level])
        {
          xml_after_table_term = 0;
          xml_insert_element (ITEM, START);
          xml_in_item[xml_table_level] = 1;
        }
      else if (xml_after_def_term && elt != DEFINITIONTERM)
        {
          xml_after_def_term = 0;
          xml_insert_element (DEFINITIONITEM, START);
          xml_in_def_item[xml_definition_level] = 1;
        }
    }

  if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
    return;

  if (executing_string && arg == END)
    switch (elt)
      {
      case TABLEITEM:
        xml_in_tableitem[xml_table_level] = 0;
        break;
      case ITEM:
        xml_in_item[xml_table_level] = 0;
        break;
      case DEFINITIONTERM:
        xml_in_def_item[xml_definition_level] = 0;
        break;
      }

  /* We are special-casing FIGURE element for docbook.  It does appear in
     the tag stack, but not in the output.  This is to make element replacement
     work beautifully.  */
  if (docbook && elt == FLOAT)
    {
      if (arg == START)
        xml_push_current_element (elt);
      else
        xml_pop_current_element ();
      return;
    }

  if (!xml_element_list[elt].name || !strlen (xml_element_list[elt].name))
    {
      /*printf ("Warning: Inserting empty element %d\n", elt);*/
      return;
    }

  if (arg == START && !xml_in_para && !xml_no_para
      && xml_element_list[elt].contained_in_para)
    xml_start_para ();

  if (arg == START && xml_in_para && !xml_element_list[elt].contained_in_para)
    xml_end_para ();

  if (arg == END && xml_in_para && !xml_element_list[elt].contained_in_para)
    xml_end_para ();

  /* Oddly, we want to do the same thing whether we starting or ending
     the detailmenu -- close any existing menu elements before inserting
     the detailmenu element.  */
  if (elt == DETAILMENU && xml_in_menu_entry)
    {
      if (xml_in_menu_entry_comment)
        {
          xml_insert_element (MENUCOMMENT, END);
          xml_in_menu_entry_comment = 0;
        }
      xml_insert_element (MENUENTRY, END);
      xml_in_menu_entry = 0;
    }

  if (docbook && xml_table_level && !in_table_title
      && !xml_in_tableitem[xml_table_level] && !xml_in_item[xml_table_level]
      && arg == START && elt != TABLEITEM && elt != TABLETERM
      && !in_indexterm && xml_current_element() == TABLE)
    {
      in_table_title = 1;
      xml_insert_element (TITLE, START);
    }

  if (arg == START && !xml_in_para && !xml_keep_space
      && !xml_element_list[elt].contained_in_para)
    xml_indent ();

  if (arg == START)
    xml_push_current_element (elt);
  else
    xml_pop_current_element ();

  /* Eat one newline before </example> and the like.  */
  if (!docbook && arg == END
      && (xml_element_list[elt].keep_space || elt == GROUP)
      && output_paragraph_offset > 0
      && output_paragraph[output_paragraph_offset-1] == '\n')
    output_paragraph_offset--;

  /* And eat whitespace before </entry> in @multitables.  */
  if (arg == END && elt == ENTRY)
      while (output_paragraph_offset > 0 &&
	     cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
        output_paragraph_offset--;

  /* Indent elements that can contain <para>.  */
  if (arg == END && !xml_in_para && !xml_keep_space
      && xml_element_list[elt].contains_para)
    xml_indent ();

  /* Here are the elements we want indented.  These do not contain <para>
     directly.  */
  if (arg == END && (elt == MENUENTRY || elt == ITEMIZE || elt == ENUMERATE
        || elt == TABLEITEM || elt == TABLE
        || elt == MULTITABLE || elt == TGROUP || elt == THEAD || elt == TBODY
        || elt == ROW || elt == INFORMALFIGURE
        || (!docbook && (elt == DEFINITION || elt == DEFINITIONTERM))))
    xml_indent ();

  insert ('<');
  if (arg == END)
    insert ('/');
  insert_string (xml_element_list[elt].name);

  /*  printf ("%s ", xml_element_list[elt].name);*/

  if (format)
    {
      char temp_string[2000]; /* xx no fixed limits */
      va_list ap;

      va_start (ap, format);
      vsnprintf (temp_string, sizeof (temp_string), format, ap);
      insert (' ');
      insert_string (temp_string);
      va_end (ap);
    }

  if (arg == START && xml_node_id && elt != NODENAME)
    {
      insert_string (" id=\"");
      insert_string (xml_node_id);
      insert ('"');
      free (xml_node_id);
      xml_node_id = NULL;
    }

  if (xml_element_list[elt].keep_space)
    {
      if (arg == START)
	{
          if (!docbook)
            insert_string (" xml:space=\"preserve\"");
	  xml_keep_space++;
	}
      else
	xml_keep_space--;
    }

  insert ('>');

  if (!xml_in_para && !xml_element_list[elt].contained_in_para
      && xml_element_list[elt].contains_para && xml_indentation_increment > 0)
    insert ('\n');

  xml_just_after_element = 1;
}

/* See the NOTE before xml_insert_element_with_attribute, for why we
   use `elt' rather than `element' here.  */
void
xml_insert_element (int elt, int arg)
{
  xml_insert_element_with_attribute (elt, arg, NULL);
}

void
xml_insert_entity (char *entity_name)
{
  int saved_escape_html = escape_html;

  if (xml)
    {
    if (!book_started)
      return;
    if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
      return;

    if (!xml_in_para && !xml_no_para && !only_macro_expansion
        && xml_element_list[xml_current_element ()].contains_para
        && !in_fixed_width_font)
      xml_start_para ();
  }

  escape_html = 0;
  add_char ('&');
  escape_html = saved_escape_html;
  insert_string (entity_name);
  add_char (';');
}

typedef struct _xml_section xml_section;
struct _xml_section {
  int level;
  char *name;
  xml_section *prev;
};

xml_section *last_section = NULL;

void
xml_begin_node (void)
{
  first_section_opened = 1;
  if (xml_in_abstract)
    {
      xml_insert_element (ABSTRACT, END);
      xml_in_abstract = 0;
    }
  if (xml_in_bookinfo)
    {
      xml_insert_element (BOOKINFO, END);
      xml_in_bookinfo = 0;
    }
  if (xml_node_open && !docbook)
    {
      if (xml_node_level != -1)
        {
          xml_close_sections (xml_node_level);
          xml_node_level = -1;
        }
      xml_insert_element (NODE, END);
    }
  xml_insert_element (NODE, START);
  xml_node_open = 1;
}

void
xml_close_sections (int level)
{
  if (!first_section_opened)
    {
      if (xml_in_abstract)
	{
	  xml_insert_element (ABSTRACT, END);
	  xml_in_abstract = 0;
	}
      if (xml_in_bookinfo)
	{
	  xml_insert_element (BOOKINFO, END);
	  xml_in_bookinfo = 0;
	}
      first_section_opened = 1;
    }

  while (last_section && last_section->level >= level)
    {
      xml_section *temp = last_section;
      xml_insert_element (xml_element(last_section->name), END);
      temp = last_section;
      last_section = last_section->prev;
      free (temp->name);
      free (temp);
    }
}

void
xml_open_section (int level, char *name)
{
  xml_section *sect = (xml_section *) xmalloc (sizeof (xml_section));

  sect->level = level;
  sect->name = xmalloc (1 + strlen (name));
  strcpy (sect->name, name);
  sect->prev = last_section;
  last_section = sect;

  if (xml_node_open && xml_node_level == -1)
    xml_node_level = level;
}

void
xml_start_menu_entry (char *tem)
{
  char *string;
  discard_until ("* ");

  /* The line number was already incremented in reader_loop when we
     saw the newline, and discard_until has now incremented again.  */
  line_number--;

  if (xml_in_menu_entry)
    {
      if (xml_in_menu_entry_comment)
        {
          xml_insert_element (MENUCOMMENT, END);
          xml_in_menu_entry_comment = 0;
        }
      xml_insert_element (MENUENTRY, END);
      xml_in_menu_entry = 0;
    }
  xml_insert_element (MENUENTRY, START);
  xml_in_menu_entry = 1;

  xml_insert_element (MENUNODE, START);
  string = expansion (tem, 0);
  add_word (string);
  xml_insert_element (MENUNODE, END);
  free (string);

  /* The menu item may use macros, so expand them now.  */
  xml_insert_element (MENUTITLE, START);
  only_macro_expansion++;
  get_until_in_line (1, ":", &string);
  only_macro_expansion--;
  execute_string ("%s", string); /* get escaping done */
  xml_insert_element (MENUTITLE, END);
  free (string);

  if (looking_at ("::"))
    discard_until (":");
  else
    { /* discard the node name */
      get_until_in_line (0, ".", &string);
      free (string);
    }
  input_text_offset++;  /* discard the second colon or the period */
  skip_whitespace_and_newlines();
  xml_insert_element (MENUCOMMENT, START);
  xml_in_menu_entry_comment ++;
}

void
xml_end_menu (void)
{
  if (xml_in_menu_entry)
    {
      if (xml_in_menu_entry_comment)
        {
          xml_insert_element (MENUCOMMENT, END);
          xml_in_menu_entry_comment --;
        }
      xml_insert_element (MENUENTRY, END);
      xml_in_menu_entry--;
    }
  xml_insert_element (MENU, END);
}

static int xml_last_character;

void
xml_add_char (int character)
{
  if (!book_started)
      return;
  if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
    return;

  if (docbook && xml_table_level && !in_table_title
      && !xml_in_item[xml_table_level] && !xml_in_tableitem[xml_table_level]
      && !cr_or_whitespace (character) && !in_indexterm)
    {
      in_table_title = 1;
      xml_insert_element (TITLE, START);
    }

  if (!first_section_opened && !xml_in_abstract && !xml_in_book_title
      && !xml_no_para && character != '\r' && character != '\n'
      && character != ' ' && !is_in_insertion_of_type (copying))
    {
      if (!xml_in_bookinfo)
	{
	  xml_insert_element (BOOKINFO, START);
	  xml_in_bookinfo = 1;
	}
      xml_insert_element (ABSTRACT, START);
      xml_in_abstract = 1;
    }

  if (!xml_sort_index && !xml_in_xref_token && !xml_dont_touch_items_defs)
    {
      if (xml_after_table_term && xml_table_level
          && !xml_in_item[xml_table_level])
        {
          xml_after_table_term = 0;
          xml_insert_element (ITEM, START);
          xml_in_item[xml_table_level] = 1;
        }
      else if (xml_after_def_term)
        {
          xml_after_def_term = 0;
          xml_insert_element (DEFINITIONITEM, START);
          xml_in_def_item[xml_definition_level] = 1;
        }
    }

  if (xml_just_after_element && !xml_in_para && !inhibit_paragraph_indentation)
    {
      if (character == '\r' || character == '\n' || character == '\t' || character == ' ')
        return;
      xml_just_after_element = 0;
    }

  if (element_stack_index > 0
      && xml_element_list[xml_current_element()].contains_para
      && !xml_in_para && !only_macro_expansion && !xml_no_para
      && !cr_or_whitespace (character) && !in_fixed_width_font)
    xml_start_para ();

  if (xml_in_para && character == '\n' && xml_last_character == '\n'
      && !only_macro_expansion && !xml_no_para
      && xml_element_list[xml_current_element()].contains_para )
    {
      xml_end_para ();
      xml_just_after_element = 1;
      return;
    }

  if (xml_in_menu_entry_comment && character == '\n' && xml_last_character == '\n')
    {
      xml_insert_element (MENUCOMMENT, END);
      xml_in_menu_entry_comment = 0;
      xml_insert_element (MENUENTRY, END);
      xml_in_menu_entry = 0;
    }

  if (xml_in_menu_entry_comment && whitespace(character)
      && cr_or_whitespace(xml_last_character))
    return;

  if (character == '\n' && !xml_in_para && !inhibit_paragraph_indentation)
    return;

  xml_last_character = character;

  if (character == '&' && escape_html)
      insert_string ("&");
  else if (character == '<' && escape_html)
      insert_string ("<");
  else if (character == '>' && escape_html)
      insert_string (">");
  else if (character == '\n' && !xml_keep_space)
    {
      if (!xml_in_para && xml_just_after_element && !multitable_active)
	return;
      else
	insert (docbook ? '\n' : ' ');
    }
  else
    insert (character);

  return;
}

void
xml_insert_footnote (char *note)
{
  if (!xml_in_para)
    xml_start_para ();

  xml_in_footnote = 1;
  xml_insert_element (FOOTNOTE, START);
  insert_string ("<para>");
  execute_string ("%s", note);
  insert_string ("</para>");
  xml_insert_element (FOOTNOTE, END);
  xml_in_footnote = 0;
}

/* We need to keep the quotation stack ourself, because insertion_stack
   loses item_function when we are closing the block, so we don't know
   what to close then.  */
typedef struct quotation_elt
{
  struct quotation_elt *next;
  char *type;
} QUOTATION_ELT;

static QUOTATION_ELT *quotation_stack = NULL;

void
xml_insert_quotation (char *type, int arg)
{
  int quotation_started = 0;

  if (arg == START)
    {
      QUOTATION_ELT *new = xmalloc (sizeof (QUOTATION_ELT));
      new->type = xstrdup (type);
      new->next = quotation_stack;
      quotation_stack = new;
    }
  else
    type = quotation_stack->type;

  /* Make use of special quotation styles of Docbook if we can.  */
  if (docbook && strlen (type))
    {
      /* Let's assume it started.  */
      quotation_started = 1;

      if (mbscasecmp (type, "tip") == 0)
        xml_insert_element (TIP, arg);
      else if (mbscasecmp (type, "note") == 0)
        xml_insert_element (NOTE, arg);
      else if (mbscasecmp (type, "important") == 0)
        xml_insert_element (IMPORTANT, arg);
      else if (mbscasecmp (type, "warning") == 0)
        xml_insert_element (WARNING, arg);
      else if (mbscasecmp (type, "caution") == 0)
        xml_insert_element (CAUTION, arg);
      else
        /* Didn't find a known quotation type :\ */
        quotation_started = 0;
    }

  if (!quotation_started)
    {
      xml_insert_element (QUOTATION, arg);
      if (strlen(type) && arg == START)
        execute_string ("@b{%s:} ", type);
    }

  if (arg == END)
    {
      QUOTATION_ELT *temp = quotation_stack;
      if (temp == NULL)
        return;
      quotation_stack = quotation_stack->next;
      free(temp->type);
      free(temp);
    }
}

/* Starting generic docbook floats.  Just starts elt with correct label
   and id attributes, and inserts title.  */
void
xml_begin_docbook_float (int elt)
{
  if (current_float_used_title ())	/* in a nested float */
    {
      xml_insert_element (elt, START);	/* just insert the tag */
      return;
    }

  /* OK, need the title, tag, etc. */
  if (elt == CARTOUCHE)    /* no labels on <sidebar> */
    {
       if (strlen (current_float_id ()) == 0)
          xml_insert_element (elt, START);
       else
          xml_insert_element_with_attribute (elt, START,
              "id=\"%s\"", xml_id (current_float_id ()));
    }
  else if (strlen (current_float_id ()) == 0)
    xml_insert_element_with_attribute (elt, START, "label=\"\"");
  else
    xml_insert_element_with_attribute (elt, START,
        "id=\"%s\" label=\"%s\"", xml_id (current_float_id ()),
        current_float_number ());

  xml_insert_element (TITLE, START);
  execute_string ("%s", current_float_title ());
  xml_insert_element (TITLE, END);

  current_float_set_title_used ();	/* mark this title, tag, etc used */
}

/*
 * Lists and Tables
 */
void
xml_begin_table (int type, char *item_function)
{
  switch (type)
    {
    case ftable:
    case vtable:
    case table:
      /*if (docbook)*/ /* 05-08 */
        {
          xml_insert_element (TABLE, START);
          xml_table_level ++;
          xml_in_tableitem[xml_table_level] = 0;
          xml_in_item[xml_table_level] = 0;
          xml_after_table_term = 0;
        }
      break;
    case itemize:
      if (!docbook || item_function==default_item_function)
	xml_insert_element (ITEMIZE, START);
      else
	xml_insert_element_with_attribute (ITEMIZE, START,
					   "mark=\"%s\"",
					   (*item_function == COMMAND_PREFIX) ?
					   &item_function[1] : item_function);
      xml_table_level ++;
      xml_in_item[xml_table_level] = 0;
      if (!docbook)
        {
          xml_insert_element (ITEMFUNCTION, START);
          if (*item_function == COMMAND_PREFIX
              && item_function[strlen (item_function) - 1] != '}'
              && command_needs_braces (item_function + 1))
            execute_string ("%s{}", item_function);
          else
            execute_string ("%s", item_function);
          xml_insert_element (ITEMFUNCTION, END);
        }
      break;
    }
}

void
xml_end_table (int type)
{
  switch (type)
    {
    case ftable:
    case vtable:
    case table:
      if (xml_in_item[xml_table_level])
        {
          xml_insert_element (ITEM, END);
          xml_in_item[xml_table_level] = 0;
        }
      if (xml_in_tableitem[xml_table_level])
        {
          xml_insert_element (TABLEITEM, END);
          xml_in_tableitem[xml_table_level] = 0;
        }
      xml_insert_element (TABLE, END);
      xml_after_table_term = 0;
      xml_table_level --;

      break;
    case itemize:
      if (xml_in_item[xml_table_level])
        {
          xml_insert_element (ITEM, END);
          xml_in_item[xml_table_level] = 0;
        }
      /* gnat-style manual contains an itemized list without items! */
      if (in_table_title)
	{
	  xml_insert_element (TITLE, END);
	  in_table_title = 0;
	}
      xml_insert_element (ITEMIZE, END);
      xml_table_level --;
      break;
    }
}

void
xml_begin_item (void)
{
  if (xml_in_item[xml_table_level])
    xml_insert_element (ITEM, END);

  xml_insert_element (ITEM, START);
  xml_in_item[xml_table_level] = 1;
}

void
xml_begin_table_item (void)
{
  if (!xml_after_table_term)
    {
      if (xml_in_item[xml_table_level])
        xml_insert_element (ITEM, END);
      if (xml_in_tableitem[xml_table_level])
        xml_insert_element (TABLEITEM, END);

      if (in_table_title)
	{
	  in_table_title = 0;
	  xml_insert_element (TITLE, END);
	}
      xml_insert_element (TABLEITEM, START);
    }
  xml_insert_element (TABLETERM, START);
  xml_in_tableitem[xml_table_level] = 1;
  xml_in_item[xml_table_level] = 0;
  xml_after_table_term = 0;
}

void
xml_continue_table_item (void)
{
  xml_insert_element (TABLETERM, END);
  xml_after_table_term = 1;
  xml_in_item[xml_table_level] = 0;
}

void
xml_begin_enumerate (char *enum_arg)
{
  if (!docbook)
    xml_insert_element_with_attribute (ENUMERATE, START, "first=\"%s\"", enum_arg);
  else
    {
      if (isdigit (*enum_arg))
        {
          int enum_val = atoi (enum_arg);

          /* Have to check the value, not just the first digit.  */
          if (enum_val == 0)
            xml_insert_element_with_attribute (ENUMERATE, START,
                "numeration=\"arabic\" role=\"0\"", NULL);
          else if (enum_val == 1)
            xml_insert_element_with_attribute (ENUMERATE, START,
                "numeration=\"arabic\"", NULL);
          else
            xml_insert_element_with_attribute (ENUMERATE, START,
                "continuation=\"continues\" numeration=\"arabic\"", NULL);
        }
      else if (isupper (*enum_arg))
        {
          if (enum_arg[0] == 'A')
            xml_insert_element_with_attribute (ENUMERATE, START,
                "numeration=\"upperalpha\"", NULL);
          else
            xml_insert_element_with_attribute (ENUMERATE, START,
                "continuation=\"continues\" numeration=\"upperalpha\"", NULL);
        }
      else
        {
          if (enum_arg[0] == 'a')
            xml_insert_element_with_attribute (ENUMERATE, START,
                "numeration=\"loweralpha\"", NULL);
          else
            xml_insert_element_with_attribute (ENUMERATE, START,
                "continuation=\"continues\" numeration=\"loweralpha\"", NULL);
        }
    }
  xml_table_level ++;
  xml_in_item[xml_table_level] = 0;
}

void
xml_end_enumerate (void)
{
  if (xml_in_item[xml_table_level])
    {
      xml_insert_element (ITEM, END);
      xml_in_item[xml_table_level] = 0;
    }
  xml_insert_element (ENUMERATE, END);
  xml_table_level --;
}

static void
xml_insert_text_file (char *name_arg)
{
  char *fullname = xmalloc (strlen (name_arg) + 4 + 1);
  FILE *image_file;
  strcpy (fullname, name_arg);
  strcat (fullname, ".txt");
  image_file = fopen (fullname, "r");
  if (image_file)
    {
      int ch;
      int save_inhibit_indentation = inhibit_paragraph_indentation;
      int save_filling_enabled = filling_enabled;

      xml_insert_element (TEXTOBJECT, START);
      xml_insert_element (DISPLAY, START);

      inhibit_paragraph_indentation = 1;
      filling_enabled = 0;
      last_char_was_newline = 0;

      /* Maybe we need to remove the final newline if the image
         file is only one line to allow in-line images.  On the
         other hand, they could just make the file without a
         final newline.  */
      while ((ch = getc (image_file)) != EOF)
        add_char (ch);

      inhibit_paragraph_indentation = save_inhibit_indentation;
      filling_enabled = save_filling_enabled;

      xml_insert_element (DISPLAY, END);
      xml_insert_element (TEXTOBJECT, END);

      if (fclose (image_file) != 0)
        perror (fullname);
    }
  else
    warning (_("@image file `%s' unreadable: %s"), fullname,
             strerror (errno));

  free (fullname);
}

/* If NAME.EXT is accessible or FORCE is nonzero, insert a docbook
   imagedata element for FMT.  Return 1 if inserted something, 0 else.  */

static int
try_docbook_image (const char *name, const char *ext, const char *fmt,
                   int force)
{
  int used = 0;
  char *fullname = xmalloc (strlen (name) + 1 + strlen (ext) + 1);
  sprintf (fullname, "%s.%s", name, ext);

  if (force || access (fullname, R_OK) == 0)
   {
     xml_insert_element (IMAGEOBJECT, START);
     xml_insert_element_with_attribute (IMAGEDATA, START,
       "fileref=\"%s\" format=\"%s\"", fullname, fmt);
     xml_insert_element (IMAGEDATA, END);
     xml_insert_element (IMAGEOBJECT, END);
     used = 1;
   }

 free (fullname);
 return used;
}

void
xml_insert_docbook_image (char *name_arg)
{
  int found = 0;
  int elt = xml_in_para ? INLINEIMAGE : MEDIAOBJECT;

  if (is_in_insertion_of_type (floatenv))
    xml_begin_docbook_float (INFORMALFIGURE);
  else if (!xml_in_para)
    xml_insert_element (INFORMALFIGURE, START);

  xml_no_para++;

  xml_insert_element (elt, START);

  /* A selected few from http://docbook.org/tdg/en/html/imagedata.html.  */
  if (try_docbook_image (name_arg, "eps", "EPS", 0))
    found++;
  if (try_docbook_image (name_arg, "gif", "GIF", 0))
    found++;
  if (try_docbook_image (name_arg, "jpg", "JPG", 0))
    found++;
  if (try_docbook_image (name_arg, "jpeg", "JPEG", 0))
    found++;
  if (try_docbook_image (name_arg, "pdf", "PDF", 0))
    found++;
  if (try_docbook_image (name_arg, "png", "PNG", 0))
    found++;
  if (try_docbook_image (name_arg, "svg", "SVG", 0))
    found++;

  /* If no luck so far, just assume we'll eventually have a jpg.  */
  if (!found)
    try_docbook_image (name_arg, "jpg", "JPG", 1);

  xml_insert_text_file (name_arg);
  xml_insert_element (elt, END);

  xml_no_para--;

  if (elt == MEDIAOBJECT)
    xml_insert_element (INFORMALFIGURE, END);
}

void
xml_asterisk (void)
{
}

/*
 *     INDEX
 */
/* Used to separate primary and secondary entries in an index -- we need
   to have real multilivel indexing support, not just string analysis.  */
#define INDEX_SEP "@this string will never appear@" /* was , */

typedef struct
{
  char *from;
  char *to;
} XML_SYNONYM;

static XML_SYNONYM **xml_synonyms = NULL;
static int xml_synonyms_count = 0;

void
xml_insert_indexterm (char *indexterm, char *index)
{
  /* @index commands can appear between @item and @itemx, @deffn and @deffnx.  */
  if (!docbook)
    {
      /* Check to see if we need to do index redirection per @synindex.  */
      int i;
      for (i = 0; i < xml_synonyms_count; i++)
        {
          if (STREQ (xml_synonyms[i]->from, index))
            index = xstrdup (xml_synonyms[i]->to);
        }

      xml_dont_touch_items_defs++;
      xml_insert_element_with_attribute (INDEXTERM, START, "index=\"%s\"", index);
      in_indexterm = 1;
      execute_string ("%s", indexterm);
      xml_insert_element (INDEXTERM, END);
      in_indexterm = 0;
      xml_dont_touch_items_defs--;
    }
  else
    {
      char *primary = NULL, *secondary = NULL;
      if (strstr (indexterm+1, INDEX_SEP))
        {
          primary = xmalloc (strlen (indexterm) + 1);
          strcpy (primary, indexterm);
          secondary = strstr (primary+1, INDEX_SEP);
          *secondary = '\0';
          secondary += strlen (INDEX_SEP);
        }
      xml_insert_element_with_attribute (INDEXTERM, START, "role=\"%s\"", index);
      in_indexterm = 1;
      xml_insert_element (PRIMARY, START);
      if (primary)
        execute_string ("%s", primary);
      else
        execute_string ("%s", indexterm);
      xml_insert_element (PRIMARY, END);
      if (primary)
        {
          xml_insert_element (SECONDARY, START);
          execute_string ("%s", secondary);
          xml_insert_element (SECONDARY, END);
        }
      xml_insert_element (INDEXTERM, END);
      in_indexterm = 0;
    }
}

int xml_last_section_output_position = 0;
static char last_division_letter = ' ';
static char index_primary[2000]; /** xx no fixed limit */
static int indexdivempty = 0;

static void
xml_close_indexentry (void)
{
  if (!in_indexentry)
    return;
  if (in_secondary)
    xml_insert_element (SECONDARYIE, END);
  xml_insert_element (INDEXENTRY, END);
  in_secondary = 0;
  in_indexentry = 0;
}

void
xml_begin_index (void)
{
  if (handling_delayed_writes)
    {
      /* We put <INDEX> */
      xml_insert_element (PRINTINDEX, START);
    }
}

void
xml_end_index (void)
{
  xml_insert_element (PRINTINDEX, END);
}

static void
xml_index_divide (char *entry)
{
  char c;
  if (strlen (entry) > (strlen (xml_element_list[CODE].name) + 2) &&
      strncmp (entry+1, xml_element_list[CODE].name, strlen (xml_element_list[CODE].name)) == 0)
    c = entry[strlen (xml_element_list[CODE].name)+2];
  else
    c = entry[0];
  if (tolower (c) != last_division_letter && isalpha (c))
    {
      last_division_letter = tolower (c);
      xml_close_indexentry ();
      if (!indexdivempty)
        {
          xml_insert_element (INDEXDIV, END);
          xml_insert_element (INDEXDIV, START);
        }
      xml_insert_element (TITLE, START);
      insert (toupper (c));
      xml_insert_element (TITLE, END);
    }
}

void
xml_synindex (char *from, char *to)
{
  int i, slot;

  slot = -1;
  for (i = 0; i < xml_synonyms_count; i++)
    if (!xml_synonyms[i])
      {
        slot = i;
        break;
      }

  if (slot < 0)
    {
      slot = xml_synonyms_count;
      xml_synonyms_count++;

      xml_synonyms = (XML_SYNONYM **) xrealloc (xml_synonyms,
          (xml_synonyms_count + 1) * sizeof (XML_SYNONYM *));
    }

  xml_synonyms[slot] = xmalloc (sizeof (XML_SYNONYM));
  xml_synonyms[slot]->from = xstrdup (from);
  xml_synonyms[slot]->to = xstrdup (to);
}

/*
 * MULTITABLE
 */

static int multitable_columns_count;
static int *multitable_column_widths;

void
xml_begin_multitable (int ncolumns, int *column_widths)
{
  int i;
  if (docbook)
    {
      if (is_in_insertion_of_type (floatenv))
        xml_begin_docbook_float (MULTITABLE);
      else
        xml_insert_element (MULTITABLE, START);

      multitable_columns_count = ncolumns;
      multitable_column_widths = xmalloc (sizeof (int) * ncolumns);
      memcpy (multitable_column_widths, column_widths,
          sizeof (int) * ncolumns);

      xml_no_para = 1;
    }
  else
    {
      xml_insert_element (MULTITABLE, START);
      for (i = 0; i < ncolumns; i++)
        {
          xml_insert_element (COLSPEC, START);
          add_word_args ("%d", column_widths[i]);
          xml_insert_element (COLSPEC, END);
        }
      xml_no_para = 1;
    }
}

static void
xml_begin_multitable_group (void)
{
  int i;

  xml_insert_element_with_attribute (TGROUP, START, "cols=\"%d\"",
      multitable_columns_count);

  for (i = 0; i < multitable_columns_count; i++)
    {
      xml_insert_element_with_attribute (COLSPEC, START,
          "colwidth=\"%d*\"", multitable_column_widths[i]);
      xml_insert_element (COLSPEC, END);
    }
}

void
xml_end_multitable_row (int first_row)
{
  if (!first_row)
    {
      xml_insert_element (ENTRY, END);
      xml_insert_element (ROW, END);
    }

  if (headitem_flag)
    {
      if (!first_row)
        {
          if (after_headitem)
            xml_insert_element (THEAD, END);
          else
            xml_insert_element (TBODY, END);
          xml_insert_element (TGROUP, END);
        }

      xml_begin_multitable_group ();
      xml_insert_element (THEAD, START);
    }
  else if (first_row)
    {
      xml_begin_multitable_group ();
      xml_insert_element (TBODY, START);
    }
  else if (after_headitem)
    {
      xml_insert_element (THEAD, END);
      xml_insert_element (TBODY, START);
    }
  else if (first_row)
    xml_insert_element (TBODY, START);

  xml_insert_element (ROW, START);
  xml_insert_element (ENTRY, START);
}

void
xml_end_multitable_column (void)
{
  xml_insert_element (ENTRY, END);
  xml_insert_element (ENTRY, START);
}

void
xml_end_multitable (void)
{
  xml_insert_element (ENTRY, END);
  xml_insert_element (ROW, END);

  if (after_headitem)
    {
      if (docbook)
        warning (_("@headitem as the last item of @multitable produces invalid Docbook documents"));
      xml_insert_element (THEAD, END);
    }
  else
    xml_insert_element (TBODY, END);

  if (docbook)
    xml_insert_element (TGROUP, END);

  xml_insert_element (MULTITABLE, END);
  xml_no_para = 0;
}

/*
 * Parameters in @def definitions
 */

#define DEFUN_SELF_DELIMITING(c) \
  ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')

void
xml_process_defun_args (char **defun_args, int auto_var_p)
{
  int pending_space = 0;
  int just_after_paramtype = 0;

  for (;;)
    {
      char *defun_arg = *defun_args++;

      if (defun_arg == NULL)
        break;

      if (defun_arg[0] == ' ')
        {
          pending_space = 1;
          continue;
        }

      if (pending_space)
        {
          add_char (' ');
          pending_space = 0;
        }

      if (DEFUN_SELF_DELIMITING (defun_arg[0]))
        {
	  xml_insert_element (DEFDELIMITER, START);
          add_char (defun_arg[0]);
	  xml_insert_element (DEFDELIMITER, END);
	  just_after_paramtype = 0;
        }
      else if (defun_arg[0] == '&')
	{
	  xml_insert_element (DEFPARAM, START);
	  add_word (defun_arg);
	  xml_insert_element (DEFPARAM, END);
	  just_after_paramtype = 0;
	}
      else if (defun_arg[0] == COMMAND_PREFIX || just_after_paramtype)
	{
	  xml_insert_element (DEFPARAM, START);
	  execute_string ("%s", defun_arg);
	  xml_insert_element (DEFPARAM, END);
	  just_after_paramtype = 0;
	}
      else if (defun_arg[0] == ',' || defun_arg[0] == ';')
	{
	  xml_insert_element (DEFDELIMITER, START);
	  add_word (defun_arg);
	  xml_insert_element (DEFDELIMITER, END);
	  just_after_paramtype = 0;
	}
      else if (auto_var_p)
	{
	  xml_insert_element (DEFPARAM, START);
	  add_word (defun_arg);
	  xml_insert_element (DEFPARAM, END);
	  just_after_paramtype = 0;
	}
      else
	{
	  xml_insert_element (DEFPARAMTYPE, START);
	  add_word (defun_arg);
	  xml_insert_element (DEFPARAMTYPE, END);
	  just_after_paramtype = 1;
	}
    }
}

void
xml_begin_definition (void)
{
  xml_insert_element (DEFINITION, START);
  xml_definition_level ++;
  xml_in_def_item[xml_definition_level] = 0;
}

void
xml_end_definition (void)
{
  if (xml_in_def_item[xml_definition_level])
    {
      xml_insert_element (DEFINITIONITEM, END);
      xml_in_def_item[xml_definition_level] = 0;
    }
  xml_after_def_term = 0;
  xml_insert_element (DEFINITION, END);
  xml_definition_level --;
}

void
xml_begin_def_term (int base_type, const char *category,
    char *defined_name, char *type_name, char *type_name2)
{
  xml_after_def_term = 0;
  if (docbook)
    xml_insert_element_with_attribute (DEFINITIONTERM, START,
				       "role=\"%s\"", category);
  else
    xml_insert_element (DEFINITIONTERM, START);

  /* Index entry */
  switch (base_type)
    {
    case deffn:
    case deftypefn:
      execute_string ("@findex %s\n", defined_name);
      break;
    case defvr:
    case deftypevr:
    case defcv:
      execute_string ("@vindex %s\n", defined_name);
      break;
    case deftypecv:
    case deftypeivar:
      execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name);
      break;
    case deftypemethod:
    case defop:
    case deftypeop:
      execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name);
      break;
    case deftp:
      execute_string ("@tindex %s\n", defined_name);
      break;
    }

  /* Start with category.  */
  if (! docbook)
    {
      xml_insert_element (DEFCATEGORY, START);
      execute_string (docbook ? "[%s]" : "%s", category);
      xml_insert_element (DEFCATEGORY, END);
      add_char(' ');
    }

  /* Output type name first for typed definitions.  */
  switch (base_type)
    {
    case deffn:
    case defvr:
    case deftp:
      break;

    case deftypefn:
    case deftypevr:
      xml_insert_element (DEFTYPE, START);
      execute_string ("%s", type_name);
      xml_insert_element (DEFTYPE, END);
      add_char (' ');
      break;

    case deftypecv:
    case deftypeivar:
    case deftypemethod:
    case deftypeop:
      xml_insert_element (DEFTYPE, START);
      execute_string ("%s", type_name2);
      xml_insert_element (DEFTYPE, END);
      add_char (' ');
      break;

    default:
      xml_insert_element (DEFCLASS, START);
      execute_string ("%s", type_name);
      xml_insert_element (DEFCLASS, END);
      add_char (' ');
      break;
    }

  /* Categorize rest of the definitions.  */
  switch (base_type)
    {
    case deffn:
    case deftypefn:
      xml_insert_element (DEFFUNCTION, START);
      execute_string ("%s", defined_name);
      xml_insert_element (DEFFUNCTION, END);
      break;

    case defvr:
    case deftypevr:
      xml_insert_element (DEFVARIABLE, START);
      execute_string ("%s", defined_name);
      xml_insert_element (DEFVARIABLE, END);
      break;

    case deftp:
      xml_insert_element (DEFDATATYPE, START);
      execute_string ("%s", defined_name);
      xml_insert_element (DEFDATATYPE, END);
      break;

    case defcv:
    case deftypecv:
    case deftypeivar:
      xml_insert_element (DEFCLASSVAR, START);
      execute_string ("%s", defined_name);
      xml_insert_element (DEFCLASSVAR, END);
      break;

    case defop:
    case deftypeop:
    case deftypemethod:
      /* Operation / Method */
      xml_insert_element (DEFOPERATION, START);
      execute_string ("%s", defined_name);
      xml_insert_element (DEFOPERATION, END);
      break;
    }
}

void
xml_end_def_term (void)
{
  xml_insert_element (DEFINITIONTERM, END);
  xml_after_def_term = 1;
}


code:
/* xml.h -- xml (including Docbook) output declarations.
   $Id: xml.h,v 1.33 2011-04-06 21:32:42 gray Exp $

   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008
   Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   Originally written by Philippe Martin <feloy@free.fr>.  */

#ifndef XML_H
#define XML_H

/* Currently sorting the index. */
extern int xml_sort_index;

/* Options. */

extern int xml_no_indent;

extern int xml_node_open;
extern int xml_no_para;
extern char *xml_node_id;
extern int xml_last_section_output_position;

extern int xml_in_xref_token;
extern int xml_in_bookinfo;
extern int xml_in_book_title;
extern int xml_in_abstract;

/* Non-zero if we are handling an element that can appear between
   @item and @itemx, @deffn and @deffnx.  */
extern int xml_dont_touch_items_defs;

/* Non-zero if whitespace in the source document should be kept as-is.  */
extern int xml_keep_space;

enum xml_element
{
  TEXINFO=0, SETFILENAME, TITLEFONT, SETTITLE, DOCUMENTDESCRIPTION,
  /* Node */
  NODE, NODENEXT, NODEPREV, NODEUP,
  /* Structuring */
  CHAPTER, SECTION, SUBSECTION, SUBSUBSECTION,
  TOP, UNNUMBERED, UNNUMBEREDSEC, UNNUMBEREDSUBSEC,
    UNNUMBEREDSUBSUBSEC,
  APPENDIX, APPENDIXSEC, APPENDIXSUBSEC, APPENDIXSUBSUBSEC,
  MAJORHEADING, CHAPHEADING, HEADING, SUBHEADING, SUBSUBHEADING,
  /* Titlepage */
  TITLEPAGE, AUTHOR, BOOKTITLE, BOOKSUBTITLE,
  /* Menu */
  MENU, DETAILMENU, MENUENTRY, MENUTITLE, MENUCOMMENT, MENUNODE,
  NODENAME,
  /* -- */
  ACRONYM, ACRONYMWORD, ACRONYMDESC,
  ABBREV, ABBREVWORD, ABBREVDESC,
  TT, CODE, COMMAND_TAG, ENV, FILE_TAG, OPTION, SAMP, KBD, URL, KEY,
  VAR, SC, DFN, EMPH, STRONG, CITE, NOTFIXEDWIDTH, I, B, R, SLANTED, SANSSERIF,
  EXDENT,
  TITLE,
  IFINFO,
  SP, CENTER,
  DIRCATEGORY,
  QUOTATION, EXAMPLE, SMALLEXAMPLE, LISP, SMALLLISP, CARTOUCHE,
    COPYING, FORMAT, SMALLFORMAT, DISPLAY, SMALLDISPLAY, VERBATIM,
  FOOTNOTE, LINEANNOTATION,
  TIP, NOTE, IMPORTANT, WARNING, CAUTION,
  ITEMIZE, ITEMFUNCTION, ITEM, ENUMERATE, TABLE, TABLEITEM, TABLETERM,
  INDEXTERM,
  MATH, DIMENSION,
  CLICKSEQUENCE, CLICK,
  XREF, XREFNODENAME, XREFINFONAME, XREFPRINTEDDESC, XREFINFOFILE,
    XREFPRINTEDNAME,
  INFOREF, INFOREFNODENAME, INFOREFREFNAME, INFOREFINFONAME,
  UREF, UREFURL, UREFDESC, UREFREPLACEMENT,
  EMAIL, EMAILADDRESS, EMAILNAME,
  GROUP, FLOAT, FLOATTYPE, FLOATPOS, CAPTION, SHORTCAPTION,
  FLOATTABLE, FLOATFIGURE, FLOATEXAMPLE, FLOATCARTOUCHE,
  PRINTINDEX, LISTOFFLOATS,
  ANCHOR,
  IMAGE, INLINEIMAGE, IMAGEALTTEXT,
  PRIMARY, SECONDARY, INFORMALFIGURE, MEDIAOBJECT, IMAGEOBJECT,
    IMAGEDATA, TEXTOBJECT,
  INDEXENTRY, PRIMARYIE, SECONDARYIE, INDEXDIV,
  MULTITABLE, TGROUP, COLSPEC, THEAD, TBODY, ENTRY, ROW,
  BOOKINFO, ABSTRACT, REPLACEABLE, ENVAR, COMMENT, FUNCTION, LEGALNOTICE,
  CONTENTS, SHORTCONTENTS, DOCUMENTLANGUAGE,
  SETVALUE, CLEARVALUE,
  DEFINITION, DEFINITIONTERM, DEFINITIONITEM,
  DEFCATEGORY, DEFFUNCTION, DEFVARIABLE, DEFPARAM, DEFDELIMITER, DEFTYPE,
  DEFPARAMTYPE, DEFDATATYPE, DEFCLASS, DEFCLASSVAR, DEFOPERATION,
  FRENCHSPACING,
  PARA
};

extern void xml_add_char (int character),
  xml_asterisk (void),
  xml_insert_element (int elt, int arg),
  xml_insert_entity (char *entity_name),
  xml_insert_footnote (char *note),
  xml_insert_quotation (char *type, int arg),
  xml_insert_indexterm (char *indexterm, char *index),
  xml_insert_docbook_image (char *name_arg),
  xml_synindex (char *from, char *to),
  xml_start_para (void),
  xml_end_para (void),
  xml_begin_document (const char *output_basename),
  xml_end_document (void),
  xml_start_menu_entry (char *tem),
  xml_end_menu (void),
  xml_end_current_element (void),
  xml_open_section (int level, char *name),
  xml_close_sections (int level),
  xml_begin_node (void),
  xml_begin_index (void),
  xml_end_index (void),
  xml_begin_multitable (int ncolumns, int *column_widths),
  xml_end_multitable (void),
  xml_end_multitable_row (int first_row),
  xml_end_multitable_column (void),
  xml_begin_table (int type, char *item_function),
  xml_end_table (int type),
  xml_begin_item (void),
  xml_begin_table_item (void),
  xml_continue_table_item (void),
  xml_begin_enumerate (char *enum_arg),
  xml_end_enumerate (void),
  xml_begin_docbook_float (int elt);

extern char *xml_id (char *id);

extern void xml_begin_definition (void),
  xml_end_definition (void),
  xml_process_defun_args (char **defun_args, int auto_var_p),
  xml_begin_def_term (int base_type, const char *category,
      char *defined_name, char *type_name, char *type_name2),
  xml_end_def_term (void);

extern int xml_current_stack_index (void),
  xml_element (char *name);

void xml_insert_element_with_attribute (int elt, int arg, char *format, ...)
  TEXINFO_PRINTFLIKE(3,4);

#endif /* XML_H */

repo_name: mthl/texinfo

license: mit


code:
/* xref.c -- cross references for Texinfo.
   $Id: xref.c,v 1.14 2007-09-26 20:53:40 karl Exp $

   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include "system.h"
#include "cmds.h"
#include "float.h"
#include "html.h"
#include "index.h"
#include "macro.h"
#include "makeinfo.h"
#include "node.h"
#include "xml.h"
#include "xref.h"

/* Flags which control initial output string for xrefs. */
int px_ref_flag = 0;
int ref_flag = 0;

/* Called in the multiple-argument case to make sure we generate a valid
   Info reference.  In the single-argument case, the :: we output
   suffices for the Info readers to find the end of the reference.  */
static void
add_xref_punctuation (void)
{
  if (px_ref_flag || ref_flag)  /* user inserts punct after @xref */
    {
      /* Check if there's already punctuation.  */
      int next_char = next_nonwhitespace_character ();

      if (next_char == -1)
        /* EOF while looking for punctuation, let's
           insert a period instead of crying.  */
        add_char ('.');
      else if (next_char != ',' && next_char != '.')
        /* period and comma terminate xrefs, and nothing else.  Instead
           of generating an Info reference that can't be followed,
           though, just insert a period.  Not pretty, but functional.  */
        add_char ('.');
    }
}

/* Return next comma-delimited argument, but do not cross a close-brace
   boundary.  Clean up whitespace, too.  If EXPAND is nonzero, replace
   the entire brace-delimited argument list with its expansion before
   looking for the next comma.  */
char *
get_xref_token (int expand)
{
  char *string = 0;

  if (docbook)
    xml_in_xref_token = 1;

  if (expand)
    {
      int old_offset = input_text_offset;
      int old_lineno = line_number;

      get_until_in_braces ("}", &string);
      if (curchar () == '}')    /* as opposed to end of text */
        input_text_offset++;
      if (input_text_offset > old_offset)
        {
          int limit = input_text_offset;

          input_text_offset = old_offset;
          line_number = old_lineno;
          only_macro_expansion++;
          replace_with_expansion (input_text_offset, &limit);
          only_macro_expansion--;
        }
      free (string);
    }

  get_until_in_braces (",", &string);
  if (curchar () == ',')
    input_text_offset++;
  fix_whitespace (string);

  if (docbook)
    xml_in_xref_token = 0;

  return string;
}

/* NOTE: If you wonder why the HTML output is produced with such a
   peculiar mix of calls to add_word and execute_string, here's the
   reason.  get_xref_token (1) expands all macros in a reference, but
   any other commands, like @value, @@, etc., are left intact.  To
   expand them, we need to run the arguments through execute_string.
   However, characters like <, &, > and others cannot be let into
   execute_string, because they will be escaped.  See the mess?  */

/* Make a cross reference. */
void
cm_xref (int arg)
{
  if (arg == START)
    {
      char *arg1 = get_xref_token (1); /* expands all macros in xref */
      char *arg2 = get_xref_token (0);
      char *arg3 = get_xref_token (0);
      char *arg4 = get_xref_token (0);
      char *arg5 = get_xref_token (0);
      char *tem;

      /* "@xref{,Foo,, Bar, Baz} is not valid usage of @xref.  The
         first argument must never be blank." --rms.
         We hereby comply by disallowing such constructs.  */
      if (!*arg1)
        line_error (_("First argument to cross-reference may not be empty"));

      if (docbook)
        {
          if (!ref_flag)
            add_word (px_ref_flag || printing_index
                ? (char *) gdt("see ") : (char *) gdt("See "));

          if (!*arg4 && !*arg5)
            {
              char *arg1_id = xml_id (arg1);

              if (*arg2 || *arg3)
                {
                  xml_insert_element_with_attribute (XREFNODENAME, START,
                                                     "linkend=\"%s\"", arg1_id);
                  free (arg1_id);
                  execute_string ("%s", *arg3 ? arg3 : arg2);
                  xml_insert_element (XREFNODENAME, END);
                }
              else
                {
                  xml_insert_element_with_attribute (XREF, START,
                                                     "linkend=\"%s\"", arg1_id);
                  xml_insert_element (XREF, END);
                  free (arg1_id);
                }
            }
          else if (*arg5)
            {
              add_word_args (gdt("See section ``%s'' in "), *arg3 ? arg3 : arg1);
              xml_insert_element (CITE, START);
              add_word (arg5);
              xml_insert_element (CITE, END);
            }
          else if (*arg4)
            {
              /* Very sad, we are losing xrefs made to ``info only'' books.  */
            }
        }
      else if (xml)
        {
          if (!ref_flag)
            add_word_args ("%s", px_ref_flag ? gdt("see ") : gdt("See "));

          xml_insert_element (XREF, START);
          xml_insert_element (XREFNODENAME, START);
          execute_string ("%s", arg1);
          xml_insert_element (XREFNODENAME, END);
          if (*arg2)
            {
              xml_insert_element (XREFINFONAME, START);
              execute_string ("%s", arg2);
              xml_insert_element (XREFINFONAME, END);
            }
          if (*arg3)
            {
              xml_insert_element (XREFPRINTEDDESC, START);
              execute_string ("%s", arg3);
              xml_insert_element (XREFPRINTEDDESC, END);
            }
          if (*arg4)
            {
              xml_insert_element (XREFINFOFILE, START);
              execute_string ("%s", arg4);
              xml_insert_element (XREFINFOFILE, END);
            }
          if (*arg5)
            {
              xml_insert_element (XREFPRINTEDNAME, START);
              execute_string ("%s", arg5);
              xml_insert_element (XREFPRINTEDNAME, END);
            }
          xml_insert_element (XREF, END);
        }
      else if (html)
        {
          if (!ref_flag)
            add_word_args ("%s", px_ref_flag ? gdt("see ") : gdt("See "));
        }
      else
        add_word_args ("%s", px_ref_flag || ref_flag ? "*note " : "*Note ");

      if (!xml)
        {
          if (*arg5 || *arg4)
            {
              /* arg1 - node name
                 arg2 - reference name
                 arg3 - title or topic (and reference name if arg2 is NULL)
                 arg4 - info file name
                 arg5 - printed manual title  */
              char *ref_name;

              if (!*arg2)
                {
                  if (*arg3)
                    ref_name = arg3;
                  else
                    ref_name = arg1;
                }
              else
                ref_name = arg2;

              if (html)
                { /* More to do eventually, down to Unicode
                     Normalization Form C.  See the HTML Xref nodes in
                     the manual.  */
                  char *file_arg = arg4;
                  add_html_elt ("<a href=");

                  {
                    /* If there's a directory part, ignore it.  */
                    char *p = strrchr (file_arg, '/');
                    if (p)
                      file_arg = p + 1;

                  /* If there's a dot, make it a NULL terminator, so the
                     extension does not get into the way.  */
                    p = strrchr (file_arg , '.');
                    if (p != NULL)
                      *p = 0;
                  }

                  if (! *file_arg)
                warning (_("Empty file name for HTML cross reference in `%s'"),
                           arg4);

                  /* Note that if we are splitting, and the referenced
                     tag is an anchor rather than a node, we will
                     produce a reference to a file whose name is
                     derived from the anchor name.  However, only
                     nodes create files, so we are referencing a
                     non-existent file.  cm_anchor, which see, deals
                     with that problem.  */
                  if (splitting)
                    execute_string ("\"../%s/", file_arg);
                  else
                    execute_string ("\"%s.html", file_arg);
                  /* Do not collapse -- to -, etc., in references.  */
                  in_fixed_width_font++;
                  tem = expansion (arg1, 0); /* expand @-commands in node */
                  in_fixed_width_font--;
                  add_anchor_name (tem, 1);
                  free (tem);
                  add_word ("\">");
                  execute_string ("%s",ref_name);
                  add_word ("");
                }
              else
                {
                  execute_string ("%s:", ref_name);
                  in_fixed_width_font++;
                  execute_string (" (%s)%s", arg4, arg1);
                  add_xref_punctuation ();
                  in_fixed_width_font--;
                }

              /* Free all of the arguments found. */
              if (arg1) free (arg1);
              if (arg2) free (arg2);
              if (arg3) free (arg3);
              if (arg4) free (arg4);
              if (arg5) free (arg5);
              return;
            }
          else
            remember_node_reference (arg1, line_number, followed_reference);

          if (*arg3)
            {
              if (html)
                {
                  add_html_elt ("");
                  execute_string ("%s", *arg2 ? arg2 : arg3);
                  add_word ("");
                }
              else
                {
                  execute_string ("%s:", *arg2 ? arg2 : arg3);
                  in_fixed_width_font++;
                  execute_string (" %s", arg1);
                  add_xref_punctuation ();
                  in_fixed_width_font--;
                }
            }
          else
            {
              if (html)
                {
                  add_html_elt ("");
                  if (*arg2)
                    execute_string ("%s", arg2);
                  else
                    {
                      char *fref = get_float_ref (arg1);
                      execute_string ("%s", fref ? fref : arg1);
                      free (fref);
                    }
                  add_word ("");
                }
              else
                {
                  if (*arg2)
                    {
                      execute_string ("%s:", arg2);
                      in_fixed_width_font++;
                      execute_string (" %s", arg1);
                      add_xref_punctuation ();
                      in_fixed_width_font--;
                    }
                  else
                    {
                      char *fref = get_float_ref (arg1);
                      if (fref)
                        { /* Reference is being made to a float.  */
                          execute_string ("%s:", fref);
                          in_fixed_width_font++;
                          execute_string (" %s", arg1);
                          add_xref_punctuation ();
                          in_fixed_width_font--;
                        }
                      else
                        {
                          in_fixed_width_font++;
                          execute_string ("%s::", arg1);
                          in_fixed_width_font--;
                        }
                    }
                }
            }
        }
      /* Free all of the arguments found. */
      if (arg1) free (arg1);
      if (arg2) free (arg2);
      if (arg3) free (arg3);
      if (arg4) free (arg4);
      if (arg5) free (arg5);
    }
  else
    { /* Check that the next non-whitespace character is valid to follow
         an xref (so Info readers can find the node names).
         `input_text_offset' is pointing at the "}" which ended the xref
         command.  This is not used for @pxref or @ref, since we insert
         the necessary punctuation above, if needed.  */
      int temp = next_nonwhitespace_character ();

      if (temp == -1)
        warning (_("End of file reached while looking for `.' or `,'"));
      else if (temp != '.' && temp != ',')
        {
          warning (_("`.' or `,' must follow @%s, not `%c'"), command, temp);
          if (temp == ')')
            warning (_("for cross-references in parentheses, use @pxref"));
        }
    }
}

void
cm_pxref (int arg)
{
  if (arg == START)
    {
      px_ref_flag++;
      cm_xref (arg);
      px_ref_flag--;
    }
  /* cm_xref isn't called with arg == END, which disables the code near
     the end of cm_xref that checks for `.' or `,' after the
     cross-reference.  This is because cm_xref generates the required
     character itself (when needed) if px_ref_flag is set.  */
}

void
cm_ref (int arg)
{
  /* See the comments in cm_pxref about the checks for punctuation.  */
  if (arg == START)
    {
      ref_flag++;
      cm_xref (arg);
      ref_flag--;
    }
}

void
cm_inforef (int arg)
{
  if (arg == START)
    {
      char *node = get_xref_token (1); /* expands all macros in inforef */
      char *pname = get_xref_token (0);
      char *file = get_xref_token (0);

      /* (see comments at cm_xref).  */
      if (!*node)
        line_error (_("First argument to @inforef may not be empty"));

      if (xml && !docbook)
        {
          xml_insert_element (INFOREF, START);
          xml_insert_element (INFOREFNODENAME, START);
          execute_string ("%s", node);
          xml_insert_element (INFOREFNODENAME, END);
          if (*pname)
            {
              xml_insert_element (INFOREFREFNAME, START);
              execute_string ("%s", pname);
              xml_insert_element (INFOREFREFNAME, END);
            }
          xml_insert_element (INFOREFINFONAME, START);
          execute_string ("%s", file);
          xml_insert_element (INFOREFINFONAME, END);

          xml_insert_element (INFOREF, END);
        }
      else if (html)
        {
          char *tem;

          add_word ((char *) gdt("see "));
          /* html fixxme: revisit this */
          add_html_elt ("");
          execute_string ("%s", *pname ? pname : tem);
          add_word ("");
          free (tem);
        }
      else
        {
          if (*pname)
            execute_string ("*note %s: (%s)%s", pname, file, node);
          else
            execute_string ("*note (%s)%s::", file, node);
        }

      free (node);
      free (pname);
      free (file);
    }
}

/* A URL reference.  */
void
cm_uref (int arg)
{
  if (arg == START)
    {
      char *url  = get_xref_token (1); /* expands all macros in uref */
      char *desc = get_xref_token (0);
      char *replacement = get_xref_token (0);

      if (docbook)
        {
          xml_insert_element_with_attribute (UREF, START, "url=\"%s\"",
					     maybe_escaped_expansion (url, 0, 1));
          if (*replacement)
            execute_string ("%s", replacement);
          else if (*desc)
            execute_string ("%s", desc);
          else
            execute_string ("%s", url);
          xml_insert_element (UREF, END);
        }
      else if (xml)
        {
          xml_insert_element (UREF, START);
          xml_insert_element (UREFURL, START);
          execute_string ("%s", url);
          xml_insert_element (UREFURL, END);
          if (*desc)
            {
              xml_insert_element (UREFDESC, START);
              execute_string ("%s", desc);
              xml_insert_element (UREFDESC, END);
            }
          if (*replacement)
            {
              xml_insert_element (UREFREPLACEMENT, START);
              execute_string ("%s", replacement);
              xml_insert_element (UREFREPLACEMENT, END);
            }
          xml_insert_element (UREF, END);
        }
      else if (html)
        { /* never need to show the url */
          add_html_elt ("");
          execute_string ("%s", *replacement ? replacement
                                : (*desc ? desc : url));
          add_word ("");
        }
      else if (*replacement) /* do not show the url */
        execute_string ("%s", replacement);
      else if (*desc)        /* show both text and url */
        {
          execute_string ("%s ", desc);
          in_fixed_width_font++;
          execute_string ("(%s)", url);
          in_fixed_width_font--;
        }
      else /* no text at all, so have the url to show */
        {
          in_fixed_width_font++;
          execute_string ("%s%s%s",
                          printing_index ? "" : "`",
                          url,
                          printing_index ? "" : "'");
          in_fixed_width_font--;
        }
      if (url)
        free (url);
      if (desc)
        free (desc);
      if (replacement)
        free (replacement);
    }
}

/* An email reference.  */
void
cm_email (int arg)
{
  if (arg == START)
    {
      char *addr = get_xref_token (1); /* expands all macros in email */
      char *name = get_xref_token (0);

      if (xml && docbook)
        {
	  if (*name)
	    {
	      xml_insert_element_with_attribute (EMAIL, START,
						 "url=\"mailto:%s\"",
						 maybe_escaped_expansion (addr, 0, 1));
              execute_string ("%s", name);
	      xml_insert_element (EMAIL, END);
	    }
	  else
	    {
	      xml_insert_element (EMAILADDRESS, START);
	      execute_string ("%s", addr);
	      xml_insert_element (EMAILADDRESS, END);
	    }
        }
      else if (xml)
        {
          xml_insert_element (EMAIL, START);
          xml_insert_element (EMAILADDRESS, START);
          execute_string ("%s", addr);
          xml_insert_element (EMAILADDRESS, END);
          if (*name)
            {
              xml_insert_element (EMAILNAME, START);
              execute_string ("%s", name);
              xml_insert_element (EMAILNAME, END);
            }
          xml_insert_element (EMAIL, END);
        }
      else if (html)
        {
          add_html_elt ("");
          execute_string ("%s", *name ? name : addr);
          add_word ("");
        }
      else
        {
          execute_string ("%s%s", name, *name ? " "  : "");
          in_fixed_width_font++;
          execute_string ("<%s>", addr);
          in_fixed_width_font--;
        }

      if (addr)
        free (addr);
      if (name)
        free (name);
    }
}


code:
/* xref.h -- declarations for the cross references.
   $Id: xref.h,v 1.4 2007-07-01 21:20:33 karl Exp $

   Copyright (C) 2004, 2007 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef XREF_H
#define XREF_H

enum reftype
{
  menu_reference, followed_reference
};

extern char *get_xref_token (int expand);

#endif /* not XREF_H */


code:
/* Setting environment variables, with out-of-memory checking.
   Copyright (C) 2001-2002, 2005-2007, 2009-2013 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include <config.h>

/* Specification.  */
#include "xsetenv.h"

#include <stdlib.h>

#include "error.h"
#include "gettext.h"

#define _(str) gettext (str)

/* Set NAME to VALUE in the environment.
   If REPLACE is nonzero, overwrite an existing value.
   With error checking.  */
void
xsetenv (const char *name, const char *value, int replace)
{
  if (setenv (name, value, replace) < 0)
    error (EXIT_FAILURE, 0, _("memory exhausted"));
}


code:
/* Setting environment variables, with out-of-memory checking.
   Copyright (C) 2001-2002, 2007, 2009-2013 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* Get unsetenv().  It can be used without error checking.  */
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Set NAME to VALUE in the environment.
   If REPLACE is nonzero, overwrite an existing value.
   With error checking.  */
extern void xsetenv (const char *name, const char *value, int replace);

#ifdef __cplusplus
}
#endif


code:
# $Id$
# Makefile.am for texinfo/man.
#
# Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
# 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# These are generated using help2man.
man_MANS = install-info.1 makeinfo.1 texindex.1 texi2dvi.1

# These require the build in info/, thus can't do if we failed to find a
# terminal library.
if HAVE_TERMLIBS
man_MANS += info.1
endif

# These are hand-written.
man_MANS += info.5 texinfo.5

# This is generated by pod2man, but let's just run it by hand.
man_MANS += pod2texi.1

# These are just .so's to the common program.
man_MANS += texi2any.1 texi2pdf.1 pdftexi2dvi.1

EXTRA_DIST = $(man_MANS) ginfo.h2m

# Maintainers should be able to regenerate.
MAINTAINERCLEANFILES = $(man_MANS)

#
# Use the programs built in our distribution, taking account of possible
# cross-compiling.  makeinfo needs a bunch of our included modules.
tpdir = $(top_srcdir)/tp
MAKEINFO_ENVIRONMENT = TEXINFO_DEV_SOURCE=1 ; export TEXINFO_DEV_SOURCE ; \
                       top_srcdir="$(top_srcdir)" ; export top_srcdir ; \
                       top_builddir="$(top_builddir)" ; export top_builddir ;

MAKEINFO = $(MAKEINFO_ENVIRIONMENT) $(PERL) "$(tpdir)"/texi2any.pl
#
mi_env = \
  TEXINFO_DEV_SOURCE=1; export TEXINFO_DEV_SOURCE; ${MAKEINFO_ENVIRONMENT}

# Set up the variables.  makeinfo, texindex are no longer a .exe(cutable).
man_rule_0 = \
  exe_ext="$(EXEEXT)" \
  && program=`expr '/$@' : '.*/\(.*\)\.1'` \
  && case $$program in \
         makeinfo) dir=tp; $(mi_env) exe_ext="";; \
            info*) dir=info; test $$program != info || program=g$$program;; \
    *install-info) dir=install-info; program=g$$program;; \
        *texindex) dir=texindex; exe_ext="";; \
                *) dir=util;; esac \
  && dir="$(top_builddir)/$(native_tools)/$$dir" \
  && h2m="$(srcdir)/$$program.h2m"

# Update the man page for a binary program; set up the variables,
# make sure the binary is up-to-date and then generate the man page.
man_rule_bin = echo "Updating man page $@" \
  && $(man_rule_0) \
  && echo cd "$$dir" '&&' $(MAKE) $(AM_MAKEFLAGS) $$program$$exe_ext \
  &&     (cd "$$dir"  &&  $(MAKE) $(AM_MAKEFLAGS) $$program$$exe_ext) \
  && echo $(HELP2MAN) --name=\""$$name"\" -I "$$h2m" "$$dir/$$program" -o '$@'\
  &&      $(HELP2MAN) --name="$$name"     -I "$$h2m" "$$dir/$$program" -o '$@'

# Using help2man depends on the package version number.
common_mandeps = $(top_srcdir)/configure.ac

# for Info, we have an additional help2man file since the standard
# SEE ALSO text from help2man does not fit.
info.1: $(top_srcdir)/info/info.c $(srcdir)/ginfo.h2m \
                  $(common_mandeps)
	@name="read Info documents" && $(man_rule_bin)

install-info.1: $(top_srcdir)/install-info/install-info.c \
                          $(common_mandeps)
	@name="update info/dir entries" && $(man_rule_bin)

# Here we need some postprocessing to avoid man misformatting.
makeinfo.1: $(tpdir)/texi2any.pl $(common_mandeps)
	@name="translate Texinfo documents" && $(man_rule_bin)
	mv $@ $@.tmp
	sed '/^\.IP$$/N;/\nAlso/s/I//;/\nThe/s/I//' $@.tmp >$@
	rm $@.tmp

texindex.1: $(top_srcdir)/texindex/ti.twjr $(common_mandeps)
	@name="sort Texinfo index files" && $(man_rule_bin)

#
# For texi2dvi, do not depend on the current user's settings.
texi2dvi_envvars = unset TEXI2DVI_BUILD_MODE; unset TEXI2DVI_BUILD_DIRECTORY

texi2dvi.1: $(top_srcdir)/util/texi2dvi $(common_mandeps)
	$(texi2dvi_envvars); $(HELP2MAN) \
	  --name="convert Texinfo documents to DVI or PDF" \
	  $(top_srcdir)/util/texi2dvi >$@


code:
# $Id$
# Additional section for the info man page.
# Copyright 2011 Free Software Foundation, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.

[SEE ALSO]
The full documentation for
.B info
is maintained as a Texinfo manual.  If the
.B info
program is properly installed at your site, the command
.IP
.B info info
.PP
should give you access to the complete manual.
(Or, if you have Emacs, M-x info will lead to the manual.)


code:
.\" info(5)
.\" $Id$
.\"
.\" Copyright 1998, 2005, 2011 Free Software Foundation, Inc.
.\"
.\" Copying and distribution of this file, with or without modification,
.\" are permitted in any medium without royalty provided the copyright
.\" notice and this notice are preserved.
.\"
.de EX
.nf
.ft CW
.in +5
..
.de EE
.in -5
.ft R
.fi
..
.TH INFO 5 "GNU Info" "FSF"
.SH NAME
info \- readable online documentation
.SH DESCRIPTION
The Info file format is an easily-parsable representation for online
documents.  It can be read by
.I emacs(1)
and
.I info(1)
among other programs.
.PP
Info files are usually created from
.I texinfo(5)
sources by
.IR makeinfo(1) ,
but can be created from scratch if so desired.
.PP
For a full description of the Texinfo language and associated tools,
please see the Texinfo manual (written in Texinfo itself).  Most likely,
running this command from your shell:
.EX
info texinfo
.EE
or this key sequence from inside Emacs:
.EX
M-x info RET m texinfo RET
.EE
will get you there.
.SH AVAILABILITY
http://www.gnu.org/software/texinfo/
.SH "REPORTING BUGS"
Please send bug reports to bug-texinfo@gnu.org,
general questions and discussion to help-texinfo@gnu.org.
.SH "SEE ALSO"
info(1), install-info(1), makeinfo(1), texi2dvi(1),
.br
texindex(1).
.br
emacs(1), tex(1).
.br
texinfo(5).