3 * Copyright (C) 1998,1999 A.J. van Os
6 * Output to a text window
16 /* Used for numbering the chapters */
17 static int aiHdrCounter
[9];
21 * vString2Diagram - put a string into a diagram
24 vString2Diagram(diagram_type
*pDiag
, output_type
*pAnchor
)
28 unsigned char ucMaxFontsize
;
31 fail(pAnchor
== NULL
);
33 /* Compute the maximum fontsize in this string */
34 ucMaxFontsize
= MIN_FONT_SIZE
;
35 for (pOutput
= pAnchor
; pOutput
!= NULL
; pOutput
= pOutput
->pNext
) {
36 if (pOutput
->ucFontsize
> ucMaxFontsize
) {
37 ucMaxFontsize
= pOutput
->ucFontsize
;
40 /* Output all substrings */
41 for (pOutput
= pAnchor
; pOutput
!= NULL
; pOutput
= pOutput
->pNext
) {
42 iWidth
= iMilliPoints2DrawUnits(pOutput
->iStringWidth
);
43 vSubstring2Diagram(pDiag
, pOutput
->szStorage
,
44 pOutput
->iNextFree
, iWidth
, pOutput
->iColour
,
45 pOutput
->ucFontstyle
, pOutput
->tFontRef
,
46 pOutput
->ucFontsize
, ucMaxFontsize
);
48 /* Goto the start of the next line */
49 vMove2NextLine(pDiag
, pAnchor
->tFontRef
, ucMaxFontsize
);
50 } /* end of vString2Diagram */
53 * iComputeNetWidth - compute the net string width
56 iComputeNetWidth(output_type
*pAnchor
)
61 fail(pAnchor
== NULL
);
63 /* Step 1: Count all but the last sub-string */
65 for (pTmp
= pAnchor
; pTmp
->pNext
!= NULL
; pTmp
= pTmp
->pNext
) {
66 fail(pTmp
->iStringWidth
< 0);
67 iNetWidth
+= pTmp
->iStringWidth
;
70 fail(pTmp
->pNext
!= NULL
);
72 /* Step 2: remove the white-space from the end of the string */
73 while (pTmp
->iNextFree
> 0 &&
74 isspace(pTmp
->szStorage
[pTmp
->iNextFree
- 1])) {
75 pTmp
->szStorage
[pTmp
->iNextFree
- 1] = '\0';
77 NO_DBG_DEC(pTmp
->iStringWidth
);
78 pTmp
->iStringWidth
= iComputeStringWidth(
83 NO_DBG_DEC(pTmp
->iStringWidth
);
86 /* Step 3: Count the last sub-string */
87 iNetWidth
+= pTmp
->iStringWidth
;
89 } /* end of iComputeNetWidth */
92 * iComputeHoles - compute number of holes
93 * (A hole is a number of whitespace characters followed by a
94 * non-whitespace character)
97 iComputeHoles(output_type
*pAnchor
)
100 int iIndex
, iCounter
;
101 BOOL bWasSpace
, bIsSpace
;
103 fail(pAnchor
== NULL
);
107 /* Count the holes */
108 for (pTmp
= pAnchor
; pTmp
!= NULL
; pTmp
= pTmp
->pNext
) {
109 fail(pTmp
->iNextFree
!= strlen(pTmp
->szStorage
));
110 for (iIndex
= 0; iIndex
<= pTmp
->iNextFree
; iIndex
++) {
111 bWasSpace
= bIsSpace
;
112 bIsSpace
= isspace(pTmp
->szStorage
[iIndex
]);
113 if (bWasSpace
&& !bIsSpace
) {
119 } /* end of iComputeHoles */
122 * Align a string and insert it into the text
125 vAlign2Window(diagram_type
*pDiag
, output_type
*pAnchor
,
126 int iScreenWidth
, unsigned char ucAlignment
)
130 fail(pDiag
== NULL
|| pAnchor
== NULL
);
131 fail(iScreenWidth
< iChar2MilliPoints(MIN_SCREEN_WIDTH
));
133 NO_DBG_MSG("vAlign2Window");
135 iNetWidth
= iComputeNetWidth(pAnchor
);
137 if (iScreenWidth
> iChar2MilliPoints(MAX_SCREEN_WIDTH
) ||
140 * Screenwidth is "infinite", so no alignment is possible
141 * Don't bother to align an empty line
143 vString2Diagram(pDiag
, pAnchor
);
147 switch (ucAlignment
) {
148 case ALIGNMENT_CENTER
:
149 vSetLeftIndentation(pDiag
, (iScreenWidth
- iNetWidth
) / 2);
151 case ALIGNMENT_RIGHT
:
152 vSetLeftIndentation(pDiag
, iScreenWidth
- iNetWidth
);
154 case ALIGNMENT_JUSTIFY
:
159 vString2Diagram(pDiag
, pAnchor
);
160 } /* end of vAlign2Window */
166 vJustify2Window(diagram_type
*pDiag
, output_type
*pAnchor
,
167 int iScreenWidth
, unsigned char ucAlignment
)
170 char *pcNew
, *pcOld
, *szStorage
;
171 int iNetWidth
, iSpaceWidth
, iFillerLen
, iToAdd
, iHoles
;
173 fail(pDiag
== NULL
|| pAnchor
== NULL
);
174 fail(iScreenWidth
< MIN_SCREEN_WIDTH
);
176 NO_DBG_MSG("vJustify2Window");
178 if (ucAlignment
!= ALIGNMENT_JUSTIFY
) {
179 vAlign2Window(pDiag
, pAnchor
, iScreenWidth
, ucAlignment
);
183 iNetWidth
= iComputeNetWidth(pAnchor
);
185 if (iScreenWidth
> iChar2MilliPoints(MAX_SCREEN_WIDTH
) ||
188 * Screenwidth is "infinite", so justify is not possible
189 * Don't bother to align an empty line
191 vString2Diagram(pDiag
, pAnchor
);
196 fail(ucAlignment
!= ALIGNMENT_JUSTIFY
);
197 iSpaceWidth
= iComputeStringWidth(" ", 1,
198 pAnchor
->tFontRef
, pAnchor
->ucFontsize
);
199 DBG_DEC(iSpaceWidth
);
200 iToAdd
= iScreenWidth
-
202 iDrawUnits2MilliPoints(pDiag
->iXleft
);
203 DBG_DEC_C(iToAdd
< 0, iToAdd
);
204 DBG_DEC_C(iToAdd
< 0, iScreenWidth
);
205 DBG_DEC_C(iToAdd
< 0, iNetWidth
);
206 DBG_DEC_C(iToAdd
< 0, iDrawUnits2MilliPoints(pDiag
->iXleft
));
207 DBG_DEC_C(iToAdd
< 0, pDiag
->iXleft
);
208 iToAdd
/= iSpaceWidth
;
211 vString2Diagram(pDiag
, pAnchor
);
215 iHoles
= iComputeHoles(pAnchor
);
216 /* Justify by adding spaces */
217 for (pTmp
= pAnchor
; pTmp
!= NULL
; pTmp
= pTmp
->pNext
) {
218 fail(pTmp
->iNextFree
!= strlen(pTmp
->szStorage
));
220 szStorage
= xmalloc(pTmp
->iNextFree
+ iToAdd
+ 1);
222 for (pcOld
= pTmp
->szStorage
; *pcOld
!= '\0'; pcOld
++) {
225 *(pcOld
+ 1) != ' ' &&
227 iFillerLen
= iToAdd
/ iHoles
;
228 iToAdd
-= iFillerLen
;
230 for (; iFillerLen
> 0; iFillerLen
--) {
236 pTmp
->szStorage
= xfree(pTmp
->szStorage
);
237 pTmp
->szStorage
= szStorage
;
238 pTmp
->iStorageSize
= pTmp
->iNextFree
+ iToAdd
+ 1;
239 pTmp
->iStringWidth
+=
240 (pcNew
- szStorage
- pTmp
->iNextFree
) * iSpaceWidth
;
241 pTmp
->iNextFree
= pcNew
- szStorage
;
242 fail(pTmp
->iNextFree
!= strlen(pTmp
->szStorage
));
244 DBG_DEC_C(iToAdd
!= 0, iToAdd
);
245 vString2Diagram(pDiag
, pAnchor
);
246 } /* end of vJustify2Window */
249 * vResetStyles - reset the style information variables
254 memset(aiHdrCounter
, 0, sizeof(aiHdrCounter
));
255 } /* end of vResetStyles */
258 * Add the style characters to the line
261 iStyle2Window(char *szLine
, const style_block_type
*pStyleInfo
)
264 int iIndex
, iStyleIndex
;
266 fail(szLine
== NULL
|| pStyleInfo
== NULL
);
269 if ((int)pStyleInfo
->ucStyle
>= 1 && (int)pStyleInfo
->ucStyle
<= 9) {
270 iStyleIndex
= (int)pStyleInfo
->ucStyle
- 1;
271 for (iIndex
= 0; iIndex
< 9; iIndex
++) {
272 if (iIndex
== iStyleIndex
) {
273 aiHdrCounter
[iIndex
]++;
274 } else if (iIndex
> iStyleIndex
) {
275 aiHdrCounter
[iIndex
] = 0;
276 } else if (aiHdrCounter
[iIndex
] < 1) {
277 aiHdrCounter
[iIndex
] = 1;
279 if (iIndex
<= iStyleIndex
) {
280 pcTxt
+= sprintf(pcTxt
, "%d",
281 aiHdrCounter
[iIndex
]);
282 if (iIndex
< iStyleIndex
) {
290 DBG_MSG_C(szLine
[0] != '\0', szLine
);
291 return pcTxt
- szLine
;
292 } /* end of iStyle2Window */
295 * vRemoveRowEnd - remove the end of table row indicator
297 * Remove the double TABLE_SEPARATOR characters from the end of the string.
300 vRemoveRowEnd(char *szRowTxt
)
304 fail(szRowTxt
== NULL
|| szRowTxt
[0] == '\0');
305 fail(szRowTxt
[strlen(szRowTxt
) - 1] != TABLE_SEPARATOR
);
306 fail(szRowTxt
[strlen(szRowTxt
) - 2] != TABLE_SEPARATOR
);
308 pcTmp
= strrchr(szRowTxt
, TABLE_SEPARATOR
);
309 if (pcTmp
== NULL
|| pcTmp
<= szRowTxt
) {
313 *pcTmp
= '\0'; /* Remove the last TABLE_SEPARATOR */
315 if (*pcTmp
== TABLE_SEPARATOR
) {
316 *pcTmp
= '\0'; /* And the second last */
320 } /* end of vRemoveRowEnd */
323 * vTableRow2Window - put a table row into a diagram
326 vTableRow2Window(diagram_type
*pDiag
, output_type
*pOutput
,
327 const row_block_type
*pRowInfo
)
330 char *aszColTxt
[TABLE_COLUMN_MAX
];
331 char *szLine
, *pcTmp
, *pcTxt
;
333 int iIndex
, iNbrOfColumns
, iColumnWidth
, iTmp
;
334 int iCharWidthLarge
, iCharWidthSmall
;
335 int iLen1
, iLen2
, iLen
;
338 fail(pDiag
== NULL
|| pOutput
== NULL
|| pRowInfo
== NULL
);
339 fail(pOutput
->szStorage
== NULL
);
340 fail(pOutput
->pNext
!= NULL
);
342 /* Character sizes */
343 iCharWidthLarge
= iComputeStringWidth("W", 1,
344 pOutput
->tFontRef
, pOutput
->ucFontsize
);
345 NO_DBG_DEC(iCharWidthLarge
);
346 iCharWidthSmall
= iComputeStringWidth("i", 1,
347 pOutput
->tFontRef
, pOutput
->ucFontsize
);
348 NO_DBG_DEC(iCharWidthSmall
);
349 /* For the time being: use a fixed width font */
350 fail(iCharWidthLarge
!= iCharWidthSmall
);
352 /* Make room for the row */
353 tSize
= iTwips2MilliPoints(pRowInfo
->iColumnWidthSum
) /
355 (int)pRowInfo
->ucNumberOfColumns
+ 3;
356 szLine
= xmalloc(tSize
);
358 vRemoveRowEnd(pOutput
->szStorage
);
360 /* Split the row text into column texts */
361 aszColTxt
[0] = pOutput
->szStorage
;
362 for (iNbrOfColumns
= 1;
363 iNbrOfColumns
< TABLE_COLUMN_MAX
;
365 aszColTxt
[iNbrOfColumns
] =
366 strchr(aszColTxt
[iNbrOfColumns
- 1],
368 if (aszColTxt
[iNbrOfColumns
] == NULL
) {
371 *aszColTxt
[iNbrOfColumns
] = '\0';
372 aszColTxt
[iNbrOfColumns
]++;
373 NO_DBG_DEC(iNbrOfColumns
);
374 NO_DBG_MSG(aszColTxt
[iNbrOfColumns
]);
377 DBG_DEC_C(iNbrOfColumns
!= pRowInfo
->ucNumberOfColumns
,
379 DBG_DEC_C(iNbrOfColumns
!= pRowInfo
->ucNumberOfColumns
,
380 pRowInfo
->ucNumberOfColumns
);
381 if (iNbrOfColumns
!= pRowInfo
->ucNumberOfColumns
) {
382 werr(0, "Skipping an unmatched table row");
383 /* Clean up before you leave */
384 szLine
= xfree(szLine
);
389 /* Print a table row line */
392 *pcTxt
++ = TABLE_SEPARATOR_CHAR
;
393 for (iIndex
= 0; iIndex
< iNbrOfColumns
; iIndex
++) {
395 iTwips2MilliPoints(pRowInfo
->asColumnWidth
[iIndex
]) /
397 fail(iColumnWidth
< 0);
398 if (iColumnWidth
< 1) {
399 /* Minimum column width */
401 } else if (iColumnWidth
> 1) {
402 /* Room for the TABLE_SEPARATOR_CHAR */
405 NO_DBG_DEC(iColumnWidth
);
406 /* Compute the length of the text for a column */
407 if (aszColTxt
[iIndex
] == NULL
) {
410 pcTmp
= strchr(aszColTxt
[iIndex
], '\n');
415 pcTmp
- aszColTxt
[iIndex
] + 1;
417 iLen2
= strlen(aszColTxt
[iIndex
]);
418 if (iLen2
> iColumnWidth
) {
419 iLen2
= iColumnWidth
;
421 iLen
= min(iLen1
, iLen2
);
424 fail(iLen
< 0 || iLen
> iColumnWidth
);
426 aszColTxt
[iIndex
][iLen
- 1] == '\n') {
427 aszColTxt
[iIndex
][iLen
- 1] = ' ';
429 if (iLen
== iColumnWidth
&&
430 !isspace(aszColTxt
[iIndex
][iLen
])) {
431 /* Search for a breaking point */
432 for (iTmp
= iLen
- 1; iTmp
>= 0; iTmp
--) {
433 if (isspace(aszColTxt
[iIndex
][iTmp
])) {
434 /* Found a breaking point */
443 aszColTxt
[iIndex
] = NULL
;
445 pcTxt
+= sprintf(pcTxt
,
446 "%.*s", iLen
, aszColTxt
[iIndex
]);
447 aszColTxt
[iIndex
] += iLen
;
448 while (*aszColTxt
[iIndex
] == ' ') {
451 if (*aszColTxt
[iIndex
] != '\0') {
452 /* The row takes more lines */
456 /* Print the filler */
457 for (iTmp
= 0; iTmp
< iColumnWidth
- iLen
; iTmp
++) {
458 *pcTxt
++ = (char)FILLER_CHAR
;
460 *pcTxt
++ = TABLE_SEPARATOR_CHAR
;
463 /* Output the table row line */
466 tRow
.szStorage
= szLine
;
467 tRow
.iNextFree
= pcTxt
- szLine
;
468 tRow
.iStringWidth
= iComputeStringWidth(
473 vString2Diagram(pDiag
, &tRow
);
475 /* Clean up before you leave */
476 szLine
= xfree(szLine
);
477 } /* end of vTableRow2Window */