Imported from antiword-0.37.tar.gz.
[antiword.git] / xml.c
blob92048ad646ce2cb60f300c03566ebcf06927f1c6
1 /*
2 * xml.c
3 * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
5 * Description:
6 * Functions to deal with the XML/DocBook format
8 */
10 #include <string.h>
11 #include "antiword.h"
14 #define vAddEndTagsUntil1(p,t) vAddEndTagsUntil2(p,t,TAG_NOTAG)
16 #if defined(DEBUG)
17 #define vStackTrace() __vStackTrace(__LINE__)
18 #else
19 #define vStackTrace() /* EMPTY */
20 #endif /* DEBUG */
22 /* The character set */
23 static encoding_type eEncoding = encoding_neutral;
24 /* Word version */
25 static int iWordVersion = -1;
26 /* Special treatment for files from Word 4/5/6 on an Apple Macintosh */
27 static BOOL bOldMacFile = FALSE;
28 /* Text is emphasised */
29 static BOOL bEmphasisOpen = FALSE;
30 /* Text is superscript */
31 static BOOL bSuperscriptOpen = FALSE;
32 /* Text is subscript */
33 static BOOL bSubscriptOpen = FALSE;
34 /* Title is open */
35 static BOOL bTitleOpen = FALSE;
36 /* Table is open */
37 static BOOL bTableOpen = FALSE;
38 /* Footnote is open */
39 static BOOL bFootnoteOpen = FALSE;
40 /* Current paragraph level */
41 static UINT uiParagraphLevel = 0;
42 /* Current list level */
43 static UINT uiListLevel = 0;
44 /* Current list level is still empty */
45 static BOOL bEmptyListLevel = TRUE;
46 /* Current header level */
47 static USHORT usHeaderLevelCurrent = 0;
48 /* Current header level is still empty */
49 static BOOL bEmptyHeaderLevel = TRUE;
50 /* Number of columns in the current table */
51 static int iTableColumnsCurrent = 0;
52 /* Footnote number */
53 static UINT uiFootnoteNumber = 0;
55 /* Constants for the stack */
56 #define INITIAL_STACK_SIZE 10
57 #if defined(DEBUG)
58 #define EXTENSION_STACK_SIZE 2
59 #else
60 #define EXTENSION_STACK_SIZE 10
61 #endif /* DEBUG */
63 /* Variables for the stack */
64 static UCHAR *aucStack = NULL;
65 static size_t tStacksize = 0;
66 static size_t tStackNextFree = 0;
68 /* Constants for the tags */
69 #define TAG_NOTAG (UCHAR)0
70 #define TAG_AUTHOR (UCHAR)1
71 #define TAG_BEGINPAGE (UCHAR)2
72 #define TAG_BOOK (UCHAR)3
73 #define TAG_BOOKINFO (UCHAR)4
74 #define TAG_CHAPTER (UCHAR)5
75 #define TAG_COLSPEC (UCHAR)6
76 #define TAG_CORPNAME (UCHAR)7
77 #define TAG_DATE (UCHAR)8
78 #define TAG_EMPHASIS (UCHAR)9
79 #define TAG_ENTRY (UCHAR)10
80 #define TAG_FILENAME (UCHAR)11
81 #define TAG_FOOTNOTE (UCHAR)12
82 #define TAG_INFORMALTABLE (UCHAR)13
83 #define TAG_ITEMIZEDLIST (UCHAR)14
84 #define TAG_LISTITEM (UCHAR)15
85 #define TAG_ORDEREDLIST (UCHAR)16
86 #define TAG_PARA (UCHAR)17
87 #define TAG_ROW (UCHAR)18
88 #define TAG_SECT1 (UCHAR)19
89 #define TAG_SECT2 (UCHAR)20
90 #define TAG_SECT3 (UCHAR)21
91 #define TAG_SECT4 (UCHAR)22
92 #define TAG_SECT5 (UCHAR)23
93 #define TAG_SUBSCRIPT (UCHAR)24
94 #define TAG_SUBTITLE (UCHAR)25
95 #define TAG_SUPERSCRIPT (UCHAR)26
96 #define TAG_SURNAME (UCHAR)27
97 #define TAG_TBODY (UCHAR)28
98 #define TAG_TGROUP (UCHAR)29
99 #define TAG_TITLE (UCHAR)30
101 typedef struct docbooktags_tag {
102 UCHAR ucTagnumber;
103 char szTagname[15];
104 BOOL bAddNewlineStart;
105 BOOL bAddNewlineEnd;
106 } docbooktags_type;
108 static const docbooktags_type atDocBookTags[] = {
109 { TAG_NOTAG, "!ERROR!", TRUE, TRUE },
110 { TAG_AUTHOR, "author", TRUE, TRUE },
111 { TAG_BEGINPAGE, "beginpage", TRUE, TRUE },
112 { TAG_BOOK, "book", TRUE, TRUE },
113 { TAG_BOOKINFO, "bookinfo", TRUE, TRUE },
114 { TAG_CHAPTER, "chapter", TRUE, TRUE },
115 { TAG_COLSPEC, "colspec", TRUE, TRUE },
116 { TAG_CORPNAME, "corpname", FALSE, FALSE },
117 { TAG_DATE, "date", FALSE, FALSE },
118 { TAG_EMPHASIS, "emphasis", FALSE, FALSE },
119 { TAG_ENTRY, "entry", TRUE, TRUE },
120 { TAG_FILENAME, "filename", FALSE, FALSE },
121 { TAG_FOOTNOTE, "footnote", FALSE, FALSE },
122 { TAG_INFORMALTABLE, "informaltable",TRUE, TRUE },
123 { TAG_ITEMIZEDLIST, "itemizedlist", TRUE, TRUE },
124 { TAG_LISTITEM, "listitem", TRUE, TRUE },
125 { TAG_ORDEREDLIST, "orderedlist", TRUE, TRUE },
126 { TAG_PARA, "para", TRUE, TRUE },
127 { TAG_ROW, "row", TRUE, TRUE },
128 { TAG_SECT1, "sect1", TRUE, TRUE },
129 { TAG_SECT2, "sect2", TRUE, TRUE },
130 { TAG_SECT3, "sect3", TRUE, TRUE },
131 { TAG_SECT4, "sect4", TRUE, TRUE },
132 { TAG_SECT5, "sect5", TRUE, TRUE },
133 { TAG_SUBSCRIPT, "subscript", FALSE, FALSE },
134 { TAG_SUBTITLE, "subtitle", FALSE, FALSE },
135 { TAG_SUPERSCRIPT, "superscript", FALSE, FALSE },
136 { TAG_SURNAME, "surname", FALSE, FALSE },
137 { TAG_TBODY, "tbody", TRUE, TRUE },
138 { TAG_TGROUP, "tgroup", TRUE, TRUE },
139 { TAG_TITLE, "title", FALSE, FALSE },
142 static void vAddStartTag(diagram_type *, UCHAR, const char *);
143 static void vAddEndTag(diagram_type *, UCHAR);
144 static void vAddCombinedTag(diagram_type *, UCHAR, const char *);
145 static void vPrintChar(diagram_type *, char);
148 #if defined(DEBUG)
150 * vCheckTagTable - check the tag table
152 static void
153 vCheckTagTable(void)
155 size_t tIndex;
157 for (tIndex = 0; tIndex < elementsof(atDocBookTags); tIndex++) {
158 if (tIndex != (size_t)atDocBookTags[tIndex].ucTagnumber) {
159 DBG_DEC(tIndex);
160 werr(1, "Array atDocBookTags is broken");
163 } /* end of vCheckTagTable */
166 * __vStackTrace - show a stack trace
168 static void
169 __vStackTrace(int iLine)
171 int iIndex;
173 fprintf(stderr, "%s[%3d]:\n", __FILE__, iLine);
175 if (tStackNextFree == 0) {
176 fprintf(stderr, "The stack is empty\n");
177 return;
179 for (iIndex = (int)tStackNextFree - 1; iIndex >= 0; iIndex--) {
180 fprintf(stderr, "%2d: %2d: '%s'\n",
181 iIndex,
182 (int)atDocBookTags[(UINT)aucStack[iIndex]].ucTagnumber,
183 atDocBookTags[(UINT)aucStack[iIndex]].szTagname);
185 } /* end of __vStackTrace */
186 #endif /* DEBUG */
189 * vPushStack - push a tag onto the stack
191 static void
192 vPushStack(UCHAR ucTag)
194 fail(tStackNextFree > tStacksize);
196 if (tStackNextFree == tStacksize) {
197 /* The stack is full; enlarge the stack */
198 tStacksize += EXTENSION_STACK_SIZE;
199 aucStack = xrealloc(aucStack, tStacksize * sizeof(UCHAR));
200 DBG_DEC(tStacksize);
203 fail(tStackNextFree >= tStacksize);
205 aucStack[tStackNextFree++] = ucTag;
206 } /* end of vPushStack */
209 * vPopStack - pop a tag from the stack
211 static UCHAR
212 ucPopStack(void)
214 DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
215 DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
216 fail(tStackNextFree > tStacksize);
217 fail(tStackNextFree == 0);
219 if (tStackNextFree == 0) {
220 werr(1, "The stack is empty, unable to continue");
221 return TAG_NOTAG;
223 return aucStack[--tStackNextFree];
224 } /* end of ucPopStack */
227 * vReadStack - read a tag from the top of the stack
229 static UCHAR
230 ucReadStack(void)
232 DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
233 DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
234 fail(tStackNextFree > tStacksize);
236 if (tStackNextFree == 0) {
237 /* The stack is empty */
238 return TAG_NOTAG;
240 return aucStack[tStackNextFree - 1];
241 } /* end of ucReadStack */
244 * vPrintLevel - print the tag level
246 static void
247 vPrintLevel(FILE *pOutFile)
249 size_t tIndex;
251 fail(pOutFile == NULL);
253 for (tIndex = 0; tIndex < tStackNextFree; tIndex++) {
254 (void)putc(' ', pOutFile);
256 } /* end of vPrintLevel */
259 * vPrintFootnote - print a footnote
261 static void
262 vPrintFootnote(diagram_type *pDiag, UINT uiFootnoteIndex)
264 const char *szText, *pcTmp;
265 BOOL bSuScript;
266 UCHAR ucTopTag;
268 TRACE_MSG("vPrintFootnote");
270 szText = szGetFootnootText(uiFootnoteIndex);
272 if (szText == NULL) {
273 szText = "";
276 /* Remove the subscript/superscript (if any) */
277 ucTopTag = ucReadStack();
278 bSuScript = ucTopTag == TAG_SUBSCRIPT || ucTopTag == TAG_SUPERSCRIPT;
279 if (bSuScript) {
280 vAddEndTag(pDiag, ucTopTag);
283 /* Start a footnote */
284 vAddStartTag(pDiag, TAG_FOOTNOTE, NULL);
285 vAddStartTag(pDiag, TAG_PARA, NULL);
287 /* Print a footnote */
288 for (pcTmp = szText; *pcTmp != '\0'; pcTmp++) {
289 if (*pcTmp == PAR_END) {
290 if (*(pcTmp + 1) != PAR_END && *(pcTmp + 1) != '\0') {
291 /* PAR_END is not empty and not last */
292 vAddEndTag(pDiag, TAG_PARA);
293 vAddStartTag(pDiag, TAG_PARA, NULL);
295 } else {
296 vPrintChar(pDiag, *pcTmp);
300 /* End a footnote */
301 vAddEndTag(pDiag, TAG_PARA);
302 vAddEndTag(pDiag, TAG_FOOTNOTE);
304 /* Repair the subscript/superscript (if any) */
305 if (bSuScript) {
306 vAddStartTag(pDiag, ucTopTag, NULL);
308 } /* end of vPrintFootnote */
311 * vPrintChar - print a character with XML encoding
313 static void
314 vPrintChar(diagram_type *pDiag, char cChar)
316 fail(pDiag == NULL);
317 fail(pDiag->pOutFile == NULL);
319 switch (cChar) {
320 case FOOTNOTE_OR_ENDNOTE:
321 uiFootnoteNumber++;
322 vPrintFootnote(pDiag, uiFootnoteNumber - 1);
323 break;
324 case '<':
325 fprintf(pDiag->pOutFile, "%s", "&lt;");
326 break;
327 case '>':
328 fprintf(pDiag->pOutFile, "%s", "&gt;");
329 break;
330 case '&':
331 fprintf(pDiag->pOutFile, "%s", "&amp;");
332 break;
333 default:
334 (void)putc(cChar, pDiag->pOutFile);
335 break;
337 } /* end of vPrintChar */
340 * vPrintSpecialChar - convert and print a character
342 static void
343 vPrintSpecialChar(diagram_type *pDiag, USHORT usChar)
345 ULONG ulChar;
346 size_t tLen, tIndex;
347 char szResult[4];
349 fail(pDiag == NULL);
350 fail(pDiag->pOutFile == NULL);
351 fail(iWordVersion < 0);
352 fail(eEncoding == encoding_neutral);
354 ulChar = ulTranslateCharacters(usChar, 0, iWordVersion,
355 conversion_xml, eEncoding, bOldMacFile);
356 tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
357 if (tLen == 1) {
358 vPrintChar(pDiag, szResult[0]);
359 } else {
360 for (tIndex = 0; tIndex < tLen; tIndex++) {
361 (void)putc(szResult[tIndex], pDiag->pOutFile);
364 } /* end of vPrintSpecialChar */
367 * vPrintSpecialString - convert and print a string
369 static void
370 vPrintSpecialString(diagram_type *pDiag, const char *szString)
372 int iIndex;
373 USHORT usChar;
375 fail(pDiag == NULL);
376 fail(pDiag->pOutFile == NULL);
377 fail(szString == NULL);
379 for (iIndex = 0; szString[iIndex] != '\0'; iIndex++) {
380 usChar = (USHORT)(UCHAR)szString[iIndex];
381 vPrintSpecialChar(pDiag, usChar);
383 } /* end of vPrintSpecialString */
386 * vAddStartTag - add the specified start tag to the file
388 static void
389 vAddStartTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
391 fail(pDiag == NULL);
392 fail(pDiag->pOutFile == NULL);
393 fail((size_t)ucTag >= elementsof(atDocBookTags));
395 if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
396 fprintf(pDiag->pOutFile, "\n");
397 vPrintLevel(pDiag->pOutFile);
400 if (szAttribute == NULL || szAttribute[0] == '\0') {
401 fprintf(pDiag->pOutFile, "<%s>",
402 atDocBookTags[(UINT)ucTag].szTagname);
403 } else {
404 fprintf(pDiag->pOutFile, "<%s %s>",
405 atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
408 if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
409 fprintf(pDiag->pOutFile, "\n");
410 pDiag->lXleft = 0;
413 vPushStack(ucTag);
415 /* Set global variables */
416 switch (ucTag) {
417 case TAG_CHAPTER:
418 usHeaderLevelCurrent = 1;
419 bEmptyHeaderLevel = TRUE;
420 break;
421 case TAG_SECT1:
422 usHeaderLevelCurrent = 2;
423 bEmptyHeaderLevel = TRUE;
424 break;
425 case TAG_SECT2:
426 usHeaderLevelCurrent = 3;
427 bEmptyHeaderLevel = TRUE;
428 break;
429 case TAG_SECT3:
430 usHeaderLevelCurrent = 4;
431 bEmptyHeaderLevel = TRUE;
432 break;
433 case TAG_SECT4:
434 usHeaderLevelCurrent = 5;
435 bEmptyHeaderLevel = TRUE;
436 break;
437 case TAG_SECT5:
438 usHeaderLevelCurrent = 6;
439 bEmptyHeaderLevel = TRUE;
440 break;
441 case TAG_TITLE:
442 fail(uiParagraphLevel != 0);
443 bTitleOpen = TRUE;
444 break;
445 case TAG_FOOTNOTE:
446 bFootnoteOpen = TRUE;
447 break;
448 case TAG_PARA:
449 fail(bTitleOpen && !bFootnoteOpen);
450 uiParagraphLevel++;
451 bEmptyHeaderLevel = FALSE;
452 break;
453 case TAG_EMPHASIS:
454 bEmphasisOpen = TRUE;
455 break;
456 case TAG_ITEMIZEDLIST:
457 case TAG_ORDEREDLIST:
458 uiListLevel++;
459 bEmptyListLevel = TRUE;
460 bEmptyHeaderLevel = FALSE;
461 break;
462 case TAG_LISTITEM:
463 bEmptyListLevel = FALSE;
464 break;
465 case TAG_SUPERSCRIPT:
466 bSuperscriptOpen = TRUE;
467 break;
468 case TAG_SUBSCRIPT:
469 bSubscriptOpen = TRUE;
470 break;
471 case TAG_INFORMALTABLE:
472 bTableOpen = TRUE;
473 bEmptyHeaderLevel = FALSE;
474 break;
475 default:
476 break;
478 } /* end of vAddStartTag */
481 * vAddEndTag - add the specified end tag to the file
483 static void
484 vAddEndTag(diagram_type *pDiag, UCHAR ucTag)
486 UCHAR ucTopTag;
488 fail(pDiag == NULL);
489 fail(pDiag->pOutFile == NULL);
490 fail((size_t)ucTag >= elementsof(atDocBookTags));
492 #if defined(DEBUG)
493 ucTopTag = ucReadStack();
494 if (ucTag != ucTopTag) {
495 DBG_DEC(ucTag);
496 DBG_MSG(atDocBookTags[(UINT)ucTag].szTagname);
497 vStackTrace();
499 #endif /* DEBUG */
501 ucTopTag = ucPopStack();
502 fail((size_t)ucTopTag >= elementsof(atDocBookTags));
503 if (ucTag != ucTopTag) {
504 DBG_DEC(ucTag);
505 DBG_DEC(ucTopTag);
506 DBG_FIXME();
507 werr(1, "Impossible tag sequence, unable to continue");
510 if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
511 fprintf(pDiag->pOutFile, "\n");
512 vPrintLevel(pDiag->pOutFile);
515 fprintf(pDiag->pOutFile, "</%s>", atDocBookTags[(UINT)ucTag].szTagname);
517 if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
518 fprintf(pDiag->pOutFile, "\n");
519 pDiag->lXleft = 0;
522 /* Set global variables */
523 switch (ucTag) {
524 case TAG_CHAPTER:
525 usHeaderLevelCurrent = 0;
526 break;
527 case TAG_SECT1:
528 usHeaderLevelCurrent = 1;
529 break;
530 case TAG_SECT2:
531 usHeaderLevelCurrent = 2;
532 break;
533 case TAG_SECT3:
534 usHeaderLevelCurrent = 3;
535 break;
536 case TAG_SECT4:
537 usHeaderLevelCurrent = 4;
538 break;
539 case TAG_SECT5:
540 usHeaderLevelCurrent = 5;
541 break;
542 case TAG_TITLE:
543 bTitleOpen = FALSE;
544 break;
545 case TAG_FOOTNOTE:
546 bFootnoteOpen = FALSE;
547 break;
548 case TAG_PARA:
549 uiParagraphLevel--;
550 break;
551 case TAG_EMPHASIS:
552 bEmphasisOpen = FALSE;
553 break;
554 case TAG_SUPERSCRIPT:
555 bSuperscriptOpen = FALSE;
556 break;
557 case TAG_ITEMIZEDLIST:
558 case TAG_ORDEREDLIST:
559 uiListLevel--;
560 break;
561 case TAG_SUBSCRIPT:
562 bSubscriptOpen = FALSE;
563 break;
564 case TAG_INFORMALTABLE:
565 bTableOpen = FALSE;
566 iTableColumnsCurrent = 0;
567 break;
568 default:
569 break;
571 } /* end of vAddEndTag */
574 * vAddEndTagOptional - add the specified end tag to the file if needed
576 static void
577 vAddEndTagOptional(diagram_type *pDiag, UCHAR ucTag)
579 UCHAR ucTopTag;
581 ucTopTag = ucReadStack();
582 if (ucTag == ucTopTag) {
583 vAddEndTag(pDiag, ucTag);
585 } /* end of vAddEndTagOptional */
588 * vAddCombinedTag - add the specified start and end tag to the file
590 static void
591 vAddCombinedTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
593 fail(pDiag == NULL);
594 fail(pDiag->pOutFile == NULL);
595 fail((size_t)ucTag >= elementsof(atDocBookTags));
597 if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
598 fprintf(pDiag->pOutFile, "\n");
599 vPrintLevel(pDiag->pOutFile);
602 if (szAttribute == NULL || szAttribute[0] == '\0') {
603 fprintf(pDiag->pOutFile, "<%s/>",
604 atDocBookTags[(UINT)ucTag].szTagname);
605 } else {
606 fprintf(pDiag->pOutFile, "<%s %s/>",
607 atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
610 if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
611 fprintf(pDiag->pOutFile, "\n");
612 pDiag->lXleft = 0;
614 } /* end of vAddCombinedTag */
617 * vAddEndTagsUntil2 - add end tags until one the specified tags is seen
619 static void
620 vAddEndTagsUntil2(diagram_type *pDiag, UCHAR ucTag1, UCHAR ucTag2)
622 UCHAR ucTopTag;
624 do {
625 ucTopTag = ucReadStack();
626 switch (ucTopTag) {
627 case TAG_CHAPTER:
628 case TAG_SECT1:
629 case TAG_SECT2:
630 case TAG_SECT3:
631 case TAG_SECT4:
632 case TAG_SECT5:
633 if (bEmptyHeaderLevel) {
635 * An empty chapter is legal in Word,
636 * but not in DocBook.
638 vAddCombinedTag(pDiag, TAG_PARA, NULL);
639 bEmptyHeaderLevel = FALSE;
641 break;
642 case TAG_ITEMIZEDLIST:
643 case TAG_ORDEREDLIST:
644 if (bEmptyListLevel) {
646 * A list without items is legal in Word,
647 * but not in DocBook. (Nor are empty items)
649 vAddStartTag(pDiag, TAG_LISTITEM, NULL);
650 vAddCombinedTag(pDiag, TAG_PARA, NULL);
651 vAddEndTag(pDiag, TAG_LISTITEM);
652 bEmptyListLevel = FALSE;
654 break;
655 default:
656 break;
658 vAddEndTag(pDiag, ucTopTag);
659 } while (ucTopTag != ucTag1 && ucTopTag != ucTag2);
660 } /* end of vAddEndTagsUntil2 */
663 * vCreateBookIntro - create title and bookinfo
665 void
666 vCreateBookIntro(diagram_type *pDiag, int iVersion)
668 const char *szTitle, *szSubject, *szAuthor;
669 const char *szLastSaveDtm, *szCompany;
670 const char *szLanguage;
671 char szTmp[13];
673 fail(pDiag == NULL);
674 fail(pDiag->pOutFile == NULL);
675 fail(iVersion < 0);
676 fail(eEncoding == encoding_neutral);
678 iWordVersion = iVersion;
679 bOldMacFile = bIsOldMacFile();
680 szTitle = szGetTitle();
681 szSubject = szGetSubject();
682 szAuthor = szGetAuthor();
683 szLastSaveDtm = szGetLastSaveDtm();
684 szCompany = szGetCompany();
686 /* Start Book */
687 szLanguage = szGetLanguage();
688 if (szLanguage != NULL) {
689 DBG_MSG(szLanguage);
690 sprintf(szTmp, "lang='%.5s'", szLanguage);
691 szLanguage = szTmp;
693 vAddStartTag(pDiag, TAG_BOOK, szLanguage);
695 /* Book title */
696 if (szTitle != NULL && szTitle[0] != '\0') {
697 vAddStartTag(pDiag, TAG_TITLE, NULL);
698 vPrintSpecialString(pDiag, szTitle);
699 vAddEndTag(pDiag, TAG_TITLE);
701 /* Bookinfo */
702 if ((szTitle != NULL && szTitle[0] != '\0') ||
703 (szSubject != NULL && szSubject[0] != '\0') ||
704 (szAuthor != NULL && szAuthor[0] != '\0') ||
705 (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') ||
706 (szCompany != NULL && szCompany[0] != '\0')) {
707 vAddStartTag(pDiag, TAG_BOOKINFO, NULL);
708 if (szTitle != NULL && szTitle[0] != '\0') {
709 vAddStartTag(pDiag, TAG_TITLE, NULL);
710 vPrintSpecialString(pDiag, szTitle);
711 vAddEndTag(pDiag, TAG_TITLE);
713 if (szSubject != NULL && szSubject[0] != '\0') {
714 vAddStartTag(pDiag, TAG_SUBTITLE, NULL);
715 vPrintSpecialString(pDiag, szSubject);
716 vAddEndTag(pDiag, TAG_SUBTITLE);
718 if (szAuthor != NULL && szAuthor[0] != '\0') {
719 vAddStartTag(pDiag, TAG_AUTHOR, NULL);
720 vAddStartTag(pDiag, TAG_SURNAME, NULL);
721 vPrintSpecialString(pDiag, szAuthor);
722 vAddEndTag(pDiag, TAG_SURNAME);
723 vAddEndTag(pDiag, TAG_AUTHOR);
725 if (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') {
726 vAddStartTag(pDiag, TAG_DATE, NULL);
727 vPrintSpecialString(pDiag, szLastSaveDtm);
728 vAddEndTag(pDiag, TAG_DATE);
730 if (szCompany != NULL && szCompany[0] != '\0') {
731 vAddStartTag(pDiag, TAG_CORPNAME, NULL);
732 vPrintSpecialString(pDiag, szCompany);
733 vAddEndTag(pDiag, TAG_CORPNAME);
735 vAddEndTag(pDiag, TAG_BOOKINFO);
737 } /* end of vCreateBookIntro */
740 * vPrologueXML - perform the XML initialization
742 void
743 vPrologueXML(diagram_type *pDiag, const options_type *pOptions)
746 fail(pDiag == NULL);
747 fail(pDiag->pOutFile == NULL);
748 fail(pOptions == NULL);
750 #if defined(DEBUG)
751 vCheckTagTable();
752 #endif /* DEBUG */
754 /* Set global variables to their start values */
755 eEncoding = pOptions->eEncoding;
756 bEmphasisOpen = FALSE;
757 bSuperscriptOpen = FALSE;
758 bSubscriptOpen = FALSE;
759 bTitleOpen = FALSE;
760 bTableOpen = FALSE;
761 bFootnoteOpen = FALSE;
762 uiParagraphLevel = 0;
763 uiListLevel = 0;
764 bEmptyListLevel = TRUE;
765 usHeaderLevelCurrent = 0;
766 bEmptyHeaderLevel = TRUE;
767 iTableColumnsCurrent = 0;
768 uiFootnoteNumber = 0;
770 pDiag->lXleft = 0;
771 pDiag->lYtop = 0;
773 /* Create an empty stack */
774 tStacksize = INITIAL_STACK_SIZE;
775 aucStack = xcalloc(tStacksize, sizeof(UCHAR));
776 tStackNextFree = 0;
777 } /* end of vPrologueXML */
780 * vEpilogueXML - clean up after everything is done
782 void
783 vEpilogueXML(diagram_type *pDiag)
785 vStackTrace();
787 vAddEndTagsUntil1(pDiag, TAG_BOOK);
789 vStackTrace();
791 /* Destroy the stack */
792 fail(tStackNextFree != 0);
793 tStacksize = 0;
794 aucStack = xfree(aucStack);
795 tStackNextFree = 0;
796 } /* end of vEpilogueXML */
799 * vPrintXML - print a XML string
801 static void
802 vPrintXML(diagram_type *pDiag, const char *szString, size_t tStringLength,
803 USHORT usFontstyle)
805 const char *szAttr;
806 int iCount;
807 size_t tNextFree;
808 BOOL bNotReady, bEmphasisNew, bSuperscriptNew, bSubscriptNew;
809 UCHAR ucTopTag, aucStorage[3];
811 fail(szString == NULL);
813 if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
814 return;
817 if (tStringLength == 1 && szString[0] == FOOTNOTE_OR_ENDNOTE) {
818 /* Don't do anything special for just a single footnote */
819 bEmphasisNew = FALSE;
820 bSuperscriptNew = FALSE;
821 bSubscriptNew = FALSE;
822 } else {
823 /* Situation normal */
824 bEmphasisNew = bIsBold(usFontstyle) ||
825 bIsItalic(usFontstyle) ||
826 bIsUnderline(usFontstyle) ||
827 bIsStrike(usFontstyle);
828 bSuperscriptNew = bIsSuperscript(usFontstyle);
829 bSubscriptNew = bIsSubscript(usFontstyle);
832 /* End what has to be ended (or more to keep the stack happy) */
833 tNextFree = 0;
834 bNotReady = TRUE;
835 do {
836 ucTopTag = ucReadStack();
837 switch (ucTopTag) {
838 case TAG_EMPHASIS:
839 fail(!bEmphasisOpen);
840 if (bEmphasisNew) {
841 aucStorage[tNextFree++] = ucTopTag;
843 vAddEndTag(pDiag, ucTopTag);
844 break;
845 case TAG_SUPERSCRIPT:
846 fail(!bSuperscriptOpen);
847 if (bSuperscriptNew) {
848 aucStorage[tNextFree++] = ucTopTag;
850 vAddEndTag(pDiag, ucTopTag);
851 break;
852 case TAG_SUBSCRIPT:
853 fail(!bSubscriptOpen);
854 if (bSubscriptNew) {
855 aucStorage[tNextFree++] = ucTopTag;
857 vAddEndTag(pDiag, ucTopTag);
858 break;
859 default:
860 bNotReady = FALSE;
861 break;
863 fail(tNextFree > elementsof(aucStorage));
864 fail(bNotReady && tNextFree == elementsof(aucStorage));
865 } while (bNotReady);
867 /* Just te make sure */
868 vStartOfParagraphXML(pDiag, 1);
870 /* Restart to keep the stack happy */
871 for (iCount = (int)tNextFree - 1; iCount > 0; iCount--) {
872 vAddStartTag(pDiag, aucStorage[iCount], NULL);
875 /* Start what has to be started */
876 if (bEmphasisNew && !bEmphasisOpen) {
877 if (bIsBold(usFontstyle)) {
878 szAttr = "role='bold'";
879 } else if (bIsItalic(usFontstyle)) {
880 szAttr = NULL;
881 } else if (bIsUnderline(usFontstyle)) {
882 szAttr = "role='underline'";
883 } else if (bIsStrike(usFontstyle)) {
884 szAttr = "role='strikethrough'";
885 } else {
886 szAttr = NULL;
888 vAddStartTag(pDiag, TAG_EMPHASIS, szAttr);
890 if (bSuperscriptNew && !bSuperscriptOpen) {
891 vAddStartTag(pDiag, TAG_SUPERSCRIPT, NULL);
893 if (bSubscriptNew && !bSubscriptOpen) {
894 vAddStartTag(pDiag, TAG_SUBSCRIPT, NULL);
897 /* The print the string */
898 for (iCount = 0; iCount < (int)tStringLength; iCount++) {
899 vPrintChar(pDiag, szString[iCount]);
901 } /* end of vPrintXML */
904 * vMove2NextLineXML - move to the next line
906 void
907 vMove2NextLineXML(diagram_type *pDiag)
909 fail(pDiag == NULL);
912 if (uiParagraphLevel != 0) {
913 We need something like HTML's <BR> tag
916 } /* end of vMove2NextLineXML */
919 * vSubstringXML - put a sub string into a diagram
921 void
922 vSubstringXML(diagram_type *pDiag,
923 const char *szString, size_t tStringLength, long lStringWidth,
924 USHORT usFontstyle)
926 fail(pDiag == NULL || szString == NULL);
927 fail(pDiag->pOutFile == NULL);
928 fail(pDiag->lXleft < 0);
929 fail(tStringLength != strlen(szString));
931 if (szString[0] == '\0' || tStringLength == 0) {
932 return;
935 vPrintXML(pDiag, szString, tStringLength, usFontstyle);
936 pDiag->lXleft += lStringWidth;
937 } /* end of vSubstringXML */
940 * Create an start of a paragraph
941 * Only works on paragraph level one, because Word doesn't allow paragraphs
942 * in paragraphs. Other paragraph levels result from DocBooks special needs.
944 void
945 vStartOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
947 fail(pDiag == NULL);
949 if (uiParagraphLevel >= uiMaxLevel || bTitleOpen) {
950 /* In Word a title is just a paragraph */
951 return;
953 if (uiListLevel != 0 && bEmptyListLevel) {
954 /* No paragraphs in a list before the first listitem */
955 return;
957 if (usHeaderLevelCurrent == 0) {
958 /* No paragraphs without an open header */
959 vAddStartTag(pDiag, TAG_CHAPTER, NULL);
960 /* Dummy title */
961 vAddCombinedTag(pDiag, TAG_TITLE, NULL);
963 vAddStartTag(pDiag, TAG_PARA, NULL);
964 } /* end of vStartOfParagraphXML */
967 * Create an end of a paragraph
968 * Only for paragraph level one and for titles
970 void
971 vEndOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
973 UCHAR ucTopTag;
975 fail(pDiag == NULL);
977 if (uiParagraphLevel > uiMaxLevel) {
978 DBG_DEC(uiParagraphLevel);
979 return;
982 for(;;) {
983 ucTopTag = ucReadStack();
984 switch (ucTopTag) {
985 case TAG_EMPHASIS:
986 fail(!bEmphasisOpen);
987 vAddEndTag(pDiag, TAG_EMPHASIS);
988 break;
989 case TAG_SUPERSCRIPT:
990 fail(!bSuperscriptOpen);
991 vAddEndTag(pDiag, TAG_SUPERSCRIPT);
992 break;
993 case TAG_SUBSCRIPT:
994 fail(!bSubscriptOpen);
995 vAddEndTag(pDiag, TAG_SUBSCRIPT);
996 break;
997 case TAG_TITLE:
998 fail(!bTitleOpen);
999 vAddEndTag(pDiag, TAG_TITLE);
1000 return;
1001 case TAG_PARA:
1002 fail(uiParagraphLevel == 0);
1003 vAddEndTag(pDiag, TAG_PARA);
1004 return;
1005 case TAG_TBODY:
1006 case TAG_TGROUP:
1007 case TAG_INFORMALTABLE:
1008 fail(!bTableOpen);
1009 vAddEndTag(pDiag, ucTopTag);
1010 break;
1011 case TAG_NOTAG:
1012 DBG_FIXME();
1013 werr(1, "Impossible tag sequence, unable to continue");
1014 break;
1015 default:
1016 DBG_DEC(ucTopTag);
1017 DBG_MSG_C((size_t)ucTopTag < elementsof(atDocBookTags),
1018 atDocBookTags[(UINT)ucTopTag].szTagname);
1019 return;
1022 } /* end of vEndOfParagraphXML */
1025 * Create an end of a page
1027 void
1028 vEndOfPageXML(diagram_type *pDiag)
1030 if (bTableOpen || usHeaderLevelCurrent == 0) {
1031 /* No beginpage in a table or outside a chapter */
1032 return;
1034 if (bTitleOpen) {
1035 /* A beginpage is not allowed when in a title */
1036 /* So start a new paragraph */
1037 vEndOfParagraphXML(pDiag, UINT_MAX);
1038 vStartOfParagraphXML(pDiag, UINT_MAX);
1039 return;
1041 vAddCombinedTag(pDiag, TAG_BEGINPAGE, NULL);
1042 } /* end of vEndOfPageXML */
1045 * vCloseHeaderLevels - close the specified header levels
1047 static void
1048 vCloseHeaderLevels(diagram_type *pDiag, USHORT usIstd)
1050 BOOL bNotReady;
1051 UCHAR ucTopTag;
1053 DBG_MSG("vCloseHeaderLevels");
1054 DBG_DEC(usIstd);
1055 DBG_DEC(usHeaderLevelCurrent);
1057 vStackTrace();
1059 bNotReady = TRUE;
1060 do {
1061 ucTopTag = ucReadStack();
1062 switch (ucTopTag) {
1063 case TAG_TITLE:
1064 case TAG_PARA:
1065 vAddEndTag(pDiag, ucTopTag);
1066 break;
1067 default:
1068 bNotReady = FALSE;
1069 break;
1071 } while (bNotReady);
1073 vStackTrace();
1075 while (usHeaderLevelCurrent >= usIstd) {
1076 if (bEmptyHeaderLevel) {
1077 vAddCombinedTag(pDiag, TAG_PARA, NULL);
1078 bEmptyHeaderLevel = FALSE;
1080 switch (usHeaderLevelCurrent) {
1081 case 1: vAddEndTag(pDiag, TAG_CHAPTER); break;
1082 case 2: vAddEndTag(pDiag, TAG_SECT1); break;
1083 case 3: vAddEndTag(pDiag, TAG_SECT2); break;
1084 case 4: vAddEndTag(pDiag, TAG_SECT3); break;
1085 case 5: vAddEndTag(pDiag, TAG_SECT4); break;
1086 case 6: vAddEndTag(pDiag, TAG_SECT5); break;
1087 default:
1088 DBG_DEC(usHeaderLevelCurrent);
1089 DBG_FIXME();
1090 return;
1094 DBG_DEC(usHeaderLevelCurrent);
1096 vStackTrace();
1097 } /* end of vCloseHeaderLevels */
1100 * vSetHeadersXML - set the headers
1102 void
1103 vSetHeadersXML(diagram_type *pDiag, USHORT usIstd)
1105 fail(pDiag == NULL);
1107 if (usIstd == 0 || usIstd > 6) {
1108 DBG_DEC_C(usIstd != 0 && usIstd <= 9, usIstd);
1109 return;
1111 DBG_DEC(usIstd);
1113 if (bTableOpen || uiListLevel != 0) {
1114 /* No headers when you're in a table or in a list */
1115 return;
1118 /* Close levels */
1119 vCloseHeaderLevels(pDiag, usIstd);
1121 DBG_DEC(usHeaderLevelCurrent);
1123 /* Open levels */
1124 while (usHeaderLevelCurrent < usIstd) {
1125 switch (usHeaderLevelCurrent) {
1126 case 0: vAddStartTag(pDiag, TAG_CHAPTER, NULL); break;
1127 case 1: vAddStartTag(pDiag, TAG_SECT1, NULL); break;
1128 case 2: vAddStartTag(pDiag, TAG_SECT2, NULL); break;
1129 case 3: vAddStartTag(pDiag, TAG_SECT3, NULL); break;
1130 case 4: vAddStartTag(pDiag, TAG_SECT4, NULL); break;
1131 case 5: vAddStartTag(pDiag, TAG_SECT5, NULL); break;
1132 default:
1133 DBG_DEC(usHeaderLevelCurrent);
1134 DBG_FIXME();
1135 return;
1137 fail(usIstd == 0);
1138 /* The next paragraph should be a title */
1139 if (usHeaderLevelCurrent < usIstd) {
1140 /* This chapter level is not in the Word document */
1141 vAddCombinedTag(pDiag, TAG_TITLE, NULL);
1142 } else {
1143 vAddStartTag(pDiag, TAG_TITLE, NULL);
1146 } /* end of vSetHeadersXML */
1149 * Create a start of a list
1151 void
1152 vStartOfListXML(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
1154 const char *szAttr;
1155 UCHAR ucTag;
1157 fail(pDiag == NULL);
1159 if (bIsEndOfTable) {
1160 /* FIXME: until a list in a table is allowed */
1161 vEndOfTableXML(pDiag);
1164 if (bTableOpen) {
1165 /* FIXME: a list in a table should be allowed */
1166 return;
1169 if (usHeaderLevelCurrent == 0) {
1170 /* No list without an open header */
1171 vAddStartTag(pDiag, TAG_CHAPTER, NULL);
1172 /* Dummy title */
1173 vAddCombinedTag(pDiag, TAG_TITLE, NULL);
1176 switch (ucNFC) {
1177 case LIST_ARABIC_NUM:
1178 case LIST_ORDINAL_NUM:
1179 case LIST_NUMBER_TXT:
1180 case LIST_ORDINAL_TXT:
1181 case LIST_OUTLINE_NUM:
1182 ucTag = TAG_ORDEREDLIST;
1183 szAttr = "numeration='arabic'";
1184 break;
1185 case LIST_UPPER_ROMAN:
1186 ucTag = TAG_ORDEREDLIST;
1187 szAttr = "numeration='upperroman'";
1188 break;
1189 case LIST_LOWER_ROMAN:
1190 ucTag = TAG_ORDEREDLIST;
1191 szAttr = "numeration='lowerroman'";
1192 break;
1193 case LIST_UPPER_ALPHA:
1194 ucTag = TAG_ORDEREDLIST;
1195 szAttr = "numeration='upperalpha'";
1196 break;
1197 case LIST_LOWER_ALPHA:
1198 ucTag = TAG_ORDEREDLIST;
1199 szAttr = "numeration='loweralpha'";
1200 break;
1201 case LIST_SPECIAL:
1202 case LIST_SPECIAL2:
1203 case LIST_BULLETS:
1204 ucTag = TAG_ITEMIZEDLIST;
1205 szAttr = "mark='bullet'";
1206 break;
1207 default:
1208 ucTag = TAG_ORDEREDLIST;
1209 szAttr = "numeration='arabic'";
1210 DBG_HEX(ucNFC);
1211 DBG_FIXME();
1212 break;
1214 vAddStartTag(pDiag, ucTag, szAttr);
1215 } /* end of vStartOfListXML */
1218 * Create an end of a list
1220 void
1221 vEndOfListXML(diagram_type *pDiag)
1223 fail(pDiag == NULL);
1225 if (bTableOpen) {
1226 /* FIXME: a list in a table should be allowed */
1227 return;
1230 if (uiListLevel != 0) {
1231 vStackTrace();
1232 vAddEndTagsUntil2(pDiag, TAG_ITEMIZEDLIST, TAG_ORDEREDLIST);
1233 vStackTrace();
1235 } /* end of vEndOfListXML */
1238 * Create a start of a list item
1240 void
1241 vStartOfListItemXML(diagram_type *pDiag, BOOL bNoMarks)
1243 const char *szAttr;
1244 UCHAR ucTopTag;
1246 fail(pDiag == NULL);
1248 if (bTableOpen) {
1249 /* FIXME: a list in a table should be allowed */
1250 return;
1253 ucTopTag = ucReadStack();
1254 if (ucTopTag != TAG_ITEMIZEDLIST && ucTopTag != TAG_ORDEREDLIST) {
1255 /* Must end a previous list item first */
1256 vAddEndTagsUntil1(pDiag, TAG_LISTITEM);
1259 DBG_DEC_C(ucReadStack() != TAG_ITEMIZEDLIST &&
1260 ucReadStack() != TAG_ORDEREDLIST, ucReadStack());
1262 /* Start a new list item */
1263 szAttr = bNoMarks ? "override='none'" : NULL;
1264 vAddStartTag(pDiag, TAG_LISTITEM, szAttr);
1265 /* Start a new paragraph (independant of level) */
1266 vAddStartTag(pDiag, TAG_PARA, NULL);
1267 } /* end of vStartOfListItemXML */
1270 * Create a start of a table
1272 static void
1273 vStartOfTable(diagram_type *pDiag, UCHAR ucBorderInfo)
1275 const char *szFrame;
1276 BOOL bNotReady;
1277 UCHAR ucTopTag;
1278 char cColSep, cRowSep;
1279 char szAttr[40];
1281 fail(pDiag == NULL);
1283 /* Close elements that cannot contain a table */
1284 bNotReady = TRUE;
1285 do {
1286 ucTopTag = ucReadStack();
1287 switch (ucTopTag) {
1288 case TAG_TITLE:
1289 fail(!bTitleOpen);
1290 vAddEndTag(pDiag, TAG_TITLE);
1291 break;
1292 case TAG_EMPHASIS:
1293 fail(!bEmphasisOpen);
1294 vAddEndTag(pDiag, TAG_EMPHASIS);
1295 break;
1296 case TAG_SUPERSCRIPT:
1297 fail(!bSuperscriptOpen);
1298 vAddEndTag(pDiag, TAG_SUPERSCRIPT);
1299 break;
1300 case TAG_SUBSCRIPT:
1301 fail(!bSubscriptOpen);
1302 vAddEndTag(pDiag, TAG_SUBSCRIPT);
1303 break;
1304 default:
1305 bNotReady = FALSE;
1306 break;
1308 } while (bNotReady);
1310 /* Create table attributes */
1311 switch (ucBorderInfo) {
1312 case TABLE_BORDER_TOP:
1313 szFrame = "top";
1314 break;
1315 case TABLE_BORDER_LEFT|TABLE_BORDER_RIGHT:
1316 szFrame = "sides";
1317 break;
1318 case TABLE_BORDER_TOP|TABLE_BORDER_BOTTOM:
1319 szFrame = "topbot";
1320 break;
1321 case TABLE_BORDER_BOTTOM:
1322 szFrame = "bottom";
1323 break;
1324 case TABLE_BORDER_TOP|TABLE_BORDER_LEFT|
1325 TABLE_BORDER_BOTTOM|TABLE_BORDER_RIGHT:
1326 szFrame = "all";
1327 break;
1328 default:
1329 szFrame = "none";
1330 break;
1332 cColSep = bIsTableBorderLeft(ucBorderInfo) ||
1333 bIsTableBorderRight(ucBorderInfo) ? '1' : '0';
1334 cRowSep = bIsTableBorderTop(ucBorderInfo) ||
1335 bIsTableBorderBottom(ucBorderInfo) ? '1' : '0';
1337 sprintf(szAttr, "frame='%.6s' colsep='%c' rowsep='%c'",
1338 szFrame, cColSep, cRowSep);
1340 if (usHeaderLevelCurrent == 0) {
1341 /* No table without an open header */
1342 vAddStartTag(pDiag, TAG_CHAPTER, NULL);
1343 /* Dummy title */
1344 vAddCombinedTag(pDiag, TAG_TITLE, NULL);
1346 vAddStartTag(pDiag, TAG_INFORMALTABLE, szAttr);
1347 } /* end of vStartOfTable */
1350 * Create a start of a table group
1352 static void
1353 vStartOfTableGroup(diagram_type *pDiag,
1354 int iNbrOfColumns, const short *asColumnWidth)
1356 double dWidth;
1357 int iIndex;
1358 char szCols[6 + 3 * sizeof(int) + 1 + 1];
1359 char szColWidth[10 + 3 * sizeof(short) + 3 + 3 + 1];
1361 fail(iNbrOfColumns < 1);
1362 fail(asColumnWidth == NULL);
1364 sprintf(szCols, "cols='%d'", iNbrOfColumns);
1365 vAddStartTag(pDiag, TAG_TGROUP, szCols);
1367 for (iIndex= 0; iIndex < iNbrOfColumns; iIndex++) {
1368 fail(asColumnWidth[iIndex] < 0);
1369 dWidth = dTwips2Points(asColumnWidth[iIndex]);
1370 if (dWidth <= 1.0) {
1371 strcpy(szColWidth, "colwidth='1.00pt'");
1372 } else {
1373 sprintf(szColWidth, "colwidth='%.2fpt'", dWidth);
1375 vAddCombinedTag(pDiag, TAG_COLSPEC, szColWidth);
1377 } /* end of vStartOfTableGroup */
1380 * Create an end of a table
1382 void
1383 vEndOfTableXML(diagram_type *pDiag)
1385 fail(pDiag == NULL);
1387 if (bTableOpen) {
1388 vAddEndTag(pDiag, TAG_TBODY);
1389 vAddEndTag(pDiag, TAG_TGROUP);
1390 vAddEndTag(pDiag, TAG_INFORMALTABLE);
1392 } /* end of vEndOfTableXML */
1395 * Add a table row
1397 void
1398 vAddTableRowXML(diagram_type *pDiag, char **aszColTxt,
1399 int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
1401 size_t tCount, tStringLength;
1402 int iIndex;
1404 fail(pDiag == NULL);
1405 fail(pDiag->pOutFile == NULL);
1406 fail(aszColTxt == NULL);
1407 fail(iNbrOfColumns < 1);
1408 fail(asColumnWidth == NULL);
1410 if (iNbrOfColumns != iTableColumnsCurrent) {
1411 /* A new number of columns */
1412 /* End the old table body and table group (if they exist) */
1413 vAddEndTagOptional(pDiag, TAG_TBODY);
1414 vAddEndTagOptional(pDiag, TAG_TGROUP);
1415 if (!bTableOpen) {
1416 /* No table yet. Start a new table */
1417 vStartOfTable(pDiag, ucBorderInfo);
1419 /* Start a new table group and a new table body */
1420 vStartOfTableGroup(pDiag, iNbrOfColumns, asColumnWidth);
1421 vAddStartTag(pDiag, TAG_TBODY, NULL);
1422 iTableColumnsCurrent = iNbrOfColumns;
1425 /* Add the table row */
1426 vAddStartTag(pDiag, TAG_ROW, NULL);
1427 for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
1428 /* Add a table cell */
1429 fail(aszColTxt[iIndex] == NULL);
1430 vAddStartTag(pDiag, TAG_ENTRY, NULL);
1431 tStringLength = strlen(aszColTxt[iIndex]);
1432 for (tCount = 0; tCount < tStringLength; tCount++) {
1433 vPrintChar(pDiag, aszColTxt[iIndex][tCount]);
1435 vAddEndTag(pDiag, TAG_ENTRY);
1437 vAddEndTag(pDiag, TAG_ROW);
1438 } /* end of vAddTableRowXML */