| OLD | NEW |
| (Empty) |
| 1 diff --git a/source/test/intltest/loctest.cpp b/source/test/intltest/loctest.cpp | |
| 2 index 1bcf771..5922e1c 100644 | |
| 3 --- a/source/test/intltest/loctest.cpp | |
| 4 +++ b/source/test/intltest/loctest.cpp | |
| 5 @@ -1,6 +1,6 @@ | |
| 6 /******************************************************************** | |
| 7 * COPYRIGHT: | |
| 8 - * Copyright (c) 1997-2014, International Business Machines Corporation and | |
| 9 + * Copyright (c) 1997-2015, International Business Machines Corporation and | |
| 10 * others. All Rights Reserved. | |
| 11 ********************************************************************/ | |
| 12 | |
| 13 @@ -181,6 +181,7 @@ LocaleTest::~LocaleTest() | |
| 14 void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
char* /*par*/ ) | |
| 15 { | |
| 16 TESTCASE_AUTO_BEGIN; | |
| 17 + TESTCASE_AUTO(TestBug11421); // Must run early in list to trigger f
ailure. | |
| 18 TESTCASE_AUTO(TestBasicGetters); | |
| 19 TESTCASE_AUTO(TestSimpleResourceInfo); | |
| 20 TESTCASE_AUTO(TestDisplayNames); | |
| 21 @@ -1756,12 +1757,13 @@ LocaleTest::TestGetBaseName(void) { | |
| 22 } testCases[] = { | |
| 23 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" }, | |
| 24 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" }, | |
| 25 - { "ja@calendar = buddhist", "ja" } | |
| 26 + { "ja@calendar = buddhist", "ja" }, | |
| 27 + { "de-u-co-phonebk", "de"} | |
| 28 }; | |
| 29 | |
| 30 int32_t i = 0; | |
| 31 | |
| 32 - for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) { | |
| 33 + for(i = 0; i < UPRV_LENGTHOF(testCases); i++) { | |
| 34 Locale loc(testCases[i].localeID); | |
| 35 if(strcmp(testCases[i].baseName, loc.getBaseName())) { | |
| 36 errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"", | |
| 37 @@ -1769,6 +1771,20 @@ LocaleTest::TestGetBaseName(void) { | |
| 38 return; | |
| 39 } | |
| 40 } | |
| 41 + | |
| 42 + // Verify that adding a keyword to an existing Locale doesn't change the ba
se name. | |
| 43 + UErrorCode status = U_ZERO_ERROR; | |
| 44 + Locale loc2("en-US"); | |
| 45 + if (strcmp("en_US", loc2.getBaseName())) { | |
| 46 + errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.
getBaseName()); | |
| 47 + } | |
| 48 + loc2.setKeywordValue("key", "value", status); | |
| 49 + if (strcmp("en_US@key=value", loc2.getName())) { | |
| 50 + errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LIN
E__, loc2.getName()); | |
| 51 + } | |
| 52 + if (strcmp("en_US", loc2.getBaseName())) { | |
| 53 + errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.
getBaseName()); | |
| 54 + } | |
| 55 } | |
| 56 | |
| 57 /** | |
| 58 @@ -2549,3 +2565,17 @@ void LocaleTest::TestIsRightToLeft() { | |
| 59 assertFalse("fil LTR", Locale("fil").isRightToLeft()); | |
| 60 assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft()); | |
| 61 } | |
| 62 + | |
| 63 +void LocaleTest::TestBug11421() { | |
| 64 + Locale::getDefault().getBaseName(); | |
| 65 + int32_t numLocales; | |
| 66 + const Locale *localeList = Locale::getAvailableLocales(numLocales); | |
| 67 + for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) { | |
| 68 + const Locale &loc = localeList[localeIndex]; | |
| 69 + if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName())
)) { | |
| 70 + errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"", | |
| 71 + __FILE__, __LINE__, loc.getName(), loc.getBaseName()); | |
| 72 + break; | |
| 73 + } | |
| 74 + } | |
| 75 +} | |
| 76 diff --git a/source/test/intltest/loctest.h b/source/test/intltest/loctest.h | |
| 77 index 53f606d..d556571 100644 | |
| 78 --- a/source/test/intltest/loctest.h | |
| 79 +++ b/source/test/intltest/loctest.h | |
| 80 @@ -1,6 +1,6 @@ | |
| 81 /******************************************************************** | |
| 82 * COPYRIGHT: | |
| 83 - * Copyright (c) 1997-2014, International Business Machines Corporation and | |
| 84 + * Copyright (c) 1997-2015, International Business Machines Corporation and | |
| 85 * others. All Rights Reserved. | |
| 86 ********************************************************************/ | |
| 87 | |
| 88 @@ -102,6 +102,7 @@ public: | |
| 89 | |
| 90 void TestGetVariantWithKeywords(void); | |
| 91 void TestIsRightToLeft(); | |
| 92 + void TestBug11421(); | |
| 93 | |
| 94 private: | |
| 95 void _checklocs(const char* label, | |
| 96 diff --git a/source/common/locid.cpp b/source/common/locid.cpp | |
| 97 index f073aad..c99c61c 100644 | |
| 98 --- a/source/common/locid.cpp | |
| 99 +++ b/source/common/locid.cpp | |
| 100 @@ -38,6 +38,7 @@ | |
| 101 #include "uassert.h" | |
| 102 #include "cmemory.h" | |
| 103 #include "cstring.h" | |
| 104 +#include "uassert.h" | |
| 105 #include "uhash.h" | |
| 106 #include "ucln_cmn.h" | |
| 107 #include "ustr_imp.h" | |
| 108 @@ -240,16 +241,16 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) | |
| 109 | |
| 110 Locale::~Locale() | |
| 111 { | |
| 112 + if (baseName != fullName) { | |
| 113 + uprv_free(baseName); | |
| 114 + } | |
| 115 + baseName = NULL; | |
| 116 /*if fullName is on the heap, we free it*/ | |
| 117 if (fullName != fullNameBuffer) | |
| 118 { | |
| 119 uprv_free(fullName); | |
| 120 fullName = NULL; | |
| 121 } | |
| 122 - if (baseName && baseName != baseNameBuffer) { | |
| 123 - uprv_free(baseName); | |
| 124 - baseName = NULL; | |
| 125 - } | |
| 126 } | |
| 127 | |
| 128 Locale::Locale() | |
| 129 @@ -421,6 +422,10 @@ Locale &Locale::operator=(const Locale &other) | |
| 130 } | |
| 131 | |
| 132 /* Free our current storage */ | |
| 133 + if (baseName != fullName) { | |
| 134 + uprv_free(baseName); | |
| 135 + } | |
| 136 + baseName = NULL; | |
| 137 if(fullName != fullNameBuffer) { | |
| 138 uprv_free(fullName); | |
| 139 fullName = fullNameBuffer; | |
| 140 @@ -436,18 +441,13 @@ Locale &Locale::operator=(const Locale &other) | |
| 141 /* Copy the full name */ | |
| 142 uprv_strcpy(fullName, other.fullName); | |
| 143 | |
| 144 - /* baseName is the cached result of getBaseName. if 'other' has a | |
| 145 - baseName and it fits in baseNameBuffer, then copy it. otherwise set | |
| 146 - it to NULL, and let the user lazy-create it (in getBaseName) if they | |
| 147 - want it. */ | |
| 148 - if(baseName && baseName != baseNameBuffer) { | |
| 149 - uprv_free(baseName); | |
| 150 - } | |
| 151 - baseName = NULL; | |
| 152 - | |
| 153 - if(other.baseName == other.baseNameBuffer) { | |
| 154 - uprv_strcpy(baseNameBuffer, other.baseNameBuffer); | |
| 155 - baseName = baseNameBuffer; | |
| 156 + /* Copy the baseName if it differs from fullName. */ | |
| 157 + if (other.baseName == other.fullName) { | |
| 158 + baseName = fullName; | |
| 159 + } else { | |
| 160 + if (other.baseName) { | |
| 161 + baseName = uprv_strdup(other.baseName); | |
| 162 + } | |
| 163 } | |
| 164 | |
| 165 /* Copy the language and country fields */ | |
| 166 @@ -479,16 +479,15 @@ Locale& Locale::init(const char* localeID, UBool canonical
ize) | |
| 167 { | |
| 168 fIsBogus = FALSE; | |
| 169 /* Free our current storage */ | |
| 170 + if (baseName != fullName) { | |
| 171 + uprv_free(baseName); | |
| 172 + } | |
| 173 + baseName = NULL; | |
| 174 if(fullName != fullNameBuffer) { | |
| 175 uprv_free(fullName); | |
| 176 fullName = fullNameBuffer; | |
| 177 } | |
| 178 | |
| 179 - if(baseName && baseName != baseNameBuffer) { | |
| 180 - uprv_free(baseName); | |
| 181 - baseName = NULL; | |
| 182 - } | |
| 183 - | |
| 184 // not a loop: | |
| 185 // just an easy way to have a common error-exit | |
| 186 // without goto and without another function | |
| 187 @@ -588,6 +587,12 @@ Locale& Locale::init(const char* localeID, UBool canonicali
ze) | |
| 188 variantBegin = (int32_t)(field[variantField] - fullName); | |
| 189 } | |
| 190 | |
| 191 + err = U_ZERO_ERROR; | |
| 192 + initBaseName(err); | |
| 193 + if (U_FAILURE(err)) { | |
| 194 + break; | |
| 195 + } | |
| 196 + | |
| 197 // successful end of init() | |
| 198 return *this; | |
| 199 } while(0); /*loop doesn't iterate*/ | |
| 200 @@ -598,6 +603,43 @@ Locale& Locale::init(const char* localeID, UBool canonicali
ze) | |
| 201 return *this; | |
| 202 } | |
| 203 | |
| 204 +/* | |
| 205 + * Set up the base name. | |
| 206 + * If there are no key words, it's exactly the full name. | |
| 207 + * If key words exist, it's the full name truncated at the '@' character. | |
| 208 + * Need to set up both at init() and after setting a keyword. | |
| 209 + */ | |
| 210 +void | |
| 211 +Locale::initBaseName(UErrorCode &status) { | |
| 212 + if (U_FAILURE(status)) { | |
| 213 + return; | |
| 214 + } | |
| 215 + U_ASSERT(baseName==NULL || baseName==fullName); | |
| 216 + const char *atPtr = uprv_strchr(fullName, '@'); | |
| 217 + const char *eqPtr = uprv_strchr(fullName, '='); | |
| 218 + if (atPtr && eqPtr && atPtr < eqPtr) { | |
| 219 + // Key words exist. | |
| 220 + int32_t baseNameLength = (int32_t)(atPtr - fullName); | |
| 221 + baseName = (char *)uprv_malloc(baseNameLength + 1); | |
| 222 + if (baseName == NULL) { | |
| 223 + status = U_MEMORY_ALLOCATION_ERROR; | |
| 224 + return; | |
| 225 + } | |
| 226 + uprv_strncpy(baseName, fullName, baseNameLength); | |
| 227 + baseName[baseNameLength] = 0; | |
| 228 + | |
| 229 + // The original computation of variantBegin leaves it equal to the leng
th | |
| 230 + // of fullName if there is no variant. It should instead be | |
| 231 + // the length of the baseName. | |
| 232 + if (variantBegin > baseNameLength) { | |
| 233 + variantBegin = baseNameLength; | |
| 234 + } | |
| 235 + } else { | |
| 236 + baseName = fullName; | |
| 237 + } | |
| 238 +} | |
| 239 + | |
| 240 + | |
| 241 int32_t | |
| 242 Locale::hashCode() const | |
| 243 { | |
| 244 @@ -607,14 +649,14 @@ Locale::hashCode() const | |
| 245 void | |
| 246 Locale::setToBogus() { | |
| 247 /* Free our current storage */ | |
| 248 + if(baseName != fullName) { | |
| 249 + uprv_free(baseName); | |
| 250 + } | |
| 251 + baseName = NULL; | |
| 252 if(fullName != fullNameBuffer) { | |
| 253 uprv_free(fullName); | |
| 254 fullName = fullNameBuffer; | |
| 255 } | |
| 256 - if(baseName && baseName != baseNameBuffer) { | |
| 257 - uprv_free(baseName); | |
| 258 - baseName = NULL; | |
| 259 - } | |
| 260 *fullNameBuffer = 0; | |
| 261 *language = 0; | |
| 262 *script = 0; | |
| 263 @@ -990,33 +1032,14 @@ void | |
| 264 Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErr
orCode &status) | |
| 265 { | |
| 266 uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAP
ACITY, &status); | |
| 267 + if (U_SUCCESS(status) && baseName == fullName) { | |
| 268 + // May have added the first keyword, meaning that the fullName is no lo
nger also the baseName. | |
| 269 + initBaseName(status); | |
| 270 + } | |
| 271 } | |
| 272 | |
| 273 const char * | |
| 274 -Locale::getBaseName() const | |
| 275 -{ | |
| 276 - // lazy init | |
| 277 - UErrorCode status = U_ZERO_ERROR; | |
| 278 - // semantically const | |
| 279 - if(baseName == 0) { | |
| 280 - ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer; | |
| 281 - int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNA
ME_CAPACITY, &status); | |
| 282 - if(baseNameSize >= ULOC_FULLNAME_CAPACITY) { | |
| 283 - ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * bas
eNameSize + 1); | |
| 284 - if (baseName == NULL) { | |
| 285 - return baseName; | |
| 286 - } | |
| 287 - uloc_getBaseName(fullName, baseName, baseNameSize+1, &status); | |
| 288 - } | |
| 289 - baseName[baseNameSize] = 0; | |
| 290 - | |
| 291 - // the computation of variantBegin leaves it equal to the length | |
| 292 - // of fullName if there is no variant. It should instead be | |
| 293 - // the length of the baseName. Patch around this for now. | |
| 294 - if (variantBegin == (int32_t)uprv_strlen(fullName)) { | |
| 295 - ((Locale*)this)->variantBegin = baseNameSize; | |
| 296 - } | |
| 297 - } | |
| 298 +Locale::getBaseName() const { | |
| 299 return baseName; | |
| 300 } | |
| 301 | |
| 302 diff --git a/source/common/unicode/locid.h b/source/common/unicode/locid.h | |
| 303 index 3546192..1ad5cb5 100644 | |
| 304 --- a/source/common/unicode/locid.h | |
| 305 +++ b/source/common/unicode/locid.h | |
| 306 @@ -1,7 +1,7 @@ | |
| 307 /* | |
| 308 ****************************************************************************** | |
| 309 * | |
| 310 -* Copyright (C) 1996-2014, International Business Machines | |
| 311 +* Copyright (C) 1996-2015, International Business Machines | |
| 312 * Corporation and others. All Rights Reserved. | |
| 313 * | |
| 314 ****************************************************************************** | |
| 315 @@ -750,7 +750,7 @@ private: | |
| 316 char fullNameBuffer[ULOC_FULLNAME_CAPACITY]; | |
| 317 // name without keywords | |
| 318 char* baseName; | |
| 319 - char baseNameBuffer[ULOC_FULLNAME_CAPACITY]; | |
| 320 + void initBaseName(UErrorCode& status); | |
| 321 | |
| 322 UBool fIsBogus; | |
| 323 | |
| 324 @@ -795,7 +795,6 @@ Locale::getScript() const | |
| 325 inline const char * | |
| 326 Locale::getVariant() const | |
| 327 { | |
| 328 - getBaseName(); // lazy init | |
| 329 return &baseName[variantBegin]; | |
| 330 } | |
| 331 | |
| OLD | NEW |