home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / out2window.c < prev    next >
C/C++ Source or Header  |  2000-11-11  |  13KB  |  519 lines

  1. /*
  2.  * out2window.c
  3.  * Copyright (C) 1998-2000 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.  
  15. /* Used for numbering the chapters */
  16. static int    aiHdrCounter[9];
  17.  
  18.  
  19. /*
  20.  * vString2Diagram - put a string into a diagram
  21.  */
  22. static void
  23. vString2Diagram(diagram_type *pDiag, output_type *pAnchor)
  24. {
  25.     output_type    *pOutput;
  26.     long        lWidth;
  27.     int        iMaxFontsize;
  28.  
  29.     fail(pDiag == NULL);
  30.     fail(pAnchor == NULL);
  31.  
  32.     /* Compute the maximum fontsize in this string */
  33.     iMaxFontsize = MIN_FONT_SIZE;
  34.     for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
  35.         if (pOutput->sFontsize > iMaxFontsize) {
  36.             iMaxFontsize = pOutput->sFontsize;
  37.         }
  38.     }
  39.  
  40.     /* Goto the next line */
  41.     vMove2NextLine(pDiag, pAnchor->tFontRef, iMaxFontsize);
  42.  
  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->iNextFree, lWidth, pOutput->iColor,
  48.             pOutput->ucFontstyle, pOutput->tFontRef,
  49.             pOutput->sFontsize, iMaxFontsize);
  50.     }
  51.  
  52.     /* Goto the start of the line */
  53.     pDiag->lXleft = 0;
  54. } /* end of vString2Diagram */
  55.  
  56. /*
  57.  * vSetLeftIndentation - set the left indentation of the given diagram
  58.  */
  59. void
  60. vSetLeftIndentation(diagram_type *pDiag, long lLeftIndentation)
  61. {
  62.     long    lX;
  63.  
  64.     fail(pDiag == NULL);
  65.     fail(lLeftIndentation < 0);
  66.  
  67.     lX = lMilliPoints2DrawUnits(lLeftIndentation);
  68.     if (lX > 0) {
  69.         pDiag->lXleft = lX;
  70.     } else {
  71.         pDiag->lXleft = 0;
  72.     }
  73. } /* end of vSetLeftIndentation */
  74.  
  75. /*
  76.  * lComputeNetWidth - compute the net string width
  77.  */
  78. static long
  79. lComputeNetWidth(output_type *pAnchor)
  80. {
  81.     output_type    *pTmp;
  82.     long        lNetWidth;
  83.  
  84.     fail(pAnchor == NULL);
  85.  
  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;
  91.     }
  92.     fail(pTmp == NULL);
  93.     fail(pTmp->pNext != NULL);
  94.  
  95.     /* Step 2: remove the white-space from the end of the string */
  96.     while (pTmp->iNextFree > 0 &&
  97.            isspace(pTmp->szStorage[pTmp->iNextFree - 1])) {
  98.         pTmp->szStorage[pTmp->iNextFree - 1] = '\0';
  99.         pTmp->iNextFree--;
  100.         NO_DBG_DEC(pTmp->lStringWidth);
  101.         pTmp->lStringWidth = lComputeStringWidth(
  102.                         pTmp->szStorage,
  103.                         pTmp->iNextFree,
  104.                         pTmp->tFontRef,
  105.                         pTmp->sFontsize);
  106.         NO_DBG_DEC(pTmp->lStringWidth);
  107.     }
  108.  
  109.     /* Step 3: Count the last sub-string */
  110.     lNetWidth += pTmp->lStringWidth;
  111.     return lNetWidth;
  112. } /* end of lComputeNetWidth */
  113.  
  114. /*
  115.  * iComputeHoles - compute number of holes
  116.  * (A hole is a number of whitespace characters followed by a
  117.  *  non-whitespace character)
  118.  */
  119. static int
  120. iComputeHoles(output_type *pAnchor)
  121. {
  122.     output_type    *pTmp;
  123.     int    iIndex, iCounter;
  124.     BOOL    bWasSpace, bIsSpace;
  125.  
  126.     fail(pAnchor == NULL);
  127.  
  128.     iCounter = 0;
  129.     bIsSpace = FALSE;
  130.     /* Count the holes */
  131.     for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
  132.         fail(pTmp->iNextFree != (int)strlen(pTmp->szStorage));
  133.         for (iIndex = 0; iIndex <= pTmp->iNextFree; iIndex++) {
  134.             bWasSpace = bIsSpace;
  135.             bIsSpace = isspace(pTmp->szStorage[iIndex]);
  136.             if (bWasSpace && !bIsSpace) {
  137.                 iCounter++;
  138.             }
  139.         }
  140.     }
  141.     return iCounter;
  142. } /* end of iComputeHoles */
  143.  
  144. /*
  145.  * Align a string and insert it into the text
  146.  */
  147. void
  148. vAlign2Window(diagram_type *pDiag, output_type *pAnchor,
  149.     long lScreenWidth, unsigned char ucAlignment)
  150. {
  151.     long    lNetWidth, lLeftIndentation;
  152.  
  153.     fail(pDiag == NULL || pAnchor == NULL);
  154.     fail(lScreenWidth < lChar2MilliPoints(MIN_SCREEN_WIDTH));
  155.  
  156.     NO_DBG_MSG("vAlign2Window");
  157.  
  158.     lNetWidth = lComputeNetWidth(pAnchor);
  159.  
  160.     if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
  161.         lNetWidth <= 0) {
  162.         /*
  163.          * Screenwidth is "infinite", so no alignment is possible
  164.          * Don't bother to align an empty line
  165.          */
  166.         vString2Diagram(pDiag, pAnchor);
  167.         return;
  168.     }
  169.  
  170.     switch (ucAlignment) {
  171.     case ALIGNMENT_CENTER:
  172.         lLeftIndentation = (lScreenWidth - lNetWidth) / 2;
  173.         DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
  174.         if (lLeftIndentation > 0) {
  175.             vSetLeftIndentation(pDiag, lLeftIndentation);
  176.         }
  177.         break;
  178.     case ALIGNMENT_RIGHT:
  179.         lLeftIndentation = lScreenWidth - lNetWidth;
  180.         DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
  181.         if (lLeftIndentation > 0) {
  182.             vSetLeftIndentation(pDiag, lLeftIndentation);
  183.         }
  184.         break;
  185.     case ALIGNMENT_JUSTIFY:
  186.     case ALIGNMENT_LEFT:
  187.     default:
  188.         break;
  189.     }
  190.     vString2Diagram(pDiag, pAnchor);
  191. } /* end of vAlign2Window */
  192.  
  193. /*
  194.  * vJustify2Window
  195.  */
  196. void
  197. vJustify2Window(diagram_type *pDiag, output_type *pAnchor,
  198.     long lScreenWidth, long lRightIndentation, unsigned char ucAlignment)
  199. {
  200.     output_type    *pTmp;
  201.     char    *pcNew, *pcOld, *szStorage;
  202.     long    lNetWidth, lSpaceWidth, lToAdd;
  203.     int    iFillerLen, iHoles;
  204.  
  205.     fail(pDiag == NULL || pAnchor == NULL);
  206.     fail(lScreenWidth < MIN_SCREEN_WIDTH);
  207.     fail(lRightIndentation > 0);
  208.  
  209.     NO_DBG_MSG("vJustify2Window");
  210.  
  211.     if (ucAlignment != ALIGNMENT_JUSTIFY) {
  212.         vAlign2Window(pDiag, pAnchor, lScreenWidth, ucAlignment);
  213.         return;
  214.     }
  215.  
  216.     lNetWidth = lComputeNetWidth(pAnchor);
  217.  
  218.     if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
  219.         lNetWidth <= 0) {
  220.         /*
  221.          * Screenwidth is "infinite", so justify is not possible
  222.          * Don't bother to align an empty line
  223.          */
  224.         vString2Diagram(pDiag, pAnchor);
  225.         return;
  226.     }
  227.  
  228.     /* Justify */
  229.     fail(ucAlignment != ALIGNMENT_JUSTIFY);
  230.     lSpaceWidth = lComputeStringWidth(" ", 1,
  231.                 pAnchor->tFontRef, pAnchor->sFontsize);
  232.     lToAdd = lScreenWidth -
  233.             lNetWidth -
  234.             lDrawUnits2MilliPoints(pDiag->lXleft) +
  235.             lRightIndentation;
  236.     DBG_DEC_C(lToAdd < 0, lSpaceWidth);
  237.     DBG_DEC_C(lToAdd < 0, lToAdd);
  238.     DBG_DEC_C(lToAdd < 0, lScreenWidth);
  239.     DBG_DEC_C(lToAdd < 0, lNetWidth);
  240.     DBG_DEC_C(lToAdd < 0, lDrawUnits2MilliPoints(pDiag->lXleft));
  241.     DBG_DEC_C(lToAdd < 0, pDiag->lXleft);
  242.     DBG_DEC_C(lToAdd < 0, lRightIndentation);
  243.     lToAdd /= lSpaceWidth;
  244.     DBG_DEC_C(lToAdd < 0, lToAdd);
  245.     if (lToAdd <= 0) {
  246.         vString2Diagram(pDiag, pAnchor);
  247.         return;
  248.     }
  249.  
  250.     iHoles = iComputeHoles(pAnchor);
  251.     /* Justify by adding spaces */
  252.     for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
  253.         fail(pTmp->iNextFree != (int)strlen(pTmp->szStorage));
  254.         fail(lToAdd < 0);
  255.         szStorage = xmalloc((size_t)(pTmp->iNextFree + lToAdd + 1));
  256.         pcNew = szStorage;
  257.         for (pcOld = pTmp->szStorage; *pcOld != '\0'; pcOld++) {
  258.             *pcNew++ = *pcOld;
  259.             if (*pcOld == ' ' &&
  260.                 *(pcOld + 1) != ' ' &&
  261.                 iHoles > 0) {
  262.                 iFillerLen = (int)(lToAdd / iHoles);
  263.                 lToAdd -= iFillerLen;
  264.                 iHoles--;
  265.                 for (; iFillerLen > 0; iFillerLen--) {
  266.                     *pcNew++ = ' ';
  267.                 }
  268.             }
  269.         }
  270.         *pcNew = '\0';
  271.         pTmp->szStorage = xfree(pTmp->szStorage);
  272.         pTmp->szStorage = szStorage;
  273.         pTmp->tStorageSize = (size_t)(pTmp->iNextFree + lToAdd + 1);
  274.         pTmp->lStringWidth +=
  275.             (pcNew - szStorage - (long)pTmp->iNextFree) *
  276.             lSpaceWidth;
  277.         pTmp->iNextFree = pcNew - szStorage;
  278.         fail(pTmp->iNextFree != (int)strlen(pTmp->szStorage));
  279.     }
  280.     DBG_DEC_C(lToAdd != 0, lToAdd);
  281.     vString2Diagram(pDiag, pAnchor);
  282. } /* end of vJustify2Window */
  283.  
  284. /*
  285.  * vResetStyles - reset the style information variables
  286.  */
  287. void
  288. vResetStyles(void)
  289. {
  290.     (void)memset(aiHdrCounter, 0, sizeof(aiHdrCounter));
  291. } /* end of vResetStyles */
  292.  
  293. /*
  294.  * Add the style characters to the line
  295.  */
  296. int
  297. iStyle2Window(char *szLine, const style_block_type *pStyleInfo)
  298. {
  299.     char    *pcTxt;
  300.     int    iIndex, iStyleIndex;
  301.  
  302.     fail(szLine == NULL || pStyleInfo == NULL);
  303.  
  304.     pcTxt = szLine;
  305.     if ((int)pStyleInfo->ucStyle >= 1 && (int)pStyleInfo->ucStyle <= 9) {
  306.         iStyleIndex = (int)pStyleInfo->ucStyle - 1;
  307.         for (iIndex = 0; iIndex < 9; iIndex++) {
  308.             if (iIndex == iStyleIndex) {
  309.                 aiHdrCounter[iIndex]++;
  310.             } else if (iIndex > iStyleIndex) {
  311.                 aiHdrCounter[iIndex] = 0;
  312.             } else if (aiHdrCounter[iIndex] < 1) {
  313.                 aiHdrCounter[iIndex] = 1;
  314.             }
  315.             if (iIndex <= iStyleIndex) {
  316.                 pcTxt += sprintf(pcTxt, "%d",
  317.                         aiHdrCounter[iIndex]);
  318.                 if (iIndex < iStyleIndex) {
  319.                     *pcTxt++ = '.';
  320.                 }
  321.             }
  322.         }
  323.         *pcTxt++ = ' ';
  324.     }
  325.     *pcTxt = '\0';
  326.     NO_DBG_MSG_C(szLine[0] != '\0', szLine);
  327.     return pcTxt - szLine;
  328. } /* end of iStyle2Window */
  329.  
  330. /*
  331.  * vRemoveRowEnd - remove the end of table row indicator
  332.  *
  333.  * Remove the double TABLE_SEPARATOR characters from the end of the string.
  334.  * Special: remove the TABLE_SEPARATOR, 0x0a sequence
  335.  */
  336. static void
  337. vRemoveRowEnd(char *szRowTxt)
  338. {
  339.     int    iLastIndex;
  340.  
  341.     fail(szRowTxt == NULL || szRowTxt[0] == '\0');
  342.  
  343.     iLastIndex = (int)strlen(szRowTxt) - 1;
  344.  
  345.     if (szRowTxt[iLastIndex] == TABLE_SEPARATOR ||
  346.         szRowTxt[iLastIndex] == '\n') {
  347.         szRowTxt[iLastIndex] = '\0';
  348.         iLastIndex--;
  349.     } else {
  350.         DBG_HEX(szRowTxt[iLastIndex]);
  351.     }
  352.  
  353.     if (iLastIndex >= 0 && szRowTxt[iLastIndex] == TABLE_SEPARATOR) {
  354.         szRowTxt[iLastIndex] = '\0';
  355.         return;
  356.     }
  357.  
  358.     DBG_HEX(szRowTxt[iLastIndex]);
  359.     DBG_MSG(szRowTxt);
  360. } /* end of vRemoveRowEnd */
  361.  
  362. /*
  363.  * vTableRow2Window - put a table row into a diagram
  364.  */
  365. void
  366. vTableRow2Window(diagram_type *pDiag, output_type *pOutput,
  367.         const row_block_type *pRowInfo)
  368. {
  369.     output_type    tRow;
  370.     char    *aszColTxt[TABLE_COLUMN_MAX];
  371.     char    *szLine, *pcTmp, *pcTxt;
  372.     long    lCharWidthLarge, lCharWidthSmall;
  373.     size_t    tSize;
  374.     int    iIndex, iNbrOfColumns, iColumnWidth, iTmp;
  375.     int    iLen1, iLen2, iLen;
  376.     BOOL    bNotReady;
  377.  
  378.     fail(pDiag == NULL || pOutput == NULL || pRowInfo == NULL);
  379.     fail(pOutput->szStorage == NULL);
  380.     fail(pOutput->pNext != NULL);
  381.  
  382.     /* Character sizes */
  383.     lCharWidthLarge = lComputeStringWidth("W", 1,
  384.                 pOutput->tFontRef, pOutput->sFontsize);
  385.     NO_DBG_DEC(lCharWidthLarge);
  386.     lCharWidthSmall = lComputeStringWidth("i", 1,
  387.                 pOutput->tFontRef, pOutput->sFontsize);
  388.     NO_DBG_DEC(lCharWidthSmall);
  389.     /* For the time being: use a fixed width font */
  390.     fail(lCharWidthLarge != lCharWidthSmall);
  391.  
  392.     /* Make room for the row */
  393.     tSize = (size_t)(lTwips2MilliPoints(pRowInfo->iColumnWidthSum) /
  394.                 lCharWidthSmall +
  395.                 (long)pRowInfo->ucNumberOfColumns + 3);
  396.     szLine = xmalloc(tSize);
  397.  
  398.     vRemoveRowEnd(pOutput->szStorage);
  399.  
  400.     /* Split the row text into column texts */
  401.     aszColTxt[0] = pOutput->szStorage;
  402.     for (iNbrOfColumns = 1;
  403.          iNbrOfColumns < TABLE_COLUMN_MAX;
  404.          iNbrOfColumns++) {
  405.         aszColTxt[iNbrOfColumns] =
  406.                 strchr(aszColTxt[iNbrOfColumns - 1],
  407.                     TABLE_SEPARATOR);
  408.         if (aszColTxt[iNbrOfColumns] == NULL) {
  409.             break;
  410.         }
  411.         *aszColTxt[iNbrOfColumns] = '\0';
  412.         aszColTxt[iNbrOfColumns]++;
  413.         NO_DBG_DEC(iNbrOfColumns);
  414.         NO_DBG_MSG(aszColTxt[iNbrOfColumns]);
  415.     }
  416.  
  417.     DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
  418.         iNbrOfColumns);
  419.     DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
  420.         pRowInfo->ucNumberOfColumns);
  421.     if (iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns) {
  422.         werr(0, "Skipping an unmatched table row");
  423.         /* Clean up before you leave */
  424.         szLine = xfree(szLine);
  425.         return;
  426.     }
  427.  
  428.     do {
  429.         /* Print a table row line */
  430.         bNotReady = FALSE;
  431.         pcTxt = szLine;
  432.         *pcTxt++ = TABLE_SEPARATOR_CHAR;
  433.         for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
  434.             iColumnWidth =
  435.                 (int)(lTwips2MilliPoints(
  436.                     pRowInfo->asColumnWidth[iIndex]) /
  437.                     lCharWidthLarge);
  438.             fail(iColumnWidth < 0);
  439.             if (iColumnWidth < 1) {
  440.                 /* Minimum column width */
  441.                 iColumnWidth = 1;
  442.             } else if (iColumnWidth > 1) {
  443.                 /* Room for the TABLE_SEPARATOR_CHAR */
  444.                 iColumnWidth--;
  445.             }
  446.             NO_DBG_DEC(iColumnWidth);
  447.             /* Compute the length of the text for a column */
  448.             if (aszColTxt[iIndex] == NULL) {
  449.                 iLen = 0;
  450.             } else {
  451.                 pcTmp = strchr(aszColTxt[iIndex], '\n');
  452.                 if (pcTmp == NULL) {
  453.                     iLen1 = INT_MAX;
  454.                 } else {
  455.                     iLen1 =
  456.                     pcTmp - aszColTxt[iIndex] + 1;
  457.                 }
  458.                 iLen2 = (int)strlen(aszColTxt[iIndex]);
  459.                 if (iLen2 > iColumnWidth) {
  460.                     iLen2 = iColumnWidth;
  461.                 }
  462.                 iLen = min(iLen1, iLen2);
  463.             }
  464.             NO_DBG_DEC(iLen);
  465.             fail(iLen < 0 || iLen > iColumnWidth);
  466.             if (iLen >= 1 &&
  467.                 aszColTxt[iIndex][iLen - 1] == '\n') {
  468.                 aszColTxt[iIndex][iLen - 1] = ' ';
  469.             }
  470.             if (iLen == iColumnWidth &&
  471.                 !isspace(aszColTxt[iIndex][iLen])) {
  472.                 /* Search for a breaking point */
  473.                 for (iTmp = iLen - 1; iTmp >= 0; iTmp--) {
  474.                     if (isspace(aszColTxt[iIndex][iTmp])) {
  475.                         /* Found a breaking point */
  476.                         iLen = iTmp + 1;
  477.                         NO_DBG_DEC(iLen);
  478.                         break;
  479.                     }
  480.                 }
  481.             }
  482.             /* Print the text */
  483.             if (iLen <= 0) {
  484.                 aszColTxt[iIndex] = NULL;
  485.             } else {
  486.                 pcTxt += sprintf(pcTxt,
  487.                     "%.*s", iLen, aszColTxt[iIndex]);
  488.                 aszColTxt[iIndex] += iLen;
  489.                 while (*aszColTxt[iIndex] == ' ') {
  490.                     aszColTxt[iIndex]++;
  491.                 }
  492.                 if (*aszColTxt[iIndex] != '\0') {
  493.                     /* The row takes more lines */
  494.                     bNotReady = TRUE;
  495.                 }
  496.             }
  497.             /* Print the filler */
  498.             for (iTmp = 0; iTmp < iColumnWidth - iLen; iTmp++) {
  499.                 *pcTxt++ = (char)FILLER_CHAR;
  500.             }
  501.             *pcTxt++ = TABLE_SEPARATOR_CHAR;
  502.             *pcTxt = '\0';
  503.         }
  504.         /* Output the table row line */
  505.         *pcTxt = '\0';
  506.         tRow = *pOutput;
  507.         tRow.szStorage = szLine;
  508.         tRow.iNextFree = pcTxt - szLine;
  509.         tRow.lStringWidth = lComputeStringWidth(
  510.                     tRow.szStorage,
  511.                     tRow.iNextFree,
  512.                     tRow.tFontRef,
  513.                     tRow.sFontsize);
  514.         vString2Diagram(pDiag, &tRow);
  515.     } while (bNotReady);
  516.     /* Clean up before you leave */
  517.     szLine = xfree(szLine);
  518. } /* end of vTableRow2Window */
  519.