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 |