3 * Copyright (C) 1998-2002 A.J. van Os; Released under GPL
19 #include <sys/types.h>
23 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
24 #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
29 #if !defined(__riscos)
31 * szGetHomeDirectory - get the name of the home directory
34 szGetHomeDirectory(void)
40 szHome
= decc$
translate_vms(getenv("HOME"));
42 szHome
= getenv("HOME");
45 if (szHome
== NULL
|| szHome
[0] == '\0') {
49 werr(0, "I can't find the name of your HOME directory");
54 } /* end of szGetHomeDirectory */
55 #endif /* !__riscos */
58 * Get the size of the given file.
59 * Returns -1 if the file does not exist or is not a proper file.
62 lGetFilesize(const char *szFilename
)
65 _kernel_swi_regs regs
;
68 (void)memset(®s
, 0, sizeof(regs
));
70 regs
.r
[1] = (int)szFilename
;
71 e
= _kernel_swi(OS_File
, ®s
, ®s
);
73 werr(0, "Get Filesize error %d: %s",
74 e
->errnum
, e
->errmess
);
78 /* It's not a proper file or the file does not exist */
81 return (long)regs
.r
[4];
85 if (stat(szFilename
, &tBuffer
) != 0) {
86 werr(0, "Get Filesize error %d", errno
);
89 if (!S_ISREG(tBuffer
.st_mode
)) {
90 /* It's not a regular file */
93 return (long)tBuffer
.st_size
;
95 } /* end of lGetFilesize */
99 vPrintBlock(const char *szFile
, int iLine
,
100 const UCHAR
*aucBlock
, size_t tLength
)
104 fail(szFile
== NULL
|| iLine
< 0 || aucBlock
== NULL
);
106 fprintf(stderr
, "%s[%3d]:\n", szFile
, iLine
);
107 for (i
= 0; i
< 32; i
++) {
108 if (16 * i
>= (int)tLength
) {
111 fprintf(stderr
, "%03x: ", (unsigned int)(16 * i
));
112 for (j
= 0; j
< 16; j
++) {
113 if (16 * i
+ j
< (int)tLength
) {
114 fprintf(stderr
, "%02x ",
115 (unsigned int)aucBlock
[16 * i
+ j
]);
118 fprintf(stderr
, "\n");
120 } /* end of vPrintBlock */
123 vPrintUnicode(const char *szFile
, int iLine
, const UCHAR
*aucUni
, size_t tLen
)
129 tLen
/= 2; /* Length in bytes to length in characters */
130 szASCII
= xmalloc(tLen
+ 1);
131 (void)unincpy(szASCII
, aucUni
, tLen
);
132 szASCII
[tLen
] = '\0';
133 (void)fprintf(stderr
, "%s[%3d]: %.*s\n",
134 szFile
, iLine
, (int)tLen
, szASCII
);
135 szASCII
= xfree(szASCII
);
136 } /* end of vPrintUnicode */
139 bCheckDoubleLinkedList(output_type
*pAnchor
)
141 output_type
*pCurr
, *pLast
;
146 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
151 for (pCurr
= pLast
; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
155 DBG_DEC_C(iInList
!= 0, iInList
);
156 return pAnchor
== pLast
&& iInList
== 0;
157 } /* end of bCheckDoubleLinkedList */
162 * This function reads the given number of bytes from the given file,
163 * starting from the given offset.
164 * Returns TRUE when successfull, otherwise FALSE
167 bReadBytes(UCHAR
*aucBytes
, size_t tMemb
, ULONG ulOffset
, FILE *pFile
)
169 fail(aucBytes
== NULL
|| pFile
== NULL
|| ulOffset
> (ULONG
)LONG_MAX
);
171 if (ulOffset
> (ULONG
)LONG_MAX
) {
174 if (fseek(pFile
, (long)ulOffset
, SEEK_SET
) != 0) {
177 if (fread(aucBytes
, sizeof(UCHAR
), tMemb
, pFile
) != tMemb
) {
181 } /* end of bReadBytes */
185 * This function fills the given buffer with the given number of bytes,
186 * starting at the given offset within the Big/Small Block Depot.
188 * Returns TRUE when successful, otherwise FALSE
191 bReadBuffer(FILE *pFile
, ULONG ulStartBlock
,
192 const ULONG
*aulBlockDepot
, size_t tBlockDepotLen
, size_t tBlockSize
,
193 UCHAR
*aucBuffer
, ULONG ulOffset
, size_t tToRead
)
195 ULONG ulBegin
, ulIndex
;
199 fail(ulStartBlock
> MAX_BLOCKNUMBER
&& ulStartBlock
!= END_OF_CHAIN
);
200 fail(aulBlockDepot
== NULL
);
201 fail(tBlockSize
!= BIG_BLOCK_SIZE
&& tBlockSize
!= SMALL_BLOCK_SIZE
);
202 fail(aucBuffer
== NULL
);
205 for (ulIndex
= ulStartBlock
;
206 ulIndex
!= END_OF_CHAIN
&& tToRead
!= 0;
207 ulIndex
= aulBlockDepot
[ulIndex
]) {
208 if (ulIndex
>= (ULONG
)tBlockDepotLen
) {
210 DBG_DEC(tBlockDepotLen
);
211 if (tBlockSize
>= BIG_BLOCK_SIZE
) {
212 werr(1, "The Big Block Depot is damaged");
214 werr(1, "The Small Block Depot is damaged");
217 if (ulOffset
>= (ULONG
)tBlockSize
) {
218 ulOffset
-= tBlockSize
;
221 ulBegin
= ulDepotOffset(ulIndex
, tBlockSize
) + ulOffset
;
222 tLen
= min(tBlockSize
- (size_t)ulOffset
, tToRead
);
224 if (!bReadBytes(aucBuffer
, tLen
, ulBegin
, pFile
)) {
225 werr(0, "Read big block 0x%lx not possible", ulBegin
);
231 DBG_DEC_C(tToRead
!= 0, tToRead
);
233 } /* end of bReadBuffer */
236 * Translate a Word colornumber into a true color for use in a drawfile
238 * Returns the true color
241 ulColor2Color(int iWordColor
)
243 static const ULONG aulColorTable
[] = {
244 /* 0 */ 0x00000000UL
, /* Automatic */
245 /* 1 */ 0x00000000UL
, /* Black */
246 /* 2 */ 0xff000000UL
, /* Blue */
247 /* 3 */ 0xffff0000UL
, /* Turquoise */
248 /* 4 */ 0x00ff0000UL
, /* Bright Green */
249 /* 5 */ 0xff00ff00UL
, /* Pink */
250 /* 6 */ 0x0000ff00UL
, /* Red */
251 /* 7 */ 0x00ffff00UL
, /* Yellow */
252 /* 8 */ 0xffffff00UL
, /* White */
253 /* 9 */ 0x80000000UL
, /* Dark Blue */
254 /* 10 */ 0x80800000UL
, /* Teal */
255 /* 11 */ 0x00800000UL
, /* Green */
256 /* 12 */ 0x80008000UL
, /* Violet */
257 /* 13 */ 0x00008000UL
, /* Dark Red */
258 /* 14 */ 0x00808000UL
, /* Dark Yellow */
259 /* 15 */ 0x80808000UL
, /* Gray 50% */
260 /* 16 */ 0xc0c0c000UL
, /* Gray 25% */
262 if (iWordColor
< 0 ||
263 iWordColor
>= (int)elementsof(aulColorTable
)) {
264 return aulColorTable
[0];
266 return aulColorTable
[iWordColor
];
267 } /* end of ulColor2Color */
270 * iFindSplit - find a place to split the string
272 * returns the index of the split character or -1 if no split found.
275 iFindSplit(const char *szString
, int iStringLen
)
279 iSplit
= iStringLen
- 1;
280 while (iSplit
>= 1) {
281 if (szString
[iSplit
] == ' ' ||
282 (szString
[iSplit
] == '-' && szString
[iSplit
- 1] != ' ')) {
288 } /* end of iFindSplit */
291 * pSplitList - split the given list in a printable part and a leftover part
293 * returns the pointer to the leftover part
296 pSplitList(output_type
*pAnchor
)
298 output_type
*pCurr
, *pLeftOver
;
301 fail(pAnchor
== NULL
);
303 for (pCurr
= pAnchor
; pCurr
->pNext
!= NULL
; pCurr
= pCurr
->pNext
)
306 for (; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
307 iIndex
= iFindSplit(pCurr
->szStorage
, pCurr
->iNextFree
);
313 if (pCurr
== NULL
|| iIndex
< 0) {
314 /* No split, no leftover */
317 /* Split over the iIndex-th character */
318 NO_DBG_MSG("pLeftOver");
319 pLeftOver
= xmalloc(sizeof(*pLeftOver
));
320 pLeftOver
->tStorageSize
= (size_t)(pCurr
->iNextFree
- iIndex
);
321 pLeftOver
->szStorage
= xmalloc(pLeftOver
->tStorageSize
);
322 pLeftOver
->iNextFree
= pCurr
->iNextFree
- iIndex
- 1;
323 (void)strncpy(pLeftOver
->szStorage
,
324 pCurr
->szStorage
+ iIndex
+ 1, (size_t)pLeftOver
->iNextFree
);
325 pLeftOver
->szStorage
[pLeftOver
->iNextFree
] = '\0';
326 NO_DBG_MSG(pLeftOver
->szStorage
);
327 pLeftOver
->iColor
= pCurr
->iColor
;
328 pLeftOver
->ucFontstyle
= pCurr
->ucFontstyle
;
329 pLeftOver
->tFontRef
= pCurr
->tFontRef
;
330 pLeftOver
->sFontsize
= pCurr
->sFontsize
;
331 pLeftOver
->lStringWidth
= lComputeStringWidth(
332 pLeftOver
->szStorage
,
333 pLeftOver
->iNextFree
,
335 pLeftOver
->sFontsize
);
336 pLeftOver
->pPrev
= NULL
;
337 pLeftOver
->pNext
= pCurr
->pNext
;
338 if (pLeftOver
->pNext
!= NULL
) {
339 pLeftOver
->pNext
->pPrev
= pLeftOver
;
341 fail(!bCheckDoubleLinkedList(pLeftOver
));
343 NO_DBG_MSG("pAnchor");
344 NO_DBG_HEX(pCurr
->szStorage
[iIndex
]);
345 while (iIndex
>= 0 && isspace((int)pCurr
->szStorage
[iIndex
])) {
348 pCurr
->iNextFree
= iIndex
+ 1;
349 pCurr
->szStorage
[pCurr
->iNextFree
] = '\0';
350 NO_DBG_MSG(pCurr
->szStorage
);
351 pCurr
->lStringWidth
= lComputeStringWidth(
357 fail(!bCheckDoubleLinkedList(pAnchor
));
360 } /* end of pSplitList */
363 * iNumber2Roman - convert a number to Roman Numerals
365 * returns the number of characters written
368 iNumber2Roman(UINT uiNumber
, BOOL bUpperCase
, char *szOutput
)
371 UINT uiNextVal
, uiValue
;
373 fail(szOutput
== NULL
);
375 uiNumber
%= 4000; /* Very high numbers can't be represented */
382 p
= bUpperCase
? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
385 while (uiNumber
>= uiValue
) {
391 return outp
- szOutput
;
394 uiNextVal
= uiValue
/ (UINT
)*q
;
395 if ((int)*q
== 2) { /* magic */
396 uiNextVal
/= (UINT
)*(q
+= 2);
398 if (uiNumber
+ uiNextVal
>= uiValue
) {
400 uiNumber
+= uiNextVal
;
403 uiValue
/= (UINT
)(*p
++);
406 } /* end of iNumber2Roman */
409 * iNumber2Alpha - convert a number to alphabetic "numbers"
411 * returns the number of characters written
414 iNumber2Alpha(UINT uiNumber
, BOOL bUpperCase
, char *szOutput
)
419 fail(szOutput
== NULL
);
427 iTmp
= bUpperCase
? 'A': 'a';
428 if (uiNumber
<= 26) {
430 *outp
++ = (char)(iTmp
+ uiNumber
);
431 } else if (uiNumber
<= 26U + 26U*26U) {
433 *outp
++ = (char)(iTmp
+ uiNumber
/ 26);
434 *outp
++ = (char)(iTmp
+ uiNumber
% 26);
435 } else if (uiNumber
<= 26U + 26U*26U + 26U*26U*26U) {
436 uiNumber
-= 26 + 26*26 + 1;
437 *outp
++ = (char)(iTmp
+ uiNumber
/ (26*26));
438 *outp
++ = (char)(iTmp
+ uiNumber
/ 26 % 26);
439 *outp
++ = (char)(iTmp
+ uiNumber
% 26);
442 return outp
- szOutput
;
443 } /* end of iNumber2Alpha */
446 * unincpy - copy a counted Unicode string to an single-byte string
449 unincpy(char *s1
, const UCHAR
*s2
, size_t n
)
456 for (dest
= s1
, len
= 0; len
< n
; dest
++, len
++) {
457 usUni
= usGetWord(len
* 2, s2
);
461 ulChar
= ulTranslateCharacters(usUni
, 0, 8,
462 encoding_neutral
, FALSE
);
463 if (ulChar
== IGNORE_CHARACTER
) {
466 *dest
= (char)ulChar
;
468 for (; len
< n
; len
++) {
472 } /* end of unincpy */
475 * unilen - calculate the length of a Unicode string
477 * returns the length in bytes
480 unilen(const UCHAR
*s
)
487 usUni
= usGetWord(tLen
* 2, s
);
493 } /* end of unilen */
496 * szBaseName - get the basename of the given filename
499 szBasename(const char *szFilename
)
503 fail(szFilename
== NULL
);
505 if (szFilename
== NULL
|| szFilename
[0] == '\0') {
509 szTmp
= strrchr(szFilename
, FILE_SEPARATOR
[0]);
514 } /* end of szBasename */
517 * lComputeLeading - compute the leading
519 * NOTE: the fontsize is given in half points
521 * Returns the leading in drawunits
524 lComputeLeading(short sFontsize
)
528 lLeading
= sFontsize
* 500L;
529 if (sFontsize
< 18) { /* Small text: 112% */
531 } else if (sFontsize
< 28) { /* Normal text: 124% */
533 } else if (sFontsize
< 48) { /* Small headlines: 104% */
535 } else { /* Large headlines: 100% */
538 lLeading
= lMilliPoints2DrawUnits(lLeading
);
542 } /* end of lComputeLeading */