xref: /openbsd/gnu/usr.bin/texinfo/makeinfo/xml.c (revision 264ca280)
1 /* xml.c -- xml output.
2    $Id: xml.c,v 1.2 2008/10/08 07:09:37 otto 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 */
34 int xml_index_divisions = 1;
35 
36 typedef struct _element
37 {
38   char name[32];
39   int contains_para;
40   int contained_in_para;
41   int keep_space;
42 } element;
43 
44 element 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 
257 element 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 
468 element *xml_element_list = NULL;
469 
470 
471 typedef 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 
487 replace_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 
516 int xml_in_menu_entry = 0;
517 int xml_in_menu_entry_comment = 0;
518 int xml_node_open = 0;
519 int xml_node_level = -1;
520 int xml_in_para = 0;
521 int xml_just_after_element = 0;
522 int xml_keep_space = 0;
523 
524 int xml_no_indent = 0;
525 
526 int xml_no_para = 0;
527 char *xml_node_id = NULL;
528 int xml_sort_index = 0;
529 
530 int xml_in_xref_token = 0;
531 int xml_in_bookinfo = 0;
532 int xml_in_book_title = 0;
533 int 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.  */
537 int 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.  */
541 static int xml_in_footnote = 0;
542 
543 static int xml_after_table_term = 0;
544 static int book_started = 0;
545 static int first_section_opened = 0;
546 
547 static int xml_in_tableitem[256];
548 static int xml_in_item[256];
549 static int xml_table_level = 0;
550 
551 static int xml_in_def_item[256];
552 static int xml_definition_level = 0;
553 int xml_after_def_term = 0;
554 
555 static int in_table_title = 0;
556 
557 static int in_indexentry = 0;
558 static int in_secondary = 0;
559 static int in_indexterm = 0;
560 
561 char *
562 xml_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 
582 int
583 xml_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 
595 void
596 xml_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 /*  */
654 static int element_stack[256];
655 static int element_stack_index = 0;
656 
657 static int
658 xml_current_element (void)
659 {
660   return element_stack[element_stack_index-1];
661 }
662 
663 static void
664 xml_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 
673 static void
674 xml_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 
683 int
684 xml_current_stack_index (void)
685 {
686   return element_stack_index;
687 }
688 
689 void
690 xml_end_current_element (void)
691 {
692   xml_insert_element (xml_current_element (), END);
693 }
694 
695 static void
696 xml_indent (void)
697 {
698   if (xml_indentation_increment > 0)
699     {
700       int i;
701       if (output_paragraph_offset > 0
702 	  && output_paragraph[output_paragraph_offset-1] != '\n')
703         insert ('\n');
704       for (i = 0; i < element_stack_index * xml_indentation_increment; i++)
705         insert (' ');
706     }
707 }
708 
709 void
710 xml_start_para (void)
711 {
712   if (xml_in_para || xml_in_footnote
713       || !xml_element_list[xml_current_element()].contains_para)
714     return;
715 
716   while (output_paragraph_offset > 0
717          && output_paragraph[output_paragraph_offset-1] == '\n')
718     output_paragraph_offset--;
719   xml_indent ();
720 
721   insert_string ("<para");
722   if (xml_no_indent)
723     insert_string (" role=\"continues\"");
724   insert_string (">");
725   xml_no_indent = 0;
726   xml_in_para = 1;
727 }
728 
729 void
730 xml_end_para (void)
731 {
732   if (!xml_in_para || xml_in_footnote)
733     return;
734 
735   while (output_paragraph_offset > 0
736 	 && cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
737     output_paragraph_offset--;
738 
739   insert_string ("</para>");
740   if (xml_indentation_increment > 0)
741     insert ('\n');
742   xml_in_para = 0;
743 }
744 
745 void
746 xml_end_document (void)
747 {
748   if (xml_node_open)
749     {
750       if (xml_node_level != -1)
751         {
752           xml_close_sections (xml_node_level);
753           xml_node_level = -1;
754         }
755       xml_insert_element (NODE, END);
756     }
757   else
758     xml_close_sections (xml_node_level);
759 
760   xml_insert_element (TEXINFO, END);
761   if (xml_indentation_increment == 0)
762     insert ('\n');
763   insert_string ("<!-- Keep this comment at the end of the file\n\
764 Local variables:\n\
765 mode: sgml\n\
766 sgml-indent-step:1\n\
767 sgml-indent-data:nil\n\
768 End:\n\
769 -->\n");
770   if (element_stack_index != 0)
771     error ("Element stack index : %d\n", element_stack_index);
772 }
773 
774 /* MUST be 0 or 1, not true or false values */
775 static int start_element_inserted = 1;
776 
777 /* NOTE: We use `elt' rather than `element' in the argument list of
778    the next function, since otherwise the Solaris SUNWspro compiler
779    barfs because `element' is a typedef declared near the beginning of
780    this file.  */
781 void
782 #if defined (VA_FPRINTF) && __STDC__
783 xml_insert_element_with_attribute (int elt, int arg, char *format, ...)
784 #else
785 xml_insert_element_with_attribute (elt, arg, format, va_alist)
786      int elt;
787      int arg;
788      char *format;
789      va_dcl
790 #endif
791 {
792   /* Look at the replace_elements table to see if we have to change the element */
793   if (xml_sort_index)
794       return;
795   if (docbook)
796     {
797       replace_element *element_list = replace_elements;
798       while (element_list->element_to_replace >= 0)
799         {
800           if ( ( (arg == START) &&
801                  (element_list->element_containing == xml_current_element ()) &&
802                  (element_list->element_to_replace == elt) ) ||
803                ( (arg == END) &&
804                  (element_list->element_containing == element_stack[element_stack_index-1-start_element_inserted]) &&
805                  (element_list->element_to_replace == elt) ) )
806             {
807               elt = element_list->element_replacing;
808               break;
809             }
810           element_list ++;
811         }
812 
813       /* Forget the element */
814       if (elt < 0)
815         {
816           if (arg == START)
817             start_element_inserted = 0;
818           else
819             /* Replace the default value, for the next time */
820             start_element_inserted = 1;
821           return;
822         }
823     }
824 
825   if (!book_started)
826     return;
827 
828   if (!xml_dont_touch_items_defs && arg == START)
829     {
830       if (xml_after_table_term && elt != TABLETERM && xml_table_level
831           && !xml_in_item[xml_table_level])
832         {
833           xml_after_table_term = 0;
834           xml_insert_element (ITEM, START);
835           xml_in_item[xml_table_level] = 1;
836         }
837       else if (xml_after_def_term && elt != DEFINITIONTERM)
838         {
839           xml_after_def_term = 0;
840           xml_insert_element (DEFINITIONITEM, START);
841           xml_in_def_item[xml_definition_level] = 1;
842         }
843     }
844 
845   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
846     return;
847 
848   if (executing_string && arg == END)
849     switch (elt)
850       {
851       case TABLEITEM:
852         xml_in_tableitem[xml_table_level] = 0;
853         break;
854       case ITEM:
855         xml_in_item[xml_table_level] = 0;
856         break;
857       case DEFINITIONTERM:
858         xml_in_def_item[xml_definition_level] = 0;
859         break;
860       }
861 
862   /* We are special-casing FIGURE element for docbook.  It does appear in
863      the tag stack, but not in the output.  This is to make element replacement
864      work beautifully.  */
865   if (docbook && elt == FLOAT)
866     {
867       if (arg == START)
868         xml_push_current_element (elt);
869       else
870         xml_pop_current_element ();
871       return;
872     }
873 
874   if (!xml_element_list[elt].name || !strlen (xml_element_list[elt].name))
875     {
876       /*printf ("Warning: Inserting empty element %d\n", elt);*/
877       return;
878     }
879 
880   if (arg == START && !xml_in_para && !xml_no_para
881       && xml_element_list[elt].contained_in_para)
882     xml_start_para ();
883 
884   if (arg == START && xml_in_para && !xml_element_list[elt].contained_in_para)
885     xml_end_para ();
886 
887   if (arg == END && xml_in_para && !xml_element_list[elt].contained_in_para)
888     xml_end_para ();
889 
890   if (docbook && xml_table_level && !in_table_title
891       && !xml_in_tableitem[xml_table_level] && !xml_in_item[xml_table_level]
892       && arg == START && elt != TABLEITEM && elt != TABLETERM
893       && !in_indexterm && xml_current_element() == TABLE)
894     {
895       in_table_title = 1;
896       xml_insert_element (TITLE, START);
897     }
898 
899   if (arg == START && !xml_in_para && !xml_keep_space
900       && !xml_element_list[elt].contained_in_para)
901     xml_indent ();
902 
903   if (arg == START)
904     xml_push_current_element (elt);
905   else
906     xml_pop_current_element ();
907 
908   /* Eat one newline before </example> and the like.  */
909   if (!docbook && arg == END
910       && (xml_element_list[elt].keep_space || elt == GROUP)
911       && output_paragraph_offset > 0
912       && output_paragraph[output_paragraph_offset-1] == '\n')
913     output_paragraph_offset--;
914 
915   /* And eat whitespace before </entry> in @multitables.  */
916   if (arg == END && elt == ENTRY)
917       while (output_paragraph_offset > 0
918 	     && cr_or_whitespace(output_paragraph[output_paragraph_offset-1]))
919     output_paragraph_offset--;
920 
921   /* Indent elements that can contain <para>.  */
922   if (arg == END && !xml_in_para && !xml_keep_space
923       && xml_element_list[elt].contains_para)
924     xml_indent ();
925 
926   /* Here are the elements we want indented.  These do not contain <para>
927      directly.  */
928   if (arg == END && (elt == MENUENTRY || elt == ITEMIZE || elt == ENUMERATE
929         || elt == TABLEITEM || elt == TABLE
930         || elt == MULTITABLE || elt == TGROUP || elt == THEAD || elt == TBODY
931         || elt == ROW || elt == INFORMALFIGURE
932         || (!docbook && (elt == DEFINITION || elt == DEFINITIONTERM))))
933     xml_indent ();
934 
935   insert ('<');
936   if (arg == END)
937     insert ('/');
938   insert_string (xml_element_list[elt].name);
939 
940   /*  printf ("%s ", xml_element_list[elt].name);*/
941 
942   if (format)
943     {
944       char temp_string[2000]; /* xx no fixed limits */
945 #ifdef VA_SPRINTF
946       va_list ap;
947 #endif
948 
949       VA_START (ap, format);
950 #ifdef VA_SPRINTF
951       VA_SPRINTF (temp_string, format, ap);
952 #else
953       sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
954 #endif
955       insert (' ');
956       insert_string (temp_string);
957       va_end (ap);
958     }
959 
960   if (arg == START && xml_node_id && elt != NODENAME)
961     {
962       insert_string (" id=\"");
963       insert_string (xml_node_id);
964       insert ('"');
965       free (xml_node_id);
966       xml_node_id = NULL;
967     }
968 
969   if (xml_element_list[elt].keep_space)
970     {
971       if (arg == START)
972 	{
973           if (!docbook)
974             insert_string (" xml:space=\"preserve\"");
975 	  xml_keep_space++;
976 	}
977       else
978 	xml_keep_space--;
979     }
980 
981   insert ('>');
982 
983   if (!xml_in_para && !xml_element_list[elt].contained_in_para
984       && xml_element_list[elt].contains_para && xml_indentation_increment > 0)
985     insert ('\n');
986 
987   xml_just_after_element = 1;
988 }
989 
990 /* See the NOTE before xml_insert_element_with_attribute, for why we
991    use `elt' rather than `element' here.  */
992 void
993 xml_insert_element (int elt, int arg)
994 {
995   xml_insert_element_with_attribute (elt, arg, NULL);
996 }
997 
998 void
999 xml_insert_entity (char *entity_name)
1000 {
1001   int saved_escape_html = escape_html;
1002 
1003   if (!book_started)
1004     return;
1005   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
1006     return;
1007 
1008   if (!xml_in_para && !xml_no_para && !only_macro_expansion
1009       && xml_element_list[xml_current_element ()].contains_para
1010       && !in_fixed_width_font)
1011     xml_start_para ();
1012 
1013   escape_html = 0;
1014   add_char ('&');
1015   escape_html = saved_escape_html;
1016   insert_string (entity_name);
1017   add_char (';');
1018 }
1019 
1020 typedef struct _xml_section xml_section;
1021 struct _xml_section {
1022   int level;
1023   char *name;
1024   xml_section *prev;
1025 };
1026 
1027 xml_section *last_section = NULL;
1028 
1029 void
1030 xml_begin_node (void)
1031 {
1032   first_section_opened = 1;
1033   if (xml_in_abstract)
1034     {
1035       xml_insert_element (ABSTRACT, END);
1036       xml_in_abstract = 0;
1037     }
1038   if (xml_in_bookinfo)
1039     {
1040       xml_insert_element (BOOKINFO, END);
1041       xml_in_bookinfo = 0;
1042     }
1043   if (xml_node_open && ! docbook)
1044     {
1045       if (xml_node_level != -1)
1046         {
1047           xml_close_sections (xml_node_level);
1048           xml_node_level = -1;
1049         }
1050       xml_insert_element (NODE, END);
1051     }
1052   xml_insert_element (NODE, START);
1053   xml_node_open = 1;
1054 }
1055 
1056 void
1057 xml_close_sections (int level)
1058 {
1059   if (!first_section_opened)
1060     {
1061       if (xml_in_abstract)
1062 	{
1063 	  xml_insert_element (ABSTRACT, END);
1064 	  xml_in_abstract = 0;
1065 	}
1066       if (xml_in_bookinfo)
1067 	{
1068 	  xml_insert_element (BOOKINFO, END);
1069 	  xml_in_bookinfo = 0;
1070 	}
1071       first_section_opened = 1;
1072     }
1073 
1074   while (last_section && last_section->level >= level)
1075     {
1076       xml_section *temp = last_section;
1077       xml_insert_element (xml_element(last_section->name), END);
1078       temp = last_section;
1079       last_section = last_section->prev;
1080       free (temp->name);
1081       free (temp);
1082     }
1083 }
1084 
1085 void
1086 xml_open_section (int level, char *name)
1087 {
1088   xml_section *sect = (xml_section *) xmalloc (sizeof (xml_section));
1089 
1090   sect->level = level;
1091   sect->name = xmalloc (1 + strlen (name));
1092   strcpy (sect->name, name);
1093   sect->prev = last_section;
1094   last_section = sect;
1095 
1096   if (xml_node_open && xml_node_level == -1)
1097     xml_node_level = level;
1098 }
1099 
1100 void
1101 xml_start_menu_entry (char *tem)
1102 {
1103   char *string;
1104   discard_until ("* ");
1105 
1106   /* The line number was already incremented in reader_loop when we
1107      saw the newline, and discard_until has now incremented again.  */
1108   line_number--;
1109 
1110   if (xml_in_menu_entry)
1111     {
1112       if (xml_in_menu_entry_comment)
1113         {
1114           xml_insert_element (MENUCOMMENT, END);
1115           xml_in_menu_entry_comment=0;
1116         }
1117       xml_insert_element (MENUENTRY, END);
1118       xml_in_menu_entry=0;
1119     }
1120   xml_insert_element (MENUENTRY, START);
1121   xml_in_menu_entry=1;
1122 
1123   xml_insert_element (MENUNODE, START);
1124   string = expansion (tem, 0);
1125   add_word (string);
1126   xml_insert_element (MENUNODE, END);
1127   free (string);
1128 
1129   /* The menu item may use macros, so expand them now.  */
1130   xml_insert_element (MENUTITLE, START);
1131   only_macro_expansion++;
1132   get_until_in_line (1, ":", &string);
1133   only_macro_expansion--;
1134   execute_string ("%s", string); /* get escaping done */
1135   xml_insert_element (MENUTITLE, END);
1136   free (string);
1137 
1138   if (looking_at ("::"))
1139     discard_until (":");
1140   else
1141     { /* discard the node name */
1142       get_until_in_line (0, ".", &string);
1143       free (string);
1144     }
1145   input_text_offset++;  /* discard the second colon or the period */
1146   skip_whitespace_and_newlines();
1147   xml_insert_element (MENUCOMMENT, START);
1148   xml_in_menu_entry_comment ++;
1149 }
1150 
1151 void
1152 xml_end_menu (void)
1153 {
1154   if (xml_in_menu_entry)
1155     {
1156       if (xml_in_menu_entry_comment)
1157         {
1158           xml_insert_element (MENUCOMMENT, END);
1159           xml_in_menu_entry_comment --;
1160         }
1161       xml_insert_element (MENUENTRY, END);
1162       xml_in_menu_entry--;
1163     }
1164   xml_insert_element (MENU, END);
1165 }
1166 
1167 static int xml_last_character;
1168 
1169 void
1170 xml_add_char (int character)
1171 {
1172   if (!book_started)
1173       return;
1174   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
1175     return;
1176 
1177   if (docbook && xml_table_level && !in_table_title
1178       && !xml_in_item[xml_table_level] && !xml_in_tableitem[xml_table_level]
1179       && !cr_or_whitespace (character) && !in_indexterm)
1180     {
1181       in_table_title = 1;
1182       xml_insert_element (TITLE, START);
1183     }
1184 
1185   if (!first_section_opened && !xml_in_abstract && !xml_in_book_title
1186       && !xml_no_para && character != '\r' && character != '\n'
1187       && character != ' ' && !is_in_insertion_of_type (copying))
1188     {
1189       if (!xml_in_bookinfo)
1190 	{
1191 	  xml_insert_element (BOOKINFO, START);
1192 	  xml_in_bookinfo = 1;
1193 	}
1194       xml_insert_element (ABSTRACT, START);
1195       xml_in_abstract = 1;
1196     }
1197 
1198   if (!xml_sort_index && !xml_in_xref_token && !xml_dont_touch_items_defs)
1199     {
1200       if (xml_after_table_term && xml_table_level
1201           && !xml_in_item[xml_table_level])
1202         {
1203           xml_after_table_term = 0;
1204           xml_insert_element (ITEM, START);
1205           xml_in_item[xml_table_level] = 1;
1206         }
1207       else if (xml_after_def_term)
1208         {
1209           xml_after_def_term = 0;
1210           xml_insert_element (DEFINITIONITEM, START);
1211           xml_in_def_item[xml_definition_level] = 1;
1212         }
1213     }
1214 
1215   if (xml_just_after_element && !xml_in_para && !inhibit_paragraph_indentation)
1216     {
1217       if (character == '\r' || character == '\n' || character == '\t' || character == ' ')
1218         return;
1219       xml_just_after_element = 0;
1220     }
1221 
1222   if (xml_element_list[xml_current_element()].contains_para
1223       && !xml_in_para && !only_macro_expansion && !xml_no_para
1224       && !cr_or_whitespace (character) && !in_fixed_width_font)
1225     xml_start_para ();
1226 
1227   if (xml_in_para && character == '\n' && xml_last_character == '\n'
1228       && !only_macro_expansion && !xml_no_para
1229       && xml_element_list[xml_current_element()].contains_para )
1230     {
1231       xml_end_para ();
1232       xml_just_after_element = 1;
1233       return;
1234     }
1235 
1236   if (xml_in_menu_entry_comment && character == '\n' && xml_last_character == '\n')
1237     {
1238       xml_insert_element (MENUCOMMENT, END);
1239       xml_in_menu_entry_comment = 0;
1240       xml_insert_element (MENUENTRY, END);
1241       xml_in_menu_entry = 0;
1242     }
1243 
1244   if (xml_in_menu_entry_comment && whitespace(character)
1245       && cr_or_whitespace(xml_last_character))
1246     return;
1247 
1248   if (character == '\n' && !xml_in_para && !inhibit_paragraph_indentation)
1249     return;
1250 
1251   xml_last_character = character;
1252 
1253   if (character == '&' && escape_html)
1254       insert_string ("&amp;");
1255   else if (character == '<' && escape_html)
1256       insert_string ("&lt;");
1257   else if (character == '\n' && !xml_keep_space)
1258     {
1259       if (!xml_in_para && xml_just_after_element && !multitable_active)
1260 	return;
1261       else
1262 	insert (docbook ? '\n' : ' ');
1263     }
1264   else
1265     insert (character);
1266 
1267   return;
1268 }
1269 
1270 void
1271 xml_insert_footnote (char *note)
1272 {
1273   if (!xml_in_para)
1274     xml_start_para ();
1275 
1276   xml_in_footnote = 1;
1277   xml_insert_element (FOOTNOTE, START);
1278   insert_string ("<para>");
1279   execute_string ("%s", note);
1280   insert_string ("</para>");
1281   xml_insert_element (FOOTNOTE, END);
1282   xml_in_footnote = 0;
1283 }
1284 
1285 /* We need to keep the quotation stack ourself, because insertion_stack
1286    loses item_function when we are closing the block, so we don't know
1287    what to close then.  */
1288 typedef struct quotation_elt
1289 {
1290   struct quotation_elt *next;
1291   char *type;
1292 } QUOTATION_ELT;
1293 
1294 static QUOTATION_ELT *quotation_stack = NULL;
1295 
1296 void
1297 xml_insert_quotation (char *type, int arg)
1298 {
1299   int quotation_started = 0;
1300 
1301   if (arg == START)
1302     {
1303       QUOTATION_ELT *new = xmalloc (sizeof (QUOTATION_ELT));
1304       new->type = xstrdup (type);
1305       new->next = quotation_stack;
1306       quotation_stack = new;
1307     }
1308   else
1309     type = quotation_stack->type;
1310 
1311   /* Make use of special quotation styles of Docbook if we can.  */
1312   if (docbook && strlen(type))
1313     {
1314       /* Let's assume it started.  */
1315       quotation_started = 1;
1316 
1317       if (strcasecmp (type, "tip") == 0)
1318         xml_insert_element (TIP, arg);
1319       else if (strcasecmp (type, "note") == 0)
1320         xml_insert_element (NOTE, arg);
1321       else if (strcasecmp (type, "important") == 0)
1322         xml_insert_element (IMPORTANT, arg);
1323       else if (strcasecmp (type, "warning") == 0)
1324         xml_insert_element (WARNING, arg);
1325       else if (strcasecmp (type, "caution") == 0)
1326         xml_insert_element (CAUTION, arg);
1327       else
1328         /* Didn't find a known quotation type :\ */
1329         quotation_started = 0;
1330     }
1331 
1332   if (!quotation_started)
1333     {
1334       xml_insert_element (QUOTATION, arg);
1335       if (strlen(type) && arg == START)
1336         execute_string ("@b{%s:} ", type);
1337     }
1338 
1339   if (arg == END)
1340     {
1341       QUOTATION_ELT *temp = quotation_stack;
1342       if (temp == NULL)
1343         return;
1344       quotation_stack = quotation_stack->next;
1345       free(temp->type);
1346       free(temp);
1347     }
1348 }
1349 
1350 /* Starting generic docbook floats.  Just starts elt with correct label
1351    and id attributes, and inserts title.  */
1352 void
1353 xml_begin_docbook_float (int elt)
1354 {
1355   if (current_float_used_title ())	/* in a nested float */
1356     {
1357       xml_insert_element (elt, START);	/* just insert the tag */
1358       return;
1359     }
1360 
1361 
1362   /* OK, need the title, tag, etc. */
1363   if (elt == CARTOUCHE)    /* no labels on <sidebar> */
1364     {
1365        if (strlen (current_float_id ()) == 0)
1366           xml_insert_element (elt, START);
1367        else
1368           xml_insert_element_with_attribute (elt, START,
1369               "id=\"%s\"", xml_id (current_float_id ()));
1370     }
1371   else if (strlen (current_float_id ()) == 0)
1372     xml_insert_element_with_attribute (elt, START, "label=\"\"");
1373   else
1374     xml_insert_element_with_attribute (elt, START,
1375         "id=\"%s\" label=\"%s\"", xml_id (current_float_id ()),
1376         current_float_number ());
1377 
1378   xml_insert_element (TITLE, START);
1379   execute_string ("%s", current_float_title ());
1380   xml_insert_element (TITLE, END);
1381 
1382   current_float_set_title_used ();	/* mark this title, tag, etc used */
1383 }
1384 
1385 /*
1386  * Lists and Tables
1387  */
1388 void
1389 xml_begin_table (int type, char *item_function)
1390 {
1391   switch (type)
1392     {
1393     case ftable:
1394     case vtable:
1395     case table:
1396       /*if (docbook)*/ /* 05-08 */
1397         {
1398           xml_insert_element (TABLE, START);
1399           xml_table_level ++;
1400           xml_in_tableitem[xml_table_level] = 0;
1401           xml_in_item[xml_table_level] = 0;
1402           xml_after_table_term = 0;
1403         }
1404       break;
1405     case itemize:
1406       if (!docbook)
1407         {
1408           xml_insert_element (ITEMIZE, START);
1409           xml_table_level ++;
1410           xml_in_item[xml_table_level] = 0;
1411           xml_insert_element (ITEMFUNCTION, START);
1412           if (*item_function == COMMAND_PREFIX
1413               && item_function[strlen (item_function) - 1] != '}'
1414               && command_needs_braces (item_function + 1))
1415             execute_string ("%s{}", item_function);
1416           else
1417             execute_string ("%s", item_function);
1418           xml_insert_element (ITEMFUNCTION, END);
1419         }
1420       else
1421         {
1422           xml_insert_element_with_attribute (ITEMIZE, START,
1423                                              "mark=\"%s\"",
1424                                              (*item_function == COMMAND_PREFIX) ?
1425                                              &item_function[1] : item_function);
1426           xml_table_level ++;
1427           xml_in_item[xml_table_level] = 0;
1428         }
1429       break;
1430     }
1431 }
1432 
1433 void
1434 xml_end_table (int type)
1435 {
1436   switch (type)
1437     {
1438     case ftable:
1439     case vtable:
1440     case table:
1441       if (xml_in_item[xml_table_level])
1442         {
1443           xml_insert_element (ITEM, END);
1444           xml_in_item[xml_table_level] = 0;
1445         }
1446       if (xml_in_tableitem[xml_table_level])
1447         {
1448           xml_insert_element (TABLEITEM, END);
1449           xml_in_tableitem[xml_table_level] = 0;
1450         }
1451       xml_insert_element (TABLE, END);
1452       xml_after_table_term = 0;
1453       xml_table_level --;
1454 
1455       break;
1456     case itemize:
1457       if (xml_in_item[xml_table_level])
1458         {
1459           xml_insert_element (ITEM, END);
1460           xml_in_item[xml_table_level] = 0;
1461         }
1462       /* gnat-style manual contains an itemized list without items! */
1463       if (in_table_title)
1464 	{
1465 	  xml_insert_element (TITLE, END);
1466 	  in_table_title = 0;
1467 	}
1468       xml_insert_element (ITEMIZE, END);
1469       xml_table_level --;
1470       break;
1471     }
1472 }
1473 
1474 void
1475 xml_begin_item (void)
1476 {
1477   if (xml_in_item[xml_table_level])
1478     xml_insert_element (ITEM, END);
1479 
1480   xml_insert_element (ITEM, START);
1481   xml_in_item[xml_table_level] = 1;
1482 }
1483 
1484 void
1485 xml_begin_table_item (void)
1486 {
1487   if (!xml_after_table_term)
1488     {
1489       if (xml_in_item[xml_table_level])
1490         xml_insert_element (ITEM, END);
1491       if (xml_in_tableitem[xml_table_level])
1492         xml_insert_element (TABLEITEM, END);
1493 
1494       if (in_table_title)
1495 	{
1496 	  in_table_title = 0;
1497 	  xml_insert_element (TITLE, END);
1498 	}
1499       xml_insert_element (TABLEITEM, START);
1500     }
1501   xml_insert_element (TABLETERM, START);
1502   xml_in_tableitem[xml_table_level] = 1;
1503   xml_in_item[xml_table_level] = 0;
1504   xml_after_table_term = 0;
1505 }
1506 
1507 void
1508 xml_continue_table_item (void)
1509 {
1510   xml_insert_element (TABLETERM, END);
1511   xml_after_table_term = 1;
1512   xml_in_item[xml_table_level] = 0;
1513 }
1514 
1515 void
1516 xml_begin_enumerate (char *enum_arg)
1517 {
1518   if (!docbook)
1519     xml_insert_element_with_attribute (ENUMERATE, START, "first=\"%s\"", enum_arg);
1520   else
1521     {
1522       if (isdigit (*enum_arg))
1523         {
1524           int enum_val = atoi (enum_arg);
1525 
1526           /* Have to check the value, not just the first digit.  */
1527           if (enum_val == 0)
1528             xml_insert_element_with_attribute (ENUMERATE, START,
1529                 "numeration=\"arabic\" role=\"0\"", NULL);
1530           else if (enum_val == 1)
1531             xml_insert_element_with_attribute (ENUMERATE, START,
1532                 "numeration=\"arabic\"", NULL);
1533           else
1534             xml_insert_element_with_attribute (ENUMERATE, START,
1535                 "continuation=\"continues\" numeration=\"arabic\"", NULL);
1536         }
1537       else if (isupper (*enum_arg))
1538         {
1539           if (enum_arg[0] == 'A')
1540             xml_insert_element_with_attribute (ENUMERATE, START,
1541                 "numeration=\"upperalpha\"", NULL);
1542           else
1543             xml_insert_element_with_attribute (ENUMERATE, START,
1544                 "continuation=\"continues\" numeration=\"upperalpha\"", NULL);
1545         }
1546       else
1547         {
1548           if (enum_arg[0] == 'a')
1549             xml_insert_element_with_attribute (ENUMERATE, START,
1550                 "numeration=\"loweralpha\"", NULL);
1551           else
1552             xml_insert_element_with_attribute (ENUMERATE, START,
1553                 "continuation=\"continues\" numeration=\"loweralpha\"", NULL);
1554         }
1555     }
1556   xml_table_level ++;
1557   xml_in_item[xml_table_level] = 0;
1558 }
1559 
1560 void
1561 xml_end_enumerate (void)
1562 {
1563   if (xml_in_item[xml_table_level])
1564     {
1565       xml_insert_element (ITEM, END);
1566       xml_in_item[xml_table_level] = 0;
1567     }
1568   xml_insert_element (ENUMERATE, END);
1569   xml_table_level --;
1570 }
1571 
1572 static void
1573 xml_insert_text_file (char *name_arg)
1574 {
1575   char *fullname = xmalloc (strlen (name_arg) + 4 + 1);
1576   FILE *image_file;
1577   strcpy (fullname, name_arg);
1578   strcat (fullname, ".txt");
1579   image_file = fopen (fullname, "r");
1580   if (image_file)
1581     {
1582       int ch;
1583       int save_inhibit_indentation = inhibit_paragraph_indentation;
1584       int save_filling_enabled = filling_enabled;
1585 
1586       xml_insert_element (TEXTOBJECT, START);
1587       xml_insert_element (DISPLAY, START);
1588 
1589       inhibit_paragraph_indentation = 1;
1590       filling_enabled = 0;
1591       last_char_was_newline = 0;
1592 
1593       /* Maybe we need to remove the final newline if the image
1594          file is only one line to allow in-line images.  On the
1595          other hand, they could just make the file without a
1596          final newline.  */
1597       while ((ch = getc (image_file)) != EOF)
1598         add_char (ch);
1599 
1600       inhibit_paragraph_indentation = save_inhibit_indentation;
1601       filling_enabled = save_filling_enabled;
1602 
1603       xml_insert_element (DISPLAY, END);
1604       xml_insert_element (TEXTOBJECT, END);
1605 
1606       if (fclose (image_file) != 0)
1607         perror (fullname);
1608     }
1609   else
1610     warning (_("@image file `%s' unreadable: %s"), fullname,
1611              strerror (errno));
1612 
1613   free (fullname);
1614 }
1615 
1616 /* If NAME.EXT is accessible or FORCE is nonzero, insert a docbook
1617    imagedata element for FMT.  Return 1 if inserted something, 0 else.  */
1618 
1619 static int
1620 try_docbook_image (const char *name, const char *ext, const char *fmt,
1621                    int force)
1622 {
1623   int used = 0;
1624   char *fullname = xmalloc (strlen (name) + 1 + strlen (ext) + 1);
1625   sprintf (fullname, "%s.%s", name, ext);
1626 
1627   if (force || access (fullname, R_OK) == 0)
1628    {
1629      xml_insert_element (IMAGEOBJECT, START);
1630      xml_insert_element_with_attribute (IMAGEDATA, START,
1631        "fileref=\"%s\" format=\"%s\"", fullname, fmt);
1632      xml_insert_element (IMAGEDATA, END);
1633      xml_insert_element (IMAGEOBJECT, END);
1634      used = 1;
1635    }
1636 
1637  free (fullname);
1638  return used;
1639 }
1640 
1641 
1642 void
1643 xml_insert_docbook_image (char *name_arg)
1644 {
1645   int found = 0;
1646   int elt = xml_in_para ? INLINEIMAGE : MEDIAOBJECT;
1647 
1648   if (is_in_insertion_of_type (floatenv))
1649     xml_begin_docbook_float (INFORMALFIGURE);
1650   else if (!xml_in_para)
1651     xml_insert_element (INFORMALFIGURE, START);
1652 
1653   xml_no_para++;
1654 
1655   xml_insert_element (elt, START);
1656 
1657   /* A selected few from http://docbook.org/tdg/en/html/imagedata.html.  */
1658   if (try_docbook_image (name_arg, "eps", "EPS", 0))
1659     found++;
1660   if (try_docbook_image (name_arg, "gif", "GIF", 0))
1661     found++;
1662   if (try_docbook_image (name_arg, "jpg", "JPG", 0))
1663     found++;
1664   if (try_docbook_image (name_arg, "jpeg", "JPEG", 0))
1665     found++;
1666   if (try_docbook_image (name_arg, "pdf", "PDF", 0))
1667     found++;
1668   if (try_docbook_image (name_arg, "png", "PNG", 0))
1669     found++;
1670   if (try_docbook_image (name_arg, "svg", "SVG", 0))
1671     found++;
1672 
1673   /* If no luck so far, just assume we'll eventually have a jpg.  */
1674   if (!found)
1675     try_docbook_image (name_arg, "jpg", "JPG", 1);
1676 
1677   xml_insert_text_file (name_arg);
1678   xml_insert_element (elt, END);
1679 
1680   xml_no_para--;
1681 
1682   if (elt == MEDIAOBJECT)
1683     xml_insert_element (INFORMALFIGURE, END);
1684 }
1685 
1686 void
1687 xml_asterisk (void)
1688 {
1689 }
1690 
1691 
1692 /*
1693  *     INDEX
1694  */
1695 /* Used to separate primary and secondary entries in an index -- we need
1696    to have real multilivel indexing support, not just string analysis.  */
1697 #define INDEX_SEP "@this string will never appear@" /* was , */
1698 
1699 typedef struct
1700 {
1701   char *from;
1702   char *to;
1703 } XML_SYNONYM;
1704 
1705 static XML_SYNONYM **xml_synonyms = NULL;
1706 static int xml_synonyms_count = 0;
1707 
1708 void
1709 xml_insert_indexterm (char *indexterm, char *index)
1710 {
1711   /* @index commands can appear between @item and @itemx, @deffn and @deffnx.  */
1712   if (!docbook)
1713     {
1714       /* Check to see if we need to do index redirection per @synindex.  */
1715       int i;
1716       for (i = 0; i < xml_synonyms_count; i++)
1717         {
1718           if (STREQ (xml_synonyms[i]->from, index))
1719             index = xstrdup (xml_synonyms[i]->to);
1720         }
1721 
1722       xml_dont_touch_items_defs++;
1723       xml_insert_element_with_attribute (INDEXTERM, START, "index=\"%s\"", index);
1724       in_indexterm = 1;
1725       execute_string ("%s", indexterm);
1726       xml_insert_element (INDEXTERM, END);
1727       in_indexterm = 0;
1728       xml_dont_touch_items_defs--;
1729     }
1730   else
1731     {
1732       char *primary = NULL, *secondary = NULL;
1733       if (strstr (indexterm+1, INDEX_SEP))
1734         {
1735           primary = xmalloc (strlen (indexterm) + 1);
1736           strcpy (primary, indexterm);
1737           secondary = strstr (primary+1, INDEX_SEP);
1738           *secondary = '\0';
1739           secondary += strlen (INDEX_SEP);
1740         }
1741       xml_insert_element_with_attribute (INDEXTERM, START, "role=\"%s\"", index);
1742       in_indexterm = 1;
1743       xml_insert_element (PRIMARY, START);
1744       if (primary)
1745         execute_string ("%s", primary);
1746       else
1747         execute_string ("%s", indexterm);
1748       xml_insert_element (PRIMARY, END);
1749       if (primary)
1750         {
1751           xml_insert_element (SECONDARY, START);
1752           execute_string ("%s", secondary);
1753           xml_insert_element (SECONDARY, END);
1754         }
1755       xml_insert_element (INDEXTERM, END);
1756       in_indexterm = 0;
1757     }
1758 }
1759 
1760 
1761 int xml_last_section_output_position = 0;
1762 static char last_division_letter = ' ';
1763 static char index_primary[2000]; /** xx no fixed limit */
1764 static int indexdivempty = 0;
1765 
1766 static void
1767 xml_close_indexentry (void)
1768 {
1769   if (!in_indexentry)
1770     return;
1771   if (in_secondary)
1772     xml_insert_element (SECONDARYIE, END);
1773   xml_insert_element (INDEXENTRY, END);
1774   in_secondary = 0;
1775   in_indexentry = 0;
1776 }
1777 
1778 void
1779 xml_begin_index (void)
1780 {
1781   typedef struct xml_index_title {
1782       struct xml_index_title *next;
1783       char *title;
1784   } XML_INDEX_TITLE;
1785 
1786   static XML_INDEX_TITLE *xml_index_titles = NULL;
1787 
1788   if (!handling_delayed_writes)
1789     { /* We assume that we just opened a section, and so that the last output is
1790          <SECTION ID="node-name"><TITLE>Title</TITLE>
1791          where SECTION can be CHAPTER, ...  */
1792 
1793       XML_INDEX_TITLE *new = xmalloc (sizeof (XML_INDEX_TITLE));
1794       xml_section *temp = last_section;
1795 
1796       int l = output_paragraph_offset-xml_last_section_output_position;
1797       char *tmp = xmalloc (l+1);
1798       char *p = tmp;
1799       strncpy (tmp, (char *) output_paragraph, l);
1800 
1801       /* We remove <SECTION */
1802       tmp[l] = '\0';
1803       while (*p != '<')
1804         p++;
1805       while (*p != ' ')
1806         p++;
1807       /* ... and its label attribute.  */
1808       if (strncmp (p, " label=", 7) == 0)
1809         {
1810           p++;
1811           while (*p != ' ')
1812             p++;
1813         }
1814 
1815       output_paragraph_offset = xml_last_section_output_position;
1816       xml_last_section_output_position = 0;
1817 
1818       xml_pop_current_element (); /* remove section element from elements stack */
1819 
1820       if (last_section)
1821         last_section = last_section->prev; /* remove section from sections stack */
1822       if (temp)
1823         {
1824           free (temp->name);
1825           free (temp);
1826         }
1827 
1828       new->title = xstrdup (p);
1829       new->next = xml_index_titles;
1830       xml_index_titles = new;
1831     }
1832   else
1833     {
1834       static int xml_index_titles_reversed = 0;
1835 
1836       if (!xml_index_titles_reversed)
1837         {
1838           xml_index_titles = (XML_INDEX_TITLE *) reverse_list
1839             ((GENERIC_LIST *) xml_index_titles);
1840           xml_index_titles_reversed = 1;
1841         }
1842 
1843       /* We put <INDEX> */
1844       xml_insert_element (PRINTINDEX, START);
1845       if (xml_index_titles)
1846         {
1847           /* Remove the final > */
1848           output_paragraph_offset--;
1849           /* and put  ID="node-name"><TITLE>Title</TITLE> */
1850           insert_string (xml_index_titles->title);
1851           free (xml_index_titles->title);
1852           xml_index_titles = xml_index_titles->next;
1853         }
1854 
1855       if (xml_index_divisions)
1856         {
1857           xml_insert_element (INDEXDIV, START);
1858           indexdivempty = 1;
1859         }
1860     }
1861 }
1862 
1863 void
1864 xml_end_index (void)
1865 {
1866   xml_close_indexentry ();
1867   if (xml_index_divisions)
1868     xml_insert_element (INDEXDIV, END);
1869   xml_insert_element (PRINTINDEX, END);
1870 }
1871 
1872 static void
1873 xml_index_divide (char *entry)
1874 {
1875   char c;
1876   if (strlen (entry) > (strlen (xml_element_list[CODE].name) + 2) &&
1877       strncmp (entry+1, xml_element_list[CODE].name, strlen (xml_element_list[CODE].name)) == 0)
1878     c = entry[strlen (xml_element_list[CODE].name)+2];
1879   else
1880     c = entry[0];
1881   if (tolower (c) != last_division_letter && isalpha (c))
1882     {
1883       last_division_letter = tolower (c);
1884       xml_close_indexentry ();
1885       if (!indexdivempty)
1886         {
1887           xml_insert_element (INDEXDIV, END);
1888           xml_insert_element (INDEXDIV, START);
1889         }
1890       xml_insert_element (TITLE, START);
1891       insert (toupper (c));
1892       xml_insert_element (TITLE, END);
1893     }
1894 }
1895 
1896 void
1897 xml_insert_indexentry (char *entry, char *node)
1898 {
1899   char *primary = NULL, *secondary;
1900   if (xml_index_divisions)
1901     xml_index_divide (entry);
1902 
1903   indexdivempty = 0;
1904   if (strstr (entry+1, INDEX_SEP))
1905     {
1906       primary = xmalloc (strlen (entry) + 1);
1907       strcpy (primary, entry);
1908       secondary = strstr (primary+1, INDEX_SEP);
1909       *secondary = '\0';
1910       secondary += strlen (INDEX_SEP);
1911 
1912       if (in_secondary && strcmp (primary, index_primary) == 0)
1913         {
1914           xml_insert_element (SECONDARYIE, END);
1915           xml_insert_element (SECONDARYIE, START);
1916           execute_string ("%s", secondary);
1917         }
1918       else
1919         {
1920           xml_close_indexentry ();
1921           xml_insert_element (INDEXENTRY, START);
1922           in_indexentry = 1;
1923           xml_insert_element (PRIMARYIE, START);
1924           execute_string ("%s", primary);
1925           xml_insert_element (PRIMARYIE, END);
1926           xml_insert_element (SECONDARYIE, START);
1927           execute_string ("%s", secondary);
1928           in_secondary = 1;
1929         }
1930     }
1931   else
1932     {
1933       xml_close_indexentry ();
1934       xml_insert_element (INDEXENTRY, START);
1935       in_indexentry = 1;
1936       xml_insert_element (PRIMARYIE, START);
1937       execute_string ("%s", entry);
1938     }
1939   add_word (", ");
1940 
1941   /* Don't link to @unnumbered sections directly.
1942      We are disabling warnings temporarily, otherwise these xrefs
1943      will cause bogus warnings about missing punctuation.  */
1944   {
1945     extern int print_warnings;
1946     int save_print_warnings = print_warnings;
1947     print_warnings = 0;
1948     execute_string ("%cxref{%s}", COMMAND_PREFIX, xstrdup (node));
1949     print_warnings = save_print_warnings;
1950   }
1951 
1952   if (primary)
1953     {
1954       strcpy (index_primary, primary);
1955       /*      xml_insert_element (SECONDARYIE, END);*/
1956       /*     *(secondary-1) = ',';*/ /* necessary ? */
1957       free (primary);
1958     }
1959   else
1960     xml_insert_element (PRIMARYIE, END);
1961 
1962   /*  xml_insert_element (INDEXENTRY, END); */
1963 }
1964 
1965 void
1966 xml_synindex (char *from, char *to)
1967 {
1968   int i, slot;
1969 
1970   slot = -1;
1971   for (i = 0; i < xml_synonyms_count; i++)
1972     if (!xml_synonyms[i])
1973       {
1974         slot = i;
1975         break;
1976       }
1977 
1978   if (slot < 0)
1979     {
1980       slot = xml_synonyms_count;
1981       xml_synonyms_count++;
1982 
1983       xml_synonyms = (XML_SYNONYM **) xrealloc (xml_synonyms,
1984           (xml_synonyms_count + 1) * sizeof (XML_SYNONYM *));
1985     }
1986 
1987   xml_synonyms[slot] = xmalloc (sizeof (XML_SYNONYM));
1988   xml_synonyms[slot]->from = xstrdup (from);
1989   xml_synonyms[slot]->to = xstrdup (to);
1990 }
1991 
1992 /*
1993  * MULTITABLE
1994  */
1995 
1996 static int multitable_columns_count;
1997 static int *multitable_column_widths;
1998 
1999 void
2000 xml_begin_multitable (int ncolumns, int *column_widths)
2001 {
2002   int i;
2003   if (docbook)
2004     {
2005       if (is_in_insertion_of_type (floatenv))
2006         xml_begin_docbook_float (MULTITABLE);
2007       else
2008         xml_insert_element (MULTITABLE, START);
2009 
2010       multitable_columns_count = ncolumns;
2011       multitable_column_widths = xmalloc (sizeof (int) * ncolumns);
2012       memcpy (multitable_column_widths, column_widths,
2013           sizeof (int) * ncolumns);
2014 
2015       xml_no_para = 1;
2016     }
2017   else
2018     {
2019       xml_insert_element (MULTITABLE, START);
2020       for (i=0; i<ncolumns; i++)
2021         {
2022           xml_insert_element (COLSPEC, START);
2023           add_word_args ("%d", column_widths[i]);
2024           xml_insert_element (COLSPEC, END);
2025         }
2026       xml_no_para = 1;
2027     }
2028 }
2029 
2030 static void
2031 xml_begin_multitable_group (void)
2032 {
2033   int i;
2034 
2035   xml_insert_element_with_attribute (TGROUP, START, "cols=\"%d\"",
2036       multitable_columns_count);
2037 
2038   for (i=0; i < multitable_columns_count; i++)
2039     {
2040       xml_insert_element_with_attribute (COLSPEC, START,
2041           "colwidth=\"%d*\"", multitable_column_widths[i]);
2042       xml_insert_element (COLSPEC, END);
2043     }
2044 }
2045 
2046 void
2047 xml_end_multitable_row (int first_row)
2048 {
2049   if (!first_row)
2050     {
2051       xml_insert_element (ENTRY, END);
2052       xml_insert_element (ROW, END);
2053     }
2054 
2055   if (headitem_flag)
2056     {
2057       if (!first_row)
2058         {
2059           if (after_headitem)
2060             xml_insert_element (THEAD, END);
2061           else
2062             xml_insert_element (TBODY, END);
2063           xml_insert_element (TGROUP, END);
2064         }
2065 
2066       xml_begin_multitable_group ();
2067       xml_insert_element (THEAD, START);
2068     }
2069   else if (first_row)
2070     {
2071       xml_begin_multitable_group ();
2072       xml_insert_element (TBODY, START);
2073     }
2074   else if (after_headitem)
2075     {
2076       xml_insert_element (THEAD, END);
2077       xml_insert_element (TBODY, START);
2078     }
2079   else if (first_row)
2080     xml_insert_element (TBODY, START);
2081 
2082   xml_insert_element (ROW, START);
2083   xml_insert_element (ENTRY, START);
2084 }
2085 
2086 void
2087 xml_end_multitable_column (void)
2088 {
2089   xml_insert_element (ENTRY, END);
2090   xml_insert_element (ENTRY, START);
2091 }
2092 
2093 void
2094 xml_end_multitable (void)
2095 {
2096   xml_insert_element (ENTRY, END);
2097   xml_insert_element (ROW, END);
2098 
2099   if (after_headitem)
2100     {
2101       if (docbook)
2102         warning (_("@headitem as the last item of @multitable produces invalid Docbook documents"));
2103       xml_insert_element (THEAD, END);
2104     }
2105   else
2106     xml_insert_element (TBODY, END);
2107 
2108   if (docbook)
2109     xml_insert_element (TGROUP, END);
2110 
2111   xml_insert_element (MULTITABLE, END);
2112   xml_no_para = 0;
2113 }
2114 
2115 /*
2116  * Parameters in @def definitions
2117  */
2118 
2119 #define DEFUN_SELF_DELIMITING(c) \
2120   ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')
2121 
2122 void
2123 xml_process_defun_args (char **defun_args, int auto_var_p)
2124 {
2125   int pending_space = 0;
2126   int just_after_paramtype = 0;
2127 
2128   for (;;)
2129     {
2130       char *defun_arg = *defun_args++;
2131 
2132       if (defun_arg == NULL)
2133         break;
2134 
2135       if (defun_arg[0] == ' ')
2136         {
2137           pending_space = 1;
2138           continue;
2139         }
2140 
2141       if (pending_space)
2142         {
2143           add_char (' ');
2144           pending_space = 0;
2145         }
2146 
2147       if (DEFUN_SELF_DELIMITING (defun_arg[0]))
2148         {
2149 	  xml_insert_element (DEFDELIMITER, START);
2150           add_char (defun_arg[0]);
2151 	  xml_insert_element (DEFDELIMITER, END);
2152 	  just_after_paramtype = 0;
2153         }
2154       else if (defun_arg[0] == '&')
2155 	{
2156 	  xml_insert_element (DEFPARAM, START);
2157 	  add_word (defun_arg);
2158 	  xml_insert_element (DEFPARAM, END);
2159 	  just_after_paramtype = 0;
2160 	}
2161       else if (defun_arg[0] == COMMAND_PREFIX || just_after_paramtype)
2162 	{
2163 	  xml_insert_element (DEFPARAM, START);
2164 	  execute_string ("%s", defun_arg);
2165 	  xml_insert_element (DEFPARAM, END);
2166 	  just_after_paramtype = 0;
2167 	}
2168       else if (defun_arg[0] == ',' || defun_arg[0] == ';')
2169 	{
2170 	  xml_insert_element (DEFDELIMITER, START);
2171 	  add_word (defun_arg);
2172 	  xml_insert_element (DEFDELIMITER, END);
2173 	  just_after_paramtype = 0;
2174 	}
2175       else if (auto_var_p)
2176 	{
2177 	  xml_insert_element (DEFPARAM, START);
2178 	  add_word (defun_arg);
2179 	  xml_insert_element (DEFPARAM, END);
2180 	  just_after_paramtype = 0;
2181 	}
2182       else
2183 	{
2184 	  xml_insert_element (DEFPARAMTYPE, START);
2185 	  add_word (defun_arg);
2186 	  xml_insert_element (DEFPARAMTYPE, END);
2187 	  just_after_paramtype = 1;
2188 	}
2189     }
2190 }
2191 
2192 void
2193 xml_begin_definition (void)
2194 {
2195   xml_insert_element (DEFINITION, START);
2196   xml_definition_level ++;
2197   xml_in_def_item[xml_definition_level] = 0;
2198 }
2199 
2200 void
2201 xml_end_definition (void)
2202 {
2203   if (xml_in_def_item[xml_definition_level])
2204     {
2205       xml_insert_element (DEFINITIONITEM, END);
2206       xml_in_def_item[xml_definition_level] = 0;
2207     }
2208   xml_after_def_term = 0;
2209   xml_insert_element (DEFINITION, END);
2210   xml_definition_level --;
2211 }
2212 
2213 void
2214 xml_begin_def_term (int base_type, const char *category,
2215     char *defined_name, char *type_name, char *type_name2)
2216 {
2217   xml_after_def_term = 0;
2218   xml_insert_element (DEFINITIONTERM, START);
2219 
2220   /* Index entry */
2221   switch (base_type)
2222     {
2223     case deffn:
2224     case deftypefn:
2225       execute_string ("@findex %s\n", defined_name);
2226       break;
2227     case defvr:
2228     case deftypevr:
2229     case defcv:
2230       execute_string ("@vindex %s\n", defined_name);
2231       break;
2232     case deftypecv:
2233     case deftypeivar:
2234       execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name);
2235       break;
2236     case deftypemethod:
2237     case defop:
2238     case deftypeop:
2239       execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name);
2240       break;
2241     case deftp:
2242       execute_string ("@tindex %s\n", defined_name);
2243       break;
2244     }
2245 
2246   /* Start with category.  */
2247   xml_insert_element (DEFCATEGORY, START);
2248   execute_string (docbook ? "--- %s:" : "%s", category);
2249   xml_insert_element (DEFCATEGORY, END);
2250   add_char(' ');
2251 
2252   /* Output type name first for typed definitions.  */
2253   switch (base_type)
2254     {
2255     case deffn:
2256     case defvr:
2257     case deftp:
2258       break;
2259 
2260     case deftypefn:
2261     case deftypevr:
2262       xml_insert_element (DEFTYPE, START);
2263       execute_string ("%s", type_name);
2264       xml_insert_element (DEFTYPE, END);
2265       add_char (' ');
2266       break;
2267 
2268     case deftypecv:
2269     case deftypeivar:
2270     case deftypemethod:
2271     case deftypeop:
2272       xml_insert_element (DEFTYPE, START);
2273       execute_string ("%s", type_name2);
2274       xml_insert_element (DEFTYPE, END);
2275       add_char (' ');
2276       break;
2277 
2278     default:
2279       xml_insert_element (DEFCLASS, START);
2280       execute_string ("%s", type_name);
2281       xml_insert_element (DEFCLASS, END);
2282       add_char (' ');
2283       break;
2284     }
2285 
2286   /* Categorize rest of the definitions.  */
2287   switch (base_type)
2288     {
2289     case deffn:
2290     case deftypefn:
2291       xml_insert_element (DEFFUNCTION, START);
2292       execute_string ("%s", defined_name);
2293       xml_insert_element (DEFFUNCTION, END);
2294       break;
2295 
2296     case defvr:
2297     case deftypevr:
2298       xml_insert_element (DEFVARIABLE, START);
2299       execute_string ("%s", defined_name);
2300       xml_insert_element (DEFVARIABLE, END);
2301       break;
2302 
2303     case deftp:
2304       xml_insert_element (DEFDATATYPE, START);
2305       execute_string ("%s", defined_name);
2306       xml_insert_element (DEFDATATYPE, END);
2307       break;
2308 
2309     case defcv:
2310     case deftypecv:
2311     case deftypeivar:
2312       xml_insert_element (DEFCLASSVAR, START);
2313       execute_string ("%s", defined_name);
2314       xml_insert_element (DEFCLASSVAR, END);
2315       break;
2316 
2317     case defop:
2318     case deftypeop:
2319     case deftypemethod:
2320       /* Operation / Method */
2321       xml_insert_element (DEFOPERATION, START);
2322       execute_string ("%s", defined_name);
2323       xml_insert_element (DEFOPERATION, END);
2324       break;
2325     }
2326 }
2327 
2328 void
2329 xml_end_def_term (void)
2330 {
2331   xml_insert_element (DEFINITIONTERM, END);
2332   xml_after_def_term = 1;
2333 }
2334