1/* xml.c -- xml output.
2   $Id: xml.c,v 1.52 2004/12/19 17:02:23 karl Exp $
3
4   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20   Originally written by Philippe Martin <feloy@free.fr>.  */
21
22#include "system.h"
23#include "makeinfo.h"
24#include "insertion.h"
25#include "files.h"
26#include "float.h"
27#include "macro.h"
28#include "cmds.h"
29#include "lang.h"
30
31#include "xml.h"
32
33/* Options */
34int xml_index_divisions = 1;
35
36typedef struct _element
37{
38  char name[32];
39  int contains_para;
40  int contained_in_para;
41  int keep_space;
42} element;
43
44element texinfoml_element_list [] = {
45  { "texinfo",             1, 0, 0 },
46  { "setfilename",         0, 0, 0 },
47  { "titlefont",           0, 0, 0 },
48  { "settitle",            0, 0, 0 },
49  { "documentdescription", 1, 0, 0 },
50
51  { "node",                1, 0, 0 },
52  { "nodenext",            0, 0, 0 },
53  { "nodeprev",            0, 0, 0 },
54  { "nodeup",              0, 0, 0 },
55
56  { "chapter",             1, 0, 0 },
57  { "section",             1, 0, 0 },
58  { "subsection",          1, 0, 0 },
59  { "subsubsection",       1, 0, 0 },
60
61  { "top",                 1, 0, 0 },
62  { "unnumbered",          1, 0, 0 },
63  { "unnumberedsec",       1, 0, 0 },
64  { "unnumberedsubsec",    1, 0, 0 },
65  { "unnumberedsubsubsec", 1, 0, 0 },
66
67  { "appendix",            1, 0, 0 },
68  { "appendixsec",         1, 0, 0 },
69  { "appendixsubsec",      1, 0, 0 },
70  { "appendixsubsubsec",   1, 0, 0 },
71
72  { "majorheading",        0, 0, 0 },
73  { "chapheading",         0, 0, 0 },
74  { "heading",             0, 0, 0 },
75  { "subheading",          0, 0, 0 },
76  { "subsubheading",       0, 0, 0 },
77
78  { "titlepage",           1, 0, 0 },
79  { "author",              0, 0, 0 },
80  { "booktitle",           0, 0, 0 },
81  { "booksubtitle",        0, 0, 0 },
82
83  { "menu",                1, 0, 0 },
84  { "detailmenu",          1, 0, 0 },
85  { "menuentry",           0, 0, 0 },
86  { "menutitle",           0, 0, 0 },
87  { "menucomment",         0, 0, 0 },
88  { "menunode",            0, 0, 0 },
89  { "nodename",            0, 0, 0 },
90
91  { "acronym",             0, 1, 0 },
92  { "acronymword",         0, 1, 0 },
93  { "acronymdesc",         0, 1, 0 },
94
95  { "abbrev",              0, 1, 0 },
96  { "abbrevword",          0, 1, 0 },
97  { "abbrevdesc",          0, 1, 0 },
98
99  { "tt",                  0, 1, 0 },
100  { "code",                0, 1, 0 },
101  { "command",             0, 1, 0 },
102  { "env",                 0, 1, 0 },
103  { "file",                0, 1, 0 },
104  { "option",              0, 1, 0 },
105  { "samp",                0, 1, 0 },
106  { "kbd",                 0, 1, 0 },
107  { "url",                 0, 1, 0 },
108  { "key",                 0, 1, 0 },
109  { "var",                 0, 1, 0 },
110  { "sc",                  0, 1, 0 },
111  { "dfn",                 0, 1, 0 },
112  { "emph",                0, 1, 0 },
113  { "strong",              0, 1, 0 },
114  { "cite",                0, 1, 0 },
115  { "notfixedwidth",       0, 1, 0 },
116  { "i",                   0, 1, 0 },
117  { "b",                   0, 1, 0 },
118  { "r",                   0, 1, 0 },
119  { "slanted",             0, 1, 0 },
120  { "sansserif",           0, 1, 0 },
121
122  { "exdent",              0, 0, 0 },
123
124  { "title",               0, 0, 0 },
125  { "ifinfo",              1, 0, 0 },
126  { "sp",                  0, 0, 0 },
127  { "center",              1, 0, 0 },
128  { "dircategory",         0, 0, 0 },
129  { "quotation",           1, 0, 0 },
130  { "example",             0, 0, 1 },
131  { "smallexample",        0, 0, 1 },
132  { "lisp",                0, 0, 1 },
133  { "smalllisp",           0, 0, 1 },
134  { "cartouche",           1, 0, 0 },
135  { "copying",             1, 0, 0 },
136  { "format",              0, 0, 1 },
137  { "smallformat",         0, 0, 1 },
138  { "display",             0, 0, 1 },
139  { "smalldisplay",        0, 0, 1 },
140  { "verbatim",            0, 0, 1 },
141  { "footnote",            0, 1, 0 },
142  { "",                    0, 1, 0 }, /* LINEANNOTATION (docbook) */
143
144  { "",                    1, 0, 0 }, /* TIP (docbook)       */
145  { "",                    1, 0, 0 }, /* NOTE (docbook)      */
146  { "",                    1, 0, 0 }, /* IMPORTANT (docbook) */
147  { "",                    1, 0, 0 }, /* WARNING (docbook)   */
148  { "",                    1, 0, 0 }, /* CAUTION (docbook)   */
149
150  { "itemize",             0, 0, 0 },
151  { "itemfunction",        0, 0, 0 },
152  { "item",                1, 0, 0 },
153  { "enumerate",           0, 0, 0 },
154  { "table",               0, 0, 0 },
155  { "tableitem",           0, 0, 0 },
156  { "tableterm",           0, 0, 0 },
157
158  { "indexterm",           0, 1, 0 },
159
160  { "math",                0, 1, 0 },
161
162  { "dmn",                 0, 1, 0 },
163
164  { "xref",                0, 1, 0 },
165  { "xrefnodename",        0, 1, 0 },
166  { "xrefinfoname",        0, 1, 0 },
167  { "xrefprinteddesc",     0, 1, 0 },
168  { "xrefinfofile",        0, 1, 0 },
169  { "xrefprintedname",     0, 1, 0 },
170
171  { "inforef",             0, 1, 0 },
172  { "inforefnodename",     0, 1, 0 },
173  { "inforefrefname",      0, 1, 0 },
174  { "inforefinfoname",     0, 1, 0 },
175
176  { "uref",                0, 1, 0 },
177  { "urefurl",             0, 1, 0 },
178  { "urefdesc",            0, 1, 0 },
179  { "urefreplacement",     0, 1, 0 },
180
181  { "email",               0, 1, 0 },
182  { "emailaddress",        0, 1, 0 },
183  { "emailname",           0, 1, 0 },
184
185  { "group",               0, 0, 0 },
186  { "float",               1, 0, 0 },
187  { "floattype",           0, 0, 0 },
188  { "floatpos",            0, 0, 0 },
189  { "caption",             0, 0, 0 },
190  { "shortcaption",        0, 0, 0 },
191
192  { "",                    0, 0, 0 }, /* TABLE (docbook) */
193  { "",                    0, 0, 0 }, /* FIGURE (docbook) */
194  { "",                    0, 0, 0 }, /* EXAMPLE (docbook) */
195  { "",                    1, 0, 0 }, /* SIDEBAR (docbook) */
196
197  { "printindex",          0, 0, 0 },
198  { "listoffloats",        0, 0, 0 },
199  { "anchor",              0, 1, 0 },
200
201  { "image",               0, 0, 0 },
202  { "inlineimage",         0, 1, 0 },
203  { "alttext",             0, 1, 0 },
204
205  { "",                    0, 1, 0 }, /* PRIMARY (docbook) */
206  { "",                    0, 1, 0 }, /* SECONDARY (docbook) */
207  { "",                    0, 0, 0 }, /* INFORMALFIGURE (docbook) */
208  { "",                    0, 0, 0 }, /* MEDIAOBJECT (docbook) */
209  { "",                    0, 0, 0 }, /* IMAGEOBJECT (docbook) */
210  { "",                    0, 0, 0 }, /* IMAGEDATA (docbook) */
211  { "",                    0, 0, 0 }, /* TEXTOBJECT (docbook) */
212  { "",                    0, 0, 0 }, /* INDEXENTRY (docbook) */
213  { "",                    0, 0, 0 }, /* PRIMARYIE (docbook) */
214  { "",                    0, 0, 0 }, /* SECONDARYIE (docbook) */
215  { "",                    0, 0, 0 }, /* INDEXDIV (docbook) */
216  { "multitable",          0, 0, 0 },
217  { "",                    0, 0, 0 }, /* TGROUP (docbook) */
218  { "columnfraction",      0, 0, 0 },
219  { "thead",               0, 0, 0 },
220  { "tbody",               0, 0, 0 },
221  { "entry",               0, 0, 0 },
222  { "row",                 0, 0, 0 },
223  { "",                    0, 0, 0 }, /* BOOKINFO (docbook) */
224  { "",                    0, 0, 0 }, /* ABSTRACT (docbook) */
225  { "",                    0, 0, 0 }, /* REPLACEABLE (docbook) */
226  { "",                    0, 0, 0 }, /* ENVAR (docbook) */
227  { "",                    0, 0, 0 }, /* COMMENT (docbook) */
228  { "",                    0, 0, 0 }, /* FUNCTION (docbook) */
229  { "",                    0, 0, 0 }, /* LEGALNOTICE (docbook) */
230
231  { "contents",            0, 0, 0 },
232  { "shortcontents",       0, 0, 0 },
233  { "documentlanguage",    0, 0, 0 },
234
235  { "setvalue",            0, 0, 0 },
236  { "clearvalue",          0, 0, 0 },
237
238  { "definition",          0, 0, 0 },
239  { "definitionterm",      0, 0, 0 },
240  { "definitionitem",      1, 0, 0 },
241  { "defcategory",         0, 0, 0 },
242  { "deffunction",         0, 0, 0 },
243  { "defvariable",         0, 0, 0 },
244  { "defparam",            0, 0, 0 },
245  { "defdelimiter",        0, 0, 0 },
246  { "deftype",             0, 0, 0 },
247  { "defparamtype",        0, 0, 0 },
248  { "defdatatype",         0, 0, 0 },
249  { "defclass",            0, 0, 0 },
250  { "defclassvar",         0, 0, 0 },
251  { "defoperation",        0, 0, 0 },
252
253  { "para",                0, 0, 0 } /* Must be last */
254  /* name / contains para / contained in para / preserve space */
255};
256
257element docbook_element_list [] = {
258  { "book",                0, 0, 0 }, /* TEXINFO */
259  { "",                    0, 0, 0 }, /* SETFILENAME */
260  { "",                    0, 0, 0 }, /* TITLEINFO */
261  { "title",               0, 0, 0 }, /* SETTITLE */
262  { "",                    1, 0, 0 }, /* DOCUMENTDESCRIPTION (?) */
263
264  { "",                    1, 0, 0 }, /* NODE */
265  { "",                    0, 0, 0 }, /* NODENEXT */
266  { "",                    0, 0, 0 }, /* NODEPREV */
267  { "",                    0, 0, 0 }, /* NODEUP */
268
269  { "chapter",             1, 0, 0 },
270  { "sect1",               1, 0, 0 }, /* SECTION */
271  { "sect2",               1, 0, 0 }, /* SUBSECTION */
272  { "sect3",               1, 0, 0 }, /* SUBSUBSECTION */
273
274  { "chapter",             1, 0, 0 }, /* TOP */
275  { "chapter",             1, 0, 0 }, /* UNNUMBERED */
276  { "sect1",               1, 0, 0 }, /* UNNUMBEREDSEC */
277  { "sect2",               1, 0, 0 }, /* UNNUMBEREDSUBSEC */
278  { "sect3",               1, 0, 0 }, /* UNNUMBEREDSUBSUBSEC */
279
280  { "appendix",            1, 0, 0 },
281  { "sect1",               1, 0, 0 }, /* APPENDIXSEC */
282  { "sect2",               1, 0, 0 }, /* APPENDIXSUBSEC */
283  { "sect3",               1, 0, 0 }, /* APPENDIXSUBSUBSEC */
284
285  { "bridgehead",          0, 0, 0 }, /* MAJORHEADING */
286  { "bridgehead",          0, 0, 0 }, /* CHAPHEADING */
287  { "bridgehead",          0, 0, 0 }, /* HEADING */
288  { "bridgehead",          0, 0, 0 }, /* SUBHEADING */
289  { "bridgehead",          0, 0, 0 }, /* SUBSUBHEADING */
290
291  { "",                    0, 0, 0 }, /* TITLEPAGE */
292  { "",                    0, 0, 0 }, /* AUTHOR */
293  { "",                    0, 0, 0 }, /* BOOKTITLE */
294  { "",                    0, 0, 0 }, /* BOOKSUBTITLE */
295
296  { "",                    1, 0, 0 }, /* MENU */
297  { "",                    1, 0, 0 }, /* DETAILMENU */
298  { "",                    1, 0, 0 }, /* MENUENTRY */
299  { "",                    0, 0, 0 }, /* MENUTITLE */
300  { "",                    1, 0, 0 }, /* MENUCOMMENT */
301  { "",                    0, 0, 0 }, /* MENUNODE */
302  { "anchor",              0, 0, 0 }, /* NODENAME */
303
304  { "acronym",             0, 1, 0 },
305  { "",                    0, 1, 0 }, /* ACRONYMWORD */
306  { "",                    0, 1, 0 }, /* ACRONYMDESC */
307
308  { "abbrev",              0, 1, 0 },
309  { "",                    0, 1, 0 }, /* ABBREVWORD */
310  { "",                    0, 1, 0 }, /* ABBREVDESC */
311
312  { "literal",             0, 1, 0 }, /* TT */
313  { "literal",             0, 1, 0 }, /* CODE */
314  { "command",             0, 1, 0 }, /* COMMAND */
315  { "envar",               0, 1, 0 }, /* ENV */
316  { "filename",            0, 1, 0 }, /* FILE */
317  { "option",              0, 1, 0 }, /* OPTION */
318  { "literal",             0, 1, 0 }, /* SAMP */
319  { "userinput",           0, 1, 0 }, /* KBD */
320  { "wordasword",          0, 1, 0 }, /* URL */
321  { "keycap",              0, 1, 0 }, /* KEY */
322  { "replaceable",         0, 1, 0 }, /* VAR */
323  { "",                    0, 1, 0 }, /* SC */
324  { "firstterm",           0, 1, 0 }, /* DFN */
325  { "emphasis",            0, 1, 0 }, /* EMPH */
326  { "emphasis",            0, 1, 0 }, /* STRONG */
327  { "citetitle",           0, 1, 0 }, /* CITE */
328  { "",                    0, 1, 0 }, /* NOTFIXEDWIDTH */
329  { "wordasword",          0, 1, 0 }, /* I */
330  { "emphasis",            0, 1, 0 }, /* B */
331  { "",                    0, 1, 0 }, /* R */
332
333  { "",                    0, 0, 0 }, /* EXDENT */
334
335  { "title",               0, 0, 0 },
336  { "",                    1, 0, 0 }, /* IFINFO */
337  { "",                    0, 0, 0 }, /* SP */
338  { "",                    1, 0, 0 }, /* CENTER */
339  { "",                    0, 0, 0 }, /* DIRCATEGORY */
340  { "blockquote",          1, 0, 0 }, /* QUOTATION */
341  { "screen",              0, 0, 1 }, /* EXAMPLE */
342  { "screen",              0, 0, 1 }, /* SMALLEXAMPLE */
343  { "programlisting",      0, 0, 1 }, /* LISP */
344  { "programlisting",      0, 0, 1 }, /* SMALLLISP */
345  { "",                    1, 0, 0 }, /* CARTOUCHE */
346  { "",                    1, 0, 0 }, /* COPYING */
347  { "screen",              0, 1, 1 }, /* FORMAT */
348  { "screen",              0, 1, 1 }, /* SMALLFORMAT */
349  { "literallayout",       0, 1, 1 }, /* DISPLAY */
350  { "literallayout",       0, 1, 1 }, /* SMALLDISPLAY */
351  { "screen",              0, 0, 1 }, /* VERBATIM */
352  { "footnote",            0, 1, 0 },
353  { "lineannotation",      0, 1, 0 },
354
355  { "tip",                 1, 0, 0 },
356  { "note",                1, 0, 0 },
357  { "important",           1, 0, 0 },
358  { "warning",             1, 0, 0 },
359  { "caution",             1, 0, 0 },
360
361  { "itemizedlist",        0, 0, 0 }, /* ITEMIZE */
362  { "",                    0, 0, 0 }, /* ITEMFUNCTION */
363  { "listitem",            1, 0, 0 }, /* ITEM */
364  { "orderedlist",         0, 0, 0 }, /* ENUMERATE */
365  { "variablelist",        0, 0, 0 }, /* TABLE */
366  { "varlistentry",        0, 0, 0 }, /* TABLEITEM */
367  { "term",                0, 0, 0 }, /* TABLETERM */
368
369  { "indexterm",           0, 1, 0 }, /* INDEXTERM */
370
371  { "",                    0, 1, 0 }, /* MATH */
372
373  { "",                    0, 1, 0 }, /* DIMENSION */
374
375  { "xref",                0, 1, 0 }, /* XREF */
376  { "link",                0, 1, 0 }, /* XREFNODENAME */
377  { "",                    0, 1, 0 }, /* XREFINFONAME */
378  { "",                    0, 1, 0 }, /* XREFPRINTEDDESC */
379  { "",                    0, 1, 0 }, /* XREFINFOFILE */
380  { "",                    0, 1, 0 }, /* XREFPRINTEDNAME */
381
382  { "",                    0, 1, 0 }, /* INFOREF */
383  { "",                    0, 1, 0 }, /* INFOREFNODENAME */
384  { "",                    0, 1, 0 }, /* INFOREFREFNAME */
385  { "",                    0, 1, 0 }, /* INFOREFINFONAME */
386
387  { "ulink",               0, 1, 0 }, /* UREF */
388  { "",                    0, 1, 0 }, /* UREFURL */
389  { "",                    0, 1, 0 }, /* UREFDESC */
390  { "",                    0, 1, 0 }, /* UREFREPLACEMENT */
391
392  { "ulink",               0, 1, 0 }, /* EMAIL */
393  { "",                    0, 1, 0 }, /* EMAILADDRESS */
394  { "",                    0, 1, 0 }, /* EMAILNAME */
395
396  { "",                    0, 0, 0 }, /* GROUP */
397  { "",                    1, 0, 0 }, /* FLOAT */
398  { "",                    0, 0, 0 }, /* FLOATTYPE */
399  { "",                    0, 0, 0 }, /* FLOATPOS */
400  { "",                    0, 0, 0 }, /* CAPTION */
401  { "",                    0, 0, 0 }, /* SHORTCAPTION */
402
403  { "table",               0, 1, 0 },
404  { "figure",              0, 1, 0 },
405  { "example",             1, 1, 0 },
406  { "sidebar",             1, 0, 0 },
407
408  { "index",               0, 1, 0 }, /* PRINTINDEX */
409  { "",                    0, 1, 0 }, /* LISTOFFLOATS */
410  { "",                    0, 1, 0 }, /* ANCHOR */
411
412  { "",                    0, 0, 0 }, /* IMAGE */
413  { "inlinemediaobject",   0, 1, 0 }, /* INLINEIMAGE */
414  { "",                    0, 0, 0 }, /* IMAGEALTTEXT */
415
416  { "primary",             0, 1, 0 }, /* PRIMARY */
417  { "secondary",           0, 1, 0 },
418  { "informalfigure",      0, 0, 0 },
419  { "mediaobject",         0, 0, 0 },
420  { "imageobject",         0, 1, 0 },
421  { "imagedata",           0, 1, 0 },
422  { "textobject",          0, 1, 0 },
423  { "indexentry",          0, 0, 0 },
424  { "primaryie",           0, 0, 0 },
425  { "secondaryie",         0, 0, 0 },
426  { "indexdiv",            0, 0, 0 },
427  { "informaltable",       0, 0, 0 },
428  { "tgroup",              0, 0, 0 },
429  { "colspec",             0, 0, 0 },
430  { "thead",               0, 0, 0 },
431  { "tbody",               0, 0, 0 },
432  { "entry",               0, 0, 0 },
433  { "row",                 0, 0, 0 },
434  { "bookinfo",            0, 0, 0 },
435  { "abstract",            1, 0, 0 },
436  { "replaceable",         0, 0, 0 },
437  { "envar",               0, 1, 0 },
438  { "comment",             0, 0, 0 },
439  { "function",            0, 1, 0 },
440  { "legalnotice",         1, 0, 0 },
441
442  { "",                    0, 0, 0 }, /* CONTENTS (xml) */
443  { "",                    0, 0, 0 }, /* SHORTCONTENTS (xml) */
444  { "",                    0, 0, 0 }, /* DOCUMENT LANGUAGE (xml) */
445
446  { "",                    0, 0, 0 }, /* SETVALUE (xml) */
447  { "",                    0, 0, 0 }, /* CLEARVALUE (xml) */
448
449  { "blockquote",          1, 0, 0 }, /* DEFINITION */
450  { "screen",              0, 0, 1 }, /* DEFINITIONTERM */
451  { "",                    0, 0, 0 }, /* DEFINITIONITEM (xml) */
452  { "",                    0, 0, 0 }, /* DEFCATEGORY (xml) */
453  { "function",            0, 0, 0 }, /* DEFFUNCTION */
454  { "varname",             0, 0, 0 }, /* DEFVARIABLE */
455  { "varname",             0, 0, 0 }, /* DEFPARAM */
456  { "",                    0, 0, 0 }, /* DEFDELIMITER (xml) */
457  { "returnvalue",         0, 0, 0 }, /* DEFTYPE */
458  { "type",                0, 0, 0 }, /* DEFPARAMTYPE */
459  { "structname",          0, 0, 0 }, /* DEFDATATYPE */
460  { "classname",           0, 0, 0 }, /* DEFCLASS */
461  { "property",            0, 0, 0 }, /* DEFCLASSVAR */
462  { "methodname",          0, 0, 0 }, /* DEFOPERATION */
463
464  { "para",                0, 0, 0 } /* Must be last */
465  /* name / contains para / contained in para / preserve space */
466};
467
468element *xml_element_list = NULL;
469
470
471typedef struct _replace_element
472{
473  int element_to_replace;
474  int element_containing;
475  int element_replacing;
476} replace_element;
477
478/* Elements to replace - Docbook only
479   -------------------
480   if `element_to_replace' have to be inserted
481   as a child of `element_containing,'
482   use `element_replacing' instead.
483
484   A value of `-1' for element_replacing means `do not use any element.'
485*/
486
487replace_element replace_elements [] = {
488  { I, TABLETERM, EMPH },
489  { B, TABLETERM, EMPH },
490  { TT, CODE, -1 },
491  { EXAMPLE, DISPLAY, -1 },
492  { CODE, DFN, -1 },
493  { CODE, VAR, -1 },
494  { EMPH, CODE, REPLACEABLE },
495  { VAR, VAR, -1},
496  { VAR, B, EMPH},
497  { B, CODE, ENVAR},
498  { CODE, I, EMPH},
499  { SAMP, VAR, -1 },
500  { FORMAT, BOOKINFO, ABSTRACT },
501  { QUOTATION, ABSTRACT, -1},
502  { LINEANNOTATION, LINEANNOTATION, -1 },
503  { LEGALNOTICE, ABSTRACT, -1 },
504  { QUOTATION, QUOTATION, -1 },
505  /* Formal versions of table and image elements.  */
506  { MULTITABLE, FLOAT, FLOATTABLE },
507  { INFORMALFIGURE, FLOAT, FLOATFIGURE },
508  { CARTOUCHE, FLOAT, FLOATCARTOUCHE },
509  /* Unnecessary markup in @defun blocks.  */
510  { VAR, DEFPARAM, -1 },
511  { CODE, DEFTYPE, -1 },
512  /* Add your elements to replace here */
513  {-1, 0, 0}
514};
515
516int xml_in_menu_entry = 0;
517int xml_in_menu_entry_comment = 0;
518int xml_node_open = 0;
519int xml_node_level = -1;
520int xml_in_para = 0;
521int xml_just_after_element = 0;
522int xml_keep_space = 0;
523
524int xml_no_indent = 0;
525
526int xml_no_para = 0;
527char *xml_node_id = NULL;
528int xml_sort_index = 0;
529
530int xml_in_xref_token = 0;
531int xml_in_bookinfo = 0;
532int xml_in_book_title = 0;
533int xml_in_abstract = 0;
534
535/* Non-zero if we are handling an element that can appear between
536   @item and @itemx, @deffn and @deffnx.  */
537int xml_dont_touch_items_defs = 0;
538
539/* We need to keep footnote state, because elements inside footnote may try
540   to close the previous parent para.  */
541static int xml_in_footnote = 0;
542
543static int xml_after_table_term = 0;
544static int book_started = 0;
545static int first_section_opened = 0;
546
547static int xml_in_tableitem[256];
548static int xml_in_item[256];
549static int xml_table_level = 0;
550
551static int xml_in_def_item[256];
552static int xml_definition_level = 0;
553int xml_after_def_term = 0;
554
555static int in_table_title = 0;
556
557static int in_indexentry = 0;
558static int in_secondary = 0;
559static int in_indexterm = 0;
560
561char *
562xml_id (char *id)
563{
564  char *tem = xmalloc (strlen (id) + 1);
565  char *p = tem;
566  strcpy (tem, id);
567  while (*p)
568    { /* Check if a character is allowed in ID attributes.  This list differs
569         slightly from XML specs that it doesn't contain underscores.
570         See http://xml.coverpages.org/sgmlsyn/sgmlsyn.htm, ``9.3 Name''  */
571      if (!strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.", *p))
572        *p = '-';
573      p++;
574    }
575  p = tem;
576  /* First character can only be a letter.  */
577  if (!strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", *p))
578    *p = 'i';
579  return tem;
580}
581
582int
583xml_element (char *name)
584{
585  int i;
586  for (i=0; i<=PARA; i++)
587    {
588      if (strcasecmp (name, texinfoml_element_list[i].name) == 0)
589        return i;
590    }
591  printf ("Error xml_element\n");
592  return -1;
593}
594
595void
596xml_begin_document (char *output_filename)
597{
598  if (book_started)
599    return;
600
601  book_started = 1;
602
603  /* Make sure this is the very first string of the output document.  */
604  output_paragraph_offset = 0;
605
606  insert_string ("<?xml version=\"1.0\"");
607
608  /* At this point, we register a delayed writing for document encoding,
609     so in the end, proper encoding attribute will be inserted here.
610     Since the user is unaware that we are implicitly executing this
611     command, we should disable warnings temporarily, in order to avoid
612     possible confusion.  (ie. if the output is not seekable,
613     register_delayed_write issues a warning.)  */
614  {
615    extern int print_warnings;
616    int save_print_warnings = print_warnings;
617    print_warnings = 0;
618    register_delayed_write ("@documentencoding");
619    print_warnings = save_print_warnings;
620  }
621
622  insert_string ("?>\n");
623
624  if (docbook)
625    {
626      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]>");
627      xml_element_list = docbook_element_list;
628    }
629  else
630    {
631      insert_string ("<!DOCTYPE texinfo PUBLIC \"-//GNU//DTD TexinfoML V");
632      insert_string (VERSION);
633      insert_string ("//EN\" \"http://www.gnu.org/software/texinfo/dtd/");
634      insert_string (VERSION);
635      insert_string ("/texinfo.dtd\">");
636      xml_element_list = texinfoml_element_list;
637    }
638  if (language_code != last_language_code)
639    {
640      if (docbook)
641        xml_insert_element_with_attribute (TEXINFO, START, "lang=\"%s\"", language_table[language_code].abbrev);
642      else
643	xml_insert_element_with_attribute (TEXINFO, START, "xml:lang=\"%s\"", language_table[language_code].abbrev);
644    }
645  if (!docbook)
646    {
647      xml_insert_element (SETFILENAME, START);
648      insert_string (output_filename);
649      xml_insert_element (SETFILENAME, END);
650    }
651}
652
653/*  */
654static int element_stack[256];
655static int element_stack_index = 0;
656
657static int
658xml_current_element (void)
659{
660  return element_stack[element_stack_index-1];
661}
662
663static void
664xml_push_current_element (int elt)
665{
666  element_stack[element_stack_index++] = elt;
667  if (element_stack_index > 200)
668    printf ("*** stack overflow (%d - %s) ***\n",
669            element_stack_index,
670            xml_element_list[elt].name);
671}
672
673static void
674xml_pop_current_element (void)
675{
676  element_stack_index--;
677  if (element_stack_index < 0)
678    printf ("*** stack underflow (%d - %d) ***\n",
679            element_stack_index,
680            xml_current_element());
681}
682
683int
684xml_current_stack_index (void)
685{
686  return element_stack_index;
687}
688
689void
690xml_end_current_element (void)
691{
692  xml_insert_element (xml_current_element (), END);
693}
694
695static void
696xml_indent (void)
697{
698  if (xml_indentation_increment > 0)
699    {
700      int i;
701      if (output_paragraph[output_paragraph_offset-1] != '\n')
702        insert ('\n');
703      for (i = 0; i < element_stack_index * xml_indentation_increment; i++)
704        insert (' ');
705    }
706}
707
708void
709xml_start_para (void)
710{
711  if (xml_in_para || xml_in_footnote
712      || !xml_element_list[xml_current_element()].contains_para)
713    return;
714
715  while (output_paragraph[output_paragraph_offset-1] == '\n')
716    output_paragraph_offset--;
717  xml_indent ();
718
719  insert_string ("<para");
720  if (xml_no_indent)
721    insert_string (" role=\"continues\"");
722  insert_string (">");
723  xml_no_indent = 0;
724  xml_in_para = 1;
725}
726
727void
728xml_end_para (void)
729{
730  if (!xml_in_para || xml_in_footnote)
731    return;
732
733  while (cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
734    output_paragraph_offset--;
735
736  insert_string ("</para>");
737  if (xml_indentation_increment > 0)
738    insert ('\n');
739  xml_in_para = 0;
740}
741
742void
743xml_end_document (void)
744{
745  if (xml_node_open)
746    {
747      if (xml_node_level != -1)
748        {
749          xml_close_sections (xml_node_level);
750          xml_node_level = -1;
751        }
752      xml_insert_element (NODE, END);
753    }
754  else
755    xml_close_sections (xml_node_level);
756
757  xml_insert_element (TEXINFO, END);
758  if (xml_indentation_increment == 0)
759    insert ('\n');
760  insert_string ("<!-- Keep this comment at the end of the file\n\
761Local variables:\n\
762mode: sgml\n\
763sgml-indent-step:1\n\
764sgml-indent-data:nil\n\
765End:\n\
766-->\n");
767  if (element_stack_index != 0)
768    error ("Element stack index : %d\n", element_stack_index);
769}
770
771/* MUST be 0 or 1, not true or false values */
772static int start_element_inserted = 1;
773
774/* NOTE: We use `elt' rather than `element' in the argument list of
775   the next function, since otherwise the Solaris SUNWspro compiler
776   barfs because `element' is a typedef declared near the beginning of
777   this file.  */
778void
779#if defined (VA_FPRINTF) && __STDC__
780xml_insert_element_with_attribute (int elt, int arg, char *format, ...)
781#else
782xml_insert_element_with_attribute (elt, arg, format, va_alist)
783     int elt;
784     int arg;
785     char *format;
786     va_dcl
787#endif
788{
789  /* Look at the replace_elements table to see if we have to change the element */
790  if (xml_sort_index)
791      return;
792  if (docbook)
793    {
794      replace_element *element_list = replace_elements;
795      while (element_list->element_to_replace >= 0)
796        {
797          if ( ( (arg == START) &&
798                 (element_list->element_containing == xml_current_element ()) &&
799                 (element_list->element_to_replace == elt) ) ||
800               ( (arg == END) &&
801                 (element_list->element_containing == element_stack[element_stack_index-1-start_element_inserted]) &&
802                 (element_list->element_to_replace == elt) ) )
803            {
804              elt = element_list->element_replacing;
805              break;
806            }
807          element_list ++;
808        }
809
810      /* Forget the element */
811      if (elt < 0)
812        {
813          if (arg == START)
814            start_element_inserted = 0;
815          else
816            /* Replace the default value, for the next time */
817            start_element_inserted = 1;
818          return;
819        }
820    }
821
822  if (!book_started)
823    return;
824
825  if (!xml_dont_touch_items_defs && arg == START)
826    {
827      if (xml_after_table_term && elt != TABLETERM && xml_table_level
828          && !xml_in_item[xml_table_level])
829        {
830          xml_after_table_term = 0;
831          xml_insert_element (ITEM, START);
832          xml_in_item[xml_table_level] = 1;
833        }
834      else if (xml_after_def_term && elt != DEFINITIONTERM)
835        {
836          xml_after_def_term = 0;
837          xml_insert_element (DEFINITIONITEM, START);
838          xml_in_def_item[xml_definition_level] = 1;
839        }
840    }
841
842  if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
843    return;
844
845  if (executing_string && arg == END)
846    switch (elt)
847      {
848      case TABLEITEM:
849        xml_in_tableitem[xml_table_level] = 0;
850        break;
851      case ITEM:
852        xml_in_item[xml_table_level] = 0;
853        break;
854      case DEFINITIONTERM:
855        xml_in_def_item[xml_definition_level] = 0;
856        break;
857      }
858
859  /* We are special-casing FIGURE element for docbook.  It does appear in
860     the tag stack, but not in the output.  This is to make element replacement
861     work beautifully.  */
862  if (docbook && elt == FLOAT)
863    {
864      if (arg == START)
865        xml_push_current_element (elt);
866      else
867        xml_pop_current_element ();
868      return;
869    }
870
871  if (!xml_element_list[elt].name || !strlen (xml_element_list[elt].name))
872    {
873      /*printf ("Warning: Inserting empty element %d\n", elt);*/
874      return;
875    }
876
877  if (arg == START && !xml_in_para && !xml_no_para
878      && xml_element_list[elt].contained_in_para)
879    xml_start_para ();
880
881  if (arg == START && xml_in_para && !xml_element_list[elt].contained_in_para)
882    xml_end_para ();
883
884  if (arg == END && xml_in_para && !xml_element_list[elt].contained_in_para)
885    xml_end_para ();
886
887  if (docbook && xml_table_level && !in_table_title
888      && !xml_in_tableitem[xml_table_level] && !xml_in_item[xml_table_level]
889      && arg == START && elt != TABLEITEM && elt != TABLETERM
890      && !in_indexterm && xml_current_element() == TABLE)
891    {
892      in_table_title = 1;
893      xml_insert_element (TITLE, START);
894    }
895
896  if (arg == START && !xml_in_para && !xml_keep_space
897      && !xml_element_list[elt].contained_in_para)
898    xml_indent ();
899
900  if (arg == START)
901    xml_push_current_element (elt);
902  else
903    xml_pop_current_element ();
904
905  /* Eat one newline before </example> and the like.  */
906  if (!docbook && arg == END
907      && (xml_element_list[elt].keep_space || elt == GROUP)
908      && output_paragraph[output_paragraph_offset-1] == '\n')
909    output_paragraph_offset--;
910
911  /* And eat whitespace before </entry> in @multitables.  */
912  if (arg == END && elt == ENTRY)
913      while (cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
914    output_paragraph_offset--;
915
916  /* Indent elements that can contain <para>.  */
917  if (arg == END && !xml_in_para && !xml_keep_space
918      && xml_element_list[elt].contains_para)
919    xml_indent ();
920
921  /* Here are the elements we want indented.  These do not contain <para>
922     directly.  */
923  if (arg == END && (elt == MENUENTRY || elt == ITEMIZE || elt == ENUMERATE
924        || elt == TABLEITEM || elt == TABLE
925        || elt == MULTITABLE || elt == TGROUP || elt == THEAD || elt == TBODY
926        || elt == ROW || elt == INFORMALFIGURE
927        || (!docbook && (elt == DEFINITION || elt == DEFINITIONTERM))))
928    xml_indent ();
929
930  insert ('<');
931  if (arg == END)
932    insert ('/');
933  insert_string (xml_element_list[elt].name);
934
935  /*  printf ("%s ", xml_element_list[elt].name);*/
936
937  if (format)
938    {
939      char temp_string[2000]; /* xx no fixed limits */
940#ifdef VA_SPRINTF
941      va_list ap;
942#endif
943
944      VA_START (ap, format);
945#ifdef VA_SPRINTF
946      VA_SPRINTF (temp_string, format, ap);
947#else
948      sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
949#endif
950      insert (' ');
951      insert_string (temp_string);
952      va_end (ap);
953    }
954
955  if (arg == START && xml_node_id && elt != NODENAME)
956    {
957      insert_string (" id=\"");
958      insert_string (xml_node_id);
959      insert ('"');
960      free (xml_node_id);
961      xml_node_id = NULL;
962    }
963
964  if (xml_element_list[elt].keep_space)
965    {
966      if (arg == START)
967	{
968          if (!docbook)
969            insert_string (" xml:space=\"preserve\"");
970	  xml_keep_space++;
971	}
972      else
973	xml_keep_space--;
974    }
975
976  insert ('>');
977
978  if (!xml_in_para && !xml_element_list[elt].contained_in_para
979      && xml_element_list[elt].contains_para && xml_indentation_increment > 0)
980    insert ('\n');
981
982  xml_just_after_element = 1;
983}
984
985/* See the NOTE before xml_insert_element_with_attribute, for why we
986   use `elt' rather than `element' here.  */
987void
988xml_insert_element (int elt, int arg)
989{
990  xml_insert_element_with_attribute (elt, arg, NULL);
991}
992
993void
994xml_insert_entity (char *entity_name)
995{
996  int saved_escape_html = escape_html;
997
998  if (!book_started)
999    return;
1000  if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
1001    return;
1002
1003  if (!xml_in_para && !xml_no_para && !only_macro_expansion
1004      && xml_element_list[xml_current_element ()].contains_para
1005      && !in_fixed_width_font)
1006    xml_start_para ();
1007
1008  escape_html = 0;
1009  add_char ('&');
1010  escape_html = saved_escape_html;
1011  insert_string (entity_name);
1012  add_char (';');
1013}
1014
1015typedef struct _xml_section xml_section;
1016struct _xml_section {
1017  int level;
1018  char *name;
1019  xml_section *prev;
1020};
1021
1022xml_section *last_section = NULL;
1023
1024void
1025xml_begin_node (void)
1026{
1027  first_section_opened = 1;
1028  if (xml_in_abstract)
1029    {
1030      xml_insert_element (ABSTRACT, END);
1031      xml_in_abstract = 0;
1032    }
1033  if (xml_in_bookinfo)
1034    {
1035      xml_insert_element (BOOKINFO, END);
1036      xml_in_bookinfo = 0;
1037    }
1038  if (xml_node_open && ! docbook)
1039    {
1040      if (xml_node_level != -1)
1041        {
1042          xml_close_sections (xml_node_level);
1043          xml_node_level = -1;
1044        }
1045      xml_insert_element (NODE, END);
1046    }
1047  xml_insert_element (NODE, START);
1048  xml_node_open = 1;
1049}
1050
1051void
1052xml_close_sections (int level)
1053{
1054  if (!first_section_opened)
1055    {
1056      if (xml_in_abstract)
1057	{
1058	  xml_insert_element (ABSTRACT, END);
1059	  xml_in_abstract = 0;
1060	}
1061      if (xml_in_bookinfo)
1062	{
1063	  xml_insert_element (BOOKINFO, END);
1064	  xml_in_bookinfo = 0;
1065	}
1066      first_section_opened = 1;
1067    }
1068
1069  while (last_section && last_section->level >= level)
1070    {
1071      xml_section *temp = last_section;
1072      xml_insert_element (xml_element(last_section->name), END);
1073      temp = last_section;
1074      last_section = last_section->prev;
1075      free (temp->name);
1076      free (temp);
1077    }
1078}
1079
1080void
1081xml_open_section (int level, char *name)
1082{
1083  xml_section *sect = (xml_section *) xmalloc (sizeof (xml_section));
1084
1085  sect->level = level;
1086  sect->name = xmalloc (1 + strlen (name));
1087  strcpy (sect->name, name);
1088  sect->prev = last_section;
1089  last_section = sect;
1090
1091  if (xml_node_open && xml_node_level == -1)
1092    xml_node_level = level;
1093}
1094
1095void
1096xml_start_menu_entry (char *tem)
1097{
1098  char *string;
1099  discard_until ("* ");
1100
1101  /* The line number was already incremented in reader_loop when we
1102     saw the newline, and discard_until has now incremented again.  */
1103  line_number--;
1104
1105  if (xml_in_menu_entry)
1106    {
1107      if (xml_in_menu_entry_comment)
1108        {
1109          xml_insert_element (MENUCOMMENT, END);
1110          xml_in_menu_entry_comment=0;
1111        }
1112      xml_insert_element (MENUENTRY, END);
1113      xml_in_menu_entry=0;
1114    }
1115  xml_insert_element (MENUENTRY, START);
1116  xml_in_menu_entry=1;
1117
1118  xml_insert_element (MENUNODE, START);
1119  string = expansion (tem, 0);
1120  add_word (string);
1121  xml_insert_element (MENUNODE, END);
1122  free (string);
1123
1124  /* The menu item may use macros, so expand them now.  */
1125  xml_insert_element (MENUTITLE, START);
1126  only_macro_expansion++;
1127  get_until_in_line (1, ":", &string);
1128  only_macro_expansion--;
1129  execute_string ("%s", string); /* get escaping done */
1130  xml_insert_element (MENUTITLE, END);
1131  free (string);
1132
1133  if (looking_at ("::"))
1134    discard_until (":");
1135  else
1136    { /* discard the node name */
1137      get_until_in_line (0, ".", &string);
1138      free (string);
1139    }
1140  input_text_offset++;  /* discard the second colon or the period */
1141  skip_whitespace_and_newlines();
1142  xml_insert_element (MENUCOMMENT, START);
1143  xml_in_menu_entry_comment ++;
1144}
1145
1146void
1147xml_end_menu (void)
1148{
1149  if (xml_in_menu_entry)
1150    {
1151      if (xml_in_menu_entry_comment)
1152        {
1153          xml_insert_element (MENUCOMMENT, END);
1154          xml_in_menu_entry_comment --;
1155        }
1156      xml_insert_element (MENUENTRY, END);
1157      xml_in_menu_entry--;
1158    }
1159  xml_insert_element (MENU, END);
1160}
1161
1162static int xml_last_character;
1163
1164void
1165xml_add_char (int character)
1166{
1167  if (!book_started)
1168      return;
1169  if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
1170    return;
1171
1172  if (docbook && xml_table_level && !in_table_title
1173      && !xml_in_item[xml_table_level] && !xml_in_tableitem[xml_table_level]
1174      && !cr_or_whitespace (character) && !in_indexterm)
1175    {
1176      in_table_title = 1;
1177      xml_insert_element (TITLE, START);
1178    }
1179
1180  if (!first_section_opened && !xml_in_abstract && !xml_in_book_title
1181      && !xml_no_para && character != '\r' && character != '\n'
1182      && character != ' ' && !is_in_insertion_of_type (copying))
1183    {
1184      if (!xml_in_bookinfo)
1185	{
1186	  xml_insert_element (BOOKINFO, START);
1187	  xml_in_bookinfo = 1;
1188	}
1189      xml_insert_element (ABSTRACT, START);
1190      xml_in_abstract = 1;
1191    }
1192
1193  if (!xml_sort_index && !xml_in_xref_token && !xml_dont_touch_items_defs)
1194    {
1195      if (xml_after_table_term && xml_table_level
1196          && !xml_in_item[xml_table_level])
1197        {
1198          xml_after_table_term = 0;
1199          xml_insert_element (ITEM, START);
1200          xml_in_item[xml_table_level] = 1;
1201        }
1202      else if (xml_after_def_term)
1203        {
1204          xml_after_def_term = 0;
1205          xml_insert_element (DEFINITIONITEM, START);
1206          xml_in_def_item[xml_definition_level] = 1;
1207        }
1208    }
1209
1210  if (xml_just_after_element && !xml_in_para && !inhibit_paragraph_indentation)
1211    {
1212      if (character == '\r' || character == '\n' || character == '\t' || character == ' ')
1213        return;
1214      xml_just_after_element = 0;
1215    }
1216
1217  if (xml_element_list[xml_current_element()].contains_para
1218      && !xml_in_para && !only_macro_expansion && !xml_no_para
1219      && !cr_or_whitespace (character) && !in_fixed_width_font)
1220    xml_start_para ();
1221
1222  if (xml_in_para && character == '\n' && xml_last_character == '\n'
1223      && !only_macro_expansion && !xml_no_para
1224      && xml_element_list[xml_current_element()].contains_para )
1225    {
1226      xml_end_para ();
1227      xml_just_after_element = 1;
1228      return;
1229    }
1230
1231  if (xml_in_menu_entry_comment && character == '\n' && xml_last_character == '\n')
1232    {
1233      xml_insert_element (MENUCOMMENT, END);
1234      xml_in_menu_entry_comment = 0;
1235      xml_insert_element (MENUENTRY, END);
1236      xml_in_menu_entry = 0;
1237    }
1238
1239  if (xml_in_menu_entry_comment && whitespace(character)
1240      && cr_or_whitespace(xml_last_character))
1241    return;
1242
1243  if (character == '\n' && !xml_in_para && !inhibit_paragraph_indentation)
1244    return;
1245
1246  xml_last_character = character;
1247
1248  if (character == '&' && escape_html)
1249      insert_string ("&amp;");
1250  else if (character == '<' && escape_html)
1251      insert_string ("&lt;");
1252  else if (character == '\n' && !xml_keep_space)
1253    {
1254      if (!xml_in_para && xml_just_after_element && !multitable_active)
1255	return;
1256      else
1257	insert (docbook ? '\n' : ' ');
1258    }
1259  else
1260    insert (character);
1261
1262  return;
1263}
1264
1265void
1266xml_insert_footnote (char *note)
1267{
1268  if (!xml_in_para)
1269    xml_start_para ();
1270
1271  xml_in_footnote = 1;
1272  xml_insert_element (FOOTNOTE, START);
1273  insert_string ("<para>");
1274  execute_string ("%s", note);
1275  insert_string ("</para>");
1276  xml_insert_element (FOOTNOTE, END);
1277  xml_in_footnote = 0;
1278}
1279
1280/* We need to keep the quotation stack ourself, because insertion_stack
1281   loses item_function when we are closing the block, so we don't know
1282   what to close then.  */
1283typedef struct quotation_elt
1284{
1285  struct quotation_elt *next;
1286  char *type;
1287} QUOTATION_ELT;
1288
1289static QUOTATION_ELT *quotation_stack = NULL;
1290
1291void
1292xml_insert_quotation (char *type, int arg)
1293{
1294  int quotation_started = 0;
1295
1296  if (arg == START)
1297    {
1298      QUOTATION_ELT *new = xmalloc (sizeof (QUOTATION_ELT));
1299      new->type = xstrdup (type);
1300      new->next = quotation_stack;
1301      quotation_stack = new;
1302    }
1303  else
1304    type = quotation_stack->type;
1305
1306  /* Make use of special quotation styles of Docbook if we can.  */
1307  if (docbook && strlen(type))
1308    {
1309      /* Let's assume it started.  */
1310      quotation_started = 1;
1311
1312      if (strcasecmp (type, "tip") == 0)
1313        xml_insert_element (TIP, arg);
1314      else if (strcasecmp (type, "note") == 0)
1315        xml_insert_element (NOTE, arg);
1316      else if (strcasecmp (type, "important") == 0)
1317        xml_insert_element (IMPORTANT, arg);
1318      else if (strcasecmp (type, "warning") == 0)
1319        xml_insert_element (WARNING, arg);
1320      else if (strcasecmp (type, "caution") == 0)
1321        xml_insert_element (CAUTION, arg);
1322      else
1323        /* Didn't find a known quotation type :\ */
1324        quotation_started = 0;
1325    }
1326
1327  if (!quotation_started)
1328    {
1329      xml_insert_element (QUOTATION, arg);
1330      if (strlen(type) && arg == START)
1331        execute_string ("@b{%s:} ", type);
1332    }
1333
1334  if (arg == END)
1335    {
1336      QUOTATION_ELT *temp = quotation_stack;
1337      if (temp == NULL)
1338        return;
1339      quotation_stack = quotation_stack->next;
1340      free(temp->type);
1341      free(temp);
1342    }
1343}
1344
1345/* Starting generic docbook floats.  Just starts elt with correct label
1346   and id attributes, and inserts title.  */
1347void
1348xml_begin_docbook_float (int elt)
1349{
1350  if (current_float_used_title ())	/* in a nested float */
1351    {
1352      xml_insert_element (elt, START);	/* just insert the tag */
1353      return;
1354    }
1355
1356
1357  /* OK, need the title, tag, etc. */
1358  if (elt == CARTOUCHE)    /* no labels on <sidebar> */
1359    {
1360       if (strlen (current_float_id ()) == 0)
1361          xml_insert_element (elt, START);
1362       else
1363          xml_insert_element_with_attribute (elt, START,
1364              "id=\"%s\"", xml_id (current_float_id ()));
1365    }
1366  else if (strlen (current_float_id ()) == 0)
1367    xml_insert_element_with_attribute (elt, START, "label=\"\"");
1368  else
1369    xml_insert_element_with_attribute (elt, START,
1370        "id=\"%s\" label=\"%s\"", xml_id (current_float_id ()),
1371        current_float_number ());
1372
1373  xml_insert_element (TITLE, START);
1374  execute_string ("%s", current_float_title ());
1375  xml_insert_element (TITLE, END);
1376
1377  current_float_set_title_used ();	/* mark this title, tag, etc used */
1378}
1379
1380/*
1381 * Lists and Tables
1382 */
1383void
1384xml_begin_table (int type, char *item_function)
1385{
1386  switch (type)
1387    {
1388    case ftable:
1389    case vtable:
1390    case table:
1391      /*if (docbook)*/ /* 05-08 */
1392        {
1393          xml_insert_element (TABLE, START);
1394          xml_table_level ++;
1395          xml_in_tableitem[xml_table_level] = 0;
1396          xml_in_item[xml_table_level] = 0;
1397          xml_after_table_term = 0;
1398        }
1399      break;
1400    case itemize:
1401      if (!docbook)
1402        {
1403          xml_insert_element (ITEMIZE, START);
1404          xml_table_level ++;
1405          xml_in_item[xml_table_level] = 0;
1406          xml_insert_element (ITEMFUNCTION, START);
1407          if (*item_function == COMMAND_PREFIX
1408              && item_function[strlen (item_function) - 1] != '}'
1409              && command_needs_braces (item_function + 1))
1410            execute_string ("%s{}", item_function);
1411          else
1412            execute_string ("%s", item_function);
1413          xml_insert_element (ITEMFUNCTION, END);
1414        }
1415      else
1416        {
1417          xml_insert_element_with_attribute (ITEMIZE, START,
1418                                             "mark=\"%s\"",
1419                                             (*item_function == COMMAND_PREFIX) ?
1420                                             &item_function[1] : item_function);
1421          xml_table_level ++;
1422          xml_in_item[xml_table_level] = 0;
1423        }
1424      break;
1425    }
1426}
1427
1428void
1429xml_end_table (int type)
1430{
1431  switch (type)
1432    {
1433    case ftable:
1434    case vtable:
1435    case table:
1436      if (xml_in_item[xml_table_level])
1437        {
1438          xml_insert_element (ITEM, END);
1439          xml_in_item[xml_table_level] = 0;
1440        }
1441      if (xml_in_tableitem[xml_table_level])
1442        {
1443          xml_insert_element (TABLEITEM, END);
1444          xml_in_tableitem[xml_table_level] = 0;
1445        }
1446      xml_insert_element (TABLE, END);
1447      xml_after_table_term = 0;
1448      xml_table_level --;
1449
1450      break;
1451    case itemize:
1452      if (xml_in_item[xml_table_level])
1453        {
1454          xml_insert_element (ITEM, END);
1455          xml_in_item[xml_table_level] = 0;
1456        }
1457      /* gnat-style manual contains an itemized list without items! */
1458      if (in_table_title)
1459	{
1460	  xml_insert_element (TITLE, END);
1461	  in_table_title = 0;
1462	}
1463      xml_insert_element (ITEMIZE, END);
1464      xml_table_level --;
1465      break;
1466    }
1467}
1468
1469void
1470xml_begin_item (void)
1471{
1472  if (xml_in_item[xml_table_level])
1473    xml_insert_element (ITEM, END);
1474
1475  xml_insert_element (ITEM, START);
1476  xml_in_item[xml_table_level] = 1;
1477}
1478
1479void
1480xml_begin_table_item (void)
1481{
1482  if (!xml_after_table_term)
1483    {
1484      if (xml_in_item[xml_table_level])
1485        xml_insert_element (ITEM, END);
1486      if (xml_in_tableitem[xml_table_level])
1487        xml_insert_element (TABLEITEM, END);
1488
1489      if (in_table_title)
1490	{
1491	  in_table_title = 0;
1492	  xml_insert_element (TITLE, END);
1493	}
1494      xml_insert_element (TABLEITEM, START);
1495    }
1496  xml_insert_element (TABLETERM, START);
1497  xml_in_tableitem[xml_table_level] = 1;
1498  xml_in_item[xml_table_level] = 0;
1499  xml_after_table_term = 0;
1500}
1501
1502void
1503xml_continue_table_item (void)
1504{
1505  xml_insert_element (TABLETERM, END);
1506  xml_after_table_term = 1;
1507  xml_in_item[xml_table_level] = 0;
1508}
1509
1510void
1511xml_begin_enumerate (char *enum_arg)
1512{
1513  if (!docbook)
1514    xml_insert_element_with_attribute (ENUMERATE, START, "first=\"%s\"", enum_arg);
1515  else
1516    {
1517      if (isdigit (*enum_arg))
1518        {
1519          int enum_val = atoi (enum_arg);
1520
1521          /* Have to check the value, not just the first digit.  */
1522          if (enum_val == 0)
1523            xml_insert_element_with_attribute (ENUMERATE, START,
1524                "numeration=\"arabic\" role=\"0\"", NULL);
1525          else if (enum_val == 1)
1526            xml_insert_element_with_attribute (ENUMERATE, START,
1527                "numeration=\"arabic\"", NULL);
1528          else
1529            xml_insert_element_with_attribute (ENUMERATE, START,
1530                "continuation=\"continues\" numeration=\"arabic\"", NULL);
1531        }
1532      else if (isupper (*enum_arg))
1533        {
1534          if (enum_arg[0] == 'A')
1535            xml_insert_element_with_attribute (ENUMERATE, START,
1536                "numeration=\"upperalpha\"", NULL);
1537          else
1538            xml_insert_element_with_attribute (ENUMERATE, START,
1539                "continuation=\"continues\" numeration=\"upperalpha\"", NULL);
1540        }
1541      else
1542        {
1543          if (enum_arg[0] == 'a')
1544            xml_insert_element_with_attribute (ENUMERATE, START,
1545                "numeration=\"loweralpha\"", NULL);
1546          else
1547            xml_insert_element_with_attribute (ENUMERATE, START,
1548                "continuation=\"continues\" numeration=\"loweralpha\"", NULL);
1549        }
1550    }
1551  xml_table_level ++;
1552  xml_in_item[xml_table_level] = 0;
1553}
1554
1555void
1556xml_end_enumerate (void)
1557{
1558  if (xml_in_item[xml_table_level])
1559    {
1560      xml_insert_element (ITEM, END);
1561      xml_in_item[xml_table_level] = 0;
1562    }
1563  xml_insert_element (ENUMERATE, END);
1564  xml_table_level --;
1565}
1566
1567static void
1568xml_insert_text_file (char *name_arg)
1569{
1570  char *fullname = xmalloc (strlen (name_arg) + 4 + 1);
1571  FILE *image_file;
1572  strcpy (fullname, name_arg);
1573  strcat (fullname, ".txt");
1574  image_file = fopen (fullname, "r");
1575  if (image_file)
1576    {
1577      int ch;
1578      int save_inhibit_indentation = inhibit_paragraph_indentation;
1579      int save_filling_enabled = filling_enabled;
1580
1581      xml_insert_element (TEXTOBJECT, START);
1582      xml_insert_element (DISPLAY, START);
1583
1584      inhibit_paragraph_indentation = 1;
1585      filling_enabled = 0;
1586      last_char_was_newline = 0;
1587
1588      /* Maybe we need to remove the final newline if the image
1589         file is only one line to allow in-line images.  On the
1590         other hand, they could just make the file without a
1591         final newline.  */
1592      while ((ch = getc (image_file)) != EOF)
1593        add_char (ch);
1594
1595      inhibit_paragraph_indentation = save_inhibit_indentation;
1596      filling_enabled = save_filling_enabled;
1597
1598      xml_insert_element (DISPLAY, END);
1599      xml_insert_element (TEXTOBJECT, END);
1600
1601      if (fclose (image_file) != 0)
1602        perror (fullname);
1603    }
1604  else
1605    warning (_("@image file `%s' unreadable: %s"), fullname,
1606             strerror (errno));
1607
1608  free (fullname);
1609}
1610
1611/* If NAME.EXT is accessible or FORCE is nonzero, insert a docbook
1612   imagedata element for FMT.  Return 1 if inserted something, 0 else.  */
1613
1614static int
1615try_docbook_image (const char *name, const char *ext, const char *fmt,
1616                   int force)
1617{
1618  int used = 0;
1619  char *fullname = xmalloc (strlen (name) + 1 + strlen (ext) + 1);
1620  sprintf (fullname, "%s.%s", name, ext);
1621
1622  if (force || access (fullname, R_OK) == 0)
1623   {
1624     xml_insert_element (IMAGEOBJECT, START);
1625     xml_insert_element_with_attribute (IMAGEDATA, START,
1626       "fileref=\"%s\" format=\"%s\"", fullname, fmt);
1627     xml_insert_element (IMAGEDATA, END);
1628     xml_insert_element (IMAGEOBJECT, END);
1629     used = 1;
1630   }
1631
1632 free (fullname);
1633 return used;
1634}
1635
1636
1637void
1638xml_insert_docbook_image (char *name_arg)
1639{
1640  int found = 0;
1641  int elt = xml_in_para ? INLINEIMAGE : MEDIAOBJECT;
1642
1643  if (is_in_insertion_of_type (floatenv))
1644    xml_begin_docbook_float (INFORMALFIGURE);
1645  else if (!xml_in_para)
1646    xml_insert_element (INFORMALFIGURE, START);
1647
1648  xml_no_para++;
1649
1650  xml_insert_element (elt, START);
1651
1652  /* A selected few from http://docbook.org/tdg/en/html/imagedata.html.  */
1653  if (try_docbook_image (name_arg, "eps", "EPS", 0))
1654    found++;
1655  if (try_docbook_image (name_arg, "gif", "GIF", 0))
1656    found++;
1657  if (try_docbook_image (name_arg, "jpg", "JPG", 0))
1658    found++;
1659  if (try_docbook_image (name_arg, "jpeg", "JPEG", 0))
1660    found++;
1661  if (try_docbook_image (name_arg, "pdf", "PDF", 0))
1662    found++;
1663  if (try_docbook_image (name_arg, "png", "PNG", 0))
1664    found++;
1665  if (try_docbook_image (name_arg, "svg", "SVG", 0))
1666    found++;
1667
1668  /* If no luck so far, just assume we'll eventually have a jpg.  */
1669  if (!found)
1670    try_docbook_image (name_arg, "jpg", "JPG", 1);
1671
1672  xml_insert_text_file (name_arg);
1673  xml_insert_element (elt, END);
1674
1675  xml_no_para--;
1676
1677  if (elt == MEDIAOBJECT)
1678    xml_insert_element (INFORMALFIGURE, END);
1679}
1680
1681void
1682xml_asterisk (void)
1683{
1684}
1685
1686
1687/*
1688 *     INDEX
1689 */
1690/* Used to separate primary and secondary entries in an index -- we need
1691   to have real multilivel indexing support, not just string analysis.  */
1692#define INDEX_SEP "@this string will never appear@" /* was , */
1693
1694typedef struct
1695{
1696  char *from;
1697  char *to;
1698} XML_SYNONYM;
1699
1700static XML_SYNONYM **xml_synonyms = NULL;
1701static int xml_synonyms_count = 0;
1702
1703void
1704xml_insert_indexterm (char *indexterm, char *index)
1705{
1706  /* @index commands can appear between @item and @itemx, @deffn and @deffnx.  */
1707  if (!docbook)
1708    {
1709      /* Check to see if we need to do index redirection per @synindex.  */
1710      int i;
1711      for (i = 0; i < xml_synonyms_count; i++)
1712        {
1713          if (STREQ (xml_synonyms[i]->from, index))
1714            index = xstrdup (xml_synonyms[i]->to);
1715        }
1716
1717      xml_dont_touch_items_defs++;
1718      xml_insert_element_with_attribute (INDEXTERM, START, "index=\"%s\"", index);
1719      in_indexterm = 1;
1720      execute_string ("%s", indexterm);
1721      xml_insert_element (INDEXTERM, END);
1722      in_indexterm = 0;
1723      xml_dont_touch_items_defs--;
1724    }
1725  else
1726    {
1727      char *primary = NULL, *secondary = NULL;
1728      if (strstr (indexterm+1, INDEX_SEP))
1729        {
1730          primary = xmalloc (strlen (indexterm) + 1);
1731          strcpy (primary, indexterm);
1732          secondary = strstr (primary+1, INDEX_SEP);
1733          *secondary = '\0';
1734          secondary += strlen (INDEX_SEP);
1735        }
1736      xml_insert_element_with_attribute (INDEXTERM, START, "role=\"%s\"", index);
1737      in_indexterm = 1;
1738      xml_insert_element (PRIMARY, START);
1739      if (primary)
1740        execute_string ("%s", primary);
1741      else
1742        execute_string ("%s", indexterm);
1743      xml_insert_element (PRIMARY, END);
1744      if (primary)
1745        {
1746          xml_insert_element (SECONDARY, START);
1747          execute_string ("%s", secondary);
1748          xml_insert_element (SECONDARY, END);
1749        }
1750      xml_insert_element (INDEXTERM, END);
1751      in_indexterm = 0;
1752    }
1753}
1754
1755
1756int xml_last_section_output_position = 0;
1757static char last_division_letter = ' ';
1758static char index_primary[2000]; /** xx no fixed limit */
1759static int indexdivempty = 0;
1760
1761static void
1762xml_close_indexentry (void)
1763{
1764  if (!in_indexentry)
1765    return;
1766  if (in_secondary)
1767    xml_insert_element (SECONDARYIE, END);
1768  xml_insert_element (INDEXENTRY, END);
1769  in_secondary = 0;
1770  in_indexentry = 0;
1771}
1772
1773void
1774xml_begin_index (void)
1775{
1776  typedef struct xml_index_title {
1777      struct xml_index_title *next;
1778      char *title;
1779  } XML_INDEX_TITLE;
1780
1781  static XML_INDEX_TITLE *xml_index_titles = NULL;
1782
1783  if (!handling_delayed_writes)
1784    { /* We assume that we just opened a section, and so that the last output is
1785         <SECTION ID="node-name"><TITLE>Title</TITLE>
1786         where SECTION can be CHAPTER, ...  */
1787
1788      XML_INDEX_TITLE *new = xmalloc (sizeof (XML_INDEX_TITLE));
1789      xml_section *temp = last_section;
1790
1791      int l = output_paragraph_offset-xml_last_section_output_position;
1792      char *tmp = xmalloc (l+1);
1793      char *p = tmp;
1794      strncpy (tmp, (char *) output_paragraph, l);
1795
1796      /* We remove <SECTION */
1797      tmp[l] = '\0';
1798      while (*p != '<')
1799        p++;
1800      while (*p != ' ')
1801        p++;
1802      /* ... and its label attribute.  */
1803      if (strncmp (p, " label=", 7) == 0)
1804        {
1805          p++;
1806          while (*p != ' ')
1807            p++;
1808        }
1809
1810      output_paragraph_offset = xml_last_section_output_position;
1811      xml_last_section_output_position = 0;
1812
1813      xml_pop_current_element (); /* remove section element from elements stack */
1814
1815      if (last_section)
1816        last_section = last_section->prev; /* remove section from sections stack */
1817      if (temp)
1818        {
1819          free (temp->name);
1820          free (temp);
1821        }
1822
1823      new->title = xstrdup (p);
1824      new->next = xml_index_titles;
1825      xml_index_titles = new;
1826    }
1827  else
1828    {
1829      static int xml_index_titles_reversed = 0;
1830
1831      if (!xml_index_titles_reversed)
1832        {
1833          xml_index_titles = (XML_INDEX_TITLE *) reverse_list
1834            ((GENERIC_LIST *) xml_index_titles);
1835          xml_index_titles_reversed = 1;
1836        }
1837
1838      /* We put <INDEX> */
1839      xml_insert_element (PRINTINDEX, START);
1840      if (xml_index_titles)
1841        {
1842          /* Remove the final > */
1843          output_paragraph_offset--;
1844          /* and put  ID="node-name"><TITLE>Title</TITLE> */
1845          insert_string (xml_index_titles->title);
1846          free (xml_index_titles->title);
1847          xml_index_titles = xml_index_titles->next;
1848        }
1849
1850      if (xml_index_divisions)
1851        {
1852          xml_insert_element (INDEXDIV, START);
1853          indexdivempty = 1;
1854        }
1855    }
1856}
1857
1858void
1859xml_end_index (void)
1860{
1861  xml_close_indexentry ();
1862  if (xml_index_divisions)
1863    xml_insert_element (INDEXDIV, END);
1864  xml_insert_element (PRINTINDEX, END);
1865}
1866
1867static void
1868xml_index_divide (char *entry)
1869{
1870  char c;
1871  if (strlen (entry) > (strlen (xml_element_list[CODE].name) + 2) &&
1872      strncmp (entry+1, xml_element_list[CODE].name, strlen (xml_element_list[CODE].name)) == 0)
1873    c = entry[strlen (xml_element_list[CODE].name)+2];
1874  else
1875    c = entry[0];
1876  if (tolower (c) != last_division_letter && isalpha (c))
1877    {
1878      last_division_letter = tolower (c);
1879      xml_close_indexentry ();
1880      if (!indexdivempty)
1881        {
1882          xml_insert_element (INDEXDIV, END);
1883          xml_insert_element (INDEXDIV, START);
1884        }
1885      xml_insert_element (TITLE, START);
1886      insert (toupper (c));
1887      xml_insert_element (TITLE, END);
1888    }
1889}
1890
1891void
1892xml_insert_indexentry (char *entry, char *node)
1893{
1894  char *primary = NULL, *secondary;
1895  if (xml_index_divisions)
1896    xml_index_divide (entry);
1897
1898  indexdivempty = 0;
1899  if (strstr (entry+1, INDEX_SEP))
1900    {
1901      primary = xmalloc (strlen (entry) + 1);
1902      strcpy (primary, entry);
1903      secondary = strstr (primary+1, INDEX_SEP);
1904      *secondary = '\0';
1905      secondary += strlen (INDEX_SEP);
1906
1907      if (in_secondary && strcmp (primary, index_primary) == 0)
1908        {
1909          xml_insert_element (SECONDARYIE, END);
1910          xml_insert_element (SECONDARYIE, START);
1911          execute_string ("%s", secondary);
1912        }
1913      else
1914        {
1915          xml_close_indexentry ();
1916          xml_insert_element (INDEXENTRY, START);
1917          in_indexentry = 1;
1918          xml_insert_element (PRIMARYIE, START);
1919          execute_string ("%s", primary);
1920          xml_insert_element (PRIMARYIE, END);
1921          xml_insert_element (SECONDARYIE, START);
1922          execute_string ("%s", secondary);
1923          in_secondary = 1;
1924        }
1925    }
1926  else
1927    {
1928      xml_close_indexentry ();
1929      xml_insert_element (INDEXENTRY, START);
1930      in_indexentry = 1;
1931      xml_insert_element (PRIMARYIE, START);
1932      execute_string ("%s", entry);
1933    }
1934  add_word (", ");
1935
1936  /* Don't link to @unnumbered sections directly.
1937     We are disabling warnings temporarily, otherwise these xrefs
1938     will cause bogus warnings about missing punctuation.  */
1939  {
1940    extern int print_warnings;
1941    int save_print_warnings = print_warnings;
1942    print_warnings = 0;
1943    execute_string ("%cxref{%s}", COMMAND_PREFIX, xstrdup (node));
1944    print_warnings = save_print_warnings;
1945  }
1946
1947  if (primary)
1948    {
1949      strcpy (index_primary, primary);
1950      /*      xml_insert_element (SECONDARYIE, END);*/
1951      /*     *(secondary-1) = ',';*/ /* necessary ? */
1952      free (primary);
1953    }
1954  else
1955    xml_insert_element (PRIMARYIE, END);
1956
1957  /*  xml_insert_element (INDEXENTRY, END); */
1958}
1959
1960void
1961xml_synindex (char *from, char *to)
1962{
1963  int i, slot;
1964
1965  slot = -1;
1966  for (i = 0; i < xml_synonyms_count; i++)
1967    if (!xml_synonyms[i])
1968      {
1969        slot = i;
1970        break;
1971      }
1972
1973  if (slot < 0)
1974    {
1975      slot = xml_synonyms_count;
1976      xml_synonyms_count++;
1977
1978      xml_synonyms = (XML_SYNONYM **) xrealloc (xml_synonyms,
1979          (xml_synonyms_count + 1) * sizeof (XML_SYNONYM *));
1980    }
1981
1982  xml_synonyms[slot] = xmalloc (sizeof (XML_SYNONYM));
1983  xml_synonyms[slot]->from = xstrdup (from);
1984  xml_synonyms[slot]->to = xstrdup (to);
1985}
1986
1987/*
1988 * MULTITABLE
1989 */
1990
1991static int multitable_columns_count;
1992static int *multitable_column_widths;
1993
1994void
1995xml_begin_multitable (int ncolumns, int *column_widths)
1996{
1997  int i;
1998  if (docbook)
1999    {
2000      if (is_in_insertion_of_type (floatenv))
2001        xml_begin_docbook_float (MULTITABLE);
2002      else
2003        xml_insert_element (MULTITABLE, START);
2004
2005      multitable_columns_count = ncolumns;
2006      multitable_column_widths = xmalloc (sizeof (int) * ncolumns);
2007      memcpy (multitable_column_widths, column_widths,
2008          sizeof (int) * ncolumns);
2009
2010      xml_no_para = 1;
2011    }
2012  else
2013    {
2014      xml_insert_element (MULTITABLE, START);
2015      for (i=0; i<ncolumns; i++)
2016        {
2017          xml_insert_element (COLSPEC, START);
2018          add_word_args ("%d", column_widths[i]);
2019          xml_insert_element (COLSPEC, END);
2020        }
2021      xml_no_para = 1;
2022    }
2023}
2024
2025static void
2026xml_begin_multitable_group (void)
2027{
2028  int i;
2029
2030  xml_insert_element_with_attribute (TGROUP, START, "cols=\"%d\"",
2031      multitable_columns_count);
2032
2033  for (i=0; i < multitable_columns_count; i++)
2034    {
2035      xml_insert_element_with_attribute (COLSPEC, START,
2036          "colwidth=\"%d*\"", multitable_column_widths[i]);
2037      xml_insert_element (COLSPEC, END);
2038    }
2039}
2040
2041void
2042xml_end_multitable_row (int first_row)
2043{
2044  if (!first_row)
2045    {
2046      xml_insert_element (ENTRY, END);
2047      xml_insert_element (ROW, END);
2048    }
2049
2050  if (headitem_flag)
2051    {
2052      if (!first_row)
2053        {
2054          if (after_headitem)
2055            xml_insert_element (THEAD, END);
2056          else
2057            xml_insert_element (TBODY, END);
2058          xml_insert_element (TGROUP, END);
2059        }
2060
2061      xml_begin_multitable_group ();
2062      xml_insert_element (THEAD, START);
2063    }
2064  else if (first_row)
2065    {
2066      xml_begin_multitable_group ();
2067      xml_insert_element (TBODY, START);
2068    }
2069  else if (after_headitem)
2070    {
2071      xml_insert_element (THEAD, END);
2072      xml_insert_element (TBODY, START);
2073    }
2074  else if (first_row)
2075    xml_insert_element (TBODY, START);
2076
2077  xml_insert_element (ROW, START);
2078  xml_insert_element (ENTRY, START);
2079}
2080
2081void
2082xml_end_multitable_column (void)
2083{
2084  xml_insert_element (ENTRY, END);
2085  xml_insert_element (ENTRY, START);
2086}
2087
2088void
2089xml_end_multitable (void)
2090{
2091  xml_insert_element (ENTRY, END);
2092  xml_insert_element (ROW, END);
2093
2094  if (after_headitem)
2095    {
2096      if (docbook)
2097        warning (_("@headitem as the last item of @multitable produces invalid Docbook documents"));
2098      xml_insert_element (THEAD, END);
2099    }
2100  else
2101    xml_insert_element (TBODY, END);
2102
2103  if (docbook)
2104    xml_insert_element (TGROUP, END);
2105
2106  xml_insert_element (MULTITABLE, END);
2107  xml_no_para = 0;
2108}
2109
2110/*
2111 * Parameters in @def definitions
2112 */
2113
2114#define DEFUN_SELF_DELIMITING(c) \
2115  ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')
2116
2117void
2118xml_process_defun_args (char **defun_args, int auto_var_p)
2119{
2120  int pending_space = 0;
2121  int just_after_paramtype = 0;
2122
2123  for (;;)
2124    {
2125      char *defun_arg = *defun_args++;
2126
2127      if (defun_arg == NULL)
2128        break;
2129
2130      if (defun_arg[0] == ' ')
2131        {
2132          pending_space = 1;
2133          continue;
2134        }
2135
2136      if (pending_space)
2137        {
2138          add_char (' ');
2139          pending_space = 0;
2140        }
2141
2142      if (DEFUN_SELF_DELIMITING (defun_arg[0]))
2143        {
2144	  xml_insert_element (DEFDELIMITER, START);
2145          add_char (defun_arg[0]);
2146	  xml_insert_element (DEFDELIMITER, END);
2147	  just_after_paramtype = 0;
2148        }
2149      else if (defun_arg[0] == '&')
2150	{
2151	  xml_insert_element (DEFPARAM, START);
2152	  add_word (defun_arg);
2153	  xml_insert_element (DEFPARAM, END);
2154	  just_after_paramtype = 0;
2155	}
2156      else if (defun_arg[0] == COMMAND_PREFIX || just_after_paramtype)
2157	{
2158	  xml_insert_element (DEFPARAM, START);
2159	  execute_string ("%s", defun_arg);
2160	  xml_insert_element (DEFPARAM, END);
2161	  just_after_paramtype = 0;
2162	}
2163      else if (defun_arg[0] == ',' || defun_arg[0] == ';')
2164	{
2165	  xml_insert_element (DEFDELIMITER, START);
2166	  add_word (defun_arg);
2167	  xml_insert_element (DEFDELIMITER, END);
2168	  just_after_paramtype = 0;
2169	}
2170      else if (auto_var_p)
2171	{
2172	  xml_insert_element (DEFPARAM, START);
2173	  add_word (defun_arg);
2174	  xml_insert_element (DEFPARAM, END);
2175	  just_after_paramtype = 0;
2176	}
2177      else
2178	{
2179	  xml_insert_element (DEFPARAMTYPE, START);
2180	  add_word (defun_arg);
2181	  xml_insert_element (DEFPARAMTYPE, END);
2182	  just_after_paramtype = 1;
2183	}
2184    }
2185}
2186
2187void
2188xml_begin_definition (void)
2189{
2190  xml_insert_element (DEFINITION, START);
2191  xml_definition_level ++;
2192  xml_in_def_item[xml_definition_level] = 0;
2193}
2194
2195void
2196xml_end_definition (void)
2197{
2198  if (xml_in_def_item[xml_definition_level])
2199    {
2200      xml_insert_element (DEFINITIONITEM, END);
2201      xml_in_def_item[xml_definition_level] = 0;
2202    }
2203  xml_after_def_term = 0;
2204  xml_insert_element (DEFINITION, END);
2205  xml_definition_level --;
2206}
2207
2208void
2209xml_begin_def_term (int base_type, const char *category,
2210    char *defined_name, char *type_name, char *type_name2)
2211{
2212  xml_after_def_term = 0;
2213  xml_insert_element (DEFINITIONTERM, START);
2214
2215  /* Index entry */
2216  switch (base_type)
2217    {
2218    case deffn:
2219    case deftypefn:
2220      execute_string ("@findex %s\n", defined_name);
2221      break;
2222    case defvr:
2223    case deftypevr:
2224    case defcv:
2225      execute_string ("@vindex %s\n", defined_name);
2226      break;
2227    case deftypecv:
2228    case deftypeivar:
2229      execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name);
2230      break;
2231    case deftypemethod:
2232    case defop:
2233    case deftypeop:
2234      execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name);
2235      break;
2236    case deftp:
2237      execute_string ("@tindex %s\n", defined_name);
2238      break;
2239    }
2240
2241  /* Start with category.  */
2242  xml_insert_element (DEFCATEGORY, START);
2243  execute_string (docbook ? "--- %s:" : "%s", category);
2244  xml_insert_element (DEFCATEGORY, END);
2245  add_char(' ');
2246
2247  /* Output type name first for typed definitions.  */
2248  switch (base_type)
2249    {
2250    case deffn:
2251    case defvr:
2252    case deftp:
2253      break;
2254
2255    case deftypefn:
2256    case deftypevr:
2257      xml_insert_element (DEFTYPE, START);
2258      execute_string ("%s", type_name);
2259      xml_insert_element (DEFTYPE, END);
2260      add_char (' ');
2261      break;
2262
2263    case deftypecv:
2264    case deftypeivar:
2265    case deftypemethod:
2266    case deftypeop:
2267      xml_insert_element (DEFTYPE, START);
2268      execute_string ("%s", type_name2);
2269      xml_insert_element (DEFTYPE, END);
2270      add_char (' ');
2271      break;
2272
2273    default:
2274      xml_insert_element (DEFCLASS, START);
2275      execute_string ("%s", type_name);
2276      xml_insert_element (DEFCLASS, END);
2277      add_char (' ');
2278      break;
2279    }
2280
2281  /* Categorize rest of the definitions.  */
2282  switch (base_type)
2283    {
2284    case deffn:
2285    case deftypefn:
2286      xml_insert_element (DEFFUNCTION, START);
2287      execute_string ("%s", defined_name);
2288      xml_insert_element (DEFFUNCTION, END);
2289      break;
2290
2291    case defvr:
2292    case deftypevr:
2293      xml_insert_element (DEFVARIABLE, START);
2294      execute_string ("%s", defined_name);
2295      xml_insert_element (DEFVARIABLE, END);
2296      break;
2297
2298    case deftp:
2299      xml_insert_element (DEFDATATYPE, START);
2300      execute_string ("%s", defined_name);
2301      xml_insert_element (DEFDATATYPE, END);
2302      break;
2303
2304    case defcv:
2305    case deftypecv:
2306    case deftypeivar:
2307      xml_insert_element (DEFCLASSVAR, START);
2308      execute_string ("%s", defined_name);
2309      xml_insert_element (DEFCLASSVAR, END);
2310      break;
2311
2312    case defop:
2313    case deftypeop:
2314    case deftypemethod:
2315      /* Operation / Method */
2316      xml_insert_element (DEFOPERATION, START);
2317      execute_string ("%s", defined_name);
2318      xml_insert_element (DEFOPERATION, END);
2319      break;
2320    }
2321}
2322
2323void
2324xml_end_def_term (void)
2325{
2326  xml_insert_element (DEFINITIONTERM, END);
2327  xml_after_def_term = 1;
2328}
2329