Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * misc.c
3
 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
4
 *
5
 * Description:
6
 * Miscellaneous functions
7
 */
8
 
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 "DeskLib:SWI.h"
16
#else
17
#include <errno.h>
18
#include <sys/types.h>
19
#include <sys/stat.h>
20
#endif /* __riscos */
21
#if !defined(S_ISREG)
22
#define S_ISREG(x)	(((x) & S_IFMT) == S_IFREG)
23
#endif /* !S_ISREG */
24
#include "antiword.h"
25
#if defined(__vms)
26
#include <unixlib.h>
27
#endif
28
 
29
#if !defined(__riscos)
30
/*
31
 * szGetHomeDirectory - get the name of the home directory
32
 */
33
const char *
34
szGetHomeDirectory(void)
35
{
36
	const char	*szHome;
37
 
38
#if defined(__vms)
39
	szHome = decc$translate_vms(getenv("HOME"));
40
#elif defined(__Plan9__)
41
	szHome = getenv("home");
42
#else
43
	szHome = getenv("HOME");
44
#endif /* __vms */
45
 
46
	if (szHome == NULL || szHome[0] == '\0') {
47
#if defined(N_PLAT_NLM)
48
		szHome = "SYS:";
49
#elif defined(__dos)
50
		szHome = "C:";
51
#else
52
		werr(0, "I can't find the name of your HOME directory");
53
		szHome = "";
54
#endif /* __dos */
55
	}
56
	return szHome;
57
} /* end of szGetHomeDirectory */
58
 
59
/*
60
 * szGetAntiwordDirectory - get the name of the Antiword directory
61
 */
62
const char *
63
szGetAntiwordDirectory(void)
64
{
65
#if defined(__vms)
66
	return decc$translate_vms(getenv("ANTIWORDHOME"));
67
#else
68
	return getenv("ANTIWORDHOME");
69
#endif /* __vms */
70
} /* end of szGetAntiwordDirectory */
71
#endif /* !__riscos */
72
 
73
/*
74
 * Get the size of the specified file.
75
 * Returns -1 if the file does not exist or is not a proper file.
76
 */
77
long
78
lGetFilesize(const char *szFilename)
79
{
80
#if defined(__riscos)
81
	os_error	*e;
82
	int	iType, iSize;
83
 
84
	e = SWI(2, 5, SWI_OS_File | XOS_Bit,
85
		17, szFilename,
86
		&iType, NULL, NULL, NULL, &iSize);
87
	if (e != NULL) {
88
		werr(0, "Get Filesize error %d: %s",
89
			e->errnum, e->errmess);
90
		return -1;
91
	}
92
	if (iType != 1) {
93
		/* It's not a proper file or the file does not exist */
94
		return -1;
95
	}
96
	return (long)iSize;
97
#else
98
	struct stat	tBuffer;
99
 
100
	errno = 0;
101
	if (stat(szFilename, &tBuffer) != 0) {
102
		werr(0, "Get Filesize error %d", errno);
103
		return -1;
104
	}
105
	if (!S_ISREG(tBuffer.st_mode)) {
106
		/* It's not a regular file */
107
		return -1;
108
	}
109
	return (long)tBuffer.st_size;
110
#endif /* __riscos */
111
} /* end of lGetFilesize */
112
 
113
#if defined(DEBUG)
114
void
115
vPrintBlock(const char	*szFile, int iLine,
116
		const UCHAR *aucBlock, size_t tLength)
117
{
118
	int i, j;
119
 
120
	fail(szFile == NULL || iLine < 0 || aucBlock == NULL);
121
 
122
	fprintf(stderr, "%s[%3d]:\n", szFile, iLine);
123
	for (i = 0; i < 32; i++) {
124
		if (16 * i >= (int)tLength) {
125
			return;
126
		}
127
		fprintf(stderr, "%03x: ", (unsigned int)(16 * i));
128
		for (j = 0; j < 16; j++) {
129
			if (16 * i + j < (int)tLength) {
130
				fprintf(stderr, "%02x ",
131
					(unsigned int)aucBlock[16 * i + j]);
132
			}
133
		}
134
		fprintf(stderr, "\n");
135
	}
136
} /* end of vPrintBlock */
137
 
138
void
139
vPrintUnicode(const char *szFile, int iLine, const UCHAR *aucUni, size_t tLen)
140
{
141
	char	*szASCII;
142
 
143
	fail(tLen % 2 != 0);
144
 
145
	tLen /= 2;	/* Length in bytes to length in characters */
146
	szASCII = xmalloc(tLen + 1);
147
	(void)unincpy(szASCII, aucUni, tLen);
148
	szASCII[tLen] = '\0';
149
	(void)fprintf(stderr, "%s[%3d]: %.*s\n",
150
				szFile, iLine, (int)tLen, szASCII);
151
	szASCII = xfree(szASCII);
152
} /* end of vPrintUnicode */
153
 
154
BOOL
155
bCheckDoubleLinkedList(output_type *pAnchor)
156
{
157
	output_type	*pCurr, *pLast;
158
	int		iInList;
159
 
160
	pLast = pAnchor;
161
	iInList = 0;
162
	for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
163
		pLast = pCurr;
164
		iInList++;
165
	}
166
	NO_DBG_DEC(iInList);
167
	for (pCurr = pLast; pCurr != NULL; pCurr = pCurr->pPrev) {
168
		pLast = pCurr;
169
		iInList--;
170
	}
171
	DBG_DEC_C(iInList != 0, iInList);
172
	return pAnchor == pLast && iInList == 0;
173
} /* end of bCheckDoubleLinkedList */
174
#endif /* DEBUG */
175
 
176
/*
177
 * bReadBytes
178
 * This function reads the specified number of bytes from the specified file,
179
 * starting from the specified offset.
180
 * Returns TRUE when successfull, otherwise FALSE
181
 */
182
BOOL
183
bReadBytes(UCHAR *aucBytes, size_t tMemb, ULONG ulOffset, FILE *pFile)
184
{
185
	fail(aucBytes == NULL || pFile == NULL || ulOffset > (ULONG)LONG_MAX);
186
 
187
	if (ulOffset > (ULONG)LONG_MAX) {
188
		return FALSE;
189
	}
190
	if (fseek(pFile, (long)ulOffset, SEEK_SET) != 0) {
191
		return FALSE;
192
	}
193
	if (fread(aucBytes, sizeof(UCHAR), tMemb, pFile) != tMemb) {
194
		return FALSE;
195
	}
196
	return TRUE;
197
} /* end of bReadBytes */
198
 
199
/*
200
 * bReadBuffer
201
 * This function fills the specified buffer with the specified number of bytes,
202
 * starting at the specified offset within the Big/Small Block Depot.
203
 *
204
 * Returns TRUE when successful, otherwise FALSE
205
 */
206
BOOL
207
bReadBuffer(FILE *pFile, ULONG ulStartBlock,
208
	const ULONG *aulBlockDepot, size_t tBlockDepotLen, size_t tBlockSize,
209
	UCHAR *aucBuffer, ULONG ulOffset, size_t tToRead)
210
{
211
	ULONG	ulBegin, ulIndex;
212
	size_t	tLen;
213
 
214
	fail(pFile == NULL);
215
	fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
216
	fail(aulBlockDepot == NULL);
217
	fail(tBlockSize != BIG_BLOCK_SIZE && tBlockSize != SMALL_BLOCK_SIZE);
218
	fail(aucBuffer == NULL);
219
	fail(tToRead == 0);
220
 
221
	for (ulIndex = ulStartBlock;
222
	     ulIndex != END_OF_CHAIN && tToRead != 0;
223
	     ulIndex = aulBlockDepot[ulIndex]) {
224
		if (ulIndex >= (ULONG)tBlockDepotLen) {
225
			DBG_DEC(ulIndex);
226
			DBG_DEC(tBlockDepotLen);
227
			if (tBlockSize >= BIG_BLOCK_SIZE) {
228
				werr(1, "The Big Block Depot is damaged");
229
			} else {
230
				werr(1, "The Small Block Depot is damaged");
231
			}
232
		}
233
		if (ulOffset >= (ULONG)tBlockSize) {
234
			ulOffset -= tBlockSize;
235
			continue;
236
		}
237
		ulBegin = ulDepotOffset(ulIndex, tBlockSize) + ulOffset;
238
		tLen = min(tBlockSize - (size_t)ulOffset, tToRead);
239
		ulOffset = 0;
240
		if (!bReadBytes(aucBuffer, tLen, ulBegin, pFile)) {
241
			werr(0, "Read big block 0x%lx not possible", ulBegin);
242
			return FALSE;
243
		}
244
		aucBuffer += tLen;
245
		tToRead -= tLen;
246
	}
247
	DBG_DEC_C(tToRead != 0, tToRead);
248
	return tToRead == 0;
249
} /* end of bReadBuffer */
250
 
251
/*
252
 * Convert a Word colornumber into a true color for use in a drawfile
253
 *
254
 * Returns the true color
255
 */
256
ULONG
257
ulColor2Color(UCHAR ucFontColor)
258
{
259
	static const ULONG	aulColorTable[] = {
260
		/*  0 */	0x00000000UL,	/* Automatic */
261
		/*  1 */	0x00000000UL,	/* Black */
262
		/*  2 */	0xff000000UL,	/* Blue */
263
		/*  3 */	0xffff0000UL,	/* Turquoise */
264
		/*  4 */	0x00ff0000UL,	/* Bright Green */
265
		/*  5 */	0xff00ff00UL,	/* Pink */
266
		/*  6 */	0x0000ff00UL,	/* Red */
267
		/*  7 */	0x00ffff00UL,	/* Yellow */
268
		/*  8 */	0xffffff00UL,	/* White */
269
		/*  9 */	0x80000000UL,	/* Dark Blue */
270
		/* 10 */	0x80800000UL,	/* Teal */
271
		/* 11 */	0x00800000UL,	/* Green */
272
		/* 12 */	0x80008000UL,	/* Violet */
273
		/* 13 */	0x00008000UL,	/* Dark Red */
274
		/* 14 */	0x00808000UL,	/* Dark Yellow */
275
		/* 15 */	0x80808000UL,	/* Gray 50% */
276
		/* 16 */	0xc0c0c000UL,	/* Gray 25% */
277
	};
278
	if ((size_t)ucFontColor >= elementsof(aulColorTable)) {
279
		return aulColorTable[0];
280
	}
281
	return aulColorTable[(int)ucFontColor];
282
} /* end of ulColor2Color */
283
 
284
/*
285
 * iFindSplit - find a place to split the string
286
 *
287
 * returns the index of the split character or -1 if no split found.
288
 */
289
static int
290
iFindSplit(const char *szString, size_t tStringLen)
291
{
292
	size_t	tSplit;
293
 
294
	if (tStringLen == 0) {
295
		return -1;
296
	}
297
	tSplit = tStringLen - 1;
298
	while (tSplit >= 1) {
299
		if (szString[tSplit] == ' ' ||
300
		    (szString[tSplit] == '-' && szString[tSplit - 1] != ' ')) {
301
			return (int)tSplit;
302
		}
303
		tSplit--;
304
	}
305
	return -1;
306
} /* end of iFindSplit */
307
 
308
/*
309
 * pSplitList - split the specified list in a printable part and a leftover part
310
 *
311
 * returns the pointer to the leftover part
312
 */
313
output_type *
314
pSplitList(output_type *pAnchor)
315
{
316
	output_type	*pCurr, *pLeftOver;
317
	int		iIndex;
318
 
319
 	fail(pAnchor == NULL);
320
 
321
	for (pCurr = pAnchor; pCurr->pNext != NULL; pCurr = pCurr->pNext)
322
		;	/* EMPTY */
323
	iIndex = -1;
324
	for (; pCurr != NULL; pCurr = pCurr->pPrev) {
325
		iIndex = iFindSplit(pCurr->szStorage, pCurr->tNextFree);
326
		if (iIndex >= 0) {
327
			break;
328
		}
329
	}
330
 
331
	if (pCurr == NULL || iIndex < 0) {
332
		/* No split, no leftover */
333
		return NULL;
334
	}
335
	/* Split over the iIndex-th character */
336
	NO_DBG_MSG("pLeftOver");
337
	pLeftOver = xmalloc(sizeof(*pLeftOver));
338
	fail(pCurr->tNextFree < (size_t)iIndex);
339
	pLeftOver->tStorageSize = pCurr->tNextFree - (size_t)iIndex;
340
	pLeftOver->szStorage = xmalloc(pLeftOver->tStorageSize);
341
	pLeftOver->tNextFree = pCurr->tNextFree - (size_t)iIndex - 1;
342
	(void)strncpy(pLeftOver->szStorage,
343
		pCurr->szStorage + iIndex + 1, pLeftOver->tNextFree);
344
	pLeftOver->szStorage[pLeftOver->tNextFree] = '\0';
345
	NO_DBG_MSG(pLeftOver->szStorage);
346
	pLeftOver->ucFontColor = pCurr->ucFontColor;
347
	pLeftOver->usFontStyle = pCurr->usFontStyle;
348
	pLeftOver->tFontRef = pCurr->tFontRef;
349
	pLeftOver->usFontSize = pCurr->usFontSize;
350
	pLeftOver->lStringWidth = lComputeStringWidth(
351
					pLeftOver->szStorage,
352
					pLeftOver->tNextFree,
353
					pLeftOver->tFontRef,
354
					pLeftOver->usFontSize);
355
	pLeftOver->pPrev = NULL;
356
	pLeftOver->pNext = pCurr->pNext;
357
	if (pLeftOver->pNext != NULL) {
358
		pLeftOver->pNext->pPrev = pLeftOver;
359
	}
360
	fail(!bCheckDoubleLinkedList(pLeftOver));
361
 
362
	NO_DBG_MSG("pAnchor");
363
	NO_DBG_HEX(pCurr->szStorage[iIndex]);
364
	while (iIndex >= 0 && isspace((int)(UCHAR)pCurr->szStorage[iIndex])) {
365
		iIndex--;
366
	}
367
	pCurr->tNextFree = (size_t)iIndex + 1;
368
	pCurr->szStorage[pCurr->tNextFree] = '\0';
369
	NO_DBG_MSG(pCurr->szStorage);
370
	pCurr->lStringWidth = lComputeStringWidth(
371
					pCurr->szStorage,
372
					pCurr->tNextFree,
373
					pCurr->tFontRef,
374
					pCurr->usFontSize);
375
	pCurr->pNext = NULL;
376
	fail(!bCheckDoubleLinkedList(pAnchor));
377
 
378
	return pLeftOver;
379
} /* end of pSplitList */
380
 
381
/*
382
 * tNumber2Roman - convert a number to Roman Numerals
383
 *
384
 * returns the number of characters written
385
 */
386
size_t
387
tNumber2Roman(UINT uiNumber, BOOL bUpperCase, char *szOutput)
388
{
389
	char	*outp, *p, *q;
390
	UINT	uiNextVal, uiValue;
391
 
392
	fail(szOutput == NULL);
393
 
394
	uiNumber %= 4000;	/* Very high numbers can't be represented */
395
	if (uiNumber == 0) {
396
		szOutput[0] = '\0';
397
		return 0;
398
	}
399
 
400
	outp = szOutput;
401
	p = bUpperCase ? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
402
	uiValue = 1000;
403
	for (;;) {
404
		while (uiNumber >= uiValue) {
405
			*outp++ = *p;
406
			uiNumber -= uiValue;
407
		}
408
		if (uiNumber == 0) {
409
			*outp = '\0';
410
			fail(outp < szOutput);
411
			return (size_t)(outp - szOutput);
412
		}
413
		q = p + 1;
414
		uiNextVal = uiValue / (UINT)(UCHAR)*q;
415
		if ((int)*q == 2) {		/* magic */
416
			uiNextVal /= (UINT)(UCHAR)*(q += 2);
417
		}
418
		if (uiNumber + uiNextVal >= uiValue) {
419
			*outp++ = *++q;
420
			uiNumber += uiNextVal;
421
		} else {
422
			p++;
423
			uiValue /= (UINT)(UCHAR)(*p++);
424
		}
425
	}
426
} /* end of tNumber2Roman */
427
 
428
/*
429
 * iNumber2Alpha - convert a number to alphabetic "numbers"
430
 *
431
 * returns the number of characters written
432
 */
433
size_t
434
tNumber2Alpha(UINT uiNumber, BOOL bUpperCase, char *szOutput)
435
{
436
	char	*outp;
437
	UINT	uiTmp;
438
 
439
	fail(szOutput == NULL);
440
 
441
	if (uiNumber == 0) {
442
		szOutput[0] = '\0';
443
		return 0;
444
	}
445
 
446
	outp = szOutput;
447
	uiTmp = (UINT)(bUpperCase ? 'A': 'a');
448
	if (uiNumber <= 26) {
449
		uiNumber -= 1;
450
		*outp++ = (char)(uiTmp + uiNumber);
451
	} else if (uiNumber <= 26U + 26U*26U) {
452
		uiNumber -= 26 + 1;
453
		*outp++ = (char)(uiTmp + uiNumber / 26);
454
		*outp++ = (char)(uiTmp + uiNumber % 26);
455
	} else if (uiNumber <= 26U + 26U*26U + 26U*26U*26U) {
456
		uiNumber -= 26 + 26*26 + 1;
457
		*outp++ = (char)(uiTmp + uiNumber / (26*26));
458
		*outp++ = (char)(uiTmp + uiNumber / 26 % 26);
459
		*outp++ = (char)(uiTmp + uiNumber % 26);
460
	}
461
	*outp = '\0';
462
	fail(outp < szOutput);
463
	return (size_t)(outp - szOutput);
464
} /* end of tNumber2Alpha */
465
 
466
/*
467
 * unincpy - copy a counted Unicode string to an single-byte string
468
 */
469
char *
470
unincpy(char *s1, const UCHAR *s2, size_t n)
471
{
472
	char	*pcDest;
473
	ULONG	ulChar;
474
	size_t	tLen;
475
	USHORT	usUni;
476
 
477
	for (pcDest = s1, tLen = 0; tLen < n; pcDest++, tLen++) {
478
		usUni = usGetWord(tLen * 2, s2);
479
		if (usUni == 0) {
480
			break;
481
		}
482
		ulChar = ulTranslateCharacters(usUni, 0, 8,
483
				conversion_unknown, encoding_neutral, FALSE);
484
		if (ulChar == IGNORE_CHARACTER) {
485
			ulChar = (ULONG)'?';
486
		}
487
		*pcDest = (char)ulChar;
488
	}
489
	for (; tLen < n; tLen++) {
490
		*pcDest++ = '\0';
491
	}
492
	return s1;
493
} /* end of unincpy */
494
 
495
/*
496
 * unilen - calculate the length of a Unicode string
497
 *
498
 * returns the length in bytes
499
 */
500
size_t
501
unilen(const UCHAR *s)
502
{
503
	size_t	tLen;
504
	USHORT	usUni;
505
 
506
	tLen = 0;
507
	for (;;) {
508
		usUni = usGetWord(tLen, s);
509
		if (usUni == 0) {
510
			return tLen;
511
		}
512
		tLen += 2;
513
	}
514
} /* end of unilen */
515
 
516
/*
517
 * szBaseName - get the basename of the specified filename
518
 */
519
const char *
520
szBasename(const char *szFilename)
521
{
522
	const char	*szTmp;
523
 
524
	fail(szFilename == NULL);
525
 
526
	if (szFilename == NULL || szFilename[0] == '\0') {
527
		return "null";
528
	}
529
 
530
	szTmp = strrchr(szFilename, FILE_SEPARATOR[0]);
531
	if (szTmp == NULL) {
532
		return szFilename;
533
	}
534
	return ++szTmp;
535
} /* end of szBasename */
536
 
537
/*
538
 * lComputeLeading - compute the leading
539
 *
540
 * NOTE: the fontsize is specified in half points
541
 *
542
 * Returns the leading in drawunits
543
 */
544
long
545
lComputeLeading(USHORT usFontSize)
546
{
547
	long	lLeading;
548
 
549
	lLeading = (long)usFontSize * 500L;
550
	if (usFontSize < 18) {		/* Small text: 112% */
551
		lLeading *= 112;
552
	} else if (usFontSize < 28) {	/* Normal text: 124% */
553
		lLeading *= 124;
554
	} else if (usFontSize < 48) {	/* Small headlines: 104% */
555
		lLeading *= 104;
556
	} else {			/* Large headlines: 100% */
557
		lLeading *= 100;
558
	}
559
	lLeading = lMilliPoints2DrawUnits(lLeading);
560
	lLeading += 50;
561
	lLeading /= 100;
562
	return lLeading;
563
} /* end of lComputeLeading */
564
 
565
/*
566
 * Convert a UCS character to an UTF-8 string
567
 *
568
 * Returns the string length of the result
569
 */
570
size_t
571
tUcs2Utf8(ULONG ulChar, char *szResult, size_t tMaxResultLen)
572
{
573
	if (szResult == NULL || tMaxResultLen == 0) {
574
		return 0;
575
	}
576
 
577
	if (ulChar < 0x80 && tMaxResultLen >= 2) {
578
		szResult[0] = (char)ulChar;
579
		szResult[1] = '\0';
580
		return 1;
581
	}
582
	if (ulChar < 0x800 && tMaxResultLen >= 3) {
583
		szResult[0] = (char)(0xc0 | ulChar >> 6);
584
		szResult[1] = (char)(0x80 | (ulChar & 0x3f));
585
		szResult[2] = '\0';
586
		return 2;
587
	}
588
	if (ulChar < 0x10000 && tMaxResultLen >= 4) {
589
		szResult[0] = (char)(0xe0 | ulChar >> 12);
590
		szResult[1] = (char)(0x80 | (ulChar >> 6 & 0x3f));
591
		szResult[2] = (char)(0x80 | (ulChar & 0x3f));
592
		szResult[3] = '\0';
593
		return 3;
594
	}
595
	if (ulChar < 0x200000 && tMaxResultLen >= 5) {
596
		szResult[0] = (char)(0xf0 | ulChar >> 18);
597
		szResult[1] = (char)(0x80 | (ulChar >> 12 & 0x3f));
598
		szResult[2] = (char)(0x80 | (ulChar >> 6 & 0x3f));
599
		szResult[3] = (char)(0x80 | (ulChar & 0x3f));
600
		szResult[4] = '\0';
601
		return 4;
602
	}
603
	szResult[0] = '\0';
604
	return 0;
605
} /* end of tUcs2Utf8 */
606
 
607
/*
608
 * vGetBulletValue - get the bullet value for the conversing type and encoding
609
 */
610
void
611
vGetBulletValue(conversion_type eConversionType, encoding_type eEncoding,
612
	char *szResult, size_t tMaxResultLen)
613
{
614
	fail(szResult == NULL);
615
	fail(tMaxResultLen < 2);
616
 
617
	if (eEncoding == encoding_utf_8) {
618
		(void)tUcs2Utf8(UNICODE_BULLET, szResult, tMaxResultLen);
619
	} else {
620
		szResult[0] = (char)ucGetBulletCharacter(eConversionType,
621
							eEncoding);
622
		szResult[1] = '\0';
623
	}
624
} /* end of vGetBulletValue */
625
 
626
/*
627
 * bAllZero - are all bytes zero?
628
 */
629
BOOL
630
bAllZero(const UCHAR *aucBytes, size_t tLength)
631
{
632
	size_t	tIndex;
633
 
634
	if (aucBytes == NULL || tLength == 0) {
635
		return TRUE;
636
	}
637
 
638
	for (tIndex = 0; tIndex < tLength; tIndex++) {
639
		if (aucBytes[tIndex] != 0) {
640
			return FALSE;
641
		}
642
	}
643
	return TRUE;
644
} /* end of bAllZero */
645
 
646
#if !defined(__riscos)
647
/*
648
 * GetCodesetFromLocale - get the codeset from the current locale
649
 *
650
 * Original version: Copyright (C) 1999  Bruno Haible
651
 * Syntax:
652
 * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
653
 *
654
 * Returns TRUE when sucessful, otherwise FALSE
655
 */
656
static BOOL
657
bGetCodesetFromLocale(char *szCodeset, size_t tMaxCodesetLength, BOOL *pbEuro)
658
{
659
#if !defined(__dos)
660
	const char	*szLocale;
661
	const char	*pcTmp;
662
	size_t		tIndex;
663
	char		szModifier[6];
664
#endif /* __dos */
665
 
666
	if (pbEuro != NULL) {
667
		*pbEuro = FALSE;	/* Until proven otherwise */
668
	}
669
	if (szCodeset == NULL || tMaxCodesetLength == 0) {
670
		return FALSE;
671
	}
672
 
673
#if defined(__dos)
674
	if (tMaxCodesetLength < 2 + sizeof(int) * 3 + 1) {
675
		DBG_DEC(tMaxCodesetLength);
676
		DBG_DEC(2 + sizeof(int) * 3 + 1);
677
		return FALSE;
678
	}
679
	/* Get the active codepage from DOS */
680
	sprintf(szCodeset, "cp%d", iGetCodepage());
681
	DBG_MSG(szCodeset);
682
#else
683
	/* Get the locale from the environment */
684
	szLocale = getenv("LC_ALL");
685
	if (szLocale == NULL || szLocale[0] == '\0') {
686
		szLocale = getenv("LC_CTYPE");
687
		if (szLocale == NULL || szLocale[0] == '\0') {
688
			szLocale = getenv("LANG");
689
		}
690
	}
691
	if (szLocale == NULL || szLocale[0] == '\0') {
692
		/* No locale, so no codeset name and no modifier */
693
		return FALSE;
694
	}
695
	DBG_MSG(szLocale);
696
	pcTmp = strchr(szLocale, '.');
697
	if (pcTmp == NULL) {
698
		/* No codeset name */
699
		szCodeset[0] = '\0';
700
	} else {
701
		/* Copy the codeset name */
702
		pcTmp++;
703
		for (tIndex = 0; tIndex < tMaxCodesetLength; tIndex++) {
704
			if (*pcTmp == '@' || *pcTmp == '+' ||
705
			    *pcTmp == ',' || *pcTmp == '_' ||
706
			    *pcTmp == '\0') {
707
				szCodeset[tIndex] = '\0';
708
				break;
709
			}
710
			szCodeset[tIndex] = *pcTmp;
711
			pcTmp++;
712
		}
713
		szCodeset[tMaxCodesetLength - 1] = '\0';
714
	}
715
	if (pbEuro == NULL) {
716
		/* No need to get the modifier */
717
		return TRUE;
718
	}
719
	pcTmp = strchr(szLocale, '@');
720
	if (pcTmp != NULL) {
721
		/* Copy the modifier */
722
		pcTmp++;
723
		for (tIndex = 0; tIndex < sizeof(szModifier); tIndex++) {
724
			if (*pcTmp == '+' || *pcTmp == ',' ||
725
			    *pcTmp == '_' || *pcTmp == '\0') {
726
				szModifier[tIndex] = '\0';
727
				break;
728
			}
729
			szModifier[tIndex] = *pcTmp;
730
			pcTmp++;
731
		}
732
		szModifier[sizeof(szModifier) - 1] = '\0';
733
		*pbEuro = STRCEQ(szModifier, "Euro");
734
	}
735
#endif /* __dos */
736
	return TRUE;
737
} /* end of bGetCodesetFromLocale */
738
 
739
/*
740
 * GetNormalizedCodeset - get the normalized codeset from the current locale
741
 *
742
 * Returns TRUE when sucessful, otherwise FALSE
743
 */
744
BOOL
745
bGetNormalizedCodeset(char *szCodeset, size_t tMaxCodesetLength, BOOL *pbEuro)
746
{
747
	BOOL	bOnlyDigits;
748
	const char	*pcSrc;
749
	char	*pcDest;
750
	char	*szTmp, *szCodesetNorm;
751
 
752
	if (pbEuro != NULL) {
753
		*pbEuro = FALSE;	/* Until proven otherwise */
754
	}
755
	if (szCodeset == NULL || tMaxCodesetLength < 4) {
756
		return FALSE;
757
	}
758
 
759
	/* Get the codeset name */
760
	szTmp = xmalloc(tMaxCodesetLength - 3);
761
	if (!bGetCodesetFromLocale(szTmp, tMaxCodesetLength - 3, pbEuro)) {
762
		szTmp = xfree(szTmp);
763
		return FALSE;
764
	}
765
	/* Normalize the codeset name */
766
	szCodesetNorm = xmalloc(tMaxCodesetLength - 3);
767
	bOnlyDigits = TRUE;
768
	pcDest = szCodesetNorm;
769
	for (pcSrc = szTmp; *pcSrc != '\0'; pcSrc++) {
770
		if (isalnum(*pcSrc)) {
771
			*pcDest = tolower(*pcSrc);
772
			if (!isdigit(*pcDest)) {
773
				bOnlyDigits = FALSE;
774
			}
775
			pcDest++;
776
		}
777
	}
778
	*pcDest = '\0';
779
	DBG_MSG(szCodesetNorm);
780
	/* Add "iso" when szCodesetNorm contains all digits */
781
	if (bOnlyDigits && szCodesetNorm[0] != '\0') {
782
		fail(strlen(szCodesetNorm) + 3 >= tMaxCodesetLength);
783
		sprintf(szCodeset, "iso%s", szCodesetNorm);
784
	} else {
785
		fail(strlen(szCodesetNorm) >= tMaxCodesetLength);
786
		strncpy(szCodeset, szCodesetNorm, pcDest - szCodesetNorm + 1);
787
		szCodeset[tMaxCodesetLength - 1] = '\0';
788
	}
789
	DBG_MSG(szCodeset);
790
	/* Clean up and leave */
791
	szCodesetNorm = xfree(szCodesetNorm);
792
	szTmp = xfree(szTmp);
793
	return TRUE;
794
} /* end of bGetNormalizedCodeset */
795
 
796
/*
797
 * szGetDefaultMappingFile - get the default mapping file
798
 *
799
 * Returns the basename of the default mapping file
800
 */
801
const char *
802
szGetDefaultMappingFile(void)
803
{
804
	static const struct {
805
		const char	*szCodeset;
806
		const char	*szMappingFile;
807
	} atMappingFile[] = {
808
		{ "iso88591",	MAPPING_FILE_8859_1 },
809
		{ "iso88592",	MAPPING_FILE_8859_2 },
810
		{ "iso88593",	"8859-3.txt" },
811
		{ "iso88594",	"8859-4.txt" },
812
		{ "iso88595",	"8859-5.txt" },
813
		{ "iso88596",	MAPPING_FILE_8859_5 },
814
		{ "iso88597",	"8859-7.txt" },
815
		{ "iso88598",	"8859-8.txt" },
816
		{ "iso88599",	"8859-9.txt" },
817
		{ "iso885910",	"8859-10.txt" },
818
		{ "iso885913",	"8859-13.txt" },
819
		{ "iso885914",	"8859-14.txt" },
820
		{ "iso885915",	MAPPING_FILE_8859_15 },
821
		{ "iso885916",	"8859-16.txt" },
822
		{ "koi8r",	MAPPING_FILE_KOI8_R },
823
		{ "koi8u",	MAPPING_FILE_KOI8_U },
824
		{ "utf8",	MAPPING_FILE_UTF_8 },
825
		{ "cp437",	MAPPING_FILE_CP437 },
826
		{ "cp850",	"cp850.txt" },
827
		{ "cp852",	MAPPING_FILE_CP852 },
828
		{ "cp862",	"cp862.txt" },
829
		{ "cp864",	"cp864.txt" },
830
		{ "cp866",	MAPPING_FILE_CP866 },
831
		{ "cp1250",	MAPPING_FILE_CP1250 },
832
		{ "cp1251",	MAPPING_FILE_CP1251 },
833
		{ "cp1252",	"cp1252.txt" },
834
	};
835
	size_t	tIndex;
836
	BOOL	bEuro;
837
	char	szCodeset[20];
838
 
839
	szCodeset[0] = '\0';
840
	bEuro = FALSE;
841
	/* Get the normalized codeset name */
842
	if (!bGetNormalizedCodeset(szCodeset, sizeof(szCodeset), &bEuro)) {
843
		return MAPPING_FILE_8859_1;
844
	}
845
	if (szCodeset[0] == '\0') {
846
		if (bEuro) {
847
			/* Default mapping file (with Euro sign) */
848
			return MAPPING_FILE_8859_15;
849
		} else {
850
			/* Default mapping file (without Euro sign) */
851
			return MAPPING_FILE_8859_1;
852
		}
853
	}
854
	/* Find the name in the table */
855
	for (tIndex = 0; tIndex < elementsof(atMappingFile); tIndex++) {
856
		if (STREQ(atMappingFile[tIndex].szCodeset, szCodeset)) {
857
			return atMappingFile[tIndex].szMappingFile;
858
		}
859
	}
860
	/* Default default mapping file */
861
#if defined(__dos)
862
	return MAPPING_FILE_CP437;
863
#else
864
	return MAPPING_FILE_8859_1;
865
#endif /* __dos */
866
} /* end of szGetDefaultMappingFile */
867
#endif /* !__riscos */
868
 
869
/*
870
 * tConvertDTTM - convert Windows Date and Time format
871
 *
872
 * returns Unix time_t or -1
873
 */
874
time_t
875
tConvertDTTM(ULONG ulDTTM)
876
{
877
	struct tm	tTime;
878
	time_t		tResult;
879
 
880
	if (ulDTTM == 0) {
881
		return (time_t)-1;
882
	}
883
	memset(&tTime, 0, sizeof(tTime));
884
	tTime.tm_min = (int)(ulDTTM & 0x0000003f);
885
	tTime.tm_hour = (int)((ulDTTM & 0x000007c0) >> 6);
886
	tTime.tm_mday = (int)((ulDTTM & 0x0000f800) >> 11);
887
	tTime.tm_mon = (int)((ulDTTM & 0x000f0000) >> 16);
888
	tTime.tm_year = (int)((ulDTTM & 0x1ff00000) >> 20);
889
	tTime.tm_isdst = -1;
890
	tTime.tm_mon--;         /* From 01-12 to 00-11 */
891
	tResult = mktime(&tTime);
892
	NO_DBG_MSG(ctime(&tResult));
893
	return tResult;
894
} /* end of tConvertDTTM */