3 * Copyright (C) 1998-2003 A.J. van Os; Released under GNU GPL
6 * Miscellaneous functions
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 */
57 * szGetAntiwordDirectory - get the name of the Antiword directory
60 szGetAntiwordDirectory(void)
64 return decc$
translate_vms(getenv("ANTIWORDHOME"));
66 return getenv("ANTIWORDHOME");
68 } /* end of szGetHomeDirectory */
69 #endif /* !__riscos */
72 * Get the size of the specified file.
73 * Returns -1 if the file does not exist or is not a proper file.
76 lGetFilesize(const char *szFilename
)
79 _kernel_swi_regs regs
;
82 (void)memset(®s
, 0, sizeof(regs
));
84 regs
.r
[1] = (int)szFilename
;
85 e
= _kernel_swi(OS_File
, ®s
, ®s
);
87 werr(0, "Get Filesize error %d: %s",
88 e
->errnum
, e
->errmess
);
92 /* It's not a proper file or the file does not exist */
95 return (long)regs
.r
[4];
99 if (stat(szFilename
, &tBuffer
) != 0) {
100 werr(0, "Get Filesize error %d", errno
);
103 if (!S_ISREG(tBuffer
.st_mode
)) {
104 /* It's not a regular file */
107 return (long)tBuffer
.st_size
;
108 #endif /* __riscos */
109 } /* end of lGetFilesize */
113 vPrintBlock(const char *szFile
, int iLine
,
114 const UCHAR
*aucBlock
, size_t tLength
)
118 fail(szFile
== NULL
|| iLine
< 0 || aucBlock
== NULL
);
120 fprintf(stderr
, "%s[%3d]:\n", szFile
, iLine
);
121 for (i
= 0; i
< 32; i
++) {
122 if (16 * i
>= (int)tLength
) {
125 fprintf(stderr
, "%03x: ", (unsigned int)(16 * i
));
126 for (j
= 0; j
< 16; j
++) {
127 if (16 * i
+ j
< (int)tLength
) {
128 fprintf(stderr
, "%02x ",
129 (unsigned int)aucBlock
[16 * i
+ j
]);
132 fprintf(stderr
, "\n");
134 } /* end of vPrintBlock */
137 vPrintUnicode(const char *szFile
, int iLine
, const UCHAR
*aucUni
, size_t tLen
)
143 tLen
/= 2; /* Length in bytes to length in characters */
144 szASCII
= xmalloc(tLen
+ 1);
145 (void)unincpy(szASCII
, aucUni
, tLen
);
146 szASCII
[tLen
] = '\0';
147 (void)fprintf(stderr
, "%s[%3d]: %.*s\n",
148 szFile
, iLine
, (int)tLen
, szASCII
);
149 szASCII
= xfree(szASCII
);
150 } /* end of vPrintUnicode */
153 bCheckDoubleLinkedList(output_type
*pAnchor
)
155 output_type
*pCurr
, *pLast
;
160 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
165 for (pCurr
= pLast
; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
169 DBG_DEC_C(iInList
!= 0, iInList
);
170 return pAnchor
== pLast
&& iInList
== 0;
171 } /* end of bCheckDoubleLinkedList */
176 * This function reads the specified number of bytes from the specified file,
177 * starting from the specified offset.
178 * Returns TRUE when successfull, otherwise FALSE
181 bReadBytes(UCHAR
*aucBytes
, size_t tMemb
, ULONG ulOffset
, FILE *pFile
)
183 fail(aucBytes
== NULL
|| pFile
== NULL
|| ulOffset
> (ULONG
)LONG_MAX
);
185 if (ulOffset
> (ULONG
)LONG_MAX
) {
188 if (fseek(pFile
, (long)ulOffset
, SEEK_SET
) != 0) {
191 if (fread(aucBytes
, sizeof(UCHAR
), tMemb
, pFile
) != tMemb
) {
195 } /* end of bReadBytes */
199 * This function fills the specified buffer with the specified number of bytes,
200 * starting at the specified offset within the Big/Small Block Depot.
202 * Returns TRUE when successful, otherwise FALSE
205 bReadBuffer(FILE *pFile
, ULONG ulStartBlock
,
206 const ULONG
*aulBlockDepot
, size_t tBlockDepotLen
, size_t tBlockSize
,
207 UCHAR
*aucBuffer
, ULONG ulOffset
, size_t tToRead
)
209 ULONG ulBegin
, ulIndex
;
213 fail(ulStartBlock
> MAX_BLOCKNUMBER
&& ulStartBlock
!= END_OF_CHAIN
);
214 fail(aulBlockDepot
== NULL
);
215 fail(tBlockSize
!= BIG_BLOCK_SIZE
&& tBlockSize
!= SMALL_BLOCK_SIZE
);
216 fail(aucBuffer
== NULL
);
219 for (ulIndex
= ulStartBlock
;
220 ulIndex
!= END_OF_CHAIN
&& tToRead
!= 0;
221 ulIndex
= aulBlockDepot
[ulIndex
]) {
222 if (ulIndex
>= (ULONG
)tBlockDepotLen
) {
224 DBG_DEC(tBlockDepotLen
);
225 if (tBlockSize
>= BIG_BLOCK_SIZE
) {
226 werr(1, "The Big Block Depot is damaged");
228 werr(1, "The Small Block Depot is damaged");
231 if (ulOffset
>= (ULONG
)tBlockSize
) {
232 ulOffset
-= tBlockSize
;
235 ulBegin
= ulDepotOffset(ulIndex
, tBlockSize
) + ulOffset
;
236 tLen
= min(tBlockSize
- (size_t)ulOffset
, tToRead
);
238 if (!bReadBytes(aucBuffer
, tLen
, ulBegin
, pFile
)) {
239 werr(0, "Read big block 0x%lx not possible", ulBegin
);
245 DBG_DEC_C(tToRead
!= 0, tToRead
);
247 } /* end of bReadBuffer */
250 * Translate a Word colornumber into a true color for use in a drawfile
252 * Returns the true color
255 ulColor2Color(UCHAR ucFontColor
)
257 static const ULONG aulColorTable
[] = {
258 /* 0 */ 0x00000000UL
, /* Automatic */
259 /* 1 */ 0x00000000UL
, /* Black */
260 /* 2 */ 0xff000000UL
, /* Blue */
261 /* 3 */ 0xffff0000UL
, /* Turquoise */
262 /* 4 */ 0x00ff0000UL
, /* Bright Green */
263 /* 5 */ 0xff00ff00UL
, /* Pink */
264 /* 6 */ 0x0000ff00UL
, /* Red */
265 /* 7 */ 0x00ffff00UL
, /* Yellow */
266 /* 8 */ 0xffffff00UL
, /* White */
267 /* 9 */ 0x80000000UL
, /* Dark Blue */
268 /* 10 */ 0x80800000UL
, /* Teal */
269 /* 11 */ 0x00800000UL
, /* Green */
270 /* 12 */ 0x80008000UL
, /* Violet */
271 /* 13 */ 0x00008000UL
, /* Dark Red */
272 /* 14 */ 0x00808000UL
, /* Dark Yellow */
273 /* 15 */ 0x80808000UL
, /* Gray 50% */
274 /* 16 */ 0xc0c0c000UL
, /* Gray 25% */
276 if ((size_t)ucFontColor
>= elementsof(aulColorTable
)) {
277 return aulColorTable
[0];
279 return aulColorTable
[(int)ucFontColor
];
280 } /* end of ulColor2Color */
283 * iFindSplit - find a place to split the string
285 * returns the index of the split character or -1 if no split found.
288 iFindSplit(const char *szString
, size_t tStringLen
)
292 if (tStringLen
== 0) {
295 tSplit
= tStringLen
- 1;
296 while (tSplit
>= 1) {
297 if (szString
[tSplit
] == ' ' ||
298 (szString
[tSplit
] == '-' && szString
[tSplit
- 1] != ' ')) {
304 } /* end of iFindSplit */
307 * pSplitList - split the specified list in a printable part and a leftover part
309 * returns the pointer to the leftover part
312 pSplitList(output_type
*pAnchor
)
314 output_type
*pCurr
, *pLeftOver
;
317 fail(pAnchor
== NULL
);
319 for (pCurr
= pAnchor
; pCurr
->pNext
!= NULL
; pCurr
= pCurr
->pNext
)
322 for (; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
323 iIndex
= iFindSplit(pCurr
->szStorage
, pCurr
->tNextFree
);
329 if (pCurr
== NULL
|| iIndex
< 0) {
330 /* No split, no leftover */
333 /* Split over the iIndex-th character */
334 NO_DBG_MSG("pLeftOver");
335 pLeftOver
= xmalloc(sizeof(*pLeftOver
));
336 fail(pCurr
->tNextFree
< (size_t)iIndex
);
337 pLeftOver
->tStorageSize
= pCurr
->tNextFree
- (size_t)iIndex
;
338 pLeftOver
->szStorage
= xmalloc(pLeftOver
->tStorageSize
);
339 pLeftOver
->tNextFree
= pCurr
->tNextFree
- (size_t)iIndex
- 1;
340 (void)strncpy(pLeftOver
->szStorage
,
341 pCurr
->szStorage
+ iIndex
+ 1, pLeftOver
->tNextFree
);
342 pLeftOver
->szStorage
[pLeftOver
->tNextFree
] = '\0';
343 NO_DBG_MSG(pLeftOver
->szStorage
);
344 pLeftOver
->ucFontColor
= pCurr
->ucFontColor
;
345 pLeftOver
->usFontStyle
= pCurr
->usFontStyle
;
346 pLeftOver
->tFontRef
= pCurr
->tFontRef
;
347 pLeftOver
->usFontSize
= pCurr
->usFontSize
;
348 pLeftOver
->lStringWidth
= lComputeStringWidth(
349 pLeftOver
->szStorage
,
350 pLeftOver
->tNextFree
,
352 pLeftOver
->usFontSize
);
353 pLeftOver
->pPrev
= NULL
;
354 pLeftOver
->pNext
= pCurr
->pNext
;
355 if (pLeftOver
->pNext
!= NULL
) {
356 pLeftOver
->pNext
->pPrev
= pLeftOver
;
358 fail(!bCheckDoubleLinkedList(pLeftOver
));
360 NO_DBG_MSG("pAnchor");
361 NO_DBG_HEX(pCurr
->szStorage
[iIndex
]);
362 while (iIndex
>= 0 && isspace((int)(UCHAR
)pCurr
->szStorage
[iIndex
])) {
365 pCurr
->tNextFree
= (size_t)iIndex
+ 1;
366 pCurr
->szStorage
[pCurr
->tNextFree
] = '\0';
367 NO_DBG_MSG(pCurr
->szStorage
);
368 pCurr
->lStringWidth
= lComputeStringWidth(
374 fail(!bCheckDoubleLinkedList(pAnchor
));
377 } /* end of pSplitList */
380 * tNumber2Roman - convert a number to Roman Numerals
382 * returns the number of characters written
385 tNumber2Roman(UINT uiNumber
, BOOL bUpperCase
, char *szOutput
)
388 UINT uiNextVal
, uiValue
;
390 fail(szOutput
== NULL
);
392 uiNumber
%= 4000; /* Very high numbers can't be represented */
399 p
= bUpperCase
? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
402 while (uiNumber
>= uiValue
) {
408 fail(outp
< szOutput
);
409 return (size_t)(outp
- szOutput
);
412 uiNextVal
= uiValue
/ (UINT
)(UCHAR
)*q
;
413 if ((int)*q
== 2) { /* magic */
414 uiNextVal
/= (UINT
)(UCHAR
)*(q
+= 2);
416 if (uiNumber
+ uiNextVal
>= uiValue
) {
418 uiNumber
+= uiNextVal
;
421 uiValue
/= (UINT
)(UCHAR
)(*p
++);
424 } /* end of tNumber2Roman */
427 * iNumber2Alpha - convert a number to alphabetic "numbers"
429 * returns the number of characters written
432 tNumber2Alpha(UINT uiNumber
, BOOL bUpperCase
, char *szOutput
)
437 fail(szOutput
== NULL
);
445 uiTmp
= (UINT
)(bUpperCase
? 'A': 'a');
446 if (uiNumber
<= 26) {
448 *outp
++ = (char)(uiTmp
+ uiNumber
);
449 } else if (uiNumber
<= 26U + 26U*26U) {
451 *outp
++ = (char)(uiTmp
+ uiNumber
/ 26);
452 *outp
++ = (char)(uiTmp
+ uiNumber
% 26);
453 } else if (uiNumber
<= 26U + 26U*26U + 26U*26U*26U) {
454 uiNumber
-= 26 + 26*26 + 1;
455 *outp
++ = (char)(uiTmp
+ uiNumber
/ (26*26));
456 *outp
++ = (char)(uiTmp
+ uiNumber
/ 26 % 26);
457 *outp
++ = (char)(uiTmp
+ uiNumber
% 26);
460 fail(outp
< szOutput
);
461 return (size_t)(outp
- szOutput
);
462 } /* end of tNumber2Alpha */
465 * unincpy - copy a counted Unicode string to an single-byte string
468 unincpy(char *s1
, const UCHAR
*s2
, size_t n
)
475 for (dest
= s1
, tLen
= 0; tLen
< n
; dest
++, tLen
++) {
476 usUni
= usGetWord(tLen
* 2, s2
);
480 ulChar
= ulTranslateCharacters(usUni
, 0, 8,
481 conversion_unknown
, encoding_neutral
, FALSE
);
482 if (ulChar
== IGNORE_CHARACTER
) {
485 *dest
= (char)ulChar
;
487 for (; tLen
< n
; tLen
++) {
491 } /* end of unincpy */
494 * unilen - calculate the length of a Unicode string
496 * returns the length in bytes
499 unilen(const UCHAR
*s
)
506 usUni
= usGetWord(tLen
, s
);
512 } /* end of unilen */
515 * szBaseName - get the basename of the specified filename
518 szBasename(const char *szFilename
)
522 fail(szFilename
== NULL
);
524 if (szFilename
== NULL
|| szFilename
[0] == '\0') {
528 szTmp
= strrchr(szFilename
, FILE_SEPARATOR
[0]);
533 } /* end of szBasename */
536 * lComputeLeading - compute the leading
538 * NOTE: the fontsize is specified in half points
540 * Returns the leading in drawunits
543 lComputeLeading(USHORT usFontSize
)
547 lLeading
= (long)usFontSize
* 500L;
548 if (usFontSize
< 18) { /* Small text: 112% */
550 } else if (usFontSize
< 28) { /* Normal text: 124% */
552 } else if (usFontSize
< 48) { /* Small headlines: 104% */
554 } else { /* Large headlines: 100% */
557 lLeading
= lMilliPoints2DrawUnits(lLeading
);
561 } /* end of lComputeLeading */
564 * Convert a UCS character to an UTF-8 string
566 * Returns the string length of the result
569 tUcs2Utf8(ULONG ulChar
, char *szResult
, size_t tMaxResultLen
)
571 if (szResult
== NULL
|| tMaxResultLen
== 0) {
575 if (ulChar
< 0x80 && tMaxResultLen
>= 2) {
576 szResult
[0] = (char)ulChar
;
580 if (ulChar
< 0x800 && tMaxResultLen
>= 3) {
581 szResult
[0] = (char)(0xc0 | ulChar
>> 6);
582 szResult
[1] = (char)(0x80 | (ulChar
& 0x3f));
586 if (ulChar
< 0x10000 && tMaxResultLen
>= 4) {
587 szResult
[0] = (char)(0xe0 | ulChar
>> 12);
588 szResult
[1] = (char)(0x80 | (ulChar
>> 6 & 0x3f));
589 szResult
[2] = (char)(0x80 | (ulChar
& 0x3f));
593 if (ulChar
< 0x200000 && tMaxResultLen
>= 5) {
594 szResult
[0] = (char)(0xf0 | ulChar
>> 18);
595 szResult
[1] = (char)(0x80 | (ulChar
>> 12 & 0x3f));
596 szResult
[2] = (char)(0x80 | (ulChar
>> 6 & 0x3f));
597 szResult
[3] = (char)(0x80 | (ulChar
& 0x3f));
603 } /* end of tUcs2Utf8 */
606 * vGetBulletValue - get the bullet value for the conversing type and encoding
609 vGetBulletValue(conversion_type eConversionType
, encoding_type eEncoding
,
610 char *szResult
, size_t tMaxResultLen
)
612 fail(szResult
== NULL
);
613 fail(tMaxResultLen
< 2);
615 if (eEncoding
== encoding_utf8
) {
616 (void)tUcs2Utf8(UNICODE_BULLET
, szResult
, tMaxResultLen
);
617 } else if (eEncoding
== encoding_iso_8859_1
&&
618 eConversionType
== conversion_ps
) {
619 szResult
[0] = OUR_BULLET_PS
;
622 szResult
[0] = OUR_BULLET_TEXT
;
625 } /* end of vGetBulletValue */
628 * bAllZero - are all bytes zero?
631 bAllZero(const UCHAR
*aucBytes
, size_t tLength
)
635 if (aucBytes
== NULL
|| tLength
== 0) {
639 for (tIndex
= 0; tIndex
< tLength
; tIndex
++) {
640 if (aucBytes
[tIndex
] != 0) {
645 } /* end of bAllZero */