Changeset 174 for trunk/src/helpers/nls.c
- Timestamp:
- Jun 14, 2002, 2:20:11 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/nls.c
r167 r174 40 40 41 41 #define INCL_DOSNLS 42 #define INCL_DOSSEMAPHORES 43 #define INCL_DOSEXCEPTIONS 44 #define INCL_DOSPROCESS 42 #define INCL_DOSDATETIME 45 43 #define INCL_DOSERRORS 46 44 #define INCL_WINSHELLDATA … … 51 49 #include <string.h> 52 50 #include <math.h> 53 #include <setjmp.h> 54 51 52 // XWP's setup.h replaces strchr and the like, and 53 // we want the originals in here 54 #define DONT_REPLACE_FOR_DBCS 55 55 #include "setup.h" // code generation and debugging options 56 56 57 #include "helpers\except.h"58 57 #include "helpers\nls.h" 59 58 #include "helpers\prfh.h" 60 59 #include "helpers\standards.h" 61 #include "helpers\stringh.h"62 #include "helpers\tree.h"63 #include "helpers\xstring.h"64 60 65 61 #pragma hdrstop … … 69 65 * See nls.c. 70 66 */ 67 68 /* ****************************************************************** 69 * 70 * DBCS support 71 * 72 ********************************************************************/ 73 74 #define MAX_LEADBYTE 256 75 76 #pragma pack(1) 77 78 typedef struct _DBCSVECTOR 79 { 80 BYTE bLow; 81 BYTE bHigh; 82 } DBCSVECTOR; 83 84 #pragma pack() 85 86 BOOL G_afLeadByte[MAX_LEADBYTE] = {0}; 87 ULONG G_fDBCS = -1; // not queried yet 88 COUNTRYCODE G_cc = { 0, 0 }; 89 DBCSVECTOR G_aDBCSVector[8]; 90 91 /* 92 *@@ nlsDBCS: 93 * returns TRUE if the system is currently using DBCS. 94 * 95 *@@added V0.9.19 (2002-06-13) [umoeller] 96 */ 97 98 BOOL nlsDBCS(VOID) 99 { 100 int i; 101 102 if (G_fDBCS != -1) 103 // already queried: 104 return G_fDBCS; 105 106 if (DosQueryDBCSEnv(8 * sizeof(DBCSVECTOR), 107 &G_cc, 108 (PCHAR)G_aDBCSVector)) 109 // not DBCS: 110 return (G_fDBCS = FALSE); 111 112 for (i = 0; 113 i < 8; 114 ++i) 115 { 116 if ( (G_aDBCSVector[i].bLow) 117 && (G_aDBCSVector[i].bHigh) 118 ) 119 { 120 int n; 121 for (n = G_aDBCSVector[i].bLow; 122 n <= G_aDBCSVector[i].bHigh; 123 ++n) 124 G_afLeadByte[n] = TRUE; 125 G_fDBCS = TRUE; 126 } 127 else 128 break; 129 } 130 131 return G_fDBCS; 132 } 133 134 /* 135 *@@ nlsQueryDBCSChar: 136 * returns the type of the DBCS character with 137 * the given index. Note that the index is the 138 * DBCS character index, not just the array 139 * index into the CHAR array. 140 * 141 * Returns: 142 * 143 * -- TYPE_SBCS: ulOfs is single byte. 144 * 145 * -- TYPE_DBCS_1ST: ulOfs is a double-byte lead char. 146 * 147 * -- TYPE_DBCS_2ND: ulOfs is a double-byte trail char. 148 * 149 * Preconditions: 150 * 151 * -- nlsDBCS must have been called to initialize our 152 * globals, and must have returned TRUE. 153 * 154 *@@added V0.9.19 (2002-06-13) [umoeller] 155 */ 156 157 ULONG nlsQueryDBCSChar(PCSZ pcszString, 158 ULONG ulOfs) 159 160 { 161 ULONG ulDBCSType = TYPE_SBCS; 162 ULONG i; 163 164 for (i = 0; 165 i <= ulOfs; 166 ++i) 167 { 168 switch (ulDBCSType) 169 { 170 case TYPE_SBCS: 171 case TYPE_DBCS_2ND: 172 ulDBCSType = G_afLeadByte[pcszString[i]]; 173 break; 174 175 case TYPE_DBCS_1ST : 176 ulDBCSType = TYPE_DBCS_2ND; 177 break; 178 } 179 } 180 181 return ulDBCSType; 182 } 183 184 /* 185 *@@ nlschr: 186 * replacement for strchr with DBCS support. 187 * 188 * If the system is not running with DBCS, 189 * this calls plain strchr automatically. 190 * 191 *@@added V0.9.19 (2002-06-13) [umoeller] 192 */ 193 194 PSZ nlschr(PCSZ p, char c) 195 { 196 PCSZ p2; 197 ULONG ulDBCS; 198 199 if (!nlsDBCS()) 200 // not DBCS: 201 return strchr(p, c); 202 203 // we're on DBCS: 204 for (p2 = p; 205 *p2; 206 ++p2) 207 { 208 if (*p2 == c) 209 { 210 // match: return this only if it's SBCS; 211 // if it's a DBCS lead char, skip it 212 switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p)) 213 { 214 case TYPE_SBCS: 215 return (PSZ)p2; 216 217 case TYPE_DBCS_1ST: 218 ++p2; 219 } 220 } 221 } 222 223 return NULL; 224 } 225 226 /* 227 *@@ nlsrchr: 228 * replacement for strrchr with DBCS support. 229 * 230 * If the system is not running with DBCS, 231 * this calls plain strrchr automatically. 232 * 233 *@@added V0.9.19 (2002-06-13) [umoeller] 234 */ 235 236 PSZ nlsrchr(PCSZ p, char c) 237 { 238 PCSZ p2; 239 ULONG ulDBCS, 240 ulLength; 241 242 if (!nlsDBCS()) 243 // not DBCS: 244 return strrchr(p, c); 245 246 // we're on DBCS: 247 ulLength = strlen(p); 248 for (p2 = p + ulLength - 1; 249 p2 >= p; 250 --p2) 251 { 252 if (*p2 == c) 253 { 254 // match: return this only if it's SBCS; 255 // if it's a DBCS trail char, skip it 256 switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p)) 257 { 258 case TYPE_SBCS: 259 return (PSZ)p2; 260 261 case TYPE_DBCS_2ND: 262 --p2; 263 } 264 } 265 } 266 267 return NULL; 268 } 269 270 /* ****************************************************************** 271 * 272 * Country-dependent formatting 273 * 274 ********************************************************************/ 71 275 72 276 /* … … 505 709 } 506 710 507 /* ****************************************************************** 508 * 509 * NLS strings 510 * 511 ********************************************************************/ 512 513 static HAB G_hab = NULLHANDLE; 514 static HMODULE G_hmod = NULLHANDLE; 515 static PCSTRINGENTITY G_paEntities = NULL; 516 static ULONG G_cEntities = 0; 517 518 /* 519 *@@ ReplaceEntities: 520 * 521 *@@added V0.9.16 (2001-09-29) [umoeller] 522 */ 523 524 static ULONG ReplaceEntities(PXSTRING pstr) 525 { 526 ULONG ul, 527 rc = 0; 528 529 for (ul = 0; 530 ul < G_cEntities; 531 ul++) 532 { 533 ULONG ulOfs = 0; 534 PCSTRINGENTITY pThis = &G_paEntities[ul]; 535 while (xstrFindReplaceC(pstr, 536 &ulOfs, 537 pThis->pcszEntity, 538 *(pThis->ppcszString))) 539 rc++; 540 } 541 542 return (rc); 543 } 544 545 /* 546 *@@ LoadString: 547 * 548 *@@added V0.9.18 (2002-03-08) [umoeller] 549 */ 550 551 static void LoadString(ULONG ulID, 552 PSZ *ppsz, 553 PULONG pulLength) // out: length of new string (ptr can be NULL) 554 { 555 CHAR szBuf[500]; 556 XSTRING str; 557 558 if (*ppsz) 559 free(*ppsz); 560 561 if (!WinLoadString(G_hab, 562 G_hmod, 563 ulID, 564 sizeof(szBuf), 565 szBuf)) 566 // loading failed: 567 sprintf(szBuf, 568 "LoadString error: string resource %d not found in module 0x%lX", 569 ulID, 570 G_hmod); 571 572 xstrInitCopy(&str, szBuf, 0); 573 ReplaceEntities(&str); 574 *ppsz = str.psz; 575 if (pulLength) 576 *pulLength = str.ulLength; 577 // do not free string 578 } 579 580 static HMTX G_hmtxStringsCache = NULLHANDLE; 581 static TREE *G_StringsCache; 582 static LONG G_cStringsInCache = 0; 583 584 /* 585 *@@ LockStrings: 586 * 587 *@@added V0.9.9 (2001-04-04) [umoeller] 588 */ 589 590 static BOOL LockStrings(VOID) 591 { 592 BOOL brc = FALSE; 593 594 if (G_hmtxStringsCache == NULLHANDLE) 595 { 596 brc = !DosCreateMutexSem(NULL, 597 &G_hmtxStringsCache, 598 0, 599 TRUE); 600 treeInit(&G_StringsCache, 601 &G_cStringsInCache); 602 } 603 else 604 brc = !DosRequestMutexSem(G_hmtxStringsCache, SEM_INDEFINITE_WAIT); 605 606 return brc; 607 } 608 609 /* 610 *@@ UnlockStrings: 611 * 612 *@@added V0.9.9 (2001-04-04) [umoeller] 613 */ 614 615 static VOID UnlockStrings(VOID) 616 { 617 DosReleaseMutexSem(G_hmtxStringsCache); 618 } 619 620 /* 621 *@@ STRINGTREENODE: 622 * internal string node structure for cmnGetString. 623 * 624 *@@added V0.9.9 (2001-04-04) [umoeller] 625 *@@changed V0.9.16 (2002-01-26) [umoeller]: no longer using malloc() for string 626 */ 627 628 typedef struct _STRINGTREENODE 629 { 630 TREE Tree; // tree node (src\helpers\tree.c) 631 CHAR szLoaded[1]; // string that was loaded; 632 // the struct is dynamic in size now 633 // V0.9.16 (2002-01-26) [umoeller] 634 } STRINGTREENODE, *PSTRINGTREENODE; 635 636 /* 637 *@@ nlsInitStrings: 638 * initializes the NLS strings cache. Call this 639 * before calling nlsGetString for the first time. 640 * 641 *@@added V0.9.18 (2002-03-08) [umoeller] 642 */ 643 644 VOID nlsInitStrings(HAB hab, // in: anchor block 645 HMODULE hmod, // in: module handle to load strings from 646 PCSTRINGENTITY paEntities, // in: entities array or NULL 647 ULONG cEntities) // in: array item count of paEntities or 0 648 { 649 G_hab = hab; 650 G_hmod = hmod; 651 G_paEntities = paEntities; 652 G_cEntities = cEntities; 653 } 654 655 /* 656 *@@ nlsGetString: 657 * returns a resource NLS string. 658 * 659 * Before calling this for the first time, initialize 660 * the engine with nlsInitStrings. 661 * 662 * After that, this function implements a fast string 663 * cache for various NLS strings. Compared to the 664 * standard method, this has the following advantages: 665 * 666 * -- Memory is only consumed for strings that are actually 667 * used. The NLSSTRINGS array had become terribly big, 668 * and lots of strings were loaded that were never used. 669 * 670 * -- Program startup should be a bit faster because we don't 671 * have to load a thousand strings at startup. 672 * 673 * -- The memory buffer holding the string is probably close 674 * to the rest of the heap data that the caller allocated, 675 * so this might lead to less memory page fragmentation. 676 * 677 * -- To add a new NLS string, before this mechanism existed, 678 * three files had to be changed (and kept in sync): common.h 679 * to add a field to the NLSSTRINGS structure, dlgids.h to 680 * add the string ID, and xfldrXXX.rc to add the resource. 681 * With the new mechanism, there's no need to change common.h 682 * any more, so the danger of forgetting something is a bit 683 * reduced. Anyway, fewer recompiles are needed (maybe), 684 * and sending in patches to the code is a bit easier. 685 * 686 * On input, specify a string resouce ID that exists 687 * in the hmod that was given to nlsInitStrings. 688 * 689 * The way this works is that the function maintains a 690 * fast cache of string IDs and only loads the string 691 * resources on demand from the given NLS DLL. If a 692 * string ID is queried for the first time, the string 693 * is loaded. Otherwise the cached copy is returned. 694 * 695 * There is a slight overhead to this function compared to 696 * simply getting a static string from an array, because 697 * the cache needs to be searched for the string ID. However, 698 * this uses a binary tree (balanced according to string IDs) 699 * internally, so this is quite fast still. 700 * 701 * This never releases the strings again. 702 * 703 * This never returns NULL. Even if loading the string failed, 704 * a string is returned; in that case, it's a meaningful error 705 * message specifying the ID that failed. 706 * 707 *@@added V0.9.9 (2001-04-04) [umoeller] 708 *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed bad string count which was never set 709 *@@changed V0.9.16 (2002-01-26) [umoeller]: optimized heap locality 710 */ 711 712 PCSZ nlsGetString(ULONG ulStringID) 713 { 714 BOOL fLocked = FALSE; 715 PSZ pszReturn = "Error"; 716 717 TRY_LOUD(excpt1) 718 { 719 if (fLocked = LockStrings()) 720 { 721 PSTRINGTREENODE pNode; 722 723 if (pNode = (PSTRINGTREENODE)treeFind(G_StringsCache, 724 ulStringID, 725 treeCompareKeys)) 726 // already loaded: 727 pszReturn = pNode->szLoaded; 728 else 729 { 730 // not loaded: load now 731 PSZ psz = NULL; 732 ULONG ulLength = 0; 733 734 LoadString(ulStringID, 735 &psz, 736 &ulLength); 737 738 if ( (!psz) 739 || (!(pNode = (PSTRINGTREENODE)malloc( sizeof(STRINGTREENODE) 740 // has one byte for null 741 // terminator already 742 + ulLength))) 743 ) 744 pszReturn = "malloc() failed."; 745 else 746 { 747 pNode->Tree.ulKey = ulStringID; 748 memcpy(pNode->szLoaded, 749 psz, 750 ulLength + 1); 751 treeInsert(&G_StringsCache, 752 &G_cStringsInCache, // fixed V0.9.16 (2001-10-19) [umoeller] 753 (TREE*)pNode, 754 treeCompareKeys); 755 pszReturn = pNode->szLoaded; 756 } 757 758 if (psz) 759 free(psz); 760 } 761 } 762 else 763 // we must always return a string, never NULL 764 pszReturn = "Cannot get strings lock."; 765 } 766 CATCH(excpt1) {} END_CATCH(); 767 768 if (fLocked) 769 UnlockStrings(); 770 771 return (pszReturn); 772 } 773 711
Note:
See TracChangeset
for help on using the changeset viewer.