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 */ 895