From fa4d7c34d95a228b0017f80bffbc06705660c79b Mon Sep 17 00:00:00 2001 From: George Rhoten Date: Sat, 28 Oct 2000 00:39:54 +0000 Subject: [PATCH] ICU-700 Windows locale mapping works better now with variants X-SVN-Rev: 2828 --- icu4c/source/common/locmap.cpp | 112 ++++++++++++++++++++++++---- icu4c/source/common/locmap.h | 7 +- icu4c/source/test/lcid/lcid.cpp | 128 +++++++++++++++++++++----------- icu4c/source/test/lcid/lcid.dsp | 7 +- 4 files changed, 193 insertions(+), 61 deletions(-) diff --git a/icu4c/source/common/locmap.cpp b/icu4c/source/common/locmap.cpp index c361930495..1229f767d7 100644 --- a/icu4c/source/common/locmap.cpp +++ b/icu4c/source/common/locmap.cpp @@ -4,7 +4,7 @@ * Corporation and others. All Rights Reserved. ********************************************************************** */ -// $Revision: 1.16 $ +// $Revision: 1.17 $ // // Provides functionality for mapping between // LCID and Posix IDs. @@ -55,16 +55,28 @@ struct ILcidPosixElement struct ILcidPosixMap { - uint32_t hostID(const char* fromPosixID) const; const char* posixID(uint32_t fromHostID) const; -// static const char* fgWildCard; + /** + * Searches for a Windows LCID + * + * @param posixid the Posix style locale id. + * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has + * no equivalent Windows LCID. + * @return the LCID + */ + uint32_t hostID(const char* fromPosixID) const; -// uint16_t hostLangID; -// const char *posixLangID; + /** + * Do not call this function. It is called by hostID. + * The function is not private because this struct must stay as a C struct, + * and this is an internal class. + */ + uint32_t searchPosixIDmap(const char* posixID, UErrorCode* status) const; uint32_t numRegions; const ILcidPosixElement* regionMaps; + }; ///////////////////////////////////////////////// @@ -299,9 +311,9 @@ static const ILcidPosixElement sv[] = { {0x041d, "sv_SE"} }; -ILCID_POSIX_ELEMENT_ARRAY(0x0441, sw, sw_KE) // The MSJDK documentation says the default country is Kenya. +ILCID_POSIX_ELEMENT_ARRAY(0x0441, sw, sw_KE)// The MSJDK documentation says the default country is Kenya. ILCID_POSIX_ELEMENT_ARRAY(0x0449, ta, ta_IN) -ILCID_POSIX_ELEMENT_ARRAY(0x044a, te, te_IN) //Todo: Data does not exist +ILCID_POSIX_ELEMENT_ARRAY(0x044a, te, te_IN) ILCID_POSIX_ELEMENT_ARRAY(0x041e, th, th_TH) ILCID_POSIX_ELEMENT_ARRAY(0x041f, tr, tr_TR) ILCID_POSIX_ELEMENT_ARRAY(0x0444, tt, tt_RU) //Todo: Data does not exist @@ -663,7 +675,7 @@ IGlobalLocales::convertToLCID(const char* posixID, UErrorCode* status) uint32_t mid; uint32_t high = LocaleCount - 1; int32_t compVal; - char langID[256]; + char langID[ULOC_FULLNAME_CAPACITY]; // Check for incomplete id. if (!posixID || uprv_strlen(posixID) < 2) @@ -694,7 +706,7 @@ IGlobalLocales::convertToLCID(const char* posixID, UErrorCode* status) // no match found *status = U_ILLEGAL_ARGUMENT_ERROR; - return 0; + return 0; // return international (root) } @@ -703,17 +715,87 @@ IGlobalLocales::convertToLCID(const char* posixID, UErrorCode* status) uint32_t ILcidPosixMap::hostID(const char* posixID) const { - uint32_t low = 1; - uint32_t mid; - uint32_t high = numRegions; - int32_t compVal; + UErrorCode status = U_ZERO_ERROR; + char hostID[ULOC_FULLNAME_CAPACITY]; + char *hostPtr = hostID; + uint32_t value; + uint32_t hostLen = strlen(posixID); + int32_t size, hostSize; // Check for incomplete id. All LCIDs have a default country, // and a 0x0400 in 0xFC00 indicates a default country. // So Windows may not like hostLangID without a default // country. - if (!numRegions || strlen(posixID) < 5) + if (!numRegions || hostLen < 5) return regionMaps->hostID; + if (hostLen >= ULOC_FULLNAME_CAPACITY) + hostLen = ULOC_FULLNAME_CAPACITY - 1; + + // We do this because the posixID may have a '-' separator and + // incorrect string case + hostSize = uloc_getLanguage(posixID, + hostID, + ULOC_LANG_CAPACITY + 1, + &status); + if (U_SUCCESS(status)) + { + hostPtr += hostSize; + hostPtr[-1] = '_'; + size = uloc_getCountry(posixID, + hostPtr, + ULOC_COUNTRY_CAPACITY + 1, + &status); + hostSize += size - 1; + if (U_SUCCESS(status) && hostSize < hostLen) + { + hostPtr += size; + hostPtr[-1] = '_'; + uloc_getVariant(posixID, hostPtr, hostLen - size, &status); + } + } + + // Try to find it the first time. + value = searchPosixIDmap(hostID, &status); + if (U_SUCCESS(status)) { + return value; + } + + // Couldn't find it. Cut off the last part of the locale + while (hostPtr > hostID && *hostPtr != '_') + { + hostPtr--; + } + if (*hostPtr == '_') + { + *hostPtr = 0; + } + + // Try it again without the last part of the locale + status = U_ZERO_ERROR; + value = searchPosixIDmap(hostID, &status); + if (U_SUCCESS(status)) { + return value; + } + + // No match found. Return the language + return regionMaps->hostID; +} + +/** + * Searches for a Windows LCID + * + * @param posixid the Posix style locale id. + * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has + * no equivalent Windows LCID. + * @return the LCID + */ +uint32_t +ILcidPosixMap::searchPosixIDmap(const char* posixID, UErrorCode* status) const +{ + uint32_t low = 1; + uint32_t mid; + uint32_t high = numRegions; + int32_t compVal; // Binary search for the map entry // The element at index 0 is always the POSIX wild card, @@ -733,9 +815,11 @@ ILcidPosixMap::hostID(const char* posixID) const } //no match found + *status = U_ILLEGAL_ARGUMENT_ERROR; return regionMaps->hostID; } + const char* ILcidPosixMap::posixID(uint32_t hostID) const { diff --git a/icu4c/source/common/locmap.h b/icu4c/source/common/locmap.h index f104cb64f9..72c703acf6 100644 --- a/icu4c/source/common/locmap.h +++ b/icu4c/source/common/locmap.h @@ -6,7 +6,7 @@ * ***************************************************************************************** */ -// $Revision: 1.10 $ +// $Revision: 1.11 $ //=============================================================================== // // File locmap.hpp : Locale Mapping Classes @@ -46,6 +46,7 @@ public: * @param hostid the Windows LCID number. * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the LCID has no * equivalent ICU locale. + * @return ICU locale */ static const char* convertToPosix(uint32_t hostid, UErrorCode* status); @@ -56,6 +57,7 @@ public: * @param posixid the Posix style locale id. * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has * no equivalent Windows LCID. + * @return the LCID */ static uint32_t convertToLCID(const char* posixID, UErrorCode* status); @@ -66,6 +68,7 @@ public: * ID. * * @param hostid the Windows LCID number. + * @return the language part of the LCID */ static inline uint16_t languageLCID(uint32_t hostID) {return LANGUAGE_LCID(hostID);} @@ -78,7 +81,7 @@ protected: static void initializeMapRegions(void); private: - + static uint32_t LocaleCount; static ILcidPosixMap* PosixIDmap; diff --git a/icu4c/source/test/lcid/lcid.cpp b/icu4c/source/test/lcid/lcid.cpp index 8a47c73ad8..73434347fd 100644 --- a/icu4c/source/test/lcid/lcid.cpp +++ b/icu4c/source/test/lcid/lcid.cpp @@ -14,10 +14,90 @@ #include "cstring.h" #include "unicode/resbund.h" +static void +testLCID(const char *localeName); + +static void +testLCID(const char *localeName, + const UnicodeString &posixName, + uint32_t *errors, + uint32_t *warnings) +{ + UErrorCode status = U_ZERO_ERROR; + uint32_t lcid; + uint32_t expectedLCID; + char lcidStringC[1024]; + ResourceBundle posixLocale((char *)0, Locale(posixName), status); + + if(status != U_ZERO_ERROR) { + if(U_SUCCESS(status)) { + printf("ERROR: Locale %-5s not installed, and it should be!\n", localeName); + } else { + printf("%%%%%%% Unexpected error %d %%%%%%%", u_errorName(status)); + } + (*errors)++; + return; + } + + UnicodeString lcidString(posixLocale.getStringEx("LocaleID", status)); + + if (U_FAILURE(status)) { + printf("ERROR: %s does not have a LocaleID (%s)\n", localeName, u_errorName(status)); + (*errors)++; + return; + } + + lcidString.extract(0, lcidString.length(), lcidStringC, ""); + lcidStringC[lcidString.length()] = '\0'; + expectedLCID = uprv_strtoul(lcidStringC, NULL, 16); + + lcid = IGlobalLocales::convertToLCID(localeName, &status); + if (U_FAILURE(status)) { + printf("WARNING: %-5s does not have an LCID mapping\n", localeName); + (*warnings)++; + return; + } + + status = U_ZERO_ERROR; + uprv_strcpy(lcidStringC, IGlobalLocales::convertToPosix(expectedLCID, &status)); + if (U_FAILURE(status)) { + printf("ERROR: %.4x does not have a POSIX mapping due to %s\n", expectedLCID, u_errorName(status)); + (*errors)++; + } + + if(lcid != expectedLCID) { + printf("ERROR: Locale %-5s wrongfully has 0x%.4x instead of 0x%.4x for LCID\n", localeName, expectedLCID, lcid); + (*errors)++; + } + if(strcmp(localeName, lcidStringC) != 0) { + char langName[1024]; + char langLCID[1024]; + uloc_getLanguage(localeName, langName, sizeof(langName), &status); + uloc_getLanguage(lcidStringC, langLCID, sizeof(langLCID), &status); + + if (expectedLCID == lcid && strcmp(langName, langLCID) == 0) { + printf("WARNING: %-5s resolves to %s (0x%.4x)\n", localeName, lcidStringC, lcid); + (*warnings)++; + } + else if (expectedLCID == lcid) { + printf("ERROR: 0x%.4x is from %-5s and the number resolves wrongfully to %s\n", expectedLCID, localeName, lcidStringC); + (*errors)++; + } + else { + printf("ERROR: 0x%.4x is from %-5s and the number resolves wrongfully to %s. It should be 0x%x.\n", expectedLCID, localeName, lcidStringC, lcid); + (*errors)++; + } + } else { + //printf("0x%x is from %s and it resolves correctly to %s(0x%x)\n", expectedLCID, localeName, lcidStringC, lcid); + //printf("%s: %x->%x\n", localeName, expectedLCID, lcid); + } +} + int main() { UErrorCode status = U_ZERO_ERROR; ResourceBundle index((char *)0, Locale("index"), status); uint32_t errors = 0; + uint32_t warnings = 0; if(U_SUCCESS(status)) { ResourceBundle installedLocales = index.get("InstalledLocales", status); @@ -25,51 +105,11 @@ int main() { installedLocales.resetIterator(); while(installedLocales.hasNext()) { char localeName[1024]; - uint32_t lcid; UnicodeString posixName = installedLocales.getNextString(status); + posixName.extract(0, posixName.length(), localeName, ""); localeName[posixName.length()] = '\0'; - ResourceBundle posixLocale((char *)0, Locale(posixName), status); - if(status == U_ZERO_ERROR) { - UnicodeString lcidString = posixLocale.getStringEx("LocaleID", status); - char lcidStringC[1024]; - lcidString.extract(0, lcidString.length(), lcidStringC, ""); - lcidStringC[lcidString.length()] = '\0'; - uint32_t expectedLCID = uprv_strtoul(lcidStringC, NULL, 16); - - status = U_ZERO_ERROR; - lcid = IGlobalLocales::convertToLCID(localeName, &status); - if (U_FAILURE(status)) { - printf("WARNING: %s does not have an LCID mapping (%s)\n", localeName, u_errorName(status)); - status = U_ZERO_ERROR; - } - else { - status = U_ZERO_ERROR; - uprv_strcpy(lcidStringC, IGlobalLocales::convertToPosix(expectedLCID, &status)); - if (U_FAILURE(status)) { - printf("ERROR: %x does not have an POSIX mapping due to error %s\n", expectedLCID, u_errorName(status)); - } - if(strcmp(localeName, lcidStringC) == 0) { - //printf("0x%x is from %s and it resolves correctly to %s(0x%x)\n", expectedLCID, localeName, lcidStringC, lcid); - //printf("%s: %x->%x\n", localeName, expectedLCID, lcid); - } else { - printf("ERROR: 0x%x is from %s and it resolves wrongfully to %s, it should have (0x%x)\n", expectedLCID, localeName, lcidStringC, lcid); - //printf("Name mismatch: %s vs. %s: %x->%x\n", localeName, lcidStringC, expectedLCID, lcid); - errors++; - } - if(lcid != expectedLCID) { - printf("ERROR: Locale %s wrongfully has 0x%x instead of 0x%x for LCID\n", localeName, expectedLCID, lcid); - //printf("LCID mismatch: %s: %x->%x\n", localeName, expectedLCID, lcid); - errors++; - } - } - } else if(U_SUCCESS(status)) { - printf("ERROR: Locale %s not installed, and it should be!\n", localeName); - errors++; - } else { - printf("%%%%%%% Unexpected error %d %%%%%%%", status); - } - + testLCID(localeName, posixName, &errors, &warnings); } } } @@ -79,6 +119,10 @@ int main() { printf("There were no errors\n"); } + if(warnings > 0) { + printf("There were %d warning(s)\n", warnings); + } + char temp; scanf("%c", &temp); diff --git a/icu4c/source/test/lcid/lcid.dsp b/icu4c/source/test/lcid/lcid.dsp index 2d0baea3e1..5bfcb80ffa 100644 --- a/icu4c/source/test/lcid/lcid.dsp +++ b/icu4c/source/test/lcid/lcid.dsp @@ -39,9 +39,10 @@ RSC=rc.exe # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../include" /I "../../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -49,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 icuuc17.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../lib" /libpath:"../../common/Release" !ELSEIF "$(CFG)" == "lcid - Win32 Debug" @@ -73,7 +74,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 icuuc.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../lib/debug" /libpath:"../../common/debug" +# ADD LINK32 icuuc17d.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../lib" /libpath:"../../common/debug" # SUBTRACT LINK32 /incremental:no !ENDIF