Imported from antiword-0.37.tar.gz.
[antiword.git] / out2window.c
blob9bdacc3149e63ca1ae3bda2b53e46305e997a19b
1 /*
2 * out2window.c
3 * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
5 * Description:
6 * Output to a text window
7 */
9 #include <string.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include "antiword.h"
14 /* Used for numbering the chapters */
15 static unsigned int auiHdrCounter[9];
19 * vString2Diagram - put a string into a diagram
21 static void
22 vString2Diagram(diagram_type *pDiag, output_type *pAnchor)
24 output_type *pOutput;
25 long lWidth;
26 USHORT usMaxFontSize;
28 TRACE_MSG("vString2Diagram");
30 fail(pDiag == NULL);
31 fail(pAnchor == NULL);
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;
41 /* Goto the next line */
42 vMove2NextLine(pDiag, pAnchor->tFontRef, usMaxFontSize);
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);
53 /* Goto the start of the line */
54 pDiag->lXleft = 0;
55 TRACE_MSG("leaving vString2Diagram");
56 } /* end of vString2Diagram */
59 * vSetLeftIndentation - set the left indentation of the specified diagram
61 void
62 vSetLeftIndentation(diagram_type *pDiag, long lLeftIndentation)
64 long lX;
66 TRACE_MSG("vSetLeftIndentation");
68 fail(pDiag == NULL);
69 fail(lLeftIndentation < 0);
71 lX = lMilliPoints2DrawUnits(lLeftIndentation);
72 if (lX > 0) {
73 pDiag->lXleft = lX;
74 } else {
75 pDiag->lXleft = 0;
77 } /* end of vSetLeftIndentation */
80 * lComputeNetWidth - compute the net string width
82 static long
83 lComputeNetWidth(output_type *pAnchor)
85 output_type *pTmp;
86 long lNetWidth;
88 TRACE_MSG("lComputeNetWidth");
90 fail(pAnchor == NULL);
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;
98 fail(pTmp == NULL);
99 fail(pTmp->pNext != NULL);
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);
115 /* Step 3: Count the last sub-string */
116 lNetWidth += pTmp->lStringWidth;
117 return lNetWidth;
118 } /* end of lComputeNetWidth */
121 * iComputeHoles - compute number of holes
122 * (A hole is a number of whitespace characters followed by a
123 * non-whitespace character)
125 static int
126 iComputeHoles(output_type *pAnchor)
128 output_type *pTmp;
129 size_t tIndex;
130 int iCounter;
131 BOOL bWasSpace, bIsSpace;
133 TRACE_MSG("iComputeHoles");
135 fail(pAnchor == NULL);
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++;
150 return iCounter;
151 } /* end of iComputeHoles */
154 * vAlign2Window - Align a string and insert it into the text
156 void
157 vAlign2Window(diagram_type *pDiag, output_type *pAnchor,
158 long lScreenWidth, UCHAR ucAlignment)
160 long lNetWidth, lLeftIndentation;
162 TRACE_MSG("vAlign2Window");
164 fail(pDiag == NULL || pAnchor == NULL);
165 fail(lScreenWidth < lChar2MilliPoints(MIN_SCREEN_WIDTH));
167 lNetWidth = lComputeNetWidth(pAnchor);
169 if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
170 lNetWidth <= 0) {
172 * Screenwidth is "infinite", so no alignment is possible
173 * Don't bother to align an empty line
175 vString2Diagram(pDiag, pAnchor);
176 TRACE_MSG("leaving vAlign2Window #1");
177 return;
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);
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);
194 break;
195 case ALIGNMENT_JUSTIFY:
196 case ALIGNMENT_LEFT:
197 default:
198 break;
200 vString2Diagram(pDiag, pAnchor);
201 TRACE_MSG("leaving vAlign2Window #2");
202 } /* end of vAlign2Window */
205 * vJustify2Window - Justify a string and insert it into the text
207 void
208 vJustify2Window(diagram_type *pDiag, output_type *pAnchor,
209 long lScreenWidth, long lRightIndentation, UCHAR ucAlignment)
211 output_type *pTmp;
212 char *pcNew, *pcOld, *szStorage;
213 long lNetWidth, lSpaceWidth, lToAdd;
214 int iFillerLen, iHoles;
216 TRACE_MSG("vJustify2Window");
218 fail(pDiag == NULL || pAnchor == NULL);
219 fail(lScreenWidth < MIN_SCREEN_WIDTH);
220 fail(lRightIndentation > 0);
222 if (ucAlignment != ALIGNMENT_JUSTIFY) {
223 vAlign2Window(pDiag, pAnchor, lScreenWidth, ucAlignment);
224 return;
227 lNetWidth = lComputeNetWidth(pAnchor);
229 if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
230 lNetWidth <= 0) {
232 * Screenwidth is "infinite", so justify is not possible
233 * Don't bother to justify an empty line
235 vString2Diagram(pDiag, pAnchor);
236 TRACE_MSG("leaving vJustify2Window #1");
237 return;
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);
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;
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++ = ' ';
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));
298 DBG_DEC_C(lToAdd != 0, lToAdd);
299 vString2Diagram(pDiag, pAnchor);
300 TRACE_MSG("leaving vJustify2Window #3");
301 } /* end of vJustify2Window */
304 * vResetStyles - reset the style information variables
306 void
307 vResetStyles(void)
309 TRACE_MSG("vResetStyles");
311 (void)memset(auiHdrCounter, 0, sizeof(auiHdrCounter));
312 } /* end of vResetStyles */
315 * tStyle2Window - Add the style characters to the line
317 * Returns the length of the resulting string
319 size_t
320 tStyle2Window(char *szLine, size_t tLineSize, const style_block_type *pStyle,
321 const section_block_type *pSection)
323 char *pcTxt;
324 size_t tIndex, tStyleIndex;
325 BOOL bNeedPrevLvl;
326 level_type_enum eNumType;
327 UCHAR ucNFC;
329 TRACE_MSG("tStyle2Window");
331 fail(szLine == NULL || pStyle == NULL || pSection == NULL);
333 if (pStyle->usIstd == 0 || pStyle->usIstd > 9) {
334 szLine[0] = '\0';
335 return 0;
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;
350 eNumType = eGetNumType(pStyle->ucNumLevel);
351 if (eNumType != level_type_outline) {
352 szLine[0] = '\0';
353 return 0;
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;
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;
403 if (tIndex < tStyleIndex) {
404 *pcTxt++ = '.';
405 } else if (tIndex == tStyleIndex) {
406 *pcTxt++ = ' ';
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 */
421 * vRemoveRowEnd - remove the end of table row indicator
423 * Remove the double TABLE_SEPARATOR characters from the end of the string.
424 * Special: remove the TABLE_SEPARATOR, 0x0a sequence
426 static void
427 vRemoveRowEnd(char *szRowTxt)
429 int iLastIndex;
431 TRACE_MSG("vRemoveRowEnd");
433 fail(szRowTxt == NULL || szRowTxt[0] == '\0');
435 iLastIndex = (int)strlen(szRowTxt) - 1;
437 if (szRowTxt[iLastIndex] == TABLE_SEPARATOR ||
438 szRowTxt[iLastIndex] == (char)0x0a) {
439 szRowTxt[iLastIndex] = '\0';
440 iLastIndex--;
441 } else {
442 DBG_HEX(szRowTxt[iLastIndex]);
445 if (iLastIndex >= 0 && szRowTxt[iLastIndex] == (char)0x0a) {
446 szRowTxt[iLastIndex] = '\0';
447 iLastIndex--;
450 if (iLastIndex >= 0 && szRowTxt[iLastIndex] == TABLE_SEPARATOR) {
451 szRowTxt[iLastIndex] = '\0';
452 return;
455 DBG_DEC(iLastIndex);
456 DBG_HEX(szRowTxt[iLastIndex]);
457 DBG_MSG(szRowTxt);
458 } /* end of vRemoveRowEnd */
461 * tComputeStringLengthMax - max string length in relation to max column width
463 * Return the maximum string length
465 static size_t
466 tComputeStringLengthMax(const char *szString, size_t tColumnWidthMax)
468 const char *pcTmp;
469 size_t tLengthMax, tLenPrev, tLen, tWidth;
471 TRACE_MSG("tComputeStringLengthMax");
473 fail(szString == NULL);
474 fail(tColumnWidthMax == 0);
476 pcTmp = strchr(szString, '\n');
477 if (pcTmp != NULL) {
478 tLengthMax = (size_t)(pcTmp - szString + 1);
479 } else {
480 tLengthMax = strlen(szString);
482 if (tLengthMax == 0) {
483 return 0;
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;
498 if (tLen >= tLengthMax) {
499 return tLengthMax;
502 } /* end of tComputeStringLengthMax */
505 * tGetBreakingPoint - get the number of bytes that fit the column
507 * Returns the number of bytes that fit the column
509 static size_t
510 tGetBreakingPoint(const char *szString,
511 size_t tLen, size_t tWidth, size_t tColumnWidthMax)
513 int iIndex;
515 TRACE_MSG("tGetBreakingPoint");
517 fail(szString == NULL);
518 fail(tLen > strlen(szString));
519 fail(tWidth > tColumnWidthMax);
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;
529 /* Search for a breaking point */
530 for (iIndex = (int)tLen - 1; iIndex >= 0; iIndex--) {
531 if (szString[iIndex] == ' ') {
532 return (size_t)iIndex;
535 /* No breaking point found, just fill the column */
536 return tLen;
537 } /* end of tGetBreakingPoint */
540 * tComputeColumnWidthMax - compute the maximum column width
542 static size_t
543 tComputeColumnWidthMax(short sWidth, long lCharWidth, double dFactor)
545 size_t tColumnWidthMax;
547 TRACE_MSG("tComputeColumnWidthMax");
549 fail(sWidth < 0);
550 fail(lCharWidth <= 0);
551 fail(dFactor <= 0.0);
553 tColumnWidthMax = (size_t)(
554 (lTwips2MilliPoints(sWidth) * dFactor + lCharWidth / 2.0) /
555 lCharWidth);
556 if (tColumnWidthMax == 0) {
557 /* Minimum column width */
558 return 1;
560 if (tColumnWidthMax > 1) {
561 /* Make room for the TABLE_SEPARATOR_CHAR */
562 tColumnWidthMax--;
564 NO_DBG_DEC(tColumnWidthMax);
565 return tColumnWidthMax;
566 } /* end of tComputeColumnWidthMax */
569 * vTableRow2Window - put a table row into a diagram
571 void
572 vTableRow2Window(diagram_type *pDiag, output_type *pOutput,
573 const row_block_type *pRowInfo,
574 conversion_type eConversionType, int iParagraphBreak)
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;
586 TRACE_MSG("vTableRow2Window");
588 fail(pDiag == NULL || pOutput == NULL || pRowInfo == NULL);
589 fail(pOutput->szStorage == NULL);
590 fail(pOutput->pNext != NULL);
591 fail(iParagraphBreak < 0);
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);
603 vRemoveRowEnd(pOutput->szStorage);
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;
616 *aszColTxt[iNbrOfColumns] = '\0';
617 aszColTxt[iNbrOfColumns]++;
618 NO_DBG_DEC(iNbrOfColumns);
619 NO_DBG_MSG(aszColTxt[iNbrOfColumns]);
622 /* Work around a bug in Word */
623 while (iNbrOfColumns > (int)pRowInfo->ucNumberOfColumns &&
624 pRowInfo->asColumnWidth[iNbrOfColumns] == 0) {
625 iNbrOfColumns--;
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;
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]);
642 #else
643 if (bAddTableRow(pDiag, aszColTxt, iNbrOfColumns,
644 pRowInfo->asColumnWidth, pRowInfo->ucBorderInfo)) {
645 /* All work has been done */
646 return;
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;
660 dMagnify /= (double)DEFAULT_SCREEN_WIDTH;
661 DBG_FLT_C(dMagnify < 0.99 || dMagnify > 1.01, dMagnify);
662 } else {
663 dMagnify = 1.0;
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];
675 * Get enough space for the row.
676 * Worst case: three bytes per UTF-8 character
678 tSize = 3 * (1 + tColumnWidthTotal + (size_t)iNbrOfColumns + 3);
679 szLine = xmalloc(tSize);
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;
695 *pcTxt++ = TABLE_SEPARATOR_CHAR;
696 *pcTxt = '\0';
697 continue;
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--;
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);
728 aszColTxt[iIndex] += tLen;
729 while (*aszColTxt[iIndex] == ' ') {
730 aszColTxt[iIndex]++;
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;
740 /* Fill up the rest */
741 for (iTmp = 0;
742 iTmp < (int)tColumnWidthMax - (int)tWidth;
743 iTmp++) {
744 *pcTxt++ = (char)FILLER_CHAR;
746 /* End of column */
747 *pcTxt++ = TABLE_SEPARATOR_CHAR;
748 *pcTxt = '\0';
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 */