out2window.c 19 KB

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