Imported from antiword-0.36.1.tar.gz.
[antiword.git] / out2window.c
blob72c8904ad7b776399095880f73e17b3bcb5d4655
1 /*
2 * out2window.c
3 * Copyright (C) 1998-2004 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"
15 /* Used for numbering the chapters */
16 static unsigned int auiHdrCounter[9];
20 * vString2Diagram - put a string into a diagram
22 static void
23 vString2Diagram(diagram_type *pDiag, output_type *pAnchor)
25 output_type *pOutput;
26 long lWidth;
27 USHORT usMaxFontSize;
29 fail(pDiag == NULL);
30 fail(pAnchor == NULL);
32 /* Compute the maximum fontsize in this string */
33 usMaxFontSize = MIN_FONT_SIZE;
34 for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
35 if (pOutput->usFontSize > usMaxFontSize) {
36 usMaxFontSize = pOutput->usFontSize;
40 /* Goto the next line */
41 vMove2NextLine(pDiag, pAnchor->tFontRef, usMaxFontSize);
43 /* Output all substrings */
44 for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
45 lWidth = lMilliPoints2DrawUnits(pOutput->lStringWidth);
46 vSubstring2Diagram(pDiag, pOutput->szStorage,
47 pOutput->tNextFree, lWidth, pOutput->ucFontColor,
48 pOutput->usFontStyle, pOutput->tFontRef,
49 pOutput->usFontSize, usMaxFontSize);
52 /* Goto the start of the line */
53 pDiag->lXleft = 0;
54 } /* end of vString2Diagram */
57 * vSetLeftIndentation - set the left indentation of the specified diagram
59 void
60 vSetLeftIndentation(diagram_type *pDiag, long lLeftIndentation)
62 long lX;
64 fail(pDiag == NULL);
65 fail(lLeftIndentation < 0);
67 lX = lMilliPoints2DrawUnits(lLeftIndentation);
68 if (lX > 0) {
69 pDiag->lXleft = lX;
70 } else {
71 pDiag->lXleft = 0;
73 } /* end of vSetLeftIndentation */
76 * lComputeNetWidth - compute the net string width
78 static long
79 lComputeNetWidth(output_type *pAnchor)
81 output_type *pTmp;
82 long lNetWidth;
84 fail(pAnchor == NULL);
86 /* Step 1: Count all but the last sub-string */
87 lNetWidth = 0;
88 for (pTmp = pAnchor; pTmp->pNext != NULL; pTmp = pTmp->pNext) {
89 fail(pTmp->lStringWidth < 0);
90 lNetWidth += pTmp->lStringWidth;
92 fail(pTmp == NULL);
93 fail(pTmp->pNext != NULL);
95 /* Step 2: remove the white-space from the end of the string */
96 while (pTmp->tNextFree != 0 &&
97 isspace((int)(UCHAR)pTmp->szStorage[pTmp->tNextFree - 1])) {
98 pTmp->szStorage[pTmp->tNextFree - 1] = '\0';
99 pTmp->tNextFree--;
100 NO_DBG_DEC(pTmp->lStringWidth);
101 pTmp->lStringWidth = lComputeStringWidth(
102 pTmp->szStorage,
103 pTmp->tNextFree,
104 pTmp->tFontRef,
105 pTmp->usFontSize);
106 NO_DBG_DEC(pTmp->lStringWidth);
109 /* Step 3: Count the last sub-string */
110 lNetWidth += pTmp->lStringWidth;
111 return lNetWidth;
112 } /* end of lComputeNetWidth */
115 * iComputeHoles - compute number of holes
116 * (A hole is a number of whitespace characters followed by a
117 * non-whitespace character)
119 static int
120 iComputeHoles(output_type *pAnchor)
122 output_type *pTmp;
123 size_t tIndex;
124 int iCounter;
125 BOOL bWasSpace, bIsSpace;
127 fail(pAnchor == NULL);
129 iCounter = 0;
130 bIsSpace = FALSE;
131 /* Count the holes */
132 for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
133 fail(pTmp->tNextFree != strlen(pTmp->szStorage));
134 for (tIndex = 0; tIndex <= pTmp->tNextFree; tIndex++) {
135 bWasSpace = bIsSpace;
136 bIsSpace = isspace((int)(UCHAR)pTmp->szStorage[tIndex]);
137 if (bWasSpace && !bIsSpace) {
138 iCounter++;
142 return iCounter;
143 } /* end of iComputeHoles */
146 * vAlign2Window - Align a string and insert it into the text
148 void
149 vAlign2Window(diagram_type *pDiag, output_type *pAnchor,
150 long lScreenWidth, UCHAR ucAlignment)
152 long lNetWidth, lLeftIndentation;
154 fail(pDiag == NULL || pAnchor == NULL);
155 fail(lScreenWidth < lChar2MilliPoints(MIN_SCREEN_WIDTH));
157 NO_DBG_MSG("vAlign2Window");
159 lNetWidth = lComputeNetWidth(pAnchor);
161 if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
162 lNetWidth <= 0) {
164 * Screenwidth is "infinite", so no alignment is possible
165 * Don't bother to align an empty line
167 vString2Diagram(pDiag, pAnchor);
168 return;
171 switch (ucAlignment) {
172 case ALIGNMENT_CENTER:
173 lLeftIndentation = (lScreenWidth - lNetWidth) / 2;
174 DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
175 if (lLeftIndentation > 0) {
176 vSetLeftIndentation(pDiag, lLeftIndentation);
178 break;
179 case ALIGNMENT_RIGHT:
180 lLeftIndentation = lScreenWidth - lNetWidth;
181 DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
182 if (lLeftIndentation > 0) {
183 vSetLeftIndentation(pDiag, lLeftIndentation);
185 break;
186 case ALIGNMENT_JUSTIFY:
187 case ALIGNMENT_LEFT:
188 default:
189 break;
191 vString2Diagram(pDiag, pAnchor);
192 } /* end of vAlign2Window */
195 * vJustify2Window - Justify a string and insert it into the text
197 void
198 vJustify2Window(diagram_type *pDiag, output_type *pAnchor,
199 long lScreenWidth, long lRightIndentation, UCHAR ucAlignment)
201 output_type *pTmp;
202 char *pcNew, *pcOld, *szStorage;
203 long lNetWidth, lSpaceWidth, lToAdd;
204 int iFillerLen, iHoles;
206 fail(pDiag == NULL || pAnchor == NULL);
207 fail(lScreenWidth < MIN_SCREEN_WIDTH);
208 fail(lRightIndentation > 0);
210 NO_DBG_MSG("vJustify2Window");
212 if (ucAlignment != ALIGNMENT_JUSTIFY) {
213 vAlign2Window(pDiag, pAnchor, lScreenWidth, ucAlignment);
214 return;
217 lNetWidth = lComputeNetWidth(pAnchor);
219 if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
220 lNetWidth <= 0) {
222 * Screenwidth is "infinite", so justify is not possible
223 * Don't bother to justify an empty line
225 vString2Diagram(pDiag, pAnchor);
226 return;
229 /* Justify */
230 fail(ucAlignment != ALIGNMENT_JUSTIFY);
231 lSpaceWidth = lComputeStringWidth(" ", 1,
232 pAnchor->tFontRef, pAnchor->usFontSize);
233 lToAdd = lScreenWidth -
234 lNetWidth -
235 lDrawUnits2MilliPoints(pDiag->lXleft) +
236 lRightIndentation;
237 #if defined(DEBUG)
238 if (lToAdd / lSpaceWidth < -1) {
239 DBG_DEC(lSpaceWidth);
240 DBG_DEC(lToAdd);
241 DBG_DEC(lScreenWidth);
242 DBG_DEC(lNetWidth);
243 DBG_DEC(lDrawUnits2MilliPoints(pDiag->lXleft));
244 DBG_DEC(pDiag->lXleft);
245 DBG_DEC(lRightIndentation);
247 #endif /* DEBUG */
248 lToAdd /= lSpaceWidth;
249 DBG_DEC_C(lToAdd < 0, lToAdd);
250 if (lToAdd <= 0) {
251 vString2Diagram(pDiag, pAnchor);
252 return;
255 /* Justify by adding spaces */
256 iHoles = iComputeHoles(pAnchor);
257 for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
258 fail(pTmp->tNextFree != strlen(pTmp->szStorage));
259 fail(lToAdd < 0);
260 szStorage = xmalloc(pTmp->tNextFree + (size_t)lToAdd + 1);
261 pcNew = szStorage;
262 for (pcOld = pTmp->szStorage; *pcOld != '\0'; pcOld++) {
263 *pcNew++ = *pcOld;
264 if (*pcOld == ' ' &&
265 *(pcOld + 1) != ' ' &&
266 iHoles > 0) {
267 iFillerLen = (int)(lToAdd / iHoles);
268 lToAdd -= iFillerLen;
269 iHoles--;
270 for (; iFillerLen > 0; iFillerLen--) {
271 *pcNew++ = ' ';
275 *pcNew = '\0';
276 pTmp->szStorage = xfree(pTmp->szStorage);
277 pTmp->szStorage = szStorage;
278 pTmp->tStorageSize = pTmp->tNextFree + (size_t)lToAdd + 1;
279 pTmp->lStringWidth +=
280 (pcNew - szStorage - (long)pTmp->tNextFree) *
281 lSpaceWidth;
282 fail(pcNew < szStorage);
283 pTmp->tNextFree = (size_t)(pcNew - szStorage);
284 fail(pTmp->tNextFree != strlen(pTmp->szStorage));
286 DBG_DEC_C(lToAdd != 0, lToAdd);
287 vString2Diagram(pDiag, pAnchor);
288 } /* end of vJustify2Window */
291 * vResetStyles - reset the style information variables
293 void
294 vResetStyles(void)
296 (void)memset(auiHdrCounter, 0, sizeof(auiHdrCounter));
297 } /* end of vResetStyles */
300 * tStyle2Window - Add the style characters to the line
302 * Returns the length of the resulting string
304 size_t
305 tStyle2Window(char *szLine, const style_block_type *pStyle,
306 const section_block_type *pSection)
308 char *pcTxt;
309 size_t tIndex, tStyleIndex;
310 BOOL bNeedPrevLvl;
311 level_type_enum eNumType;
312 UCHAR ucNFC;
314 fail(szLine == NULL || pStyle == NULL || pSection == NULL);
316 if (pStyle->usIstd == 0 || pStyle->usIstd > 9) {
317 szLine[0] = '\0';
318 return 0;
321 /* Set the numbers */
322 tStyleIndex = (size_t)pStyle->usIstd - 1;
323 for (tIndex = 0; tIndex < 9; tIndex++) {
324 if (tIndex == tStyleIndex) {
325 auiHdrCounter[tIndex]++;
326 } else if (tIndex > tStyleIndex) {
327 auiHdrCounter[tIndex] = 0;
328 } else if (auiHdrCounter[tIndex] == 0) {
329 auiHdrCounter[tIndex] = 1;
333 eNumType = eGetNumType(pStyle->ucNumLevel);
334 if (eNumType != level_type_outline) {
335 szLine[0] = '\0';
336 return 0;
339 /* Print the numbers */
340 pcTxt = szLine;
341 bNeedPrevLvl = (pSection->usNeedPrevLvl & BIT(tStyleIndex)) != 0;
342 for (tIndex = 0; tIndex <= tStyleIndex; tIndex++) {
343 if (tIndex == tStyleIndex ||
344 (bNeedPrevLvl && tIndex < tStyleIndex)) {
345 ucNFC = pSection->aucNFC[tIndex];
346 switch(ucNFC) {
347 case LIST_ARABIC_NUM:
348 case LIST_NUMBER_TXT:
349 case LIST_ORDINAL_TXT:
350 pcTxt += sprintf(pcTxt, "%u",
351 auiHdrCounter[tIndex]);
352 break;
353 case LIST_UPPER_ROMAN:
354 case LIST_LOWER_ROMAN:
355 pcTxt += tNumber2Roman(
356 auiHdrCounter[tIndex],
357 ucNFC == LIST_UPPER_ROMAN,
358 pcTxt);
359 break;
360 case LIST_UPPER_ALPHA:
361 case LIST_LOWER_ALPHA:
362 pcTxt += tNumber2Alpha(
363 auiHdrCounter[tIndex],
364 ucNFC == LIST_UPPER_ALPHA,
365 pcTxt);
366 break;
367 case LIST_OUTLINE_NUM:
368 pcTxt += sprintf(pcTxt, "%02u",
369 auiHdrCounter[tIndex]);
370 break;
371 default:
372 DBG_DEC(ucNFC);
373 DBG_FIXME();
374 pcTxt += sprintf(pcTxt, "%u",
375 auiHdrCounter[tIndex]);
376 break;
378 if (tIndex < tStyleIndex) {
379 *pcTxt++ = '.';
380 } else if (tIndex == tStyleIndex) {
381 *pcTxt++ = ' ';
385 *pcTxt = '\0';
386 NO_DBG_MSG_C((int)pStyle->usIstd >= 1 &&
387 (int)pStyle->usIstd <= 9 &&
388 eNumType != level_type_none &&
389 eNumType != level_type_outline, szLine);
390 NO_DBG_MSG_C(szLine[0] != '\0', szLine);
391 fail(pcTxt < szLine);
392 return (size_t)(pcTxt - szLine);
393 } /* end of tStyle2Window */
396 * vRemoveRowEnd - remove the end of table row indicator
398 * Remove the double TABLE_SEPARATOR characters from the end of the string.
399 * Special: remove the TABLE_SEPARATOR, 0x0a sequence
401 static void
402 vRemoveRowEnd(char *szRowTxt)
404 int iLastIndex;
406 fail(szRowTxt == NULL || szRowTxt[0] == '\0');
408 iLastIndex = (int)strlen(szRowTxt) - 1;
410 if (szRowTxt[iLastIndex] == TABLE_SEPARATOR ||
411 szRowTxt[iLastIndex] == (char)0x0a) {
412 szRowTxt[iLastIndex] = '\0';
413 iLastIndex--;
414 } else {
415 DBG_HEX(szRowTxt[iLastIndex]);
418 if (iLastIndex >= 0 && szRowTxt[iLastIndex] == (char)0x0a) {
419 szRowTxt[iLastIndex] = '\0';
420 iLastIndex--;
423 if (iLastIndex >= 0 && szRowTxt[iLastIndex] == TABLE_SEPARATOR) {
424 szRowTxt[iLastIndex] = '\0';
425 return;
428 DBG_DEC(iLastIndex);
429 DBG_HEX(szRowTxt[iLastIndex]);
430 DBG_MSG(szRowTxt);
431 } /* end of vRemoveRowEnd */
434 * tComputeStringLengthMax - max string length in relation to max column width
436 * Return the maximum string length
438 static size_t
439 tComputeStringLengthMax(const char *szString, size_t tColumnWidthMax)
441 const char *pcTmp;
442 size_t tLengthMax, tLenPrev, tLen, tWidth;
444 fail(szString == NULL);
445 fail(tColumnWidthMax == 0);
447 pcTmp = strchr(szString, '\n');
448 if (pcTmp != NULL) {
449 tLengthMax = (size_t)(pcTmp - szString + 1);
450 } else {
451 tLengthMax = strlen(szString);
453 if (tLengthMax == 0) {
454 return 0;
457 tLen = 0;
458 tWidth = 0;
459 for (;;) {
460 tLenPrev = tLen;
461 tLen += tGetCharacterLength(szString + tLen);
462 DBG_DEC_C(tLen > tLengthMax, tLen);
463 DBG_DEC_C(tLen > tLengthMax, tLengthMax);
464 fail(tLen > tLengthMax);
465 tWidth = tCountColumns(szString, tLen);
466 if (tWidth > tColumnWidthMax) {
467 return tLenPrev;
469 if (tLen >= tLengthMax) {
470 return tLengthMax;
473 } /* end of tComputeStringLengthMax */
476 * tGetBreakingPoint - get the number of bytes that fit the column
478 * Returns the number of bytes that fit the column
480 static size_t
481 tGetBreakingPoint(const char *szString,
482 size_t tLen, size_t tWidth, size_t tColumnWidthMax)
484 int iIndex;
486 fail(szString == NULL);
487 fail(tLen > strlen(szString));
488 fail(tWidth > tColumnWidthMax);
490 if (tWidth < tColumnWidthMax ||
491 (tWidth == tColumnWidthMax &&
492 (szString[tLen] == ' ' ||
493 szString[tLen] == '\n' ||
494 szString[tLen] == '\0'))) {
495 /* The string already fits, do nothing */
496 return tLen;
498 /* Search for a breaking point */
499 for (iIndex = (int)tLen - 1; iIndex >= 0; iIndex--) {
500 if (szString[iIndex] == ' ') {
501 return (size_t)iIndex;
504 /* No breaking point found, just fill the column */
505 return tLen;
506 } /* end of tGetBreakingPoint */
509 * tComputeColumnWidthMax - compute the maximum column width
511 static size_t
512 tComputeColumnWidthMax(short sWidth, long lCharWidth, double dFactor)
514 size_t tColumnWidthMax;
516 fail(sWidth < 0);
517 fail(lCharWidth <= 0);
518 fail(dFactor <= 0.0);
520 tColumnWidthMax = (size_t)(
521 (lTwips2MilliPoints(sWidth) * dFactor + lCharWidth / 2.0) /
522 lCharWidth);
523 if (tColumnWidthMax == 0) {
524 /* Minimum column width */
525 return 1;
527 if (tColumnWidthMax > 1) {
528 /* Make room for the TABLE_SEPARATOR_CHAR */
529 tColumnWidthMax--;
531 NO_DBG_DEC(tColumnWidthMax);
532 return tColumnWidthMax;
533 } /* end of tComputeColumnWidthMax */
536 * vTableRow2Window - put a table row into a diagram
538 void
539 vTableRow2Window(diagram_type *pDiag, output_type *pOutput,
540 const row_block_type *pRowInfo,
541 conversion_type eConversionType, int iParagraphBreak)
543 output_type tRow;
544 char *aszColTxt[TABLE_COLUMN_MAX];
545 char *szLine, *pcTxt;
546 double dMagnify;
547 long lCharWidthLarge, lCharWidthSmall;
548 size_t tColumnWidthTotal, atColumnWidthMax[TABLE_COLUMN_MAX];
549 size_t tSize, tColumnWidthMax, tWidth, tLen;
550 int iIndex, iNbrOfColumns, iTmp;
551 BOOL bNotReady;
553 fail(pDiag == NULL || pOutput == NULL || pRowInfo == NULL);
554 fail(pOutput->szStorage == NULL);
555 fail(pOutput->pNext != NULL);
556 fail(iParagraphBreak < 0);
558 /* Character sizes */
559 lCharWidthLarge = lComputeStringWidth("W", 1,
560 pOutput->tFontRef, pOutput->usFontSize);
561 NO_DBG_DEC(lCharWidthLarge);
562 lCharWidthSmall = lComputeStringWidth("i", 1,
563 pOutput->tFontRef, pOutput->usFontSize);
564 NO_DBG_DEC(lCharWidthSmall);
565 /* For the time being: use a fixed width font */
566 fail(lCharWidthLarge != lCharWidthSmall);
568 vRemoveRowEnd(pOutput->szStorage);
570 /* Split the row text into a set of column texts */
571 aszColTxt[0] = pOutput->szStorage;
572 for (iNbrOfColumns = 1;
573 iNbrOfColumns < TABLE_COLUMN_MAX;
574 iNbrOfColumns++) {
575 aszColTxt[iNbrOfColumns] =
576 strchr(aszColTxt[iNbrOfColumns - 1],
577 TABLE_SEPARATOR);
578 if (aszColTxt[iNbrOfColumns] == NULL) {
579 break;
581 *aszColTxt[iNbrOfColumns] = '\0';
582 aszColTxt[iNbrOfColumns]++;
583 NO_DBG_DEC(iNbrOfColumns);
584 NO_DBG_MSG(aszColTxt[iNbrOfColumns]);
587 /* Work around a bug in Word */
588 while (iNbrOfColumns > (int)pRowInfo->ucNumberOfColumns &&
589 pRowInfo->asColumnWidth[iNbrOfColumns] == 0) {
590 iNbrOfColumns--;
593 DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
594 iNbrOfColumns);
595 DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
596 pRowInfo->ucNumberOfColumns);
597 if (iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns) {
598 werr(0, "Skipping an unmatched table row");
599 return;
602 #if defined(__FULL_TEXT_SEARCH)
603 /* No table formatting: use for full-text search (untested) */
604 for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
605 fprintf(pDiag->pOutFile, "%s\n" , aszColTxt[iIndex]);
607 #else
608 if (bAddTableRow(pDiag, aszColTxt, iNbrOfColumns,
609 pRowInfo->asColumnWidth, pRowInfo->ucBorderInfo)) {
610 /* All work has been done */
611 return;
614 /* Fill the table with maximum column widths */
615 if (eConversionType == conversion_text ||
616 eConversionType == conversion_fmt_text) {
617 if (iParagraphBreak == 0 ||
618 iParagraphBreak >= MAX_SCREEN_WIDTH) {
619 dMagnify = (double)MAX_SCREEN_WIDTH;
620 } else if (iParagraphBreak <= MIN_SCREEN_WIDTH) {
621 dMagnify = (double)MIN_SCREEN_WIDTH;
622 } else {
623 dMagnify = (double)iParagraphBreak;
625 dMagnify /= (double)DEFAULT_SCREEN_WIDTH;
626 DBG_FLT_C(dMagnify < 0.99 || dMagnify > 1.01, dMagnify);
627 } else {
628 dMagnify = 1.0;
630 tColumnWidthTotal = 0;
631 for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
632 atColumnWidthMax[iIndex] = tComputeColumnWidthMax(
633 pRowInfo->asColumnWidth[iIndex],
634 lCharWidthLarge,
635 dMagnify);
636 tColumnWidthTotal += atColumnWidthMax[iIndex];
640 * Get enough space for the row.
641 * Worst case: three bytes per UTF-8 character
643 tSize = 3 * (1 + tColumnWidthTotal + (size_t)iNbrOfColumns + 3);
644 szLine = xmalloc(tSize);
646 do {
647 /* Print one line of a table row */
648 bNotReady = FALSE;
649 pcTxt = szLine;
650 *pcTxt++ = TABLE_SEPARATOR_CHAR;
651 for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
652 tColumnWidthMax = atColumnWidthMax[iIndex];
653 if (aszColTxt[iIndex] == NULL) {
654 /* Add an empty column */
655 for (iTmp = 0;
656 iTmp < (int)tColumnWidthMax;
657 iTmp++) {
658 *pcTxt++ = (char)FILLER_CHAR;
660 *pcTxt++ = TABLE_SEPARATOR_CHAR;
661 *pcTxt = '\0';
662 continue;
664 /* Compute the length and width of the column text */
665 tLen = tComputeStringLengthMax(
666 aszColTxt[iIndex], tColumnWidthMax);
667 NO_DBG_DEC(tLen);
668 while (tLen != 0 &&
669 (aszColTxt[iIndex][tLen - 1] == '\n' ||
670 aszColTxt[iIndex][tLen - 1] == ' ')) {
671 aszColTxt[iIndex][tLen - 1] = ' ';
672 tLen--;
674 tWidth = tCountColumns(aszColTxt[iIndex], tLen);
675 fail(tWidth > tColumnWidthMax);
676 tLen = tGetBreakingPoint(aszColTxt[iIndex],
677 tLen, tWidth, tColumnWidthMax);
678 tWidth = tCountColumns(aszColTxt[iIndex], tLen);
679 if (tLen == 0 && *aszColTxt[iIndex] == '\0') {
680 /* No text at all */
681 aszColTxt[iIndex] = NULL;
682 } else {
683 /* Add the text */
684 pcTxt += sprintf(pcTxt,
685 "%.*s", (int)tLen, aszColTxt[iIndex]);
686 if (tLen == 0 && *aszColTxt[iIndex] != ' ') {
687 tLen = tGetCharacterLength(
688 aszColTxt[iIndex]);
689 DBG_CHR(*aszColTxt[iIndex]);
690 DBG_FIXME();
691 fail(tLen == 0);
693 aszColTxt[iIndex] += tLen;
694 while (*aszColTxt[iIndex] == ' ') {
695 aszColTxt[iIndex]++;
697 if (*aszColTxt[iIndex] == '\0') {
698 /* This row is now complete */
699 aszColTxt[iIndex] = NULL;
700 } else {
701 /* This row needs more lines */
702 bNotReady = TRUE;
705 /* Fill up the rest */
706 for (iTmp = 0;
707 iTmp < (int)tColumnWidthMax - (int)tWidth;
708 iTmp++) {
709 *pcTxt++ = (char)FILLER_CHAR;
711 /* End of column */
712 *pcTxt++ = TABLE_SEPARATOR_CHAR;
713 *pcTxt = '\0';
715 /* Output the table row line */
716 *pcTxt = '\0';
717 tRow = *pOutput;
718 tRow.szStorage = szLine;
719 fail(pcTxt < szLine);
720 tRow.tNextFree = (size_t)(pcTxt - szLine);
721 tRow.lStringWidth = lComputeStringWidth(
722 tRow.szStorage,
723 tRow.tNextFree,
724 tRow.tFontRef,
725 tRow.usFontSize);
726 vString2Diagram(pDiag, &tRow);
727 } while (bNotReady);
728 /* Clean up before you leave */
729 szLine = xfree(szLine);
730 #endif /* __FULL_TEXT_SEARCH */
731 } /* end of vTableRow2Window */