mirror of
https://github.com/simon987/antiword.git
synced 2025-04-10 13:06:41 +00:00
1439 lines
33 KiB
C
1439 lines
33 KiB
C
/*
|
|
* xml.c
|
|
* Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
|
|
*
|
|
* Description:
|
|
* Functions to deal with the XML/DocBook format
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "antiword.h"
|
|
|
|
|
|
#define vAddEndTagsUntil1(p,t) vAddEndTagsUntil2(p,t,TAG_NOTAG)
|
|
|
|
#if defined(DEBUG)
|
|
#define vStackTrace() __vStackTrace(__LINE__)
|
|
#else
|
|
#define vStackTrace() /* EMPTY */
|
|
#endif /* DEBUG */
|
|
|
|
/* The character set */
|
|
static encoding_type eEncoding = encoding_neutral;
|
|
/* Word version */
|
|
static int iWordVersion = -1;
|
|
/* Special treatment for files from Word 4/5/6 on an Apple Macintosh */
|
|
static BOOL bOldMacFile = FALSE;
|
|
/* Text is emphasised */
|
|
static BOOL bEmphasisOpen = FALSE;
|
|
/* Text is superscript */
|
|
static BOOL bSuperscriptOpen = FALSE;
|
|
/* Text is subscript */
|
|
static BOOL bSubscriptOpen = FALSE;
|
|
/* Title is open */
|
|
static BOOL bTitleOpen = FALSE;
|
|
/* Table is open */
|
|
static BOOL bTableOpen = FALSE;
|
|
/* Footnote is open */
|
|
static BOOL bFootnoteOpen = FALSE;
|
|
/* Current paragraph level */
|
|
static UINT uiParagraphLevel = 0;
|
|
/* Current list level */
|
|
static UINT uiListLevel = 0;
|
|
/* Current list level is still empty */
|
|
static BOOL bEmptyListLevel = TRUE;
|
|
/* Current header level */
|
|
static USHORT usHeaderLevelCurrent = 0;
|
|
/* Current header level is still empty */
|
|
static BOOL bEmptyHeaderLevel = TRUE;
|
|
/* Number of columns in the current table */
|
|
static int iTableColumnsCurrent = 0;
|
|
/* Footnote number */
|
|
static UINT uiFootnoteNumber = 0;
|
|
|
|
/* Constants for the stack */
|
|
#define INITIAL_STACK_SIZE 10
|
|
#if defined(DEBUG)
|
|
#define EXTENSION_STACK_SIZE 2
|
|
#else
|
|
#define EXTENSION_STACK_SIZE 10
|
|
#endif /* DEBUG */
|
|
|
|
/* Variables for the stack */
|
|
static UCHAR *aucStack = NULL;
|
|
static size_t tStacksize = 0;
|
|
static size_t tStackNextFree = 0;
|
|
|
|
/* Constants for the tags */
|
|
#define TAG_NOTAG (UCHAR)0
|
|
#define TAG_AUTHOR (UCHAR)1
|
|
#define TAG_BEGINPAGE (UCHAR)2
|
|
#define TAG_BOOK (UCHAR)3
|
|
#define TAG_BOOKINFO (UCHAR)4
|
|
#define TAG_CHAPTER (UCHAR)5
|
|
#define TAG_COLSPEC (UCHAR)6
|
|
#define TAG_CORPNAME (UCHAR)7
|
|
#define TAG_DATE (UCHAR)8
|
|
#define TAG_EMPHASIS (UCHAR)9
|
|
#define TAG_ENTRY (UCHAR)10
|
|
#define TAG_FILENAME (UCHAR)11
|
|
#define TAG_FOOTNOTE (UCHAR)12
|
|
#define TAG_INFORMALTABLE (UCHAR)13
|
|
#define TAG_ITEMIZEDLIST (UCHAR)14
|
|
#define TAG_LISTITEM (UCHAR)15
|
|
#define TAG_ORDEREDLIST (UCHAR)16
|
|
#define TAG_PARA (UCHAR)17
|
|
#define TAG_ROW (UCHAR)18
|
|
#define TAG_SECT1 (UCHAR)19
|
|
#define TAG_SECT2 (UCHAR)20
|
|
#define TAG_SECT3 (UCHAR)21
|
|
#define TAG_SECT4 (UCHAR)22
|
|
#define TAG_SECT5 (UCHAR)23
|
|
#define TAG_SUBSCRIPT (UCHAR)24
|
|
#define TAG_SUBTITLE (UCHAR)25
|
|
#define TAG_SUPERSCRIPT (UCHAR)26
|
|
#define TAG_SURNAME (UCHAR)27
|
|
#define TAG_TBODY (UCHAR)28
|
|
#define TAG_TGROUP (UCHAR)29
|
|
#define TAG_TITLE (UCHAR)30
|
|
|
|
typedef struct docbooktags_tag {
|
|
UCHAR ucTagnumber;
|
|
char szTagname[15];
|
|
BOOL bAddNewlineStart;
|
|
BOOL bAddNewlineEnd;
|
|
} docbooktags_type;
|
|
|
|
static const docbooktags_type atDocBookTags[] = {
|
|
{ TAG_NOTAG, "!ERROR!", TRUE, TRUE },
|
|
{ TAG_AUTHOR, "author", TRUE, TRUE },
|
|
{ TAG_BEGINPAGE, "beginpage", TRUE, TRUE },
|
|
{ TAG_BOOK, "book", TRUE, TRUE },
|
|
{ TAG_BOOKINFO, "bookinfo", TRUE, TRUE },
|
|
{ TAG_CHAPTER, "chapter", TRUE, TRUE },
|
|
{ TAG_COLSPEC, "colspec", TRUE, TRUE },
|
|
{ TAG_CORPNAME, "corpname", FALSE, FALSE },
|
|
{ TAG_DATE, "date", FALSE, FALSE },
|
|
{ TAG_EMPHASIS, "emphasis", FALSE, FALSE },
|
|
{ TAG_ENTRY, "entry", TRUE, TRUE },
|
|
{ TAG_FILENAME, "filename", FALSE, FALSE },
|
|
{ TAG_FOOTNOTE, "footnote", FALSE, FALSE },
|
|
{ TAG_INFORMALTABLE, "informaltable",TRUE, TRUE },
|
|
{ TAG_ITEMIZEDLIST, "itemizedlist", TRUE, TRUE },
|
|
{ TAG_LISTITEM, "listitem", TRUE, TRUE },
|
|
{ TAG_ORDEREDLIST, "orderedlist", TRUE, TRUE },
|
|
{ TAG_PARA, "para", TRUE, TRUE },
|
|
{ TAG_ROW, "row", TRUE, TRUE },
|
|
{ TAG_SECT1, "sect1", TRUE, TRUE },
|
|
{ TAG_SECT2, "sect2", TRUE, TRUE },
|
|
{ TAG_SECT3, "sect3", TRUE, TRUE },
|
|
{ TAG_SECT4, "sect4", TRUE, TRUE },
|
|
{ TAG_SECT5, "sect5", TRUE, TRUE },
|
|
{ TAG_SUBSCRIPT, "subscript", FALSE, FALSE },
|
|
{ TAG_SUBTITLE, "subtitle", FALSE, FALSE },
|
|
{ TAG_SUPERSCRIPT, "superscript", FALSE, FALSE },
|
|
{ TAG_SURNAME, "surname", FALSE, FALSE },
|
|
{ TAG_TBODY, "tbody", TRUE, TRUE },
|
|
{ TAG_TGROUP, "tgroup", TRUE, TRUE },
|
|
{ TAG_TITLE, "title", FALSE, FALSE },
|
|
};
|
|
|
|
static void vAddStartTag(diagram_type *, UCHAR, const char *);
|
|
static void vAddEndTag(diagram_type *, UCHAR);
|
|
static void vAddCombinedTag(diagram_type *, UCHAR, const char *);
|
|
static void vPrintChar(diagram_type *, char);
|
|
|
|
|
|
#if defined(DEBUG)
|
|
/*
|
|
* vCheckTagTable - check the tag table
|
|
*/
|
|
static void
|
|
vCheckTagTable(void)
|
|
{
|
|
size_t tIndex;
|
|
|
|
for (tIndex = 0; tIndex < elementsof(atDocBookTags); tIndex++) {
|
|
if (tIndex != (size_t)atDocBookTags[tIndex].ucTagnumber) {
|
|
DBG_DEC(tIndex);
|
|
werr(1, "Array atDocBookTags is broken");
|
|
}
|
|
}
|
|
} /* end of vCheckTagTable */
|
|
|
|
/*
|
|
* __vStackTrace - show a stack trace
|
|
*/
|
|
static void
|
|
__vStackTrace(int iLine)
|
|
{
|
|
int iIndex;
|
|
|
|
fprintf(stderr, "%s[%3d]:\n", __FILE__, iLine);
|
|
|
|
if (tStackNextFree == 0) {
|
|
fprintf(stderr, "The stack is empty\n");
|
|
return;
|
|
}
|
|
for (iIndex = (int)tStackNextFree - 1; iIndex >= 0; iIndex--) {
|
|
fprintf(stderr, "%2d: %2d: '%s'\n",
|
|
iIndex,
|
|
(int)atDocBookTags[(UINT)aucStack[iIndex]].ucTagnumber,
|
|
atDocBookTags[(UINT)aucStack[iIndex]].szTagname);
|
|
}
|
|
} /* end of __vStackTrace */
|
|
#endif /* DEBUG */
|
|
|
|
/*
|
|
* vPushStack - push a tag onto the stack
|
|
*/
|
|
static void
|
|
vPushStack(UCHAR ucTag)
|
|
{
|
|
fail(tStackNextFree > tStacksize);
|
|
|
|
if (tStackNextFree == tStacksize) {
|
|
/* The stack is full; enlarge the stack */
|
|
tStacksize += EXTENSION_STACK_SIZE;
|
|
aucStack = xrealloc(aucStack, tStacksize * sizeof(UCHAR));
|
|
DBG_DEC(tStacksize);
|
|
}
|
|
|
|
fail(tStackNextFree >= tStacksize);
|
|
|
|
aucStack[tStackNextFree++] = ucTag;
|
|
} /* end of vPushStack */
|
|
|
|
/*
|
|
* vPopStack - pop a tag from the stack
|
|
*/
|
|
static UCHAR
|
|
ucPopStack(void)
|
|
{
|
|
DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
|
|
DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
|
|
fail(tStackNextFree > tStacksize);
|
|
fail(tStackNextFree == 0);
|
|
|
|
if (tStackNextFree == 0) {
|
|
werr(1, "The stack is empty, unable to continue");
|
|
return TAG_NOTAG;
|
|
}
|
|
return aucStack[--tStackNextFree];
|
|
} /* end of ucPopStack */
|
|
|
|
/*
|
|
* vReadStack - read a tag from the top of the stack
|
|
*/
|
|
static UCHAR
|
|
ucReadStack(void)
|
|
{
|
|
DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
|
|
DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
|
|
fail(tStackNextFree > tStacksize);
|
|
|
|
if (tStackNextFree == 0) {
|
|
/* The stack is empty */
|
|
return TAG_NOTAG;
|
|
}
|
|
return aucStack[tStackNextFree - 1];
|
|
} /* end of ucReadStack */
|
|
|
|
/*
|
|
* vPrintLevel - print the tag level
|
|
*/
|
|
static void
|
|
vPrintLevel(FILE *pOutFile)
|
|
{
|
|
size_t tIndex;
|
|
|
|
fail(pOutFile == NULL);
|
|
|
|
for (tIndex = 0; tIndex < tStackNextFree; tIndex++) {
|
|
(void)putc(' ', pOutFile);
|
|
}
|
|
} /* end of vPrintLevel */
|
|
|
|
/*
|
|
* vPrintFootnote - print a footnote
|
|
*/
|
|
static void
|
|
vPrintFootnote(diagram_type *pDiag, UINT uiFootnoteIndex)
|
|
{
|
|
const char *szText, *pcTmp;
|
|
BOOL bSuScript;
|
|
UCHAR ucTopTag;
|
|
|
|
TRACE_MSG("vPrintFootnote");
|
|
|
|
szText = szGetFootnootText(uiFootnoteIndex);
|
|
|
|
if (szText == NULL) {
|
|
szText = "";
|
|
}
|
|
|
|
/* Remove the subscript/superscript (if any) */
|
|
ucTopTag = ucReadStack();
|
|
bSuScript = ucTopTag == TAG_SUBSCRIPT || ucTopTag == TAG_SUPERSCRIPT;
|
|
if (bSuScript) {
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
}
|
|
|
|
/* Start a footnote */
|
|
vAddStartTag(pDiag, TAG_FOOTNOTE, NULL);
|
|
vAddStartTag(pDiag, TAG_PARA, NULL);
|
|
|
|
/* Print a footnote */
|
|
for (pcTmp = szText; *pcTmp != '\0'; pcTmp++) {
|
|
if (*pcTmp == PAR_END) {
|
|
if (*(pcTmp + 1) != PAR_END && *(pcTmp + 1) != '\0') {
|
|
/* PAR_END is not empty and not last */
|
|
vAddEndTag(pDiag, TAG_PARA);
|
|
vAddStartTag(pDiag, TAG_PARA, NULL);
|
|
}
|
|
} else {
|
|
vPrintChar(pDiag, *pcTmp);
|
|
}
|
|
}
|
|
|
|
/* End a footnote */
|
|
vAddEndTag(pDiag, TAG_PARA);
|
|
vAddEndTag(pDiag, TAG_FOOTNOTE);
|
|
|
|
/* Repair the subscript/superscript (if any) */
|
|
if (bSuScript) {
|
|
vAddStartTag(pDiag, ucTopTag, NULL);
|
|
}
|
|
} /* end of vPrintFootnote */
|
|
|
|
/*
|
|
* vPrintChar - print a character with XML encoding
|
|
*/
|
|
static void
|
|
vPrintChar(diagram_type *pDiag, char cChar)
|
|
{
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
|
|
switch (cChar) {
|
|
case FOOTNOTE_OR_ENDNOTE:
|
|
uiFootnoteNumber++;
|
|
vPrintFootnote(pDiag, uiFootnoteNumber - 1);
|
|
break;
|
|
case '<':
|
|
fprintf(pDiag->pOutFile, "%s", "<");
|
|
break;
|
|
case '>':
|
|
fprintf(pDiag->pOutFile, "%s", ">");
|
|
break;
|
|
case '&':
|
|
fprintf(pDiag->pOutFile, "%s", "&");
|
|
break;
|
|
default:
|
|
(void)putc(cChar, pDiag->pOutFile);
|
|
break;
|
|
}
|
|
} /* end of vPrintChar */
|
|
|
|
/*
|
|
* vPrintSpecialChar - convert and print a character
|
|
*/
|
|
static void
|
|
vPrintSpecialChar(diagram_type *pDiag, USHORT usChar)
|
|
{
|
|
ULONG ulChar;
|
|
size_t tLen, tIndex;
|
|
char szResult[4];
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(iWordVersion < 0);
|
|
fail(eEncoding == encoding_neutral);
|
|
|
|
ulChar = ulTranslateCharacters(usChar, 0, iWordVersion,
|
|
conversion_xml, eEncoding, bOldMacFile);
|
|
tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
|
|
if (tLen == 1) {
|
|
vPrintChar(pDiag, szResult[0]);
|
|
} else {
|
|
for (tIndex = 0; tIndex < tLen; tIndex++) {
|
|
(void)putc(szResult[tIndex], pDiag->pOutFile);
|
|
}
|
|
}
|
|
} /* end of vPrintSpecialChar */
|
|
|
|
/*
|
|
* vPrintSpecialString - convert and print a string
|
|
*/
|
|
static void
|
|
vPrintSpecialString(diagram_type *pDiag, const char *szString)
|
|
{
|
|
int iIndex;
|
|
USHORT usChar;
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(szString == NULL);
|
|
|
|
for (iIndex = 0; szString[iIndex] != '\0'; iIndex++) {
|
|
usChar = (USHORT)(UCHAR)szString[iIndex];
|
|
vPrintSpecialChar(pDiag, usChar);
|
|
}
|
|
} /* end of vPrintSpecialString */
|
|
|
|
/*
|
|
* vAddStartTag - add the specified start tag to the file
|
|
*/
|
|
static void
|
|
vAddStartTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
|
|
{
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail((size_t)ucTag >= elementsof(atDocBookTags));
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
vPrintLevel(pDiag->pOutFile);
|
|
}
|
|
|
|
if (szAttribute == NULL || szAttribute[0] == '\0') {
|
|
fprintf(pDiag->pOutFile, "<%s>",
|
|
atDocBookTags[(UINT)ucTag].szTagname);
|
|
} else {
|
|
fprintf(pDiag->pOutFile, "<%s %s>",
|
|
atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
|
|
}
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
pDiag->lXleft = 0;
|
|
}
|
|
|
|
vPushStack(ucTag);
|
|
|
|
/* Set global variables */
|
|
switch (ucTag) {
|
|
case TAG_CHAPTER:
|
|
usHeaderLevelCurrent = 1;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_SECT1:
|
|
usHeaderLevelCurrent = 2;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_SECT2:
|
|
usHeaderLevelCurrent = 3;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_SECT3:
|
|
usHeaderLevelCurrent = 4;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_SECT4:
|
|
usHeaderLevelCurrent = 5;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_SECT5:
|
|
usHeaderLevelCurrent = 6;
|
|
bEmptyHeaderLevel = TRUE;
|
|
break;
|
|
case TAG_TITLE:
|
|
fail(uiParagraphLevel != 0);
|
|
bTitleOpen = TRUE;
|
|
break;
|
|
case TAG_FOOTNOTE:
|
|
bFootnoteOpen = TRUE;
|
|
break;
|
|
case TAG_PARA:
|
|
fail(bTitleOpen && !bFootnoteOpen);
|
|
uiParagraphLevel++;
|
|
bEmptyHeaderLevel = FALSE;
|
|
break;
|
|
case TAG_EMPHASIS:
|
|
bEmphasisOpen = TRUE;
|
|
break;
|
|
case TAG_ITEMIZEDLIST:
|
|
case TAG_ORDEREDLIST:
|
|
uiListLevel++;
|
|
bEmptyListLevel = TRUE;
|
|
bEmptyHeaderLevel = FALSE;
|
|
break;
|
|
case TAG_LISTITEM:
|
|
bEmptyListLevel = FALSE;
|
|
break;
|
|
case TAG_SUPERSCRIPT:
|
|
bSuperscriptOpen = TRUE;
|
|
break;
|
|
case TAG_SUBSCRIPT:
|
|
bSubscriptOpen = TRUE;
|
|
break;
|
|
case TAG_INFORMALTABLE:
|
|
bTableOpen = TRUE;
|
|
bEmptyHeaderLevel = FALSE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} /* end of vAddStartTag */
|
|
|
|
/*
|
|
* vAddEndTag - add the specified end tag to the file
|
|
*/
|
|
static void
|
|
vAddEndTag(diagram_type *pDiag, UCHAR ucTag)
|
|
{
|
|
UCHAR ucTopTag;
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail((size_t)ucTag >= elementsof(atDocBookTags));
|
|
|
|
#if defined(DEBUG)
|
|
ucTopTag = ucReadStack();
|
|
if (ucTag != ucTopTag) {
|
|
DBG_DEC(ucTag);
|
|
DBG_MSG(atDocBookTags[(UINT)ucTag].szTagname);
|
|
vStackTrace();
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
ucTopTag = ucPopStack();
|
|
fail((size_t)ucTopTag >= elementsof(atDocBookTags));
|
|
if (ucTag != ucTopTag) {
|
|
DBG_DEC(ucTag);
|
|
DBG_DEC(ucTopTag);
|
|
DBG_FIXME();
|
|
werr(1, "Impossible tag sequence, unable to continue");
|
|
}
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
vPrintLevel(pDiag->pOutFile);
|
|
}
|
|
|
|
fprintf(pDiag->pOutFile, "</%s>", atDocBookTags[(UINT)ucTag].szTagname);
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
pDiag->lXleft = 0;
|
|
}
|
|
|
|
/* Set global variables */
|
|
switch (ucTag) {
|
|
case TAG_CHAPTER:
|
|
usHeaderLevelCurrent = 0;
|
|
break;
|
|
case TAG_SECT1:
|
|
usHeaderLevelCurrent = 1;
|
|
break;
|
|
case TAG_SECT2:
|
|
usHeaderLevelCurrent = 2;
|
|
break;
|
|
case TAG_SECT3:
|
|
usHeaderLevelCurrent = 3;
|
|
break;
|
|
case TAG_SECT4:
|
|
usHeaderLevelCurrent = 4;
|
|
break;
|
|
case TAG_SECT5:
|
|
usHeaderLevelCurrent = 5;
|
|
break;
|
|
case TAG_TITLE:
|
|
bTitleOpen = FALSE;
|
|
break;
|
|
case TAG_FOOTNOTE:
|
|
bFootnoteOpen = FALSE;
|
|
break;
|
|
case TAG_PARA:
|
|
uiParagraphLevel--;
|
|
break;
|
|
case TAG_EMPHASIS:
|
|
bEmphasisOpen = FALSE;
|
|
break;
|
|
case TAG_SUPERSCRIPT:
|
|
bSuperscriptOpen = FALSE;
|
|
break;
|
|
case TAG_ITEMIZEDLIST:
|
|
case TAG_ORDEREDLIST:
|
|
uiListLevel--;
|
|
break;
|
|
case TAG_SUBSCRIPT:
|
|
bSubscriptOpen = FALSE;
|
|
break;
|
|
case TAG_INFORMALTABLE:
|
|
bTableOpen = FALSE;
|
|
iTableColumnsCurrent = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} /* end of vAddEndTag */
|
|
|
|
/*
|
|
* vAddEndTagOptional - add the specified end tag to the file if needed
|
|
*/
|
|
static void
|
|
vAddEndTagOptional(diagram_type *pDiag, UCHAR ucTag)
|
|
{
|
|
UCHAR ucTopTag;
|
|
|
|
ucTopTag = ucReadStack();
|
|
if (ucTag == ucTopTag) {
|
|
vAddEndTag(pDiag, ucTag);
|
|
}
|
|
} /* end of vAddEndTagOptional */
|
|
|
|
/*
|
|
* vAddCombinedTag - add the specified start and end tag to the file
|
|
*/
|
|
static void
|
|
vAddCombinedTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
|
|
{
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail((size_t)ucTag >= elementsof(atDocBookTags));
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
vPrintLevel(pDiag->pOutFile);
|
|
}
|
|
|
|
if (szAttribute == NULL || szAttribute[0] == '\0') {
|
|
fprintf(pDiag->pOutFile, "<%s/>",
|
|
atDocBookTags[(UINT)ucTag].szTagname);
|
|
} else {
|
|
fprintf(pDiag->pOutFile, "<%s %s/>",
|
|
atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
|
|
}
|
|
|
|
if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
|
|
fprintf(pDiag->pOutFile, "\n");
|
|
pDiag->lXleft = 0;
|
|
}
|
|
} /* end of vAddCombinedTag */
|
|
|
|
/*
|
|
* vAddEndTagsUntil2 - add end tags until one the specified tags is seen
|
|
*/
|
|
static void
|
|
vAddEndTagsUntil2(diagram_type *pDiag, UCHAR ucTag1, UCHAR ucTag2)
|
|
{
|
|
UCHAR ucTopTag;
|
|
|
|
do {
|
|
ucTopTag = ucReadStack();
|
|
switch (ucTopTag) {
|
|
case TAG_CHAPTER:
|
|
case TAG_SECT1:
|
|
case TAG_SECT2:
|
|
case TAG_SECT3:
|
|
case TAG_SECT4:
|
|
case TAG_SECT5:
|
|
if (bEmptyHeaderLevel) {
|
|
/*
|
|
* An empty chapter is legal in Word,
|
|
* but not in DocBook.
|
|
*/
|
|
vAddCombinedTag(pDiag, TAG_PARA, NULL);
|
|
bEmptyHeaderLevel = FALSE;
|
|
}
|
|
break;
|
|
case TAG_ITEMIZEDLIST:
|
|
case TAG_ORDEREDLIST:
|
|
if (bEmptyListLevel) {
|
|
/*
|
|
* A list without items is legal in Word,
|
|
* but not in DocBook. (Nor are empty items)
|
|
*/
|
|
vAddStartTag(pDiag, TAG_LISTITEM, NULL);
|
|
vAddCombinedTag(pDiag, TAG_PARA, NULL);
|
|
vAddEndTag(pDiag, TAG_LISTITEM);
|
|
bEmptyListLevel = FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
} while (ucTopTag != ucTag1 && ucTopTag != ucTag2);
|
|
} /* end of vAddEndTagsUntil2 */
|
|
|
|
/*
|
|
* vCreateBookIntro - create title and bookinfo
|
|
*/
|
|
void
|
|
vCreateBookIntro(diagram_type *pDiag, int iVersion)
|
|
{
|
|
const char *szTitle, *szSubject, *szAuthor;
|
|
const char *szLastSaveDtm, *szCompany;
|
|
const char *szLanguage;
|
|
char szTmp[13];
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(iVersion < 0);
|
|
fail(eEncoding == encoding_neutral);
|
|
|
|
iWordVersion = iVersion;
|
|
bOldMacFile = bIsOldMacFile();
|
|
szTitle = szGetTitle();
|
|
szSubject = szGetSubject();
|
|
szAuthor = szGetAuthor();
|
|
szLastSaveDtm = szGetLastSaveDtm();
|
|
szCompany = szGetCompany();
|
|
|
|
/* Start Book */
|
|
szLanguage = szGetLanguage();
|
|
if (szLanguage != NULL) {
|
|
DBG_MSG(szLanguage);
|
|
sprintf(szTmp, "lang='%.5s'", szLanguage);
|
|
szLanguage = szTmp;
|
|
}
|
|
vAddStartTag(pDiag, TAG_BOOK, szLanguage);
|
|
|
|
/* Book title */
|
|
if (szTitle != NULL && szTitle[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_TITLE, NULL);
|
|
vPrintSpecialString(pDiag, szTitle);
|
|
vAddEndTag(pDiag, TAG_TITLE);
|
|
}
|
|
/* Bookinfo */
|
|
if ((szTitle != NULL && szTitle[0] != '\0') ||
|
|
(szSubject != NULL && szSubject[0] != '\0') ||
|
|
(szAuthor != NULL && szAuthor[0] != '\0') ||
|
|
(szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') ||
|
|
(szCompany != NULL && szCompany[0] != '\0')) {
|
|
vAddStartTag(pDiag, TAG_BOOKINFO, NULL);
|
|
if (szTitle != NULL && szTitle[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_TITLE, NULL);
|
|
vPrintSpecialString(pDiag, szTitle);
|
|
vAddEndTag(pDiag, TAG_TITLE);
|
|
}
|
|
if (szSubject != NULL && szSubject[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_SUBTITLE, NULL);
|
|
vPrintSpecialString(pDiag, szSubject);
|
|
vAddEndTag(pDiag, TAG_SUBTITLE);
|
|
}
|
|
if (szAuthor != NULL && szAuthor[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_AUTHOR, NULL);
|
|
vAddStartTag(pDiag, TAG_SURNAME, NULL);
|
|
vPrintSpecialString(pDiag, szAuthor);
|
|
vAddEndTag(pDiag, TAG_SURNAME);
|
|
vAddEndTag(pDiag, TAG_AUTHOR);
|
|
}
|
|
if (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_DATE, NULL);
|
|
vPrintSpecialString(pDiag, szLastSaveDtm);
|
|
vAddEndTag(pDiag, TAG_DATE);
|
|
}
|
|
if (szCompany != NULL && szCompany[0] != '\0') {
|
|
vAddStartTag(pDiag, TAG_CORPNAME, NULL);
|
|
vPrintSpecialString(pDiag, szCompany);
|
|
vAddEndTag(pDiag, TAG_CORPNAME);
|
|
}
|
|
vAddEndTag(pDiag, TAG_BOOKINFO);
|
|
}
|
|
} /* end of vCreateBookIntro */
|
|
|
|
/*
|
|
* vPrologueXML - perform the XML initialization
|
|
*/
|
|
void
|
|
vPrologueXML(diagram_type *pDiag, const options_type *pOptions)
|
|
{
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(pOptions == NULL);
|
|
|
|
#if defined(DEBUG)
|
|
vCheckTagTable();
|
|
#endif /* DEBUG */
|
|
|
|
/* Set global variables to their start values */
|
|
eEncoding = pOptions->eEncoding;
|
|
bEmphasisOpen = FALSE;
|
|
bSuperscriptOpen = FALSE;
|
|
bSubscriptOpen = FALSE;
|
|
bTitleOpen = FALSE;
|
|
bTableOpen = FALSE;
|
|
bFootnoteOpen = FALSE;
|
|
uiParagraphLevel = 0;
|
|
uiListLevel = 0;
|
|
bEmptyListLevel = TRUE;
|
|
usHeaderLevelCurrent = 0;
|
|
bEmptyHeaderLevel = TRUE;
|
|
iTableColumnsCurrent = 0;
|
|
uiFootnoteNumber = 0;
|
|
|
|
pDiag->lXleft = 0;
|
|
pDiag->lYtop = 0;
|
|
|
|
/* Create an empty stack */
|
|
tStacksize = INITIAL_STACK_SIZE;
|
|
aucStack = xcalloc(tStacksize, sizeof(UCHAR));
|
|
tStackNextFree = 0;
|
|
} /* end of vPrologueXML */
|
|
|
|
/*
|
|
* vEpilogueXML - clean up after everything is done
|
|
*/
|
|
void
|
|
vEpilogueXML(diagram_type *pDiag)
|
|
{
|
|
vStackTrace();
|
|
|
|
vAddEndTagsUntil1(pDiag, TAG_BOOK);
|
|
|
|
vStackTrace();
|
|
|
|
/* Destroy the stack */
|
|
fail(tStackNextFree != 0);
|
|
tStacksize = 0;
|
|
aucStack = xfree(aucStack);
|
|
tStackNextFree = 0;
|
|
} /* end of vEpilogueXML */
|
|
|
|
/*
|
|
* vPrintXML - print a XML string
|
|
*/
|
|
static void
|
|
vPrintXML(diagram_type *pDiag, const char *szString, size_t tStringLength,
|
|
USHORT usFontstyle)
|
|
{
|
|
const char *szAttr;
|
|
int iCount;
|
|
size_t tNextFree;
|
|
BOOL bNotReady, bEmphasisNew, bSuperscriptNew, bSubscriptNew;
|
|
UCHAR ucTopTag, aucStorage[3];
|
|
|
|
fail(szString == NULL);
|
|
|
|
if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
|
|
return;
|
|
}
|
|
|
|
if (tStringLength == 1 && szString[0] == FOOTNOTE_OR_ENDNOTE) {
|
|
/* Don't do anything special for just a single footnote */
|
|
bEmphasisNew = FALSE;
|
|
bSuperscriptNew = FALSE;
|
|
bSubscriptNew = FALSE;
|
|
} else {
|
|
/* Situation normal */
|
|
bEmphasisNew = bIsBold(usFontstyle) ||
|
|
bIsItalic(usFontstyle) ||
|
|
bIsUnderline(usFontstyle) ||
|
|
bIsStrike(usFontstyle);
|
|
bSuperscriptNew = bIsSuperscript(usFontstyle);
|
|
bSubscriptNew = bIsSubscript(usFontstyle);
|
|
}
|
|
|
|
/* End what has to be ended (or more to keep the stack happy) */
|
|
tNextFree = 0;
|
|
bNotReady = TRUE;
|
|
do {
|
|
ucTopTag = ucReadStack();
|
|
switch (ucTopTag) {
|
|
case TAG_EMPHASIS:
|
|
fail(!bEmphasisOpen);
|
|
if (bEmphasisNew) {
|
|
aucStorage[tNextFree++] = ucTopTag;
|
|
}
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
break;
|
|
case TAG_SUPERSCRIPT:
|
|
fail(!bSuperscriptOpen);
|
|
if (bSuperscriptNew) {
|
|
aucStorage[tNextFree++] = ucTopTag;
|
|
}
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
break;
|
|
case TAG_SUBSCRIPT:
|
|
fail(!bSubscriptOpen);
|
|
if (bSubscriptNew) {
|
|
aucStorage[tNextFree++] = ucTopTag;
|
|
}
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
break;
|
|
default:
|
|
bNotReady = FALSE;
|
|
break;
|
|
}
|
|
fail(tNextFree > elementsof(aucStorage));
|
|
fail(bNotReady && tNextFree == elementsof(aucStorage));
|
|
} while (bNotReady);
|
|
|
|
/* Just te make sure */
|
|
vStartOfParagraphXML(pDiag, 1);
|
|
|
|
/* Restart to keep the stack happy */
|
|
for (iCount = (int)tNextFree - 1; iCount > 0; iCount--) {
|
|
vAddStartTag(pDiag, aucStorage[iCount], NULL);
|
|
}
|
|
|
|
/* Start what has to be started */
|
|
if (bEmphasisNew && !bEmphasisOpen) {
|
|
if (bIsBold(usFontstyle)) {
|
|
szAttr = "role='bold'";
|
|
} else if (bIsItalic(usFontstyle)) {
|
|
szAttr = NULL;
|
|
} else if (bIsUnderline(usFontstyle)) {
|
|
szAttr = "role='underline'";
|
|
} else if (bIsStrike(usFontstyle)) {
|
|
szAttr = "role='strikethrough'";
|
|
} else {
|
|
szAttr = NULL;
|
|
}
|
|
vAddStartTag(pDiag, TAG_EMPHASIS, szAttr);
|
|
}
|
|
if (bSuperscriptNew && !bSuperscriptOpen) {
|
|
vAddStartTag(pDiag, TAG_SUPERSCRIPT, NULL);
|
|
}
|
|
if (bSubscriptNew && !bSubscriptOpen) {
|
|
vAddStartTag(pDiag, TAG_SUBSCRIPT, NULL);
|
|
}
|
|
|
|
/* The print the string */
|
|
for (iCount = 0; iCount < (int)tStringLength; iCount++) {
|
|
vPrintChar(pDiag, szString[iCount]);
|
|
}
|
|
} /* end of vPrintXML */
|
|
|
|
/*
|
|
* vMove2NextLineXML - move to the next line
|
|
*/
|
|
void
|
|
vMove2NextLineXML(diagram_type *pDiag)
|
|
{
|
|
fail(pDiag == NULL);
|
|
|
|
/*
|
|
if (uiParagraphLevel != 0) {
|
|
We need something like HTML's <BR> tag
|
|
}
|
|
*/
|
|
} /* end of vMove2NextLineXML */
|
|
|
|
/*
|
|
* vSubstringXML - put a sub string into a diagram
|
|
*/
|
|
void
|
|
vSubstringXML(diagram_type *pDiag,
|
|
const char *szString, size_t tStringLength, long lStringWidth,
|
|
USHORT usFontstyle)
|
|
{
|
|
fail(pDiag == NULL || szString == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(pDiag->lXleft < 0);
|
|
fail(tStringLength != strlen(szString));
|
|
|
|
if (szString[0] == '\0' || tStringLength == 0) {
|
|
return;
|
|
}
|
|
|
|
vPrintXML(pDiag, szString, tStringLength, usFontstyle);
|
|
pDiag->lXleft += lStringWidth;
|
|
} /* end of vSubstringXML */
|
|
|
|
/*
|
|
* Create an start of a paragraph
|
|
* Only works on paragraph level one, because Word doesn't allow paragraphs
|
|
* in paragraphs. Other paragraph levels result from DocBooks special needs.
|
|
*/
|
|
void
|
|
vStartOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
|
|
{
|
|
fail(pDiag == NULL);
|
|
|
|
if (uiParagraphLevel >= uiMaxLevel || bTitleOpen) {
|
|
/* In Word a title is just a paragraph */
|
|
return;
|
|
}
|
|
if (uiListLevel != 0 && bEmptyListLevel) {
|
|
/* No paragraphs in a list before the first listitem */
|
|
return;
|
|
}
|
|
if (usHeaderLevelCurrent == 0) {
|
|
/* No paragraphs without an open header */
|
|
vAddStartTag(pDiag, TAG_CHAPTER, NULL);
|
|
/* Dummy title */
|
|
vAddCombinedTag(pDiag, TAG_TITLE, NULL);
|
|
}
|
|
vAddStartTag(pDiag, TAG_PARA, NULL);
|
|
} /* end of vStartOfParagraphXML */
|
|
|
|
/*
|
|
* Create an end of a paragraph
|
|
* Only for paragraph level one and for titles
|
|
*/
|
|
void
|
|
vEndOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
|
|
{
|
|
UCHAR ucTopTag;
|
|
|
|
fail(pDiag == NULL);
|
|
|
|
if (uiParagraphLevel > uiMaxLevel) {
|
|
DBG_DEC(uiParagraphLevel);
|
|
return;
|
|
}
|
|
|
|
for(;;) {
|
|
ucTopTag = ucReadStack();
|
|
switch (ucTopTag) {
|
|
case TAG_EMPHASIS:
|
|
fail(!bEmphasisOpen);
|
|
vAddEndTag(pDiag, TAG_EMPHASIS);
|
|
break;
|
|
case TAG_SUPERSCRIPT:
|
|
fail(!bSuperscriptOpen);
|
|
vAddEndTag(pDiag, TAG_SUPERSCRIPT);
|
|
break;
|
|
case TAG_SUBSCRIPT:
|
|
fail(!bSubscriptOpen);
|
|
vAddEndTag(pDiag, TAG_SUBSCRIPT);
|
|
break;
|
|
case TAG_TITLE:
|
|
fail(!bTitleOpen);
|
|
vAddEndTag(pDiag, TAG_TITLE);
|
|
return;
|
|
case TAG_PARA:
|
|
fail(uiParagraphLevel == 0);
|
|
vAddEndTag(pDiag, TAG_PARA);
|
|
return;
|
|
case TAG_TBODY:
|
|
case TAG_TGROUP:
|
|
case TAG_INFORMALTABLE:
|
|
fail(!bTableOpen);
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
break;
|
|
case TAG_NOTAG:
|
|
DBG_FIXME();
|
|
werr(1, "Impossible tag sequence, unable to continue");
|
|
break;
|
|
default:
|
|
DBG_DEC(ucTopTag);
|
|
DBG_MSG_C((size_t)ucTopTag < elementsof(atDocBookTags),
|
|
atDocBookTags[(UINT)ucTopTag].szTagname);
|
|
return;
|
|
}
|
|
}
|
|
} /* end of vEndOfParagraphXML */
|
|
|
|
/*
|
|
* Create an end of a page
|
|
*/
|
|
void
|
|
vEndOfPageXML(diagram_type *pDiag)
|
|
{
|
|
if (bTableOpen || usHeaderLevelCurrent == 0) {
|
|
/* No beginpage in a table or outside a chapter */
|
|
return;
|
|
}
|
|
if (bTitleOpen) {
|
|
/* A beginpage is not allowed when in a title */
|
|
/* So start a new paragraph */
|
|
vEndOfParagraphXML(pDiag, UINT_MAX);
|
|
vStartOfParagraphXML(pDiag, UINT_MAX);
|
|
return;
|
|
}
|
|
vAddCombinedTag(pDiag, TAG_BEGINPAGE, NULL);
|
|
} /* end of vEndOfPageXML */
|
|
|
|
/*
|
|
* vCloseHeaderLevels - close the specified header levels
|
|
*/
|
|
static void
|
|
vCloseHeaderLevels(diagram_type *pDiag, USHORT usIstd)
|
|
{
|
|
BOOL bNotReady;
|
|
UCHAR ucTopTag;
|
|
|
|
DBG_MSG("vCloseHeaderLevels");
|
|
DBG_DEC(usIstd);
|
|
DBG_DEC(usHeaderLevelCurrent);
|
|
|
|
vStackTrace();
|
|
|
|
bNotReady = TRUE;
|
|
do {
|
|
ucTopTag = ucReadStack();
|
|
switch (ucTopTag) {
|
|
case TAG_TITLE:
|
|
case TAG_PARA:
|
|
vAddEndTag(pDiag, ucTopTag);
|
|
break;
|
|
default:
|
|
bNotReady = FALSE;
|
|
break;
|
|
}
|
|
} while (bNotReady);
|
|
|
|
vStackTrace();
|
|
|
|
while (usHeaderLevelCurrent >= usIstd) {
|
|
if (bEmptyHeaderLevel) {
|
|
vAddCombinedTag(pDiag, TAG_PARA, NULL);
|
|
bEmptyHeaderLevel = FALSE;
|
|
}
|
|
switch (usHeaderLevelCurrent) {
|
|
case 1: vAddEndTag(pDiag, TAG_CHAPTER); break;
|
|
case 2: vAddEndTag(pDiag, TAG_SECT1); break;
|
|
case 3: vAddEndTag(pDiag, TAG_SECT2); break;
|
|
case 4: vAddEndTag(pDiag, TAG_SECT3); break;
|
|
case 5: vAddEndTag(pDiag, TAG_SECT4); break;
|
|
case 6: vAddEndTag(pDiag, TAG_SECT5); break;
|
|
default:
|
|
DBG_DEC(usHeaderLevelCurrent);
|
|
DBG_FIXME();
|
|
return;
|
|
}
|
|
}
|
|
|
|
DBG_DEC(usHeaderLevelCurrent);
|
|
|
|
vStackTrace();
|
|
} /* end of vCloseHeaderLevels */
|
|
|
|
/*
|
|
* vSetHeadersXML - set the headers
|
|
*/
|
|
void
|
|
vSetHeadersXML(diagram_type *pDiag, USHORT usIstd)
|
|
{
|
|
fail(pDiag == NULL);
|
|
|
|
if (usIstd == 0 || usIstd > 6) {
|
|
DBG_DEC_C(usIstd != 0 && usIstd <= 9, usIstd);
|
|
return;
|
|
}
|
|
DBG_DEC(usIstd);
|
|
|
|
if (bTableOpen || uiListLevel != 0) {
|
|
/* No headers when you're in a table or in a list */
|
|
return;
|
|
}
|
|
|
|
/* Close levels */
|
|
vCloseHeaderLevels(pDiag, usIstd);
|
|
|
|
DBG_DEC(usHeaderLevelCurrent);
|
|
|
|
/* Open levels */
|
|
while (usHeaderLevelCurrent < usIstd) {
|
|
switch (usHeaderLevelCurrent) {
|
|
case 0: vAddStartTag(pDiag, TAG_CHAPTER, NULL); break;
|
|
case 1: vAddStartTag(pDiag, TAG_SECT1, NULL); break;
|
|
case 2: vAddStartTag(pDiag, TAG_SECT2, NULL); break;
|
|
case 3: vAddStartTag(pDiag, TAG_SECT3, NULL); break;
|
|
case 4: vAddStartTag(pDiag, TAG_SECT4, NULL); break;
|
|
case 5: vAddStartTag(pDiag, TAG_SECT5, NULL); break;
|
|
default:
|
|
DBG_DEC(usHeaderLevelCurrent);
|
|
DBG_FIXME();
|
|
return;
|
|
}
|
|
fail(usIstd == 0);
|
|
/* The next paragraph should be a title */
|
|
if (usHeaderLevelCurrent < usIstd) {
|
|
/* This chapter level is not in the Word document */
|
|
vAddCombinedTag(pDiag, TAG_TITLE, NULL);
|
|
} else {
|
|
vAddStartTag(pDiag, TAG_TITLE, NULL);
|
|
}
|
|
}
|
|
} /* end of vSetHeadersXML */
|
|
|
|
/*
|
|
* Create a start of a list
|
|
*/
|
|
void
|
|
vStartOfListXML(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
|
|
{
|
|
const char *szAttr;
|
|
UCHAR ucTag;
|
|
|
|
fail(pDiag == NULL);
|
|
|
|
if (bIsEndOfTable) {
|
|
/* FIXME: until a list in a table is allowed */
|
|
vEndOfTableXML(pDiag);
|
|
}
|
|
|
|
if (bTableOpen) {
|
|
/* FIXME: a list in a table should be allowed */
|
|
return;
|
|
}
|
|
|
|
if (usHeaderLevelCurrent == 0) {
|
|
/* No list without an open header */
|
|
vAddStartTag(pDiag, TAG_CHAPTER, NULL);
|
|
/* Dummy title */
|
|
vAddCombinedTag(pDiag, TAG_TITLE, NULL);
|
|
}
|
|
|
|
switch (ucNFC) {
|
|
case LIST_ARABIC_NUM:
|
|
case LIST_ORDINAL_NUM:
|
|
case LIST_NUMBER_TXT:
|
|
case LIST_ORDINAL_TXT:
|
|
case LIST_OUTLINE_NUM:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='arabic'";
|
|
break;
|
|
case LIST_UPPER_ROMAN:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='upperroman'";
|
|
break;
|
|
case LIST_LOWER_ROMAN:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='lowerroman'";
|
|
break;
|
|
case LIST_UPPER_ALPHA:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='upperalpha'";
|
|
break;
|
|
case LIST_LOWER_ALPHA:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='loweralpha'";
|
|
break;
|
|
case LIST_SPECIAL:
|
|
case LIST_SPECIAL2:
|
|
case LIST_BULLETS:
|
|
ucTag = TAG_ITEMIZEDLIST;
|
|
szAttr = "mark='bullet'";
|
|
break;
|
|
default:
|
|
ucTag = TAG_ORDEREDLIST;
|
|
szAttr = "numeration='arabic'";
|
|
DBG_HEX(ucNFC);
|
|
DBG_FIXME();
|
|
break;
|
|
}
|
|
vAddStartTag(pDiag, ucTag, szAttr);
|
|
} /* end of vStartOfListXML */
|
|
|
|
/*
|
|
* Create an end of a list
|
|
*/
|
|
void
|
|
vEndOfListXML(diagram_type *pDiag)
|
|
{
|
|
fail(pDiag == NULL);
|
|
|
|
if (bTableOpen) {
|
|
/* FIXME: a list in a table should be allowed */
|
|
return;
|
|
}
|
|
|
|
if (uiListLevel != 0) {
|
|
vStackTrace();
|
|
vAddEndTagsUntil2(pDiag, TAG_ITEMIZEDLIST, TAG_ORDEREDLIST);
|
|
vStackTrace();
|
|
}
|
|
} /* end of vEndOfListXML */
|
|
|
|
/*
|
|
* Create a start of a list item
|
|
*/
|
|
void
|
|
vStartOfListItemXML(diagram_type *pDiag, BOOL bNoMarks)
|
|
{
|
|
const char *szAttr;
|
|
UCHAR ucTopTag;
|
|
|
|
fail(pDiag == NULL);
|
|
|
|
if (bTableOpen) {
|
|
/* FIXME: a list in a table should be allowed */
|
|
return;
|
|
}
|
|
|
|
ucTopTag = ucReadStack();
|
|
if (ucTopTag != TAG_ITEMIZEDLIST && ucTopTag != TAG_ORDEREDLIST) {
|
|
/* Must end a previous list item first */
|
|
vAddEndTagsUntil1(pDiag, TAG_LISTITEM);
|
|
}
|
|
|
|
DBG_DEC_C(ucReadStack() != TAG_ITEMIZEDLIST &&
|
|
ucReadStack() != TAG_ORDEREDLIST, ucReadStack());
|
|
|
|
/* Start a new list item */
|
|
szAttr = bNoMarks ? "override='none'" : NULL;
|
|
vAddStartTag(pDiag, TAG_LISTITEM, szAttr);
|
|
/* Start a new paragraph (independant of level) */
|
|
vAddStartTag(pDiag, TAG_PARA, NULL);
|
|
} /* end of vStartOfListItemXML */
|
|
|
|
/*
|
|
* Create a start of a table
|
|
*/
|
|
static void
|
|
vStartOfTable(diagram_type *pDiag, UCHAR ucBorderInfo)
|
|
{
|
|
const char *szFrame;
|
|
BOOL bNotReady;
|
|
UCHAR ucTopTag;
|
|
char cColSep, cRowSep;
|
|
char szAttr[40];
|
|
|
|
fail(pDiag == NULL);
|
|
|
|
/* Close elements that cannot contain a table */
|
|
bNotReady = TRUE;
|
|
do {
|
|
ucTopTag = ucReadStack();
|
|
switch (ucTopTag) {
|
|
case TAG_TITLE:
|
|
fail(!bTitleOpen);
|
|
vAddEndTag(pDiag, TAG_TITLE);
|
|
break;
|
|
case TAG_EMPHASIS:
|
|
fail(!bEmphasisOpen);
|
|
vAddEndTag(pDiag, TAG_EMPHASIS);
|
|
break;
|
|
case TAG_SUPERSCRIPT:
|
|
fail(!bSuperscriptOpen);
|
|
vAddEndTag(pDiag, TAG_SUPERSCRIPT);
|
|
break;
|
|
case TAG_SUBSCRIPT:
|
|
fail(!bSubscriptOpen);
|
|
vAddEndTag(pDiag, TAG_SUBSCRIPT);
|
|
break;
|
|
default:
|
|
bNotReady = FALSE;
|
|
break;
|
|
}
|
|
} while (bNotReady);
|
|
|
|
/* Create table attributes */
|
|
switch (ucBorderInfo) {
|
|
case TABLE_BORDER_TOP:
|
|
szFrame = "top";
|
|
break;
|
|
case TABLE_BORDER_LEFT|TABLE_BORDER_RIGHT:
|
|
szFrame = "sides";
|
|
break;
|
|
case TABLE_BORDER_TOP|TABLE_BORDER_BOTTOM:
|
|
szFrame = "topbot";
|
|
break;
|
|
case TABLE_BORDER_BOTTOM:
|
|
szFrame = "bottom";
|
|
break;
|
|
case TABLE_BORDER_TOP|TABLE_BORDER_LEFT|
|
|
TABLE_BORDER_BOTTOM|TABLE_BORDER_RIGHT:
|
|
szFrame = "all";
|
|
break;
|
|
default:
|
|
szFrame = "none";
|
|
break;
|
|
}
|
|
cColSep = bIsTableBorderLeft(ucBorderInfo) ||
|
|
bIsTableBorderRight(ucBorderInfo) ? '1' : '0';
|
|
cRowSep = bIsTableBorderTop(ucBorderInfo) ||
|
|
bIsTableBorderBottom(ucBorderInfo) ? '1' : '0';
|
|
|
|
sprintf(szAttr, "frame='%.6s' colsep='%c' rowsep='%c'",
|
|
szFrame, cColSep, cRowSep);
|
|
|
|
if (usHeaderLevelCurrent == 0) {
|
|
/* No table without an open header */
|
|
vAddStartTag(pDiag, TAG_CHAPTER, NULL);
|
|
/* Dummy title */
|
|
vAddCombinedTag(pDiag, TAG_TITLE, NULL);
|
|
}
|
|
vAddStartTag(pDiag, TAG_INFORMALTABLE, szAttr);
|
|
} /* end of vStartOfTable */
|
|
|
|
/*
|
|
* Create a start of a table group
|
|
*/
|
|
static void
|
|
vStartOfTableGroup(diagram_type *pDiag,
|
|
int iNbrOfColumns, const short *asColumnWidth)
|
|
{
|
|
double dWidth;
|
|
int iIndex;
|
|
char szCols[6 + 3 * sizeof(int) + 1 + 1];
|
|
char szColWidth[10 + 3 * sizeof(short) + 3 + 3 + 1];
|
|
|
|
fail(iNbrOfColumns < 1);
|
|
fail(asColumnWidth == NULL);
|
|
|
|
sprintf(szCols, "cols='%d'", iNbrOfColumns);
|
|
vAddStartTag(pDiag, TAG_TGROUP, szCols);
|
|
|
|
for (iIndex= 0; iIndex < iNbrOfColumns; iIndex++) {
|
|
fail(asColumnWidth[iIndex] < 0);
|
|
dWidth = dTwips2Points(asColumnWidth[iIndex]);
|
|
if (dWidth <= 1.0) {
|
|
strcpy(szColWidth, "colwidth='1.00pt'");
|
|
} else {
|
|
sprintf(szColWidth, "colwidth='%.2fpt'", dWidth);
|
|
}
|
|
vAddCombinedTag(pDiag, TAG_COLSPEC, szColWidth);
|
|
}
|
|
} /* end of vStartOfTableGroup */
|
|
|
|
/*
|
|
* Create an end of a table
|
|
*/
|
|
void
|
|
vEndOfTableXML(diagram_type *pDiag)
|
|
{
|
|
fail(pDiag == NULL);
|
|
|
|
if (bTableOpen) {
|
|
vAddEndTag(pDiag, TAG_TBODY);
|
|
vAddEndTag(pDiag, TAG_TGROUP);
|
|
vAddEndTag(pDiag, TAG_INFORMALTABLE);
|
|
}
|
|
} /* end of vEndOfTableXML */
|
|
|
|
/*
|
|
* Add a table row
|
|
*/
|
|
void
|
|
vAddTableRowXML(diagram_type *pDiag, char **aszColTxt,
|
|
int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
|
|
{
|
|
size_t tCount, tStringLength;
|
|
int iIndex;
|
|
|
|
fail(pDiag == NULL);
|
|
fail(pDiag->pOutFile == NULL);
|
|
fail(aszColTxt == NULL);
|
|
fail(iNbrOfColumns < 1);
|
|
fail(asColumnWidth == NULL);
|
|
|
|
if (iNbrOfColumns != iTableColumnsCurrent) {
|
|
/* A new number of columns */
|
|
/* End the old table body and table group (if they exist) */
|
|
vAddEndTagOptional(pDiag, TAG_TBODY);
|
|
vAddEndTagOptional(pDiag, TAG_TGROUP);
|
|
if (!bTableOpen) {
|
|
/* No table yet. Start a new table */
|
|
vStartOfTable(pDiag, ucBorderInfo);
|
|
}
|
|
/* Start a new table group and a new table body */
|
|
vStartOfTableGroup(pDiag, iNbrOfColumns, asColumnWidth);
|
|
vAddStartTag(pDiag, TAG_TBODY, NULL);
|
|
iTableColumnsCurrent = iNbrOfColumns;
|
|
}
|
|
|
|
/* Add the table row */
|
|
vAddStartTag(pDiag, TAG_ROW, NULL);
|
|
for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
|
|
/* Add a table cell */
|
|
fail(aszColTxt[iIndex] == NULL);
|
|
vAddStartTag(pDiag, TAG_ENTRY, NULL);
|
|
tStringLength = strlen(aszColTxt[iIndex]);
|
|
for (tCount = 0; tCount < tStringLength; tCount++) {
|
|
vPrintChar(pDiag, aszColTxt[iIndex][tCount]);
|
|
}
|
|
vAddEndTag(pDiag, TAG_ENTRY);
|
|
}
|
|
vAddEndTag(pDiag, TAG_ROW);
|
|
} /* end of vAddTableRowXML */
|