Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * xml.c
3
 * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
4
 *
5
 * Description:
6
 * Functions to deal with the XML/DocBook format
7
 *
8
 */
9
 
10
#include <string.h>
11
#include "antiword.h"
12
 
13
 
14
#define vAddEndTagsUntil1(p,t)	vAddEndTagsUntil2(p,t,TAG_NOTAG)	
15
 
16
#if defined(DEBUG)
17
#define vStackTrace()	__vStackTrace(__LINE__)
18
#else
19
#define vStackTrace()	/* EMPTY */
20
#endif /* DEBUG */
21
 
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;
54
 
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 */
62
 
63
/* Variables for the stack */
64
static UCHAR	*aucStack = NULL;
65
static size_t	tStacksize = 0;
66
static size_t	tStackNextFree = 0;
67
 
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
100
 
101
typedef struct docbooktags_tag {
102
	UCHAR	ucTagnumber;
103
	char	szTagname[15];
104
	BOOL	bAddNewlineStart;
105
	BOOL	bAddNewlineEnd;
106
} docbooktags_type;
107
 
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	},
140
};
141
 
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);
146
 
147
 
148
#if defined(DEBUG)
149
/*
150
 * vCheckTagTable - check the tag table
151
 */
152
static void
153
vCheckTagTable(void)
154
{
155
	size_t	tIndex;
156
 
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");
161
		}
162
	}
163
} /* end of vCheckTagTable */
164
 
165
/*
166
 * __vStackTrace - show a stack trace
167
 */
168
static void
169
__vStackTrace(int iLine)
170
{
171
	int	iIndex;
172
 
173
	fprintf(stderr, "%s[%3d]:\n", __FILE__, iLine);
174
 
175
	if (tStackNextFree == 0) {
176
		fprintf(stderr, "The stack is empty\n");
177
		return;
178
	}
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);
184
	}
185
} /* end of __vStackTrace */
186
#endif /* DEBUG */
187
 
188
/*
189
 * vPushStack - push a tag onto the stack
190
 */
191
static void
192
vPushStack(UCHAR ucTag)
193
{
194
	fail(tStackNextFree > tStacksize);
195
 
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);
201
	}
202
 
203
	fail(tStackNextFree >= tStacksize);
204
 
205
	aucStack[tStackNextFree++] = ucTag;
206
} /* end of vPushStack */
207
 
208
/*
209
 * vPopStack - pop a tag from the stack
210
 */
211
static UCHAR
212
ucPopStack(void)
213
{
214
	DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
215
	DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
216
	fail(tStackNextFree > tStacksize);
217
	fail(tStackNextFree == 0);
218
 
219
	if (tStackNextFree == 0) {
220
		werr(1, "The stack is empty, unable to continue");
221
		return TAG_NOTAG;
222
	}
223
	return aucStack[--tStackNextFree];
224
} /* end of ucPopStack */
225
 
226
/*
227
 * vReadStack - read a tag from the top of the stack
228
 */
229
static UCHAR
230
ucReadStack(void)
231
{
232
	DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
233
	DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
234
	fail(tStackNextFree > tStacksize);
235
 
236
	if (tStackNextFree == 0) {
237
		/* The stack is empty */
238
		return TAG_NOTAG;
239
	}
240
	return aucStack[tStackNextFree - 1];
241
} /* end of ucReadStack */
242
 
243
/*
244
 * vPrintLevel - print the tag level
245
 */
246
static void
247
vPrintLevel(FILE *pOutFile)
248
{
249
	size_t	tIndex;
250
 
251
	fail(pOutFile == NULL);
252
 
253
	for (tIndex = 0; tIndex < tStackNextFree; tIndex++) {
254
		(void)putc(' ', pOutFile);
255
	}
256
} /* end of vPrintLevel */
257
 
258
/*
259
 * vPrintFootnote - print a footnote
260
 */
261
static void
262
vPrintFootnote(diagram_type *pDiag, UINT uiFootnoteIndex)
263
{
264
	const char	*szText, *pcTmp;
265
	BOOL	bSuScript;
266
	UCHAR	ucTopTag;
267
 
268
	TRACE_MSG("vPrintFootnote");
269
 
270
	szText = szGetFootnootText(uiFootnoteIndex);
271
 
272
	if (szText == NULL) {
273
		szText = "";
274
	}
275
 
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);
281
	}
282
 
283
	/* Start a footnote */
284
	vAddStartTag(pDiag, TAG_FOOTNOTE, NULL);
285
	vAddStartTag(pDiag, TAG_PARA, NULL);
286
 
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);
294
			}
295
		} else {
296
			vPrintChar(pDiag, *pcTmp);
297
		}
298
	}
299
 
300
	/* End a footnote */
301
	vAddEndTag(pDiag, TAG_PARA);
302
	vAddEndTag(pDiag, TAG_FOOTNOTE);
303
 
304
	/* Repair the subscript/superscript (if any) */
305
	if (bSuScript) {
306
		vAddStartTag(pDiag, ucTopTag, NULL);
307
	}
308
} /* end of vPrintFootnote */
309
 
310
/*
311
 * vPrintChar - print a character with XML encoding
312
 */
313
static void
314
vPrintChar(diagram_type *pDiag, char cChar)
315
{
316
	fail(pDiag == NULL);
317
	fail(pDiag->pOutFile == NULL);
318
 
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;
336
	}
337
} /* end of vPrintChar */
338
 
339
/*
340
 * vPrintSpecialChar - convert and print a character
341
 */
342
static void
343
vPrintSpecialChar(diagram_type *pDiag, USHORT usChar)
344
{
345
	ULONG   ulChar;
346
	size_t  tLen, tIndex;
347
	char    szResult[4];
348
 
349
	fail(pDiag == NULL);
350
	fail(pDiag->pOutFile == NULL);
351
	fail(iWordVersion < 0);
352
	fail(eEncoding == encoding_neutral);
353
 
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);
362
		}
363
	}
364
} /* end of vPrintSpecialChar */
365
 
366
/*
367
 * vPrintSpecialString - convert and print a string
368
 */
369
static void
370
vPrintSpecialString(diagram_type *pDiag, const char *szString)
371
{
372
	int	iIndex;
373
	USHORT	usChar;
374
 
375
	fail(pDiag == NULL);
376
	fail(pDiag->pOutFile == NULL);
377
	fail(szString == NULL);
378
 
379
	for (iIndex = 0; szString[iIndex] != '\0'; iIndex++) {
380
		usChar = (USHORT)(UCHAR)szString[iIndex];
381
		vPrintSpecialChar(pDiag, usChar);
382
	}
383
} /* end of vPrintSpecialString */
384
 
385
/*
386
 * vAddStartTag - add the specified start tag to the file
387
 */
388
static void
389
vAddStartTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
390
{
391
	fail(pDiag == NULL);
392
	fail(pDiag->pOutFile == NULL);
393
	fail((size_t)ucTag >= elementsof(atDocBookTags));
394
 
395
	if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
396
		fprintf(pDiag->pOutFile, "\n");
397
		vPrintLevel(pDiag->pOutFile);
398
	}
399
 
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);
406
	}
407
 
408
	if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
409
		fprintf(pDiag->pOutFile, "\n");
410
		pDiag->lXleft = 0;
411
	}
412
 
413
	vPushStack(ucTag);
414
 
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;
477
	}
478
} /* end of vAddStartTag */
479
 
480
/*
481
 * vAddEndTag - add the specified end tag to the file
482
 */
483
static void
484
vAddEndTag(diagram_type *pDiag, UCHAR ucTag)
485
{
486
	UCHAR	ucTopTag;
487
 
488
	fail(pDiag == NULL);
489
	fail(pDiag->pOutFile == NULL);
490
	fail((size_t)ucTag >= elementsof(atDocBookTags));
491
 
492
#if defined(DEBUG)
493
	ucTopTag = ucReadStack();
494
	if (ucTag != ucTopTag) {
495
		DBG_DEC(ucTag);
496
		DBG_MSG(atDocBookTags[(UINT)ucTag].szTagname);
497
		vStackTrace();
498
	}
499
#endif /* DEBUG */
500
 
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");
508
	}
509
 
510
	if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
511
		fprintf(pDiag->pOutFile, "\n");
512
		vPrintLevel(pDiag->pOutFile);
513
	}
514
 
515
	fprintf(pDiag->pOutFile, "</%s>", atDocBookTags[(UINT)ucTag].szTagname);
516
 
517
	if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
518
		fprintf(pDiag->pOutFile, "\n");
519
		pDiag->lXleft = 0;
520
	}
521
 
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;
570
	}
571
} /* end of vAddEndTag */
572
 
573
/*
574
 * vAddEndTagOptional - add the specified end tag to the file if needed
575
 */
576
static void
577
vAddEndTagOptional(diagram_type *pDiag, UCHAR ucTag)
578
{
579
	UCHAR	ucTopTag;
580
 
581
	ucTopTag = ucReadStack();
582
	if (ucTag == ucTopTag) {
583
		vAddEndTag(pDiag, ucTag);
584
	}
585
} /* end of vAddEndTagOptional */
586
 
587
/*
588
 * vAddCombinedTag - add the specified start and end tag to the file
589
 */
590
static void
591
vAddCombinedTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
592
{
593
	fail(pDiag == NULL);
594
	fail(pDiag->pOutFile == NULL);
595
	fail((size_t)ucTag >= elementsof(atDocBookTags));
596
 
597
	if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
598
		fprintf(pDiag->pOutFile, "\n");
599
		vPrintLevel(pDiag->pOutFile);
600
	}
601
 
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);
608
	}
609
 
610
	if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
611
		fprintf(pDiag->pOutFile, "\n");
612
		pDiag->lXleft = 0;
613
	}
614
} /* end of vAddCombinedTag */
615
 
616
/*
617
 * vAddEndTagsUntil2 - add end tags until one the specified tags is seen
618
 */
619
static void
620
vAddEndTagsUntil2(diagram_type *pDiag, UCHAR ucTag1, UCHAR ucTag2)
621
{
622
	UCHAR	ucTopTag;
623
 
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) {
634
				/*
635
				 * An empty chapter is legal in Word,
636
				 * but not in DocBook.
637
				 */
638
				vAddCombinedTag(pDiag, TAG_PARA, NULL);
639
				bEmptyHeaderLevel = FALSE;
640
			}
641
			break;
642
		case TAG_ITEMIZEDLIST:
643
		case TAG_ORDEREDLIST:
644
			if (bEmptyListLevel) {
645
				/*
646
				 * A list without items is legal in Word,
647
				 * but not in DocBook. (Nor are empty items)
648
				 */
649
				vAddStartTag(pDiag, TAG_LISTITEM, NULL);
650
				vAddCombinedTag(pDiag, TAG_PARA, NULL);
651
				vAddEndTag(pDiag, TAG_LISTITEM);
652
				bEmptyListLevel = FALSE;
653
			}
654
			break;
655
		default:
656
			break;
657
		}
658
		vAddEndTag(pDiag, ucTopTag);
659
	} while (ucTopTag != ucTag1 && ucTopTag != ucTag2);
660
} /* end of vAddEndTagsUntil2 */
661
 
662
/*
663
 * vCreateBookIntro - create title and bookinfo
664
 */
665
void
666
vCreateBookIntro(diagram_type *pDiag, int iVersion)
667
{
668
	const char	*szTitle, *szSubject, *szAuthor;
669
	const char	*szLastSaveDtm, *szCompany;
670
	const char	*szLanguage;
671
	char		szTmp[13];
672
 
673
	fail(pDiag == NULL);
674
	fail(pDiag->pOutFile == NULL);
675
	fail(iVersion < 0);
676
	fail(eEncoding == encoding_neutral);
677
 
678
	iWordVersion = iVersion;
679
	bOldMacFile = bIsOldMacFile();
680
	szTitle = szGetTitle();
681
	szSubject = szGetSubject();
682
	szAuthor = szGetAuthor();
683
	szLastSaveDtm = szGetLastSaveDtm();
684
	szCompany = szGetCompany();
685
 
686
	/* Start Book */
687
	szLanguage = szGetLanguage();
688
	if (szLanguage != NULL) {
689
		DBG_MSG(szLanguage);
690
		sprintf(szTmp, "lang='%.5s'", szLanguage);
691
		szLanguage = szTmp;
692
	}
693
	vAddStartTag(pDiag, TAG_BOOK, szLanguage);
694
 
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);
700
	}
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);
712
		}
713
		if (szSubject != NULL && szSubject[0] != '\0') {
714
			vAddStartTag(pDiag, TAG_SUBTITLE, NULL);
715
			vPrintSpecialString(pDiag, szSubject);
716
			vAddEndTag(pDiag, TAG_SUBTITLE);
717
		}
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);
724
		}
725
		if (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') {
726
			vAddStartTag(pDiag, TAG_DATE, NULL);
727
			vPrintSpecialString(pDiag, szLastSaveDtm);
728
			vAddEndTag(pDiag, TAG_DATE);
729
		}
730
		if (szCompany != NULL && szCompany[0] != '\0') {
731
			vAddStartTag(pDiag, TAG_CORPNAME, NULL);
732
			vPrintSpecialString(pDiag, szCompany);
733
			vAddEndTag(pDiag, TAG_CORPNAME);
734
		}
735
		vAddEndTag(pDiag, TAG_BOOKINFO);
736
	}
737
} /* end of vCreateBookIntro */
738
 
739
/*
740
 * vPrologueXML - perform the XML initialization
741
 */
742
void
743
vPrologueXML(diagram_type *pDiag, const options_type *pOptions)
744
{
745
 
746
	fail(pDiag == NULL);
747
	fail(pDiag->pOutFile == NULL);
748
	fail(pOptions == NULL);
749
 
750
#if defined(DEBUG)
751
	vCheckTagTable();
752
#endif /* DEBUG */
753
 
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;
769
 
770
	pDiag->lXleft = 0;
771
	pDiag->lYtop = 0;
772
 
773
	/* Create an empty stack */
774
	tStacksize = INITIAL_STACK_SIZE;
775
	aucStack = xcalloc(tStacksize, sizeof(UCHAR));
776
	tStackNextFree = 0;
777
} /* end of vPrologueXML */
778
 
779
/*
780
 * vEpilogueXML - clean up after everything is done
781
 */
782
void
783
vEpilogueXML(diagram_type *pDiag)
784
{
785
	vStackTrace();
786
 
787
	vAddEndTagsUntil1(pDiag, TAG_BOOK);
788
 
789
	vStackTrace();
790
 
791
	/* Destroy the stack */
792
	fail(tStackNextFree != 0);
793
	tStacksize = 0;
794
	aucStack = xfree(aucStack);
795
	tStackNextFree = 0;
796
} /* end of vEpilogueXML */
797
 
798
/*
799
 * vPrintXML - print a XML string
800
 */
801
static void
802
vPrintXML(diagram_type *pDiag, const char *szString, size_t tStringLength,
803
		USHORT usFontstyle)
804
{
805
	const char	*szAttr;
806
	int	iCount;
807
	size_t	tNextFree;
808
	BOOL	bNotReady, bEmphasisNew, bSuperscriptNew, bSubscriptNew;
809
	UCHAR	ucTopTag, aucStorage[3];
810
 
811
	fail(szString == NULL);
812
 
813
	if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
814
		return;
815
	}
816
 
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);
830
	}
831
 
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;
842
			}
843
			vAddEndTag(pDiag, ucTopTag);
844
			break;
845
		case TAG_SUPERSCRIPT:
846
			fail(!bSuperscriptOpen);
847
			if (bSuperscriptNew) {
848
				aucStorage[tNextFree++] = ucTopTag;
849
			}
850
			vAddEndTag(pDiag, ucTopTag);
851
			break;
852
		case TAG_SUBSCRIPT:
853
			fail(!bSubscriptOpen);
854
			if (bSubscriptNew) {
855
				aucStorage[tNextFree++] = ucTopTag;
856
			}
857
			vAddEndTag(pDiag, ucTopTag);
858
			break;
859
		default:
860
			bNotReady = FALSE;
861
			break;
862
		}
863
		fail(tNextFree > elementsof(aucStorage));
864
		fail(bNotReady && tNextFree == elementsof(aucStorage));
865
	} while (bNotReady);
866
 
867
	/* Just te make sure */
868
	vStartOfParagraphXML(pDiag, 1);
869
 
870
	/* Restart to keep the stack happy */
871
	for (iCount = (int)tNextFree - 1; iCount > 0; iCount--) {
872
		vAddStartTag(pDiag, aucStorage[iCount], NULL);
873
	}
874
 
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;
887
		}
888
		vAddStartTag(pDiag, TAG_EMPHASIS, szAttr);
889
	}
890
	if (bSuperscriptNew && !bSuperscriptOpen) {
891
		vAddStartTag(pDiag, TAG_SUPERSCRIPT, NULL);
892
	}
893
	if (bSubscriptNew && !bSubscriptOpen) {
894
		vAddStartTag(pDiag, TAG_SUBSCRIPT, NULL);
895
	}
896
 
897
	/* The print the string */
898
	for (iCount = 0; iCount < (int)tStringLength; iCount++) {
899
		vPrintChar(pDiag, szString[iCount]);
900
	}
901
} /* end of vPrintXML */
902
 
903
/*
904
 * vMove2NextLineXML - move to the next line
905
 */
906
void
907
vMove2NextLineXML(diagram_type *pDiag)
908
{
909
	fail(pDiag == NULL);
910
 
911
	/*
912
	if (uiParagraphLevel != 0) {
913
		We need something like HTML's <BR> tag
914
	}
915
	*/
916
} /* end of vMove2NextLineXML */
917
 
918
/*
919
 * vSubstringXML - put a sub string into a diagram
920
 */
921
void
922
vSubstringXML(diagram_type *pDiag,
923
	const char *szString, size_t tStringLength, long lStringWidth,
924
	USHORT usFontstyle)
925
{
926
	fail(pDiag == NULL || szString == NULL);
927
	fail(pDiag->pOutFile == NULL);
928
	fail(pDiag->lXleft < 0);
929
	fail(tStringLength != strlen(szString));
930
 
931
	if (szString[0] == '\0' || tStringLength == 0) {
932
		return;
933
	}
934
 
935
	vPrintXML(pDiag, szString, tStringLength, usFontstyle);
936
	pDiag->lXleft += lStringWidth;
937
} /* end of vSubstringXML */
938
 
939
/*
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.
943
 */
944
void
945
vStartOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
946
{
947
	fail(pDiag == NULL);
948
 
949
	if (uiParagraphLevel >= uiMaxLevel || bTitleOpen) {
950
		/* In Word a title is just a paragraph */
951
		return;
952
	}
953
	if (uiListLevel != 0 && bEmptyListLevel) {
954
		/* No paragraphs in a list before the first listitem */
955
		return;
956
	}
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);
962
	}
963
	vAddStartTag(pDiag, TAG_PARA, NULL);
964
} /* end of vStartOfParagraphXML */
965
 
966
/*
967
 * Create an end of a paragraph
968
 * Only for paragraph level one and for titles
969
 */
970
void
971
vEndOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
972
{
973
	UCHAR	ucTopTag;
974
 
975
	fail(pDiag == NULL);
976
 
977
	if (uiParagraphLevel > uiMaxLevel) {
978
		DBG_DEC(uiParagraphLevel);
979
		return;
980
	}
981
 
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;
1020
		}
1021
	}
1022
} /* end of vEndOfParagraphXML */
1023
 
1024
/*
1025
 * Create an end of a page
1026
 */
1027
void
1028
vEndOfPageXML(diagram_type *pDiag)
1029
{
1030
	if (bTableOpen || usHeaderLevelCurrent == 0) {
1031
		/* No beginpage in a table or outside a chapter */
1032
		return;
1033
	}
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;
1040
	}
1041
	vAddCombinedTag(pDiag, TAG_BEGINPAGE, NULL);
1042
} /* end of vEndOfPageXML */
1043
 
1044
/*
1045
 * vCloseHeaderLevels - close the specified header levels
1046
 */
1047
static void
1048
vCloseHeaderLevels(diagram_type *pDiag, USHORT usIstd)
1049
{
1050
	BOOL	bNotReady;
1051
	UCHAR	ucTopTag;
1052
 
1053
	DBG_MSG("vCloseHeaderLevels");
1054
	DBG_DEC(usIstd);
1055
	DBG_DEC(usHeaderLevelCurrent);
1056
 
1057
	vStackTrace();
1058
 
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;
1070
		}
1071
	} while (bNotReady);
1072
 
1073
	vStackTrace();
1074
 
1075
	while (usHeaderLevelCurrent >= usIstd) {
1076
		if (bEmptyHeaderLevel) {
1077
			vAddCombinedTag(pDiag, TAG_PARA, NULL);
1078
			bEmptyHeaderLevel = FALSE;
1079
		}
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;
1091
		}
1092
	}
1093
 
1094
	DBG_DEC(usHeaderLevelCurrent);
1095
 
1096
	vStackTrace();
1097
} /* end of vCloseHeaderLevels */
1098
 
1099
/*
1100
 * vSetHeadersXML - set the headers
1101
 */
1102
void
1103
vSetHeadersXML(diagram_type *pDiag, USHORT usIstd)
1104
{
1105
	fail(pDiag == NULL);
1106
 
1107
	if (usIstd == 0 || usIstd > 6) {
1108
		DBG_DEC_C(usIstd != 0 && usIstd <= 9, usIstd);
1109
		return;
1110
	}
1111
	DBG_DEC(usIstd);
1112
 
1113
	if (bTableOpen || uiListLevel != 0) {
1114
		/* No headers when you're in a table or in a list */
1115
		return;
1116
	}
1117
 
1118
	/* Close levels */
1119
	vCloseHeaderLevels(pDiag, usIstd);
1120
 
1121
	DBG_DEC(usHeaderLevelCurrent);
1122
 
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;
1136
		}
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);
1144
		}
1145
	}
1146
} /* end of vSetHeadersXML */
1147
 
1148
/*
1149
 * Create a start of a list
1150
 */
1151
void
1152
vStartOfListXML(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
1153
{
1154
	const char	*szAttr;
1155
	UCHAR		ucTag;
1156
 
1157
	fail(pDiag == NULL);
1158
 
1159
	if (bIsEndOfTable) {
1160
		/* FIXME: until a list in a table is allowed */
1161
		vEndOfTableXML(pDiag);
1162
	}
1163
 
1164
	if (bTableOpen) {
1165
		/* FIXME: a list in a table should be allowed */
1166
		return;
1167
	}
1168
 
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);
1174
	}
1175
 
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;
1213
	}
1214
	vAddStartTag(pDiag, ucTag, szAttr);
1215
} /* end of vStartOfListXML */
1216
 
1217
/*
1218
 * Create an end of a list
1219
 */
1220
void
1221
vEndOfListXML(diagram_type *pDiag)
1222
{
1223
	fail(pDiag == NULL);
1224
 
1225
	if (bTableOpen) {
1226
		/* FIXME: a list in a table should be allowed */
1227
		return;
1228
	}
1229
 
1230
	if (uiListLevel != 0) {
1231
		vStackTrace();
1232
		vAddEndTagsUntil2(pDiag, TAG_ITEMIZEDLIST, TAG_ORDEREDLIST);
1233
		vStackTrace();
1234
	}
1235
} /* end of vEndOfListXML */
1236
 
1237
/*
1238
 * Create a start of a list item
1239
 */
1240
void
1241
vStartOfListItemXML(diagram_type *pDiag, BOOL bNoMarks)
1242
{
1243
	const char	*szAttr;
1244
	UCHAR	ucTopTag;
1245
 
1246
	fail(pDiag == NULL);
1247
 
1248
	if (bTableOpen) {
1249
		/* FIXME: a list in a table should be allowed */
1250
		return;
1251
	}
1252
 
1253
	ucTopTag = ucReadStack();
1254
	if (ucTopTag != TAG_ITEMIZEDLIST && ucTopTag != TAG_ORDEREDLIST) {
1255
		/* Must end a previous list item first */
1256
		vAddEndTagsUntil1(pDiag, TAG_LISTITEM);
1257
	}
1258
 
1259
	DBG_DEC_C(ucReadStack() != TAG_ITEMIZEDLIST &&
1260
		ucReadStack() != TAG_ORDEREDLIST, ucReadStack());
1261
 
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 */
1268
 
1269
/*
1270
 * Create a start of a table
1271
 */
1272
static void
1273
vStartOfTable(diagram_type *pDiag, UCHAR ucBorderInfo)
1274
{
1275
	const char	*szFrame;
1276
	BOOL	bNotReady;
1277
	UCHAR	ucTopTag;
1278
	char	cColSep, cRowSep;
1279
	char	szAttr[40];
1280
 
1281
	fail(pDiag == NULL);
1282
 
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;
1307
		}
1308
	} while (bNotReady);
1309
 
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;
1331
	}
1332
	cColSep = bIsTableBorderLeft(ucBorderInfo) ||
1333
		  bIsTableBorderRight(ucBorderInfo) ? '1' : '0';
1334
	cRowSep = bIsTableBorderTop(ucBorderInfo) ||
1335
		  bIsTableBorderBottom(ucBorderInfo) ? '1' : '0';
1336
 
1337
	sprintf(szAttr, "frame='%.6s' colsep='%c' rowsep='%c'",
1338
			szFrame, cColSep, cRowSep);
1339
 
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);
1345
	}
1346
	vAddStartTag(pDiag, TAG_INFORMALTABLE, szAttr);
1347
} /* end of vStartOfTable */
1348
 
1349
/*
1350
 * Create a start of a table group
1351
 */
1352
static void
1353
vStartOfTableGroup(diagram_type *pDiag,
1354
	int iNbrOfColumns, const short *asColumnWidth)
1355
{
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];
1360
 
1361
	fail(iNbrOfColumns < 1);
1362
	fail(asColumnWidth == NULL);
1363
 
1364
	sprintf(szCols, "cols='%d'", iNbrOfColumns);
1365
	vAddStartTag(pDiag, TAG_TGROUP, szCols);
1366
 
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);
1374
		}
1375
		vAddCombinedTag(pDiag, TAG_COLSPEC, szColWidth);
1376
	}
1377
} /* end of vStartOfTableGroup */
1378
 
1379
/*
1380
 * Create an end of a table
1381
 */
1382
void
1383
vEndOfTableXML(diagram_type *pDiag)
1384
{
1385
	fail(pDiag == NULL);
1386
 
1387
	if (bTableOpen) {
1388
		vAddEndTag(pDiag, TAG_TBODY);
1389
		vAddEndTag(pDiag, TAG_TGROUP);
1390
		vAddEndTag(pDiag, TAG_INFORMALTABLE);
1391
	}
1392
} /* end of vEndOfTableXML */
1393
 
1394
/*
1395
 * Add a table row
1396
 */
1397
void
1398
vAddTableRowXML(diagram_type *pDiag, char **aszColTxt,
1399
	int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
1400
{
1401
	size_t	tCount, tStringLength;
1402
	int	iIndex;
1403
 
1404
	fail(pDiag == NULL);
1405
	fail(pDiag->pOutFile == NULL);
1406
	fail(aszColTxt == NULL);
1407
	fail(iNbrOfColumns < 1);
1408
	fail(asColumnWidth == NULL);
1409
 
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);
1418
		}
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;
1423
	}
1424
 
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]);
1434
		}
1435
		vAddEndTag(pDiag, TAG_ENTRY);
1436
	}
1437
	vAddEndTag(pDiag, TAG_ROW);
1438
} /* end of vAddTableRowXML */