Imported from antiword-0.33.tar.gz.
[antiword.git] / misc.c
blob7898f513b2a7ac2ebec6a57afbf4272b17241096
1 /*
2 * misc.c
3 * Copyright (C) 1998-2002 A.J. van Os; Released under GPL
5 * Description:
6 * misc. functions
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <time.h>
14 #if defined(__riscos)
15 #include "kernel.h"
16 #include "swis.h"
17 #else
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #endif /* __riscos */
22 #if defined(__dos)
23 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
24 #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
25 #endif /* __dos */
26 #include "antiword.h"
29 #if !defined(__riscos)
31 * szGetHomeDirectory - get the name of the home directory
33 const char *
34 szGetHomeDirectory(void)
36 const char *szHome;
38 #if defined(__vms)
39 #include <unixlib.h>
40 szHome = decc$translate_vms(getenv("HOME"));
41 #else
42 szHome = getenv("HOME");
43 #endif /* __vms */
45 if (szHome == NULL || szHome[0] == '\0') {
46 #if defined(__dos)
47 szHome = "C:";
48 #else
49 werr(0, "I can't find the name of your HOME directory");
50 szHome = "";
51 #endif /* __dos */
53 return szHome;
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.
61 long
62 lGetFilesize(const char *szFilename)
64 #if defined(__riscos)
65 _kernel_swi_regs regs;
66 _kernel_oserror *e;
68 (void)memset(&regs, 0, sizeof(regs));
69 regs.r[0] = 17;
70 regs.r[1] = (int)szFilename;
71 e = _kernel_swi(OS_File, &regs, &regs);
72 if (e != NULL) {
73 werr(0, "Get Filesize error %d: %s",
74 e->errnum, e->errmess);
75 return -1;
77 if (regs.r[0] != 1) {
78 /* It's not a proper file or the file does not exist */
79 return -1;
81 return (long)regs.r[4];
82 #else
83 struct stat tBuffer;
85 if (stat(szFilename, &tBuffer) != 0) {
86 werr(0, "Get Filesize error %d", errno);
87 return -1;
89 if (!S_ISREG(tBuffer.st_mode)) {
90 /* It's not a regular file */
91 return -1;
93 return (long)tBuffer.st_size;
94 #endif /* __riscos */
95 } /* end of lGetFilesize */
97 #if defined(DEBUG)
98 void
99 vPrintBlock(const char *szFile, int iLine,
100 const UCHAR *aucBlock, size_t tLength)
102 int i, j;
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) {
109 return;
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 */
122 void
123 vPrintUnicode(const char *szFile, int iLine, const UCHAR *aucUni, size_t tLen)
125 char *szASCII;
127 fail(tLen % 2 != 0);
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 */
138 BOOL
139 bCheckDoubleLinkedList(output_type *pAnchor)
141 output_type *pCurr, *pLast;
142 int iInList;
144 pLast = pAnchor;
145 iInList = 0;
146 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
147 pLast = pCurr;
148 iInList++;
150 NO_DBG_DEC(iInList);
151 for (pCurr = pLast; pCurr != NULL; pCurr = pCurr->pPrev) {
152 pLast = pCurr;
153 iInList--;
155 DBG_DEC_C(iInList != 0, iInList);
156 return pAnchor == pLast && iInList == 0;
157 } /* end of bCheckDoubleLinkedList */
158 #endif /* DEBUG */
161 * bReadBytes
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
166 BOOL
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) {
172 return FALSE;
174 if (fseek(pFile, (long)ulOffset, SEEK_SET) != 0) {
175 return FALSE;
177 if (fread(aucBytes, sizeof(UCHAR), tMemb, pFile) != tMemb) {
178 return FALSE;
180 return TRUE;
181 } /* end of bReadBytes */
184 * bReadBuffer
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
190 BOOL
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;
196 size_t tLen;
198 fail(pFile == NULL);
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);
203 fail(tToRead == 0);
205 for (ulIndex = ulStartBlock;
206 ulIndex != END_OF_CHAIN && tToRead != 0;
207 ulIndex = aulBlockDepot[ulIndex]) {
208 if (ulIndex >= (ULONG)tBlockDepotLen) {
209 DBG_DEC(ulIndex);
210 DBG_DEC(tBlockDepotLen);
211 if (tBlockSize >= BIG_BLOCK_SIZE) {
212 werr(1, "The Big Block Depot is damaged");
213 } else {
214 werr(1, "The Small Block Depot is damaged");
217 if (ulOffset >= (ULONG)tBlockSize) {
218 ulOffset -= tBlockSize;
219 continue;
221 ulBegin = ulDepotOffset(ulIndex, tBlockSize) + ulOffset;
222 tLen = min(tBlockSize - (size_t)ulOffset, tToRead);
223 ulOffset = 0;
224 if (!bReadBytes(aucBuffer, tLen, ulBegin, pFile)) {
225 werr(0, "Read big block 0x%lx not possible", ulBegin);
226 return FALSE;
228 aucBuffer += tLen;
229 tToRead -= tLen;
231 DBG_DEC_C(tToRead != 0, tToRead);
232 return tToRead == 0;
233 } /* end of bReadBuffer */
236 * Translate a Word colornumber into a true color for use in a drawfile
238 * Returns the true color
240 ULONG
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.
274 static int
275 iFindSplit(const char *szString, int iStringLen)
277 int iSplit;
279 iSplit = iStringLen - 1;
280 while (iSplit >= 1) {
281 if (szString[iSplit] == ' ' ||
282 (szString[iSplit] == '-' && szString[iSplit - 1] != ' ')) {
283 return iSplit;
285 iSplit--;
287 return -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
295 output_type *
296 pSplitList(output_type *pAnchor)
298 output_type *pCurr, *pLeftOver;
299 int iIndex;
301 fail(pAnchor == NULL);
303 for (pCurr = pAnchor; pCurr->pNext != NULL; pCurr = pCurr->pNext)
304 ; /* EMPTY */
305 iIndex = -1;
306 for (; pCurr != NULL; pCurr = pCurr->pPrev) {
307 iIndex = iFindSplit(pCurr->szStorage, pCurr->iNextFree);
308 if (iIndex >= 0) {
309 break;
313 if (pCurr == NULL || iIndex < 0) {
314 /* No split, no leftover */
315 return NULL;
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,
334 pLeftOver->tFontRef,
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])) {
346 iIndex--;
348 pCurr->iNextFree = iIndex + 1;
349 pCurr->szStorage[pCurr->iNextFree] = '\0';
350 NO_DBG_MSG(pCurr->szStorage);
351 pCurr->lStringWidth = lComputeStringWidth(
352 pCurr->szStorage,
353 pCurr->iNextFree,
354 pCurr->tFontRef,
355 pCurr->sFontsize);
356 pCurr->pNext = NULL;
357 fail(!bCheckDoubleLinkedList(pAnchor));
359 return pLeftOver;
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)
370 char *outp, *p, *q;
371 UINT uiNextVal, uiValue;
373 fail(szOutput == NULL);
375 uiNumber %= 4000; /* Very high numbers can't be represented */
376 if (uiNumber == 0) {
377 szOutput[0] = '\0';
378 return 0;
381 outp = szOutput;
382 p = bUpperCase ? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
383 uiValue = 1000;
384 for (;;) {
385 while (uiNumber >= uiValue) {
386 *outp++ = *p;
387 uiNumber -= uiValue;
389 if (uiNumber == 0) {
390 *outp = '\0';
391 return outp - szOutput;
393 q = p + 1;
394 uiNextVal = uiValue / (UINT)*q;
395 if ((int)*q == 2) { /* magic */
396 uiNextVal /= (UINT)*(q += 2);
398 if (uiNumber + uiNextVal >= uiValue) {
399 *outp++ = *++q;
400 uiNumber += uiNextVal;
401 } else {
402 p++;
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)
416 char *outp;
417 int iTmp;
419 fail(szOutput == NULL);
421 if (uiNumber == 0) {
422 szOutput[0] = '\0';
423 return 0;
426 outp = szOutput;
427 iTmp = bUpperCase ? 'A': 'a';
428 if (uiNumber <= 26) {
429 uiNumber -= 1;
430 *outp++ = (char)(iTmp + uiNumber);
431 } else if (uiNumber <= 26U + 26U*26U) {
432 uiNumber -= 26 + 1;
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);
441 *outp = '\0';
442 return outp - szOutput;
443 } /* end of iNumber2Alpha */
446 * unincpy - copy a counted Unicode string to an single-byte string
448 char *
449 unincpy(char *s1, const UCHAR *s2, size_t n)
451 char *dest;
452 ULONG ulChar;
453 size_t len;
454 USHORT usUni;
456 for (dest = s1, len = 0; len < n; dest++, len++) {
457 usUni = usGetWord(len * 2, s2);
458 if (usUni == 0) {
459 break;
461 ulChar = ulTranslateCharacters(usUni, 0, 8,
462 encoding_neutral, FALSE);
463 if (ulChar == IGNORE_CHARACTER) {
464 ulChar = (ULONG)'?';
466 *dest = (char)ulChar;
468 for (; len < n; len++) {
469 *dest++ = '\0';
471 return s1;
472 } /* end of unincpy */
475 * unilen - calculate the length of a Unicode string
477 * returns the length in bytes
479 size_t
480 unilen(const UCHAR *s)
482 size_t tLen;
483 USHORT usUni;
485 tLen = 0;
486 for (;;) {
487 usUni = usGetWord(tLen * 2, s);
488 if (usUni == 0) {
489 return tLen;
491 tLen += 2;
493 } /* end of unilen */
496 * szBaseName - get the basename of the given filename
498 const char *
499 szBasename(const char *szFilename)
501 const char *szTmp;
503 fail(szFilename == NULL);
505 if (szFilename == NULL || szFilename[0] == '\0') {
506 return "null";
509 szTmp = strrchr(szFilename, FILE_SEPARATOR[0]);
510 if (szTmp == NULL) {
511 return szFilename;
513 return ++szTmp;
514 } /* end of szBasename */
517 * lComputeLeading - compute the leading
519 * NOTE: the fontsize is given in half points
521 * Returns the leading in drawunits
523 long
524 lComputeLeading(short sFontsize)
526 long lLeading;
528 lLeading = sFontsize * 500L;
529 if (sFontsize < 18) { /* Small text: 112% */
530 lLeading *= 112;
531 } else if (sFontsize < 28) { /* Normal text: 124% */
532 lLeading *= 124;
533 } else if (sFontsize < 48) { /* Small headlines: 104% */
534 lLeading *= 104;
535 } else { /* Large headlines: 100% */
536 lLeading *= 100;
538 lLeading = lMilliPoints2DrawUnits(lLeading);
539 lLeading += 50;
540 lLeading /= 100;
541 return lLeading;
542 } /* end of lComputeLeading */