/* 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;
#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 */
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 (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];
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 */
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);
}
/* 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);
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];
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 */