]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/antiword/out2window.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / aux / antiword / out2window.c
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 */