1 /* xml.c -- xml output. 2 $Id: xml.c,v 1.1.1.1 2002/06/10 13:21:23 espie 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 /* */ 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 ("&"); 879 else if (character == '<' && escape_html) 880 insert_string ("<"); 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 } 1431