Merge from vendor branch BINUTILS:
[dragonfly.git] / contrib / texinfo / makeinfo / xml.c
1 /* xml.c -- xml output.
2    $Id: xml.c,v 1.11 2002/03/23 20:41:12 karl Exp $
3
4    Copyright (C) 2001, 02 Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    Written by Philippe Martin <feloy@free.fr>.  */
21
22 #include "system.h"
23 #include "makeinfo.h"
24 #include "insertion.h"
25 #include "macro.h"
26 #include "cmds.h"
27 #include "lang.h"
28
29 #include "xml.h"
30
31 /* Options */
32 int xml_index_divisions = 1;
33
34
35 void xml_close_sections (/* int level */);
36
37 typedef struct _element
38 {
39   char name[32];
40   int contains_para;
41   int contained_in_para;
42 } element;
43
44 element texinfoml_element_list [] = {
45   { "texinfo",             1, 0 },
46   { "setfilename",         0, 0 },
47   { "titlefont",           0, 0 },
48   { "settitle",            0, 0 },
49
50   { "node",                1, 0 },
51   { "nodenext",            0, 0 },
52   { "nodeprev",            0, 0 },
53   { "nodeup",              0, 0 },
54
55   { "chapter",             1, 0 },
56   { "section",             1, 0 },
57   { "subsection",          1, 0 },
58   { "subsubsection",       1, 0 },
59
60   { "top",                 1, 0 },
61   { "unnumbered",          1, 0 },
62   { "unnumberedsec",       1, 0 },
63   { "unnumberedsubsec",    1, 0 },
64   { "unnumberedsubsubsec", 1, 0 },
65
66   { "appendix",            1, 0 },
67   { "appendixsec",         1, 0 },
68   { "appendixsubsec",      1, 0 },
69   { "appendixsubsubsec",   1, 0 },
70
71   { "majorheading",        1, 0 },
72   { "chapheading",         1, 0 },
73   { "heading",             1, 0 },
74   { "subheading",          1, 0 },
75   { "subsubheading",       1, 0 },
76
77   { "menu",                1, 0 },
78   { "menuentry",           1, 0 },
79   { "menutitle",           0, 0 },
80   { "menucomment",         1, 0 },
81   { "menunode",            0, 0 },
82   { "nodename",            0, 0 },
83
84   { "acronym",             0, 1 },
85   { "tt",                  0, 1 },
86   { "code",                0, 1 },
87   { "kbd",                 0, 1 },
88   { "url",                 0, 1 },
89   { "key",                 0, 1 },
90   { "var",                 0, 1 },
91   { "sc",                  0, 1 },
92   { "dfn",                 0, 1 },
93   { "emph",                0, 1 },
94   { "strong",              0, 1 },
95   { "cite",                0, 1 },
96   { "notfixedwidth",       0, 1 }, 
97   { "i",                   0, 1 },
98   { "b",                   0, 1 },
99   { "r",                   0, 1 },
100
101   { "title",               0, 0 },
102   { "ifinfo",              1, 0 },
103   { "sp",                  0, 0 },
104   { "center",              1, 0 },
105   { "dircategory",         0, 0 },
106   { "quotation",           1, 0 },
107   { "example",             1, 0 },
108   { "smallexample",        1, 0 },
109   { "lisp",                1, 0 },
110   { "smalllisp",           1, 0 },
111   { "cartouche",           1, 0 },
112   { "copying",             1, 0 },
113   { "format",              1, 0 },
114   { "smallformat",         1, 0 },
115   { "display",             1, 0 },
116   { "smalldisplay",        1, 0 },
117   { "footnote",            0, 1 },
118
119   { "itemize",             0, 0 },
120   { "itemfunction",        0, 0 },
121   { "item",                1, 0 },
122   { "enumerate",           0, 0 },
123   { "table",               0, 0 },
124   { "tableitem",           0, 0 }, /* not used */ /* TABLEITEM */
125   { "tableterm",           0, 0 }, /* not used */ /* TABLETERM */
126
127   { "indexterm",           0, 1 },
128
129   { "xref",                0, 1 },
130   { "xrefnodename",        0, 1 },
131   { "xrefinfoname",        0, 1 },
132   { "xrefprinteddesc",     0, 1 },
133   { "xrefinfofile",        0, 1 },
134   { "xrefprintedname",     0, 1 },
135
136   { "inforef",             0, 1 },
137   { "inforefnodename",     0, 1 },
138   { "inforefrefname",      0, 1 },
139   { "inforefinfoname",     0, 1 },
140
141   { "uref",                0, 1 },
142   { "urefurl",             0, 1 },
143   { "urefdesc",            0, 1 },
144   { "urefreplacement",     0, 1 },
145
146   { "email",               0, 1 },
147   { "emailaddress",        0, 1 },
148   { "emailname",           0, 1 },
149
150   { "group",               0, 0 },
151   
152   { "printindex",          0, 0 },
153   { "anchor",              0, 1 },
154   { "image",               0, 1 },
155   { "",                    0, 1 }, /* PRIMARY (docbook) */
156   { "",                    0, 1 }, /* SECONDARY (docbook) */
157   { "",                    0, 0 }, /* INFORMALFIGURE (docbook) */
158   { "",                    0, 0 }, /* MEDIAOBJECT (docbook) */
159   { "",                    0, 0 }, /* IMAGEOBJECT (docbook) */
160   { "",                    0, 0 }, /* IMAGEDATA (docbook) */
161   { "",                    0, 0 }, /* TEXTOBJECT (docbook) */
162   { "",                    0, 0 }, /* INDEXENTRY (docbook) */
163   { "",                    0, 0 }, /* PRIMARYIE (docbook) */
164   { "",                    0, 0 }, /* SECONDARYIE (docbook) */
165   { "",                    0, 0 }, /* INDEXDIV (docbook) */
166   { "multitable",          0, 0 },
167   { "",                    0, 0 }, /* TGROUP (docbook) */
168   { "columnfraction",      0, 0 }, 
169   { "",                    0, 0 }, /* TBODY (docbook) */
170   { "entry",               0, 0 }, /* ENTRY (docbook) */
171   { "row",                 0, 0 }, /* ROW (docbook) */
172   { "",                    0, 0 }, /* BOOKINFO (docbook) */
173   { "",                    0, 0 }, /* ABSTRACT (docbook) */
174   { "",                    0, 0 }, /* REPLACEABLE (docbook) */
175   { "para",                0, 0 } /* Must be last */
176   /* name / contains para / contained in para */
177 };
178
179 element docbook_element_list [] = {
180   { "book",                0, 0 }, /* TEXINFO */
181   { "",                    0, 0 }, /* SETFILENAME */
182   { "",                    0, 0 }, /* TITLEINFO */
183   { "title",               0, 0 }, /* SETTITLE */
184
185   { "",                    1, 0 }, /* NODE */
186   { "",                    0, 0 }, /* NODENEXT */
187   { "",                    0, 0 }, /* NODEPREV */
188   { "",                    0, 0 }, /* NODEUP */
189
190   { "chapter",             1, 0 },
191   { "sect1",               1, 0 }, /* SECTION */
192   { "sect2",               1, 0 }, /* SUBSECTION */
193   { "sect3",               1, 0 }, /* SUBSUBSECTION */
194
195   { "chapter",             1, 0 }, /* TOP */
196   { "chapter",             1, 0 }, /* UNNUMBERED */
197   { "sect1",               1, 0 }, /* UNNUMBEREDSEC */
198   { "sect2",               1, 0 }, /* UNNUMBEREDSUBSEC */
199   { "sect3",               1, 0 }, /* UNNUMBEREDSUBSUBSEC */
200
201   { "appendix",            1, 0 },
202   { "sect1",               1, 0 }, /* APPENDIXSEC */
203   { "sect2",               1, 0 }, /* APPENDIXSUBSEC */
204   { "sect3",               1, 0 }, /* APPENDIXSUBSUBSEC */
205
206   { "chapter",             1, 0 }, /* MAJORHEADING */
207   { "chapter",             1, 0 }, /* CHAPHEADING */
208   { "sect1",               1, 0 }, /* HEADING */
209   { "sect2",               1, 0 }, /* SUBHEADING */
210   { "sect3",               1, 0 }, /* SUBSUBHEADING */
211
212   { "",                    1, 0 }, /* MENU */
213   { "",                    1, 0 }, /* MENUENTRY */
214   { "",                    0, 0 }, /* MENUTITLE */
215   { "",                    1, 0 }, /* MENUCOMMENT */
216   { "",                    0, 0 }, /* MENUNODE */
217   { "anchor",              0, 0 }, /* NODENAME */
218
219   { "acronym",             0, 1 },
220   { "wordasword",          0, 1 }, /* TT */
221   { "command",             0, 1 }, /* CODE */
222   { "userinput",           0, 1 }, /* KBD */
223   { "wordasword",          0, 1 }, /* URL */
224   { "keycap",              0, 1 }, /* KEY */
225   { "varname",             0, 1 }, /* VAR */
226   { "",                    0, 1 }, /* SC */
227   { "firstterm",           0, 1 }, /* DFN */
228   { "emphasis",            0, 1 }, /* EMPH */
229   { "emphasis",            0, 1 }, /* STRONG */
230   { "citation",            0, 1 }, /* CITE */
231   { "",                    0, 1 },  /* NOTFIXEDWIDTH */
232   { "wordasword",          0, 1 }, /* I */
233   { "wordasword",          0, 1 }, /* B */
234   { "",                    0, 1 }, /* R */
235
236   { "title",               0, 0 },
237   { "",                    1, 0 }, /* IFINFO */
238   { "",                    0, 0 }, /* SP */
239   { "",                    1, 0 }, /* CENTER */
240   { "",                    0, 0 }, /* DIRCATEGORY */
241   { "blockquote",          1, 0 }, /* QUOTATION */
242   { "screen",              0, 1 },
243   { "screen",              0, 1 }, /* SMALLEXAMPLE */
244   { "screen",              0, 1 }, /* LISP */
245   { "screen",              0, 1 }, /* SMALLLISP */
246   { "",                    1, 0 }, /* CARTOUCHE */
247   { "",                    1, 0 }, /* COPYING */
248   { "screen",              0, 1 }, /* FORMAT */
249   { "screen",              0, 1 }, /* SMALLFORMAT */
250   { "screen",              0, 1 }, /* DISPLAY */
251   { "screen",              0, 1 }, /* SMALLDISPLAY */
252   { "footnote",            0, 1 },
253
254   { "itemizedlist",        0, 0 }, /* ITEMIZE */
255   { "",                    0, 0 }, /* ITEMFUNCTION */
256   { "listitem",            1, 0 },
257   { "orderedlist",         0, 0 }, /* ENUMERATE */
258   { "variablelist",        0, 0 }, /* TABLE */
259   { "varlistentry",        0, 0 }, /* TABLEITEM */
260   { "term",                0, 0 }, /* TABLETERM */
261
262   { "indexterm",           0, 1 },
263
264   { "xref",                0, 1 }, /* XREF */
265   { "link",                0, 1 }, /* XREFNODENAME */
266   { "",                    0, 1 }, /* XREFINFONAME */
267   { "",                    0, 1 }, /* XREFPRINTEDDESC */
268   { "",                    0, 1 }, /* XREFINFOFILE */
269   { "",                    0, 1 }, /* XREFPRINTEDNAME */
270
271   { "",                    0, 1 }, /* INFOREF */
272   { "",                    0, 1 }, /* INFOREFNODENAME */
273   { "",                    0, 1 }, /* INFOREFREFNAME */
274   { "",                    0, 1 }, /* INFOREFINFONAME */
275
276   { "",                    0, 1 }, /* UREF */
277   { "",                    0, 1 }, /* UREFURL */
278   { "",                    0, 1 }, /* UREFDESC */
279   { "",                    0, 1 }, /* UREFREPLACEMENT */
280
281   { "ulink",               0, 1 }, /* EMAIL */
282   { "",                    0, 1 }, /* EMAILADDRESS */
283   { "",                    0, 1 }, /* EMAILNAME */
284
285   { "",                    0, 0 }, /* GROUP */
286   
287   { "index",               0, 0 }, /* PRINTINDEX */
288   { "",                    0, 1 }, /* ANCHOR */
289   { "",                    0, 1 }, /* IMAGE */
290   { "primary",             0, 1 }, /* PRIMARY */
291   { "secondary",           0, 1 },
292   { "informalfigure",      0, 0 },
293   { "mediaobject",         0, 0 },
294   { "imageobject",         0, 0 },
295   { "imagedata",           0, 0 },
296   { "textobject",          0, 0 },
297   { "indexentry",          0, 0 },
298   { "primaryie",           0, 0 },
299   { "secondaryie",         0, 0 },
300   { "indexdiv",            0, 0 },
301   { "informaltable",       0, 0 },
302   { "tgroup",              0, 0 },
303   { "colspec",             0, 0 },
304   { "tbody",               0, 0 },
305   { "entry",               0, 0 },
306   { "row",                 0, 0 },
307   { "bookinfo",            0, 0 },
308   { "abstract",            1, 0 },
309   { "replaceable",         0, 0 },
310
311   { "para",                0, 0 } /* Must be last */
312   /* name / contains para / contained in para */
313 };
314
315 element *xml_element_list = NULL;
316
317
318 typedef struct _replace_element
319 {
320   int element_to_replace;
321   int element_containing;
322   int element_replacing;
323 } replace_element;
324
325 /* Elements to replace - Docbook only
326    -------------------
327    if `element_to_replace' have to be inserted 
328    as a child of `element_containing,' 
329    use `element_replacing' instead.
330
331    A value of `-1' for element_replacing means `do not use any element.'
332 */
333
334 replace_element replace_elements [] = {
335   { I, TABLETERM, EMPH },
336   { B, TABLETERM, EMPH },
337   { TT, CODE, -1 },
338   { EXAMPLE, DISPLAY, -1 },
339   { CODE, DFN, -1 },
340   { CODE, VAR, -1 },
341   { EMPH, CODE, REPLACEABLE },
342   /* Add your elements to replace here */
343   {-1, 0, 0}
344 };
345
346 int xml_in_menu_entry = 0;
347 int xml_in_menu_entry_comment = 0;
348 int xml_node_open = 0;
349 int xml_node_level = -1;
350 int xml_in_para = 0;
351 int xml_just_after_element = 0;
352
353 int xml_no_para = 0;
354 char *xml_node_id = NULL;
355 int xml_sort_index = 0;
356
357 static int xml_after_table_term = 0;
358 static int book_started = 0;
359 static int first_section_opened = 0;
360 static int in_abstract = 0;
361
362 static int xml_current_element ();
363
364 void 
365 #if defined (VA_FPRINTF) && __STDC__
366 xml_insert_element_with_attribute (int elt, int arg, char *format, ...);
367 #else
368 xml_insert_element_with_attribute ();
369 #endif
370
371 char *
372 xml_id (id)
373     char *id;
374 {
375   char *tem = xmalloc (strlen (id) + 1);
376   char *p = tem;
377   strcpy (tem, id);
378   while (*p++)
379     {
380       if (*p == ' ' || *p == '&' || *p == '/' || *p == '+')
381         *p = '-';
382     }
383   p = tem;
384   while (*p == '-')
385     *p = 'i';
386   return tem;
387 }
388
389 int
390 xml_element (name)
391     char *name;
392 {
393   int i;
394   for (i=0; i<=PARA; i++)
395     {
396       if (strcasecmp (name, texinfoml_element_list[i].name) == 0)
397         return i;
398     }
399   printf ("Error xml_element\n");
400   return -1;
401 }
402
403 void
404 xml_begin_document (output_filename)
405     char *output_filename;
406 {
407   if (book_started)
408     return;
409
410   book_started = 1;
411   if (docbook)
412     {
413       insert_string ("<!DOCTYPE Book PUBLIC \"-//OASIS//DTD DocBook V3.1//EN\">");
414       xml_element_list = docbook_element_list;
415     }
416   else
417     {
418       insert_string ("<!DOCTYPE texinfo SYSTEM \"texinfo.dtd\">");
419       xml_element_list = texinfoml_element_list;
420     }
421   if (docbook)
422     {
423       if (language_code != last_language_code)
424         xml_insert_element_with_attribute (TEXINFO, START, "lang=\"%s\"", language_table[language_code].abbrev);
425     }
426   else
427     xml_insert_element (TEXINFO, START);
428   if (!docbook)
429     {
430       xml_insert_element (SETFILENAME, START);
431       insert_string (output_filename);
432       xml_insert_element (SETFILENAME, END);
433     }
434 }
435
436 /* \f */
437 static int element_stack[256];
438 static int element_stack_index = 0;
439
440 static void 
441 xml_push_current_element (elt)
442     int elt;
443 {
444   element_stack[element_stack_index++] = elt;
445   if (element_stack_index > 200)
446     printf ("*** stack overflow (%d - %s) ***\n", 
447             element_stack_index, 
448             xml_element_list[elt].name);
449 }
450
451 void
452 xml_pop_current_element ()
453 {
454   element_stack_index--;
455   if (element_stack_index < 0)
456     printf ("*** stack underflow (%d - %d) ***\n", 
457             element_stack_index, 
458             xml_current_element());
459 }
460
461 static int
462 xml_current_element ()
463 {
464   return element_stack[element_stack_index-1];
465 }
466
467 static void
468 xml_indent ()
469 {
470   int i;
471   insert ('\n');
472   for (i = 0; i < element_stack_index; i++)
473     insert (' ');
474 }
475
476 static void
477 xml_indent_end_para ()
478 {
479   int i;
480   for (i = 0; i < element_stack_index; i++)
481     insert (' ');
482 }
483
484 void
485 xml_end_document ()
486 {
487   if (xml_node_open)
488     {
489       if (xml_node_level != -1)
490         {
491           xml_close_sections (xml_node_level);
492           xml_node_level = -1;
493         }
494       xml_insert_element (NODE, END);
495     }
496   xml_insert_element (TEXINFO, END);
497   insert_string ("\n");
498   insert_string ("<!-- Keep this comment at the end of the file\n\
499 Local variables:\n\
500 mode: sgml\n\
501 sgml-indent-step:1\n\
502 sgml-indent-data:nil\n\
503 End:\n\
504 -->\n");
505   if (element_stack_index != 0)
506     error ("Element stack index : %d\n", element_stack_index);
507 }
508
509 /* MUST be 0 or 1, not true or false values */
510 static int start_element_inserted = 1;
511
512 /* NOTE: We use `elt' rather than `element' in the argument list of
513    the next function, since otherwise the Solaris SUNWspro compiler
514    barfs because `element' is a typedef declared near the beginning of
515    this file.  */
516 void 
517 #if defined (VA_FPRINTF) && __STDC__
518 xml_insert_element_with_attribute (int elt, int arg, char *format, ...)
519 #else
520 xml_insert_element_with_attribute (elt, arg, format, va_alist)
521      int elt;
522      int arg;
523      char *format;
524      va_dcl
525 #endif
526 {
527   /* Look at the replace_elements table to see if we have to change the element */
528   if (xml_sort_index)
529     return;
530   if (docbook)
531     {
532       replace_element *element_list = replace_elements;
533       while (element_list->element_to_replace >= 0)
534         {
535           if ( ( (arg == START) &&
536                  (element_list->element_containing == xml_current_element ()) &&
537                  (element_list->element_to_replace == elt) ) ||
538                ( (arg == END) &&
539                  (element_list->element_containing == element_stack[element_stack_index-1-start_element_inserted]) &&
540                  (element_list->element_to_replace == elt) ) )
541             {
542               elt = element_list->element_replacing;
543               break;
544             }
545           element_list ++;
546         }
547       
548       /* Forget the element */
549       if (elt < 0)
550         {
551           if (arg == START)
552             start_element_inserted = 0;
553           else
554             /* Replace the default value, for the next time */
555             start_element_inserted = 1;
556           return;
557         }
558     }
559
560   if (!book_started)
561     return;
562
563   if (xml_after_table_term && elt != TABLETERM)
564     {
565       xml_after_table_term = 0;
566       xml_insert_element (ITEM, START);
567     }
568
569   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
570     return;
571
572   if (!xml_element_list[elt].name || !strlen (xml_element_list[elt].name))
573     {
574       /* printf ("Warning: Inserting empty element %d\n", elt);*/
575       return;
576     }
577
578   if (arg == START && !xml_in_para && !xml_no_para
579       && xml_element_list[elt].contained_in_para 
580       && xml_element_list[xml_current_element()].contains_para )
581     {
582       xml_indent ();
583       insert_string ("<para>");
584       xml_in_para = 1;
585     }
586
587
588   if (arg == START && xml_in_para && !xml_element_list[elt].contained_in_para)
589     {
590       xml_indent_end_para ();
591       insert_string ("</para>");
592       xml_in_para = 0;
593     }
594   
595   if (arg == END && xml_in_para && !xml_element_list[elt].contained_in_para)
596     {
597       xml_indent_end_para ();
598       insert_string ("</para>");
599       xml_in_para = 0;
600     }
601
602   if (arg == START && !xml_in_para && !xml_element_list[elt].contained_in_para)
603     xml_indent ();
604
605   if (arg == START)
606     xml_push_current_element (elt);
607   else
608     xml_pop_current_element ();
609
610   insert ('<');
611   if (arg == END)
612     insert ('/');
613   insert_string (xml_element_list[elt].name);
614   
615   /*  printf ("%s ", xml_element_list[elt].name);*/
616
617   if (format)
618     {
619       char temp_string[2000]; /* xx no fixed limits */
620 #ifdef VA_SPRINTF
621       va_list ap;
622 #endif
623
624       VA_START (ap, format);
625 #ifdef VA_SPRINTF
626       VA_SPRINTF (temp_string, format, ap);
627 #else
628       sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
629 #endif 
630       insert (' ');
631       insert_string (temp_string);
632       va_end (ap);
633     }
634
635   if (arg == START && xml_node_id && elt != NODENAME)
636     {
637       insert_string (" id=\"");
638       insert_string (xml_node_id);
639       insert_string ("\"");
640       free (xml_node_id);
641       xml_node_id = NULL;
642     }
643
644   insert ('>');
645
646   xml_just_after_element = 1;
647 }
648
649 /* See the NOTE before xml_insert_element_with_attribute, for why we
650    use `elt' rather than `element' here.  */
651 void
652 xml_insert_element (int elt, int arg)
653 {
654   xml_insert_element_with_attribute (elt, arg, NULL);
655 }
656
657 void
658 xml_insert_entity (char *entity_name)
659 {
660   int saved_escape_html = escape_html;
661
662   if (!book_started)
663     return;
664   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
665     return;
666
667   if (!xml_in_para && !xml_no_para && !only_macro_expansion 
668       && xml_element_list[xml_current_element ()].contains_para)
669     {
670       insert_string ("<para>");
671       xml_in_para = 1;
672     }
673   escape_html = 0;
674   insert ('&');
675   escape_html = saved_escape_html;
676   insert_string (entity_name);
677   insert (';');
678 }
679
680 typedef struct _xml_section xml_section;
681 struct _xml_section {
682   int level;
683   char *name;
684   xml_section *prev;
685 };
686
687 xml_section *last_section = NULL;
688
689 void
690 xml_begin_node ()
691 {
692   if (xml_node_open && ! docbook)
693     {
694       if (xml_node_level != -1)
695         {
696           xml_close_sections (xml_node_level);
697           xml_node_level = -1;
698         }
699       xml_insert_element (NODE, END);
700     }
701   xml_insert_element (NODE, START);
702   xml_node_open = 1;
703 }
704
705 void
706 xml_close_sections (level)
707     int level;
708 {
709   if (!first_section_opened && in_abstract)
710     {
711       xml_insert_element (ABSTRACT, END);
712       xml_insert_element (BOOKINFO, END);
713       first_section_opened = 1;
714     }
715   while (last_section && last_section->level >= level)
716     {
717       xml_section *temp = last_section;
718       xml_insert_element (xml_element(last_section->name), END);
719       temp = last_section;
720       last_section = last_section->prev;
721       free (temp->name);
722       free (temp);
723     }
724 }
725
726 void
727 xml_open_section (level, name)
728     int level;
729     char *name;
730 {
731   xml_section *sect = (xml_section *) xmalloc (sizeof (xml_section));
732
733   sect->level = level;
734   sect->name = xmalloc (1 + strlen (name));
735   strcpy (sect->name, name);
736   sect->prev = last_section;
737   last_section = sect;
738
739   if (xml_node_open && xml_node_level == -1)
740     xml_node_level = level;
741 }
742
743 void
744 xml_start_menu_entry (tem)
745     char *tem;
746 {
747   char *string;
748   discard_until ("* ");
749
750   /* The line number was already incremented in reader_loop when we
751      saw the newline, and discard_until has now incremented again.  */
752   line_number--;
753
754   if (xml_in_menu_entry)
755     {
756       if (xml_in_menu_entry_comment)
757         {
758           xml_insert_element (MENUCOMMENT, END);
759           xml_in_menu_entry_comment=0;
760         }
761       xml_insert_element (MENUENTRY, END);
762       xml_in_menu_entry=0;
763     }
764   xml_insert_element (MENUENTRY, START);
765   xml_in_menu_entry=1;
766
767   xml_insert_element (MENUNODE, START);
768   string = expansion (tem, 0);
769   add_word (string);
770   xml_insert_element (MENUNODE, END);
771   free (string);
772   
773   /* The menu item may use macros, so expand them now.  */
774   xml_insert_element (MENUTITLE, START);
775   only_macro_expansion++;
776   get_until_in_line (1, ":", &string);
777   only_macro_expansion--;
778   execute_string ("%s", string); /* get escaping done */
779   xml_insert_element (MENUTITLE, END);
780   free (string);
781
782   if (looking_at ("::"))
783     discard_until (":");
784   else
785     { /* discard the node name */
786       get_until_in_line (0, ".", &string);
787       free (string);
788     }
789   input_text_offset++;  /* discard the second colon or the period */
790   xml_insert_element (MENUCOMMENT, START);
791   xml_in_menu_entry_comment ++;
792 }
793
794 void
795 xml_end_menu ()
796 {
797   if (xml_in_menu_entry)
798     {
799       if (xml_in_menu_entry_comment)
800         {
801           xml_insert_element (MENUCOMMENT, END);
802           xml_in_menu_entry_comment --;
803         }
804       xml_insert_element (MENUENTRY, END);
805       xml_in_menu_entry--;
806     }
807   xml_insert_element (MENU, END);
808 }
809
810 static int xml_last_character;
811
812 void
813 xml_add_char (character)
814     int character;
815 {
816   if (!book_started)
817     return;
818   if (docbook && !only_macro_expansion && (in_menu || in_detailmenu))
819     return;
820
821   if (!first_section_opened && !in_abstract && xml_current_element () == TEXINFO
822       && !xml_no_para && character != '\r' && character != '\n' && character != ' ')
823     {
824       xml_insert_element (BOOKINFO, START);
825       xml_insert_element (ABSTRACT, START);
826       in_abstract = 1;
827     }
828
829   if (xml_after_table_term && !xml_sort_index)
830     {
831       xml_after_table_term = 0;
832       xml_insert_element (ITEM, START);
833     }
834   
835   if (xml_just_after_element && !xml_in_para && !inhibit_paragraph_indentation)
836     {
837       if (character == '\r' || character == '\n' || character == '\t' || character == ' ')
838         return;
839       xml_just_after_element = 0;      
840     }
841   
842   if (xml_element_list[xml_current_element()].contains_para 
843       && !xml_in_para && !only_macro_expansion && !xml_no_para)
844     {
845       xml_indent ();
846       insert_string ("<para>\n");
847       xml_in_para = 1;
848     }
849   
850   if (xml_in_para)
851     {
852       if (character == '\n')
853         {
854           if (xml_last_character == '\n' && !only_macro_expansion && !xml_no_para
855               && xml_element_list[xml_current_element()].contains_para )
856             {
857               xml_indent_end_para ();
858               insert_string ("</para>");
859               xml_in_para = 0;
860               xml_just_after_element = 1;
861               if (xml_in_menu_entry_comment)
862                 {
863                   xml_insert_element (MENUCOMMENT, END);
864                   xml_in_menu_entry_comment = 0;
865                   xml_insert_element (MENUENTRY, END);
866                   xml_in_menu_entry = 0;
867                 }
868             }
869         }
870     }
871   
872   if (character == '\n' && !xml_in_para && !inhibit_paragraph_indentation)
873     return;
874
875   xml_last_character = character;
876
877   if (character == '&' && escape_html)
878       insert_string ("&amp;");
879   else if (character == '<' && escape_html)
880       insert_string ("&lt;");
881   else
882     insert (character);
883   
884   return;
885 }
886
887 void
888 xml_insert_footnote (note)
889     char *note;
890 {
891   xml_insert_element (FOOTNOTE, START);
892   insert_string ("<para>");
893   execute_string ("%s", note);
894   insert_string ("</para>");
895   xml_insert_element (FOOTNOTE, END);
896 }
897
898
899 /*
900  * Lists and Tables
901  */
902 static int xml_in_item[256];
903 static int xml_table_level = 0;
904
905 void
906 xml_begin_table (type, item_function)
907     enum insertion_type type;
908     char *item_function;
909 {
910   switch (type)
911     {
912     case ftable:
913     case vtable:
914     case table:
915       /*if (docbook)*/ /* 05-08 */
916         {
917           xml_insert_element (TABLE, START);
918           xml_table_level ++;      
919           xml_in_item[xml_table_level] = 0;
920         }
921       break;
922     case itemize:
923       if (!docbook)
924         {
925           xml_insert_element (ITEMIZE, START);
926           xml_table_level ++;      
927           xml_in_item[xml_table_level] = 0;
928           xml_insert_element (ITEMFUNCTION, START);
929           if (*item_function == COMMAND_PREFIX
930               && item_function[strlen (item_function) - 1] != '}'
931               && command_needs_braces (item_function + 1))
932             execute_string ("%s{}", item_function);
933           else
934             execute_string ("%s", item_function);
935           xml_insert_element (ITEMFUNCTION, END);
936         } 
937       else 
938         {
939           xml_insert_element_with_attribute (ITEMIZE, START, 
940                                              "mark=\"%s\"",
941                                              (*item_function == COMMAND_PREFIX) ?
942                                              &item_function[1] : item_function);
943           xml_table_level ++;      
944           xml_in_item[xml_table_level] = 0;
945         }
946       break;
947     }
948 }
949
950 void
951 xml_end_table (type)
952     enum insertion_type type;
953 {
954   switch (type)
955     {
956     case ftable:
957     case vtable:
958     case table:
959       /*      if (docbook)*/ /* 05-08 */
960         {
961           if (xml_in_item[xml_table_level])
962             {
963               xml_insert_element (ITEM, END);
964               xml_insert_element (TABLEITEM, END);
965               xml_in_item[xml_table_level] = 0;
966             }
967           xml_insert_element (TABLE, END);
968           xml_table_level --;
969         }
970       break;
971     case itemize:
972       if (xml_in_item[xml_table_level])
973         {
974           xml_insert_element (ITEM, END);
975           xml_in_item[xml_table_level] = 0;
976         }
977       xml_insert_element (ITEMIZE, END);
978       xml_table_level --;
979       break;
980     }
981 }
982
983 void
984 xml_begin_item ()
985 {
986   if (xml_in_item[xml_table_level])
987     xml_insert_element (ITEM, END);
988
989   xml_insert_element (ITEM, START);
990   xml_in_item[xml_table_level] = 1;
991 }
992
993 void
994 xml_begin_table_item ()
995 {
996   if (!xml_after_table_term)
997     {
998       if (xml_in_item[xml_table_level])
999         {
1000           xml_insert_element (ITEM, END);
1001           xml_insert_element (TABLEITEM, END);
1002         }
1003       xml_insert_element (TABLEITEM, START);
1004     }
1005   xml_insert_element (TABLETERM, START);
1006   xml_in_item[xml_table_level] = 1;
1007   xml_after_table_term = 0;
1008 }
1009
1010 void
1011 xml_continue_table_item ()
1012 {
1013   xml_insert_element (TABLETERM, END);
1014   xml_after_table_term = 1;
1015 }
1016
1017 void
1018 xml_begin_enumerate (enum_arg)
1019     char *enum_arg;
1020 {
1021   if (!docbook)
1022     xml_insert_element_with_attribute (ENUMERATE, START, "first=\"%s\"", enum_arg);
1023   else
1024     {    
1025       if (isdigit (*enum_arg))
1026       {
1027         if (enum_arg[0] == '1')
1028           xml_insert_element_with_attribute (ENUMERATE, START, 
1029                                              "numeration=\"Arabic\"", NULL);
1030         else
1031           xml_insert_element_with_attribute (ENUMERATE, START, 
1032                                              "continuation=\"Continues\" numeration=\"Arabic\"", NULL);
1033       }
1034       else if (isupper (*enum_arg))
1035         {
1036         if (enum_arg[0] == 'A')
1037           xml_insert_element_with_attribute (ENUMERATE, START, 
1038                                              "numeration=\"Upperalpha\"", NULL);
1039         else
1040           xml_insert_element_with_attribute (ENUMERATE, START, 
1041                                              "continuation=\"Continues\" numeration=\"Upperalpha\"", NULL);
1042       }
1043       else
1044         {
1045           if (enum_arg[0] == 'a')
1046           xml_insert_element_with_attribute (ENUMERATE, START, 
1047                                              "numeration=\"Loweralpha\"", NULL);
1048         else
1049           xml_insert_element_with_attribute (ENUMERATE, START, 
1050                                              "continuation=\"Continues\" numeration=\"Loweralpha\"", NULL);
1051         }      
1052     }
1053   xml_table_level ++;
1054   xml_in_item[xml_table_level] = 0;
1055 }
1056
1057 void
1058 xml_end_enumerate ()
1059 {
1060   if (xml_in_item[xml_table_level])
1061     {
1062       xml_insert_element (ITEM, END);
1063       xml_in_item[xml_table_level] = 0;
1064     }
1065   xml_insert_element (ENUMERATE, END);
1066   xml_table_level --;
1067 }
1068
1069 static void
1070 xml_insert_text_file (name_arg)
1071     char *name_arg;
1072 {
1073   char *fullname = xmalloc (strlen (name_arg) + 4 + 1);
1074   FILE *image_file;
1075   strcpy (fullname, name_arg);
1076   strcat (fullname, ".txt");
1077   image_file = fopen (fullname, "r");
1078   if (image_file)
1079     {
1080       int ch;
1081       int save_inhibit_indentation = inhibit_paragraph_indentation;
1082       int save_filling_enabled = filling_enabled;
1083       
1084       xml_insert_element (TEXTOBJECT, START);
1085       xml_insert_element (DISPLAY, START);
1086
1087       inhibit_paragraph_indentation = 1;
1088       filling_enabled = 0;
1089       last_char_was_newline = 0;
1090       
1091       /* Maybe we need to remove the final newline if the image
1092          file is only one line to allow in-line images.  On the
1093          other hand, they could just make the file without a
1094          final newline.  */
1095       while ((ch = getc (image_file)) != EOF)
1096         add_char (ch);
1097       
1098       inhibit_paragraph_indentation = save_inhibit_indentation;
1099       filling_enabled = save_filling_enabled;
1100
1101       xml_insert_element (DISPLAY, END);
1102       xml_insert_element (TEXTOBJECT, END);
1103       
1104       if (fclose (image_file) != 0)
1105         perror (fullname);
1106     }
1107   else
1108     warning (_("@image file `%s' unreadable: %s"), fullname,
1109              strerror (errno));
1110   
1111   free (fullname);
1112 }
1113
1114 void
1115 xml_insert_docbook_image (name_arg)
1116     char *name_arg;
1117 {
1118   xml_insert_element (INFORMALFIGURE, START);
1119   xml_insert_element (MEDIAOBJECT, START);
1120
1121   xml_insert_element (IMAGEOBJECT, START);
1122   xml_insert_element_with_attribute (IMAGEDATA, START, "fileref=\"%s.eps\" format=\"eps\"", name_arg);
1123   xml_pop_current_element ();
1124   xml_insert_element (IMAGEOBJECT, END);
1125
1126   xml_insert_element (IMAGEOBJECT, START);
1127   xml_insert_element_with_attribute (IMAGEDATA, START, "fileref=\"%s.jpg\" format=\"jpg\"", name_arg);
1128   xml_pop_current_element ();
1129   xml_insert_element (IMAGEOBJECT, END);
1130
1131   xml_insert_text_file (name_arg);
1132
1133   xml_insert_element (MEDIAOBJECT, END);
1134   xml_insert_element (INFORMALFIGURE, END);
1135 }
1136
1137 void
1138 xml_asterisk ()
1139 {
1140 }
1141
1142
1143 /*
1144  *     INDEX
1145  */
1146 /* Used to separate primary and secondary entries in an index */
1147 #define INDEX_SEP ", "
1148
1149 xml_insert_indexterm (indexterm, index)
1150     char *indexterm;
1151     char *index;
1152 {
1153   if (!docbook)
1154     {
1155       xml_insert_element_with_attribute (INDEXTERM, START, "index=\"%s\"", index);
1156       execute_string ("%s", indexterm);
1157       xml_insert_element (INDEXTERM, END);
1158     }
1159   else
1160     {      
1161       char *expanded;
1162       char *primary = NULL, *secondary;
1163       xml_sort_index = 1;
1164       xml_no_para = 1;
1165       expanded = expansion (indexterm);
1166       xml_sort_index = 0;
1167       xml_no_para = 0;
1168       if (strstr (expanded+1, INDEX_SEP))
1169         {
1170           primary = xmalloc (strlen (expanded) + 1);
1171           strcpy (primary, expanded);
1172           secondary = strstr (primary+1, INDEX_SEP);
1173           *secondary = '\0';
1174           secondary += strlen (INDEX_SEP);
1175         }
1176       xml_insert_element_with_attribute (INDEXTERM, START, "role=\"%s\"", index);
1177       xml_insert_element (PRIMARY, START);
1178       if (primary)
1179         insert_string (primary);
1180       else
1181         insert_string (expanded);
1182       xml_insert_element (PRIMARY, END);
1183       if (primary)
1184         {
1185           xml_insert_element (SECONDARY, START);
1186           insert_string (secondary);
1187           xml_insert_element (SECONDARY, END);
1188         }
1189       xml_insert_element (INDEXTERM, END);
1190       free (expanded);
1191     }
1192 }
1193
1194
1195 int xml_last_section_output_position = 0;
1196 static char last_division_letter = ' ';
1197 static char index_primary[2000]; /** xx no fixed limit */
1198 static int indexdivempty = 0;
1199
1200 static int in_indexentry = 0;
1201 static int in_secondary = 0;
1202 static void 
1203 xml_close_indexentry ()
1204 {
1205   if (!in_indexentry)
1206     return;
1207   if (in_secondary)
1208     xml_insert_element (SECONDARYIE, END);
1209   xml_insert_element (INDEXENTRY, END);
1210   in_secondary = 0;
1211   in_indexentry = 0;
1212 }
1213
1214 void
1215 xml_begin_index ()
1216 {
1217   /* 
1218      We assume that we just opened a section, and so that the last output is
1219      <SECTION ID="node-name"><TITLE>Title</TITLE>
1220      where SECTION can be CHAPTER, ...
1221    */
1222
1223   xml_section *temp = last_section;
1224
1225   int l = output_paragraph_offset-xml_last_section_output_position;
1226   char *tmp = xmalloc (l+1);
1227   char *p = tmp;
1228   strncpy (tmp, output_paragraph, l);
1229
1230   /* We remove <SECTION */
1231   tmp[l] = '\0';
1232   while (*p != '<')
1233     p++;
1234   while (*p != ' ')
1235     p++;
1236
1237   output_paragraph_offset = xml_last_section_output_position;
1238   xml_last_section_output_position = 0;
1239
1240   xml_pop_current_element (); /* remove section element from elements stack */
1241                                 
1242   last_section = last_section->prev; /* remove section from sections stack */
1243   free (temp->name);
1244   free (temp);
1245   
1246   /* We put <INDEX> */
1247   xml_insert_element (PRINTINDEX, START);
1248   /* Remove the final > */
1249   output_paragraph_offset--;
1250
1251   /* and put  ID="node-name"><TITLE>Title</TITLE> */
1252   insert_string (p);
1253
1254   if (xml_index_divisions)
1255     {
1256       xml_insert_element (INDEXDIV, START);
1257       indexdivempty = 1;
1258     }
1259 }
1260
1261 void
1262 xml_end_index ()
1263 {
1264   xml_close_indexentry ();
1265   if (xml_index_divisions)    
1266     xml_insert_element (INDEXDIV, END);
1267   xml_insert_element (PRINTINDEX, END);  
1268 }
1269
1270 void
1271 xml_index_divide (entry)
1272     char *entry;
1273 {
1274   char c;
1275   if (strlen (entry) > (strlen (xml_element_list[CODE].name) + 2) && 
1276       strncmp (entry+1, xml_element_list[CODE].name, strlen (xml_element_list[CODE].name)) == 0)   
1277     c = entry[strlen (xml_element_list[CODE].name)+2];
1278   else 
1279     c = entry[0];
1280   if (tolower (c) != last_division_letter && isalpha (c))
1281     {
1282       last_division_letter = tolower (c);
1283       xml_close_indexentry ();
1284       if (!indexdivempty)
1285         {
1286           xml_insert_element (INDEXDIV, END);
1287           xml_insert_element (INDEXDIV, START);
1288         }
1289       xml_insert_element (TITLE, START);
1290       insert (toupper (c));
1291       xml_insert_element (TITLE, END);
1292     }
1293 }
1294
1295 void
1296 xml_insert_indexentry (entry, node)
1297     char *entry;
1298     char *node;
1299 {
1300   char *primary = NULL, *secondary;
1301   if (xml_index_divisions)
1302     xml_index_divide (entry);
1303
1304   indexdivempty = 0;
1305   if (strstr (entry+1, INDEX_SEP))
1306     {
1307       primary = xmalloc (strlen (entry) + 1);
1308       strcpy (primary, entry);
1309       secondary = strstr (primary+1, INDEX_SEP);
1310       *secondary = '\0';
1311       secondary += strlen (INDEX_SEP);
1312
1313       if (in_secondary && strcmp (primary, index_primary) == 0)
1314         {
1315           xml_insert_element (SECONDARYIE, END);
1316           xml_insert_element (SECONDARYIE, START);        
1317           insert_string (secondary);
1318         } 
1319       else
1320         {
1321           xml_close_indexentry ();
1322           xml_insert_element (INDEXENTRY, START);
1323           in_indexentry = 1;
1324           xml_insert_element (PRIMARYIE, START);
1325           insert_string (primary);
1326           xml_insert_element (PRIMARYIE, END);
1327           xml_insert_element (SECONDARYIE, START);
1328           insert_string (secondary);
1329           in_secondary = 1;
1330         }
1331     }
1332   else
1333     {
1334       xml_close_indexentry ();
1335       xml_insert_element (INDEXENTRY, START);
1336       in_indexentry = 1;
1337       xml_insert_element (PRIMARYIE, START);
1338       insert_string (entry);
1339     }
1340   add_word_args (", %s", _("see "));
1341   xml_insert_element_with_attribute (XREF, START, "linkend=\"%s\"", xml_id (node));
1342   xml_pop_current_element ();
1343
1344   if (primary)
1345     {
1346       strcpy (index_primary, primary);
1347       /*      xml_insert_element (SECONDARYIE, END);*/
1348       /*     *(secondary-1) = ',';*/ /* necessary ? */
1349       free (primary);
1350     }
1351   else
1352     xml_insert_element (PRIMARYIE, END);
1353
1354   /*  xml_insert_element (INDEXENTRY, END); */
1355 }
1356
1357 /*
1358  * MULTITABLE
1359  */
1360 void
1361 xml_begin_multitable (ncolumns, column_widths)
1362     int ncolumns;
1363     int *column_widths;
1364 {
1365   int i;
1366   if (docbook)
1367     {
1368       xml_insert_element (MULTITABLE, START);
1369       xml_insert_element_with_attribute (TGROUP, START, "cols=\"%d\"", ncolumns);
1370       for (i=0; i<ncolumns; i++)
1371         {
1372           xml_insert_element_with_attribute (COLSPEC, START, "colwidth=\"%d*\"", column_widths[i]);
1373           xml_pop_current_element ();
1374         }
1375       xml_insert_element (TBODY, START);
1376       xml_no_para = 1;
1377     }
1378   else 
1379     {
1380       xml_insert_element (MULTITABLE, START);
1381       for (i=0; i<ncolumns; i++)
1382         {
1383           xml_insert_element (COLSPEC, START);
1384           add_word_args ("%d", column_widths[i]);
1385           xml_insert_element (COLSPEC, END);
1386         }
1387       xml_no_para = 1;
1388     }
1389 }
1390
1391 void
1392 xml_end_multitable_row (first_row)
1393     int first_row;
1394 {
1395   if (!first_row)
1396     {
1397       xml_insert_element (ENTRY, END);
1398       xml_insert_element (ROW, END);
1399     }
1400   xml_insert_element (ROW, START);
1401   xml_insert_element (ENTRY, START);
1402 }
1403
1404 void
1405 xml_end_multitable_column ()
1406 {
1407   xml_insert_element (ENTRY, END);
1408   xml_insert_element (ENTRY, START);
1409 }
1410
1411 void
1412 xml_end_multitable ()
1413 {
1414   if (docbook)
1415     {
1416       xml_insert_element (ENTRY, END);
1417       xml_insert_element (ROW, END);
1418       xml_insert_element (TBODY, END);
1419       xml_insert_element (TGROUP, END);
1420       xml_insert_element (MULTITABLE, END);
1421       xml_no_para = 0;
1422     }
1423   else 
1424     {
1425       xml_insert_element (ENTRY, END);
1426       xml_insert_element (ROW, END);
1427       xml_insert_element (MULTITABLE, END);
1428       xml_no_para = 0;
1429     }
1430 }