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
 * out2window.c
3
 * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
4
 *
5
 * Description:
6
 * Output to a text window
7
 */
8
 
9
#include <string.h>
10
#include <stdlib.h>
11
#include <ctype.h>
12
#include "antiword.h"
13
 
14
/* Used for numbering the chapters */
15
static unsigned int	auiHdrCounter[9];
16
 
17
 
18
/*
19
 * vString2Diagram - put a string into a diagram
20
 */
21
static void
22
vString2Diagram(diagram_type *pDiag, output_type *pAnchor)
23
{
24
	output_type	*pOutput;
25
	long		lWidth;
26
	USHORT		usMaxFontSize;
27
 
28
	TRACE_MSG("vString2Diagram");
29
 
30
	fail(pDiag == NULL);
31
	fail(pAnchor == NULL);
32
 
33
	/* Compute the maximum fontsize in this string */
34
	usMaxFontSize = MIN_FONT_SIZE;
35
	for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
36
		if (pOutput->usFontSize > usMaxFontSize) {
37
			usMaxFontSize = pOutput->usFontSize;
38
		}
39
	}
40
 
41
	/* Goto the next line */
42
	vMove2NextLine(pDiag, pAnchor->tFontRef, usMaxFontSize);
43
 
44
	/* Output all substrings */
45
	for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
46
		lWidth = lMilliPoints2DrawUnits(pOutput->lStringWidth);
47
		vSubstring2Diagram(pDiag, pOutput->szStorage,
48
			pOutput->tNextFree, lWidth, pOutput->ucFontColor,
49
			pOutput->usFontStyle, pOutput->tFontRef,
50
			pOutput->usFontSize, usMaxFontSize);
51
	}
52
 
53
	/* Goto the start of the line */
54
	pDiag->lXleft = 0;
55
	TRACE_MSG("leaving vString2Diagram");
56
} /* end of vString2Diagram */
57
 
58
/*
59
 * vSetLeftIndentation - set the left indentation of the specified diagram
60
 */
61
void
62
vSetLeftIndentation(diagram_type *pDiag, long lLeftIndentation)
63
{
64
	long	lX;
65
 
66
	TRACE_MSG("vSetLeftIndentation");
67
 
68
	fail(pDiag == NULL);
69
	fail(lLeftIndentation < 0);
70
 
71
	lX = lMilliPoints2DrawUnits(lLeftIndentation);
72
	if (lX > 0) {
73
		pDiag->lXleft = lX;
74
	} else {
75
		pDiag->lXleft = 0;
76
	}
77
} /* end of vSetLeftIndentation */
78
 
79
/*
80
 * lComputeNetWidth - compute the net string width
81
 */
82
static long
83
lComputeNetWidth(output_type *pAnchor)
84
{
85
	output_type	*pTmp;
86
	long		lNetWidth;
87
 
88
	TRACE_MSG("lComputeNetWidth");
89
 
90
	fail(pAnchor == NULL);
91
 
92
	/* Step 1: Count all but the last sub-string */
93
	lNetWidth = 0;
94
	for (pTmp = pAnchor; pTmp->pNext != NULL; pTmp = pTmp->pNext) {
95
		fail(pTmp->lStringWidth < 0);
96
		lNetWidth += pTmp->lStringWidth;
97
	}
98
	fail(pTmp == NULL);
99
	fail(pTmp->pNext != NULL);
100
 
101
	/* Step 2: remove the white-space from the end of the string */
102
	while (pTmp->tNextFree != 0 &&
103
	       isspace((int)(UCHAR)pTmp->szStorage[pTmp->tNextFree - 1])) {
104
		pTmp->szStorage[pTmp->tNextFree - 1] = '\0';
105
		pTmp->tNextFree--;
106
		NO_DBG_DEC(pTmp->lStringWidth);
107
		pTmp->lStringWidth = lComputeStringWidth(
108
						pTmp->szStorage,
109
						pTmp->tNextFree,
110
						pTmp->tFontRef,
111
						pTmp->usFontSize);
112
		NO_DBG_DEC(pTmp->lStringWidth);
113
	}
114
 
115
	/* Step 3: Count the last sub-string */
116
	lNetWidth += pTmp->lStringWidth;
117
	return lNetWidth;
118
} /* end of lComputeNetWidth */
119
 
120
/*
121
 * iComputeHoles - compute number of holes
122
 * (A hole is a number of whitespace characters followed by a
123
 *  non-whitespace character)
124
 */
125
static int
126
iComputeHoles(output_type *pAnchor)
127
{
128
	output_type	*pTmp;
129
	size_t	tIndex;
130
	int	iCounter;
131
	BOOL	bWasSpace, bIsSpace;
132
 
133
	TRACE_MSG("iComputeHoles");
134
 
135
	fail(pAnchor == NULL);
136
 
137
	iCounter = 0;
138
	bIsSpace = FALSE;
139
	/* Count the holes */
140
	for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
141
		fail(pTmp->tNextFree != strlen(pTmp->szStorage));
142
		for (tIndex = 0; tIndex <= pTmp->tNextFree; tIndex++) {
143
			bWasSpace = bIsSpace;
144
			bIsSpace = isspace((int)(UCHAR)pTmp->szStorage[tIndex]);
145
			if (bWasSpace && !bIsSpace) {
146
				iCounter++;
147
			}
148
		}
149
	}
150
	return iCounter;
151
} /* end of iComputeHoles */
152
 
153
/*
154
 * vAlign2Window - Align a string and insert it into the text
155
 */
156
void
157
vAlign2Window(diagram_type *pDiag, output_type *pAnchor,
158
	long lScreenWidth, UCHAR ucAlignment)
159
{
160
	long	lNetWidth, lLeftIndentation;
161
 
162
	TRACE_MSG("vAlign2Window");
163
 
164
	fail(pDiag == NULL || pAnchor == NULL);
165
	fail(lScreenWidth < lChar2MilliPoints(MIN_SCREEN_WIDTH));
166
 
167
	lNetWidth = lComputeNetWidth(pAnchor);
168
 
169
	if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
170
	    lNetWidth <= 0) {
171
		/*
172
		 * Screenwidth is "infinite", so no alignment is possible
173
		 * Don't bother to align an empty line
174
		 */
175
		vString2Diagram(pDiag, pAnchor);
176
		TRACE_MSG("leaving vAlign2Window #1");
177
		return;
178
	}
179
 
180
	switch (ucAlignment) {
181
	case ALIGNMENT_CENTER:
182
		lLeftIndentation = (lScreenWidth - lNetWidth) / 2;
183
		DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
184
		if (lLeftIndentation > 0) {
185
			vSetLeftIndentation(pDiag, lLeftIndentation);
186
		}
187
		break;
188
	case ALIGNMENT_RIGHT:
189
		lLeftIndentation = lScreenWidth - lNetWidth;
190
		DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
191
		if (lLeftIndentation > 0) {
192
			vSetLeftIndentation(pDiag, lLeftIndentation);
193
		}
194
		break;
195
	case ALIGNMENT_JUSTIFY:
196
	case ALIGNMENT_LEFT:
197
	default:
198
		break;
199
	}
200
	vString2Diagram(pDiag, pAnchor);
201
	TRACE_MSG("leaving vAlign2Window #2");
202
} /* end of vAlign2Window */
203
 
204
/*
205
 * vJustify2Window - Justify a string and insert it into the text
206
 */
207
void
208
vJustify2Window(diagram_type *pDiag, output_type *pAnchor,
209
	long lScreenWidth, long lRightIndentation, UCHAR ucAlignment)
210
{
211
	output_type	*pTmp;
212
	char	*pcNew, *pcOld, *szStorage;
213
	long	lNetWidth, lSpaceWidth, lToAdd;
214
	int	iFillerLen, iHoles;
215
 
216
	TRACE_MSG("vJustify2Window");
217
 
218
	fail(pDiag == NULL || pAnchor == NULL);
219
	fail(lScreenWidth < MIN_SCREEN_WIDTH);
220
	fail(lRightIndentation > 0);
221
 
222
	if (ucAlignment != ALIGNMENT_JUSTIFY) {
223
		vAlign2Window(pDiag, pAnchor, lScreenWidth, ucAlignment);
224
		return;
225
	}
226
 
227
	lNetWidth = lComputeNetWidth(pAnchor);
228
 
229
	if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
230
	    lNetWidth <= 0) {
231
		/*
232
		 * Screenwidth is "infinite", so justify is not possible
233
		 * Don't bother to justify an empty line
234
		 */
235
		vString2Diagram(pDiag, pAnchor);
236
		TRACE_MSG("leaving vJustify2Window #1");
237
		return;
238
	}
239
 
240
	/* Justify */
241
	fail(ucAlignment != ALIGNMENT_JUSTIFY);
242
	lSpaceWidth = lComputeStringWidth(" ", 1,
243
				pAnchor->tFontRef, pAnchor->usFontSize);
244
	lToAdd = lScreenWidth -
245
			lNetWidth -
246
			lDrawUnits2MilliPoints(pDiag->lXleft) +
247
			lRightIndentation;
248
#if defined(DEBUG)
249
	if (lToAdd / lSpaceWidth < -1) {
250
		DBG_DEC(lSpaceWidth);
251
		DBG_DEC(lToAdd);
252
		DBG_DEC(lScreenWidth);
253
		DBG_DEC(lNetWidth);
254
		DBG_DEC(lDrawUnits2MilliPoints(pDiag->lXleft));
255
		DBG_DEC(pDiag->lXleft);
256
		DBG_DEC(lRightIndentation);
257
	}
258
#endif /* DEBUG */
259
	lToAdd /= lSpaceWidth;
260
	DBG_DEC_C(lToAdd < 0, lToAdd);
261
	if (lToAdd <= 0) {
262
		vString2Diagram(pDiag, pAnchor);
263
		TRACE_MSG("leaving vJustify2Window #2");
264
		return;
265
	}
266
 
267
	/* Justify by adding spaces */
268
	iHoles = iComputeHoles(pAnchor);
269
	for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
270
		fail(pTmp->tNextFree != strlen(pTmp->szStorage));
271
		fail(lToAdd < 0);
272
		szStorage = xmalloc(pTmp->tNextFree + (size_t)lToAdd + 1);
273
		pcNew = szStorage;
274
		for (pcOld = pTmp->szStorage; *pcOld != '\0'; pcOld++) {
275
			*pcNew++ = *pcOld;
276
			if (*pcOld == ' ' &&
277
			    *(pcOld + 1) != ' ' &&
278
			    iHoles > 0) {
279
				iFillerLen = (int)(lToAdd / iHoles);
280
				lToAdd -= iFillerLen;
281
				iHoles--;
282
				for (; iFillerLen > 0; iFillerLen--) {
283
					*pcNew++ = ' ';
284
				}
285
			}
286
		}
287
		*pcNew = '\0';
288
		pTmp->szStorage = xfree(pTmp->szStorage);
289
		pTmp->szStorage = szStorage;
290
		pTmp->tStorageSize = pTmp->tNextFree + (size_t)lToAdd + 1;
291
		pTmp->lStringWidth +=
292
			(pcNew - szStorage - (long)pTmp->tNextFree) *
293
			lSpaceWidth;
294
		fail(pcNew < szStorage);
295
		pTmp->tNextFree = (size_t)(pcNew - szStorage);
296
		fail(pTmp->tNextFree != strlen(pTmp->szStorage));
297
	}
298
	DBG_DEC_C(lToAdd != 0, lToAdd);
299
	vString2Diagram(pDiag, pAnchor);
300
	TRACE_MSG("leaving vJustify2Window #3");
301
} /* end of vJustify2Window */
302
 
303
/*
304
 * vResetStyles - reset the style information variables
305
 */
306
void
307
vResetStyles(void)
308
{
309
	TRACE_MSG("vResetStyles");
310
 
311
	(void)memset(auiHdrCounter, 0, sizeof(auiHdrCounter));
312
} /* end of vResetStyles */
313
 
314
/*
315
 * tStyle2Window - Add the style characters to the line
316
 *
317
 * Returns the length of the resulting string
318
 */
319
size_t
320
tStyle2Window(char *szLine, size_t tLineSize, const style_block_type *pStyle,
321
	const section_block_type *pSection)
322
{
323
	char	*pcTxt;
324
	size_t	tIndex, tStyleIndex;
325
	BOOL	bNeedPrevLvl;
326
	level_type_enum	eNumType;
327
	UCHAR	ucNFC;
328
 
329
	TRACE_MSG("tStyle2Window");
330
 
331
	fail(szLine == NULL || pStyle == NULL || pSection == NULL);
332
 
333
	if (pStyle->usIstd == 0 || pStyle->usIstd > 9) {
334
		szLine[0] = '\0';
335
		return 0;
336
	}
337
 
338
	/* Set the numbers */
339
	tStyleIndex = (size_t)pStyle->usIstd - 1;
340
	for (tIndex = 0; tIndex < 9; tIndex++) {
341
		if (tIndex == tStyleIndex) {
342
			auiHdrCounter[tIndex]++;
343
		} else if (tIndex > tStyleIndex) {
344
			auiHdrCounter[tIndex] = 0;
345
		} else if (auiHdrCounter[tIndex] == 0) {
346
			auiHdrCounter[tIndex] = 1;
347
		}
348
	}
349
 
350
	eNumType = eGetNumType(pStyle->ucNumLevel);
351
	if (eNumType != level_type_outline) {
352
		szLine[0] = '\0';
353
		return 0;
354
	}
355
 
356
	/* Print the numbers */
357
	pcTxt = szLine;
358
	bNeedPrevLvl = (pSection->usNeedPrevLvl & BIT(tStyleIndex)) != 0;
359
	for (tIndex = 0; tIndex <= tStyleIndex; tIndex++) {
360
		if (tIndex == tStyleIndex ||
361
		    (bNeedPrevLvl && tIndex < tStyleIndex)) {
362
			if (pcTxt - szLine >= tLineSize - 25) {
363
				/* Prevent a possible buffer overflow */
364
				DBG_DEC(pcTxt - szLine);
365
				DBG_DEC(tLineSize - 25);
366
				DBG_FIXME();
367
				szLine[0] = '\0';
368
				return 0;
369
			}
370
			ucNFC = pSection->aucNFC[tIndex];
371
			switch(ucNFC) {
372
			case LIST_ARABIC_NUM:
373
			case LIST_NUMBER_TXT:
374
			case LIST_ORDINAL_TXT:
375
				pcTxt += sprintf(pcTxt, "%u",
376
					auiHdrCounter[tIndex]);
377
				break;
378
			case LIST_UPPER_ROMAN:
379
			case LIST_LOWER_ROMAN:
380
				pcTxt += tNumber2Roman(
381
					auiHdrCounter[tIndex],
382
					ucNFC == LIST_UPPER_ROMAN,
383
					pcTxt);
384
				break;
385
			case LIST_UPPER_ALPHA:
386
			case LIST_LOWER_ALPHA:
387
				pcTxt += tNumber2Alpha(
388
					auiHdrCounter[tIndex],
389
					ucNFC == LIST_UPPER_ALPHA,
390
					pcTxt);
391
				break;
392
			case LIST_OUTLINE_NUM:
393
				pcTxt += sprintf(pcTxt, "%02u",
394
					auiHdrCounter[tIndex]);
395
				break;
396
			default:
397
				DBG_DEC(ucNFC);
398
				DBG_FIXME();
399
				pcTxt += sprintf(pcTxt, "%u",
400
					auiHdrCounter[tIndex]);
401
				break;
402
			}
403
			if (tIndex < tStyleIndex) {
404
				*pcTxt++ = '.';
405
			} else if (tIndex == tStyleIndex) {
406
				*pcTxt++ = ' ';
407
			}
408
		}
409
	}
410
	*pcTxt = '\0';
411
	NO_DBG_MSG_C((int)pStyle->usIstd >= 1 &&
412
		(int)pStyle->usIstd <= 9 &&
413
		eNumType != level_type_none &&
414
		eNumType != level_type_outline, szLine);
415
	NO_DBG_MSG_C(szLine[0] != '\0', szLine);
416
	fail(pcTxt < szLine);
417
	return (size_t)(pcTxt - szLine);
418
} /* end of tStyle2Window */
419
 
420
/*
421
 * vRemoveRowEnd - remove the end of table row indicator
422
 *
423
 * Remove the double TABLE_SEPARATOR characters from the end of the string.
424
 * Special: remove the TABLE_SEPARATOR, 0x0a sequence
425
 */
426
static void
427
vRemoveRowEnd(char *szRowTxt)
428
{
429
	int	iLastIndex;
430
 
431
	TRACE_MSG("vRemoveRowEnd");
432
 
433
	fail(szRowTxt == NULL || szRowTxt[0] == '\0');
434
 
435
	iLastIndex = (int)strlen(szRowTxt) - 1;
436
 
437
	if (szRowTxt[iLastIndex] == TABLE_SEPARATOR ||
438
	    szRowTxt[iLastIndex] == (char)0x0a) {
439
		szRowTxt[iLastIndex] = '\0';
440
		iLastIndex--;
441
	} else {
442
		DBG_HEX(szRowTxt[iLastIndex]);
443
	}
444
 
445
	if (iLastIndex >= 0 && szRowTxt[iLastIndex] == (char)0x0a) {
446
		szRowTxt[iLastIndex] = '\0';
447
		iLastIndex--;
448
	}
449
 
450
	if (iLastIndex >= 0 && szRowTxt[iLastIndex] == TABLE_SEPARATOR) {
451
		szRowTxt[iLastIndex] = '\0';
452
		return;
453
	}
454
 
455
	DBG_DEC(iLastIndex);
456
	DBG_HEX(szRowTxt[iLastIndex]);
457
	DBG_MSG(szRowTxt);
458
} /* end of vRemoveRowEnd */
459
 
460
/*
461
 * tComputeStringLengthMax - max string length in relation to max column width
462
 *
463
 * Return the maximum string length
464
 */
465
static size_t
466
tComputeStringLengthMax(const char *szString, size_t tColumnWidthMax)
467
{
468
	const char	*pcTmp;
469
	size_t	tLengthMax, tLenPrev, tLen, tWidth;
470
 
471
	TRACE_MSG("tComputeStringLengthMax");
472
 
473
	fail(szString == NULL);
474
	fail(tColumnWidthMax == 0);
475
 
476
	pcTmp = strchr(szString, '\n');
477
	if (pcTmp != NULL) {
478
		tLengthMax = (size_t)(pcTmp - szString + 1);
479
	} else {
480
		tLengthMax = strlen(szString);
481
	}
482
	if (tLengthMax == 0) {
483
		return 0;
484
	}
485
 
486
	tLen = 0;
487
	tWidth = 0;
488
	for (;;) {
489
		tLenPrev = tLen;
490
		tLen += tGetCharacterLength(szString + tLen);
491
		DBG_DEC_C(tLen > tLengthMax, tLen);
492
		DBG_DEC_C(tLen > tLengthMax, tLengthMax);
493
		fail(tLen > tLengthMax);
494
		tWidth = tCountColumns(szString, tLen);
495
		if (tWidth > tColumnWidthMax) {
496
			return tLenPrev;
497
		}
498
		if (tLen >= tLengthMax) {
499
			return tLengthMax;
500
		}
501
	}
502
} /* end of tComputeStringLengthMax */
503
 
504
/*
505
 * tGetBreakingPoint - get the number of bytes that fit the column
506
 *
507
 * Returns the number of bytes that fit the column
508
 */
509
static size_t
510
tGetBreakingPoint(const char *szString,
511
	size_t tLen, size_t tWidth, size_t tColumnWidthMax)
512
{
513
	int	iIndex;
514
 
515
	TRACE_MSG("tGetBreakingPoint");
516
 
517
	fail(szString == NULL);
518
	fail(tLen > strlen(szString));
519
	fail(tWidth > tColumnWidthMax);
520
 
521
	if (tWidth < tColumnWidthMax ||
522
	    (tWidth == tColumnWidthMax &&
523
	     (szString[tLen] == ' ' ||
524
	      szString[tLen] == '\n' ||
525
	      szString[tLen] == '\0'))) {
526
		/* The string already fits, do nothing */
527
		return tLen;
528
	}
529
	/* Search for a breaking point */
530
	for (iIndex = (int)tLen - 1; iIndex >= 0; iIndex--) {
531
		if (szString[iIndex] == ' ') {
532
			return (size_t)iIndex;
533
		}
534
	}
535
	/* No breaking point found, just fill the column */
536
	return tLen;
537
} /* end of tGetBreakingPoint */
538
 
539
/*
540
 * tComputeColumnWidthMax - compute the maximum column width
541
 */
542
static size_t
543
tComputeColumnWidthMax(short sWidth, long lCharWidth, double dFactor)
544
{
545
	size_t	tColumnWidthMax;
546
 
547
	TRACE_MSG("tComputeColumnWidthMax");
548
 
549
	fail(sWidth < 0);
550
	fail(lCharWidth <= 0);
551
	fail(dFactor <= 0.0);
552
 
553
	tColumnWidthMax = (size_t)(
554
		(lTwips2MilliPoints(sWidth) * dFactor + lCharWidth / 2.0) /
555
		 lCharWidth);
556
	if (tColumnWidthMax == 0) {
557
		/* Minimum column width */
558
		return 1;
559
	}
560
	if (tColumnWidthMax > 1) {
561
		/* Make room for the TABLE_SEPARATOR_CHAR */
562
		tColumnWidthMax--;
563
	}
564
	NO_DBG_DEC(tColumnWidthMax);
565
	return tColumnWidthMax;
566
} /* end of tComputeColumnWidthMax */
567
 
568
/*
569
 * vTableRow2Window - put a table row into a diagram
570
 */
571
void
572
vTableRow2Window(diagram_type *pDiag, output_type *pOutput,
573
	const row_block_type *pRowInfo,
574
	conversion_type eConversionType, int iParagraphBreak)
575
{
576
	output_type	tRow;
577
	char	*aszColTxt[TABLE_COLUMN_MAX];
578
	char	*szLine, *pcTxt;
579
	double	dMagnify;
580
	long	lCharWidthLarge, lCharWidthSmall;
581
	size_t	tColumnWidthTotal, atColumnWidthMax[TABLE_COLUMN_MAX];
582
	size_t	tSize, tColumnWidthMax, tWidth, tLen;
583
	int	iIndex, iNbrOfColumns, iTmp;
584
	BOOL	bNotReady;
585
 
586
	TRACE_MSG("vTableRow2Window");
587
 
588
	fail(pDiag == NULL || pOutput == NULL || pRowInfo == NULL);
589
	fail(pOutput->szStorage == NULL);
590
	fail(pOutput->pNext != NULL);
591
	fail(iParagraphBreak < 0);
592
 
593
	/* Character sizes */
594
	lCharWidthLarge = lComputeStringWidth("W", 1,
595
				pOutput->tFontRef, pOutput->usFontSize);
596
	NO_DBG_DEC(lCharWidthLarge);
597
	lCharWidthSmall = lComputeStringWidth("i", 1,
598
				pOutput->tFontRef, pOutput->usFontSize);
599
	NO_DBG_DEC(lCharWidthSmall);
600
	/* For the time being: use a fixed width font */
601
	fail(lCharWidthLarge != lCharWidthSmall);
602
 
603
	vRemoveRowEnd(pOutput->szStorage);
604
 
605
	/* Split the row text into a set of column texts */
606
	aszColTxt[0] = pOutput->szStorage;
607
	for (iNbrOfColumns = 1;
608
	     iNbrOfColumns < TABLE_COLUMN_MAX;
609
	     iNbrOfColumns++) {
610
		aszColTxt[iNbrOfColumns] =
611
				strchr(aszColTxt[iNbrOfColumns - 1],
612
					TABLE_SEPARATOR);
613
		if (aszColTxt[iNbrOfColumns] == NULL) {
614
			break;
615
		}
616
		*aszColTxt[iNbrOfColumns] = '\0';
617
		aszColTxt[iNbrOfColumns]++;
618
		NO_DBG_DEC(iNbrOfColumns);
619
		NO_DBG_MSG(aszColTxt[iNbrOfColumns]);
620
	}
621
 
622
	/* Work around a bug in Word */
623
	while (iNbrOfColumns > (int)pRowInfo->ucNumberOfColumns &&
624
	       pRowInfo->asColumnWidth[iNbrOfColumns] == 0) {
625
		iNbrOfColumns--;
626
	}
627
 
628
	DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
629
		iNbrOfColumns);
630
	DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
631
		pRowInfo->ucNumberOfColumns);
632
	if (iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns) {
633
		werr(0, "Skipping an unmatched table row");
634
		return;
635
	}
636
 
637
#if defined(__FULL_TEXT_SEARCH)
638
	/* No table formatting: use for full-text search (untested) */
639
	for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
640
		fprintf(pDiag->pOutFile, "%s\n" , aszColTxt[iIndex]);
641
	}
642
#else
643
	if (bAddTableRow(pDiag, aszColTxt, iNbrOfColumns,
644
			pRowInfo->asColumnWidth, pRowInfo->ucBorderInfo)) {
645
		/* All work has been done */
646
		return;
647
	}
648
 
649
	/* Fill the table with maximum column widths */
650
	if (eConversionType == conversion_text ||
651
	    eConversionType == conversion_fmt_text) {
652
		if (iParagraphBreak == 0 ||
653
		    iParagraphBreak >= MAX_SCREEN_WIDTH) {
654
			dMagnify = (double)MAX_SCREEN_WIDTH;
655
		} else if (iParagraphBreak <= MIN_SCREEN_WIDTH) {
656
			dMagnify = (double)MIN_SCREEN_WIDTH;
657
		} else {
658
			dMagnify = (double)iParagraphBreak;
659
		}
660
		dMagnify /= (double)DEFAULT_SCREEN_WIDTH;
661
		DBG_FLT_C(dMagnify < 0.99 || dMagnify > 1.01, dMagnify);
662
	} else {
663
		dMagnify = 1.0;
664
	}
665
	tColumnWidthTotal = 0;
666
	for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
667
		atColumnWidthMax[iIndex] = tComputeColumnWidthMax(
668
					pRowInfo->asColumnWidth[iIndex],
669
					lCharWidthLarge,
670
					dMagnify);
671
		tColumnWidthTotal += atColumnWidthMax[iIndex];
672
	}
673
 
674
	/*
675
	 * Get enough space for the row.
676
	 * Worst case: three bytes per UTF-8 character
677
	 */
678
	tSize = 3 * (1 + tColumnWidthTotal + (size_t)iNbrOfColumns + 3);
679
	szLine = xmalloc(tSize);
680
 
681
	do {
682
		/* Print one line of a table row */
683
		bNotReady = FALSE;
684
		pcTxt = szLine;
685
		*pcTxt++ = TABLE_SEPARATOR_CHAR;
686
		for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
687
			tColumnWidthMax = atColumnWidthMax[iIndex];
688
			if (aszColTxt[iIndex] == NULL) {
689
				/* Add an empty column */
690
				for (iTmp = 0;
691
				     iTmp < (int)tColumnWidthMax;
692
				     iTmp++) {
693
					*pcTxt++ = (char)FILLER_CHAR;
694
				}
695
				*pcTxt++ = TABLE_SEPARATOR_CHAR;
696
				*pcTxt = '\0';
697
				continue;
698
			}
699
			/* Compute the length and width of the column text */
700
			tLen = tComputeStringLengthMax(
701
					aszColTxt[iIndex], tColumnWidthMax);
702
			NO_DBG_DEC(tLen);
703
			while (tLen != 0 &&
704
					(aszColTxt[iIndex][tLen - 1] == '\n' ||
705
					 aszColTxt[iIndex][tLen - 1] == ' ')) {
706
				aszColTxt[iIndex][tLen - 1] = ' ';
707
				tLen--;
708
			}
709
			tWidth = tCountColumns(aszColTxt[iIndex], tLen);
710
			fail(tWidth > tColumnWidthMax);
711
			tLen = tGetBreakingPoint(aszColTxt[iIndex],
712
					tLen, tWidth, tColumnWidthMax);
713
			tWidth = tCountColumns(aszColTxt[iIndex], tLen);
714
			if (tLen == 0 && *aszColTxt[iIndex] == '\0') {
715
				/* No text at all */
716
				aszColTxt[iIndex] = NULL;
717
			} else {
718
				/* Add the text */
719
				pcTxt += sprintf(pcTxt,
720
					"%.*s", (int)tLen, aszColTxt[iIndex]);
721
				if (tLen == 0 && *aszColTxt[iIndex] != ' ') {
722
					tLen = tGetCharacterLength(
723
							aszColTxt[iIndex]);
724
					DBG_CHR(*aszColTxt[iIndex]);
725
					DBG_FIXME();
726
					fail(tLen == 0);
727
				}
728
				aszColTxt[iIndex] += tLen;
729
				while (*aszColTxt[iIndex] == ' ') {
730
					aszColTxt[iIndex]++;
731
				}
732
				if (*aszColTxt[iIndex] == '\0') {
733
					/* This row is now complete */
734
					aszColTxt[iIndex] = NULL;
735
				} else {
736
					/* This row needs more lines */
737
					bNotReady = TRUE;
738
				}
739
			}
740
			/* Fill up the rest */
741
			for (iTmp = 0;
742
			     iTmp < (int)tColumnWidthMax - (int)tWidth;
743
			     iTmp++) {
744
				*pcTxt++ = (char)FILLER_CHAR;
745
			}
746
			/* End of column */
747
			*pcTxt++ = TABLE_SEPARATOR_CHAR;
748
			*pcTxt = '\0';
749
		}
750
		/* Output the table row line */
751
		*pcTxt = '\0';
752
		tRow = *pOutput;
753
		tRow.szStorage = szLine;
754
		fail(pcTxt < szLine);
755
		tRow.tNextFree = (size_t)(pcTxt - szLine);
756
		tRow.lStringWidth = lComputeStringWidth(
757
					tRow.szStorage,
758
					tRow.tNextFree,
759
					tRow.tFontRef,
760
					tRow.usFontSize);
761
		vString2Diagram(pDiag, &tRow);
762
		TRACE_MSG("after vString2Diagram in vTableRow2Window");
763
	} while (bNotReady);
764
	/* Clean up before you leave */
765
	szLine = xfree(szLine);
766
	TRACE_MSG("leaving vTableRow2Window");
767
#endif /* __FULL_TEXT_SEARCH */
768
} /* end of vTableRow2Window */