]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
b331163b | 3 | * Copyright (C) 1997-2015, International Business Machines Corporation and * |
b75a7d8f A |
4 | * others. All Rights Reserved. * |
5 | ******************************************************************************* | |
6 | * | |
7 | * File DECIMFMT.CPP | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 02/19/97 aliu Converted from java. | |
13 | * 03/20/97 clhuang Implemented with new APIs. | |
14 | * 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it. | |
15 | * 04/3/97 aliu Rewrote parsing and formatting completely, and | |
16 | * cleaned up and debugged. Actually works now. | |
17 | * Implemented NAN and INF handling, for both parsing | |
18 | * and formatting. Extensive testing & debugging. | |
19 | * 04/10/97 aliu Modified to compile on AIX. | |
20 | * 04/16/97 aliu Rewrote to use DigitList, which has been resurrected. | |
21 | * Changed DigitCount to int per code review. | |
22 | * 07/09/97 helena Made ParsePosition into a class. | |
23 | * 08/26/97 aliu Extensive changes to applyPattern; completely | |
24 | * rewritten from the Java. | |
25 | * 09/09/97 aliu Ported over support for exponential formats. | |
26 | * 07/20/98 stephen JDK 1.2 sync up. | |
27 | * Various instances of '0' replaced with 'NULL' | |
28 | * Check for grouping size in subFormat() | |
29 | * Brought subParse() in line with Java 1.2 | |
30 | * Added method appendAffix() | |
31 | * 08/24/1998 srl Removed Mutex calls. This is not a thread safe class! | |
32 | * 02/22/99 stephen Removed character literals for EBCDIC safety | |
33 | * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes | |
34 | * 06/28/99 stephen Fixed bugs in toPattern(). | |
729e4ab9 | 35 | * 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad, |
b75a7d8f A |
36 | * fPadPosition |
37 | ******************************************************************************** | |
38 | */ | |
729e4ab9 | 39 | |
b75a7d8f A |
40 | #include "unicode/utypes.h" |
41 | ||
42 | #if !UCONFIG_NO_FORMATTING | |
43 | ||
46f4442e | 44 | #include "unicode/uniset.h" |
729e4ab9 A |
45 | #include "unicode/currpinf.h" |
46 | #include "unicode/plurrule.h" | |
4388f060 A |
47 | #include "unicode/utf16.h" |
48 | #include "unicode/numsys.h" | |
49 | #include "unicode/localpointer.h" | |
50 | #include "uresimp.h" | |
374ca955 | 51 | #include "ucurrimp.h" |
729e4ab9 | 52 | #include "charstr.h" |
4388f060 | 53 | #include "patternprops.h" |
b75a7d8f | 54 | #include "cstring.h" |
b75a7d8f | 55 | #include "uassert.h" |
729e4ab9 | 56 | #include "hash.h" |
4388f060 | 57 | #include "decfmtst.h" |
57a6839d A |
58 | #include "plurrule_impl.h" |
59 | #include "decimalformatpattern.h" | |
b331163b | 60 | #include "fmtableimp.h" |
2ca993e8 A |
61 | #include "decimfmtimpl.h" |
62 | #include "visibledigits.h" | |
729e4ab9 | 63 | |
51004dcb A |
64 | /* |
65 | * On certain platforms, round is a macro defined in math.h | |
66 | * This undefine is to avoid conflict between the macro and | |
67 | * the function defined below. | |
68 | */ | |
69 | #ifdef round | |
70 | #undef round | |
71 | #endif | |
b75a7d8f | 72 | |
57a6839d | 73 | |
b75a7d8f A |
74 | U_NAMESPACE_BEGIN |
75 | ||
57a6839d A |
76 | #ifdef FMT_DEBUG |
77 | #include <stdio.h> | |
78 | static void _debugout(const char *f, int l, const UnicodeString& s) { | |
79 | char buf[2000]; | |
80 | s.extract((int32_t) 0, s.length(), buf, "utf-8"); | |
81 | printf("%s:%d: %s\n", f,l, buf); | |
82 | } | |
83 | #define debugout(x) _debugout(__FILE__,__LINE__,x) | |
84 | #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x); | |
85 | static const UnicodeString dbg_null("<NULL>",""); | |
86 | #define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null)) | |
87 | #else | |
88 | #define debugout(x) | |
89 | #define debug(x) | |
90 | #endif | |
91 | ||
92 | ||
729e4ab9 A |
93 | /* For currency parsing purose, |
94 | * Need to remember all prefix patterns and suffix patterns of | |
95 | * every currency format pattern, | |
96 | * including the pattern of default currecny style | |
97 | * and plural currency style. And the patterns are set through applyPattern. | |
98 | */ | |
99 | struct AffixPatternsForCurrency : public UMemory { | |
100 | // negative prefix pattern | |
101 | UnicodeString negPrefixPatternForCurrency; | |
102 | // negative suffix pattern | |
103 | UnicodeString negSuffixPatternForCurrency; | |
104 | // positive prefix pattern | |
105 | UnicodeString posPrefixPatternForCurrency; | |
106 | // positive suffix pattern | |
107 | UnicodeString posSuffixPatternForCurrency; | |
108 | int8_t patternType; | |
109 | ||
110 | AffixPatternsForCurrency(const UnicodeString& negPrefix, | |
111 | const UnicodeString& negSuffix, | |
112 | const UnicodeString& posPrefix, | |
113 | const UnicodeString& posSuffix, | |
114 | int8_t type) { | |
115 | negPrefixPatternForCurrency = negPrefix; | |
116 | negSuffixPatternForCurrency = negSuffix; | |
117 | posPrefixPatternForCurrency = posPrefix; | |
118 | posSuffixPatternForCurrency = posSuffix; | |
119 | patternType = type; | |
120 | } | |
57a6839d A |
121 | #ifdef FMT_DEBUG |
122 | void dump() const { | |
123 | debugout( UnicodeString("AffixPatternsForCurrency( -=\"") + | |
124 | negPrefixPatternForCurrency + (UnicodeString)"\"/\"" + | |
125 | negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" + | |
126 | posPrefixPatternForCurrency + (UnicodeString)"\"/\"" + | |
127 | posSuffixPatternForCurrency + (UnicodeString)"\" )"); | |
128 | } | |
129 | #endif | |
729e4ab9 A |
130 | }; |
131 | ||
132 | /* affix for currency formatting when the currency sign in the pattern | |
133 | * equals to 3, such as the pattern contains 3 currency sign or | |
134 | * the formatter style is currency plural format style. | |
135 | */ | |
136 | struct AffixesForCurrency : public UMemory { | |
137 | // negative prefix | |
138 | UnicodeString negPrefixForCurrency; | |
139 | // negative suffix | |
140 | UnicodeString negSuffixForCurrency; | |
141 | // positive prefix | |
142 | UnicodeString posPrefixForCurrency; | |
143 | // positive suffix | |
144 | UnicodeString posSuffixForCurrency; | |
145 | ||
146 | int32_t formatWidth; | |
147 | ||
148 | AffixesForCurrency(const UnicodeString& negPrefix, | |
149 | const UnicodeString& negSuffix, | |
150 | const UnicodeString& posPrefix, | |
151 | const UnicodeString& posSuffix) { | |
152 | negPrefixForCurrency = negPrefix; | |
153 | negSuffixForCurrency = negSuffix; | |
154 | posPrefixForCurrency = posPrefix; | |
155 | posSuffixForCurrency = posSuffix; | |
156 | } | |
57a6839d A |
157 | #ifdef FMT_DEBUG |
158 | void dump() const { | |
159 | debugout( UnicodeString("AffixesForCurrency( -=\"") + | |
160 | negPrefixForCurrency + (UnicodeString)"\"/\"" + | |
161 | negSuffixForCurrency + (UnicodeString)"\" +=\"" + | |
162 | posPrefixForCurrency + (UnicodeString)"\"/\"" + | |
163 | posSuffixForCurrency + (UnicodeString)"\" )"); | |
164 | } | |
165 | #endif | |
729e4ab9 A |
166 | }; |
167 | ||
168 | U_CDECL_BEGIN | |
169 | ||
729e4ab9 A |
170 | /** |
171 | * @internal ICU 4.2 | |
172 | */ | |
173 | static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2); | |
174 | ||
175 | ||
729e4ab9 A |
176 | static UBool |
177 | U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) { | |
178 | const AffixPatternsForCurrency* affix_1 = | |
179 | (AffixPatternsForCurrency*)val1.pointer; | |
180 | const AffixPatternsForCurrency* affix_2 = | |
181 | (AffixPatternsForCurrency*)val2.pointer; | |
182 | return affix_1->negPrefixPatternForCurrency == | |
183 | affix_2->negPrefixPatternForCurrency && | |
184 | affix_1->negSuffixPatternForCurrency == | |
185 | affix_2->negSuffixPatternForCurrency && | |
186 | affix_1->posPrefixPatternForCurrency == | |
187 | affix_2->posPrefixPatternForCurrency && | |
188 | affix_1->posSuffixPatternForCurrency == | |
189 | affix_2->posSuffixPatternForCurrency && | |
190 | affix_1->patternType == affix_2->patternType; | |
191 | } | |
192 | ||
193 | U_CDECL_END | |
194 | ||
b75a7d8f | 195 | |
4388f060 | 196 | |
46f4442e | 197 | |
b75a7d8f A |
198 | // ***************************************************************************** |
199 | // class DecimalFormat | |
200 | // ***************************************************************************** | |
201 | ||
374ca955 | 202 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat) |
b75a7d8f A |
203 | |
204 | // Constants for characters used in programmatic (unlocalized) patterns. | |
374ca955 A |
205 | #define kPatternZeroDigit ((UChar)0x0030) /*'0'*/ |
206 | #define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/ | |
207 | #define kPatternGroupingSeparator ((UChar)0x002C) /*','*/ | |
208 | #define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/ | |
209 | #define kPatternPerMill ((UChar)0x2030) | |
210 | #define kPatternPercent ((UChar)0x0025) /*'%'*/ | |
211 | #define kPatternDigit ((UChar)0x0023) /*'#'*/ | |
212 | #define kPatternSeparator ((UChar)0x003B) /*';'*/ | |
213 | #define kPatternExponent ((UChar)0x0045) /*'E'*/ | |
214 | #define kPatternPlus ((UChar)0x002B) /*'+'*/ | |
215 | #define kPatternMinus ((UChar)0x002D) /*'-'*/ | |
216 | #define kPatternPadEscape ((UChar)0x002A) /*'*'*/ | |
217 | #define kQuote ((UChar)0x0027) /*'\''*/ | |
218 | /** | |
219 | * The CURRENCY_SIGN is the standard Unicode symbol for currency. It | |
220 | * is used in patterns and substitued with either the currency symbol, | |
221 | * or if it is doubled, with the international currency symbol. If the | |
222 | * CURRENCY_SIGN is seen in a pattern, then the decimal separator is | |
223 | * replaced with the monetary decimal separator. | |
224 | */ | |
225 | #define kCurrencySign ((UChar)0x00A4) | |
226 | #define kDefaultPad ((UChar)0x0020) /* */ | |
b75a7d8f A |
227 | |
228 | const int32_t DecimalFormat::kDoubleIntegerDigits = 309; | |
229 | const int32_t DecimalFormat::kDoubleFractionDigits = 340; | |
230 | ||
374ca955 A |
231 | const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8; |
232 | ||
b75a7d8f A |
233 | /** |
234 | * These are the tags we expect to see in normal resource bundle files associated | |
235 | * with a locale. | |
236 | */ | |
729e4ab9 A |
237 | const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used |
238 | static const char fgNumberElements[]="NumberElements"; | |
239 | static const char fgLatn[]="latn"; | |
240 | static const char fgPatterns[]="patterns"; | |
241 | static const char fgDecimalFormat[]="decimalFormat"; | |
242 | static const char fgCurrencyFormat[]="currencyFormat"; | |
57a6839d | 243 | |
374ca955 A |
244 | inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; } |
245 | inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; } | |
b75a7d8f A |
246 | |
247 | //------------------------------------------------------------------------------ | |
248 | // Constructs a DecimalFormat instance in the default locale. | |
729e4ab9 A |
249 | |
250 | DecimalFormat::DecimalFormat(UErrorCode& status) { | |
57a6839d | 251 | init(); |
b75a7d8f A |
252 | UParseError parseError; |
253 | construct(status, parseError); | |
254 | } | |
255 | ||
256 | //------------------------------------------------------------------------------ | |
257 | // Constructs a DecimalFormat instance with the specified number format | |
258 | // pattern in the default locale. | |
259 | ||
260 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
729e4ab9 | 261 | UErrorCode& status) { |
57a6839d | 262 | init(); |
b75a7d8f A |
263 | UParseError parseError; |
264 | construct(status, parseError, &pattern); | |
265 | } | |
266 | ||
267 | //------------------------------------------------------------------------------ | |
268 | // Constructs a DecimalFormat instance with the specified number format | |
269 | // pattern and the number format symbols in the default locale. The | |
270 | // created instance owns the symbols. | |
271 | ||
272 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
273 | DecimalFormatSymbols* symbolsToAdopt, | |
729e4ab9 | 274 | UErrorCode& status) { |
57a6839d | 275 | init(); |
b75a7d8f A |
276 | UParseError parseError; |
277 | if (symbolsToAdopt == NULL) | |
278 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
279 | construct(status, parseError, &pattern, symbolsToAdopt); | |
280 | } | |
729e4ab9 | 281 | |
b75a7d8f A |
282 | DecimalFormat::DecimalFormat( const UnicodeString& pattern, |
283 | DecimalFormatSymbols* symbolsToAdopt, | |
284 | UParseError& parseErr, | |
729e4ab9 | 285 | UErrorCode& status) { |
57a6839d | 286 | init(); |
b75a7d8f A |
287 | if (symbolsToAdopt == NULL) |
288 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
289 | construct(status,parseErr, &pattern, symbolsToAdopt); | |
290 | } | |
729e4ab9 | 291 | |
b75a7d8f A |
292 | //------------------------------------------------------------------------------ |
293 | // Constructs a DecimalFormat instance with the specified number format | |
294 | // pattern and the number format symbols in the default locale. The | |
295 | // created instance owns the clone of the symbols. | |
729e4ab9 | 296 | |
b75a7d8f A |
297 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
298 | const DecimalFormatSymbols& symbols, | |
729e4ab9 | 299 | UErrorCode& status) { |
57a6839d | 300 | init(); |
b75a7d8f A |
301 | UParseError parseError; |
302 | construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols)); | |
303 | } | |
304 | ||
729e4ab9 A |
305 | //------------------------------------------------------------------------------ |
306 | // Constructs a DecimalFormat instance with the specified number format | |
307 | // pattern, the number format symbols, and the number format style. | |
308 | // The created instance owns the clone of the symbols. | |
309 | ||
310 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
311 | DecimalFormatSymbols* symbolsToAdopt, | |
4388f060 | 312 | UNumberFormatStyle style, |
729e4ab9 | 313 | UErrorCode& status) { |
57a6839d | 314 | init(); |
729e4ab9 A |
315 | fStyle = style; |
316 | UParseError parseError; | |
317 | construct(status, parseError, &pattern, symbolsToAdopt); | |
318 | } | |
319 | ||
320 | //----------------------------------------------------------------------------- | |
321 | // Common DecimalFormat initialization. | |
322 | // Put all fields of an uninitialized object into a known state. | |
323 | // Common code, shared by all constructors. | |
57a6839d A |
324 | // Can not fail. Leave the object in good enough shape that the destructor |
325 | // or assignment operator can run successfully. | |
729e4ab9 | 326 | void |
57a6839d | 327 | DecimalFormat::init() { |
51004dcb | 328 | fBoolFlags.clear(); |
4388f060 | 329 | fStyle = UNUM_DECIMAL; |
729e4ab9 | 330 | fAffixPatternsForCurrency = NULL; |
729e4ab9 | 331 | fCurrencyPluralInfo = NULL; |
51004dcb A |
332 | #if UCONFIG_HAVE_PARSEALLINPUT |
333 | fParseAllInput = UNUM_MAYBE; | |
334 | #endif | |
335 | ||
57a6839d | 336 | fStaticSets = NULL; |
2ca993e8 | 337 | fImpl = NULL; |
729e4ab9 A |
338 | } |
339 | ||
b75a7d8f A |
340 | //------------------------------------------------------------------------------ |
341 | // Constructs a DecimalFormat instance with the specified number format | |
342 | // pattern and the number format symbols in the desired locale. The | |
343 | // created instance owns the symbols. | |
344 | ||
345 | void | |
57a6839d | 346 | DecimalFormat::construct(UErrorCode& status, |
b75a7d8f A |
347 | UParseError& parseErr, |
348 | const UnicodeString* pattern, | |
349 | DecimalFormatSymbols* symbolsToAdopt) | |
350 | { | |
2ca993e8 | 351 | LocalPointer<DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt); |
b75a7d8f A |
352 | if (U_FAILURE(status)) |
353 | return; | |
354 | ||
2ca993e8 | 355 | if (adoptedSymbols.isNull()) |
b75a7d8f | 356 | { |
2ca993e8 A |
357 | adoptedSymbols.adoptInstead( |
358 | new DecimalFormatSymbols(Locale::getDefault(), status)); | |
359 | if (adoptedSymbols.isNull() && U_SUCCESS(status)) { | |
b75a7d8f | 360 | status = U_MEMORY_ALLOCATION_ERROR; |
2ca993e8 A |
361 | } |
362 | if (U_FAILURE(status)) { | |
b75a7d8f A |
363 | return; |
364 | } | |
365 | } | |
57a6839d A |
366 | fStaticSets = DecimalFormatStaticSets::getStaticSets(status); |
367 | if (U_FAILURE(status)) { | |
368 | return; | |
369 | } | |
b75a7d8f A |
370 | |
371 | UnicodeString str; | |
372 | // Uses the default locale's number format pattern if there isn't | |
373 | // one specified. | |
374 | if (pattern == NULL) | |
375 | { | |
2ca993e8 A |
376 | UErrorCode nsStatus = U_ZERO_ERROR; |
377 | LocalPointer<NumberingSystem> ns( | |
378 | NumberingSystem::createInstance(nsStatus)); | |
379 | if (U_FAILURE(nsStatus)) { | |
380 | status = nsStatus; | |
381 | return; | |
382 | } | |
383 | ||
374ca955 | 384 | int32_t len = 0; |
4388f060 A |
385 | UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status); |
386 | ||
387 | UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status); | |
388 | resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status); | |
389 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); | |
390 | const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); | |
391 | if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) { | |
392 | status = U_ZERO_ERROR; | |
393 | resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status); | |
394 | resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status); | |
395 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); | |
396 | resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); | |
397 | } | |
374ca955 | 398 | str.setTo(TRUE, resStr, len); |
b75a7d8f | 399 | pattern = &str; |
374ca955 | 400 | ures_close(resource); |
4388f060 | 401 | ures_close(top); |
b75a7d8f A |
402 | } |
403 | ||
2ca993e8 A |
404 | fImpl = new DecimalFormatImpl(this, *pattern, adoptedSymbols.getAlias(), parseErr, status); |
405 | if (fImpl) { | |
406 | adoptedSymbols.orphan(); | |
407 | } else if (U_SUCCESS(status)) { | |
408 | status = U_MEMORY_ALLOCATION_ERROR; | |
409 | } | |
410 | if (U_FAILURE(status)) { | |
411 | return; | |
412 | } | |
4388f060 | 413 | |
b75a7d8f A |
414 | if (U_FAILURE(status)) |
415 | { | |
416 | return; | |
417 | } | |
418 | ||
729e4ab9 A |
419 | const UnicodeString* patternUsed; |
420 | UnicodeString currencyPluralPatternForOther; | |
421 | // apply pattern | |
4388f060 | 422 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
2ca993e8 | 423 | fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status); |
729e4ab9 A |
424 | if (U_FAILURE(status)) { |
425 | return; | |
426 | } | |
427 | ||
428 | // the pattern used in format is not fixed until formatting, | |
429 | // in which, the number is known and | |
430 | // will be used to pick the right pattern based on plural count. | |
431 | // Here, set the pattern as the pattern of plural count == "other". | |
432 | // For most locale, the patterns are probably the same for all | |
433 | // plural count. If not, the right pattern need to be re-applied | |
434 | // during format. | |
4388f060 | 435 | fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther); |
2ca993e8 A |
436 | // TODO(refactor): Revisit, we are setting the pattern twice. |
437 | fImpl->applyPatternFavorCurrencyPrecision( | |
438 | currencyPluralPatternForOther, status); | |
729e4ab9 | 439 | patternUsed = ¤cyPluralPatternForOther; |
729e4ab9 A |
440 | |
441 | } else { | |
442 | patternUsed = pattern; | |
443 | } | |
444 | ||
445 | if (patternUsed->indexOf(kCurrencySign) != -1) { | |
446 | // initialize for currency, not only for plural format, | |
447 | // but also for mix parsing | |
2ca993e8 | 448 | handleCurrencySignInPattern(status); |
729e4ab9 | 449 | } |
2ca993e8 | 450 | } |
729e4ab9 | 451 | |
2ca993e8 A |
452 | void |
453 | DecimalFormat::handleCurrencySignInPattern(UErrorCode& status) { | |
454 | // initialize for currency, not only for plural format, | |
455 | // but also for mix parsing | |
456 | if (U_FAILURE(status)) { | |
457 | return; | |
b75a7d8f | 458 | } |
2ca993e8 A |
459 | if (fCurrencyPluralInfo == NULL) { |
460 | fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status); | |
461 | if (U_FAILURE(status)) { | |
462 | return; | |
463 | } | |
464 | } | |
465 | // need it for mix parsing | |
466 | if (fAffixPatternsForCurrency == NULL) { | |
467 | setupCurrencyAffixPatterns(status); | |
b75a7d8f | 468 | } |
b75a7d8f A |
469 | } |
470 | ||
2ca993e8 A |
471 | static void |
472 | applyPatternWithNoSideEffects( | |
473 | const UnicodeString& pattern, | |
474 | UParseError& parseError, | |
475 | UnicodeString &negPrefix, | |
476 | UnicodeString &negSuffix, | |
477 | UnicodeString &posPrefix, | |
478 | UnicodeString &posSuffix, | |
479 | UErrorCode& status) { | |
480 | if (U_FAILURE(status)) | |
481 | { | |
482 | return; | |
483 | } | |
484 | DecimalFormatPatternParser patternParser; | |
485 | DecimalFormatPattern out; | |
486 | patternParser.applyPatternWithoutExpandAffix( | |
487 | pattern, | |
488 | out, | |
489 | parseError, | |
490 | status); | |
491 | if (U_FAILURE(status)) { | |
492 | return; | |
493 | } | |
494 | negPrefix = out.fNegPrefixPattern; | |
495 | negSuffix = out.fNegSuffixPattern; | |
496 | posPrefix = out.fPosPrefixPattern; | |
497 | posSuffix = out.fPosSuffixPattern; | |
498 | } | |
729e4ab9 A |
499 | |
500 | void | |
501 | DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) { | |
502 | if (U_FAILURE(status)) { | |
503 | return; | |
504 | } | |
505 | UParseError parseErr; | |
506 | fAffixPatternsForCurrency = initHashForAffixPattern(status); | |
507 | if (U_FAILURE(status)) { | |
508 | return; | |
509 | } | |
510 | ||
2ca993e8 | 511 | NumberingSystem *ns = NumberingSystem::createInstance(fImpl->fSymbols->getLocale(),status); |
4388f060 A |
512 | if (U_FAILURE(status)) { |
513 | return; | |
514 | } | |
515 | ||
729e4ab9 A |
516 | // Save the default currency patterns of this locale. |
517 | // Here, chose onlyApplyPatternWithoutExpandAffix without | |
518 | // expanding the affix patterns into affixes. | |
519 | UnicodeString currencyPattern; | |
520 | UErrorCode error = U_ZERO_ERROR; | |
521 | ||
2ca993e8 | 522 | UResourceBundle *resource = ures_open(NULL, fImpl->fSymbols->getLocale().getName(), &error); |
4388f060 A |
523 | UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error); |
524 | resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error); | |
525 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); | |
729e4ab9 | 526 | int32_t patLen = 0; |
4388f060 A |
527 | const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); |
528 | if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) { | |
529 | error = U_ZERO_ERROR; | |
530 | resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error); | |
531 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); | |
532 | patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); | |
533 | } | |
534 | ures_close(numElements); | |
729e4ab9 | 535 | ures_close(resource); |
4388f060 | 536 | delete ns; |
729e4ab9 A |
537 | |
538 | if (U_SUCCESS(error)) { | |
2ca993e8 A |
539 | UnicodeString negPrefix; |
540 | UnicodeString negSuffix; | |
541 | UnicodeString posPrefix; | |
542 | UnicodeString posSuffix; | |
543 | applyPatternWithNoSideEffects(UnicodeString(patResStr, patLen), | |
544 | parseErr, | |
545 | negPrefix, negSuffix, posPrefix, posSuffix, status); | |
729e4ab9 | 546 | AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( |
2ca993e8 A |
547 | negPrefix, |
548 | negSuffix, | |
549 | posPrefix, | |
550 | posSuffix, | |
729e4ab9 | 551 | UCURR_SYMBOL_NAME); |
4388f060 | 552 | fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status); |
729e4ab9 A |
553 | } |
554 | ||
555 | // save the unique currency plural patterns of this locale. | |
556 | Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern; | |
557 | const UHashElement* element = NULL; | |
b331163b | 558 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
559 | Hashtable pluralPatternSet; |
560 | while ((element = pluralPtn->nextElement(pos)) != NULL) { | |
561 | const UHashTok valueTok = element->value; | |
562 | const UnicodeString* value = (UnicodeString*)valueTok.pointer; | |
563 | const UHashTok keyTok = element->key; | |
564 | const UnicodeString* key = (UnicodeString*)keyTok.pointer; | |
565 | if (pluralPatternSet.geti(*value) != 1) { | |
2ca993e8 A |
566 | UnicodeString negPrefix; |
567 | UnicodeString negSuffix; | |
568 | UnicodeString posPrefix; | |
569 | UnicodeString posSuffix; | |
729e4ab9 | 570 | pluralPatternSet.puti(*value, 1, status); |
2ca993e8 A |
571 | applyPatternWithNoSideEffects( |
572 | *value, parseErr, | |
573 | negPrefix, negSuffix, posPrefix, posSuffix, status); | |
729e4ab9 | 574 | AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( |
2ca993e8 A |
575 | negPrefix, |
576 | negSuffix, | |
577 | posPrefix, | |
578 | posSuffix, | |
729e4ab9 A |
579 | UCURR_LONG_NAME); |
580 | fAffixPatternsForCurrency->put(*key, affixPtn, status); | |
581 | } | |
582 | } | |
583 | } | |
584 | ||
585 | ||
b75a7d8f A |
586 | //------------------------------------------------------------------------------ |
587 | ||
588 | DecimalFormat::~DecimalFormat() | |
589 | { | |
729e4ab9 | 590 | deleteHashForAffixPattern(); |
729e4ab9 | 591 | delete fCurrencyPluralInfo; |
2ca993e8 | 592 | delete fImpl; |
b75a7d8f A |
593 | } |
594 | ||
595 | //------------------------------------------------------------------------------ | |
596 | // copy constructor | |
597 | ||
729e4ab9 A |
598 | DecimalFormat::DecimalFormat(const DecimalFormat &source) : |
599 | NumberFormat(source) { | |
57a6839d | 600 | init(); |
b75a7d8f A |
601 | *this = source; |
602 | } | |
603 | ||
604 | //------------------------------------------------------------------------------ | |
605 | // assignment operator | |
b75a7d8f | 606 | |
51004dcb A |
607 | template <class T> |
608 | static void _clone_ptr(T** pdest, const T* source) { | |
609 | delete *pdest; | |
610 | if (source == NULL) { | |
611 | *pdest = NULL; | |
b75a7d8f | 612 | } else { |
51004dcb | 613 | *pdest = static_cast<T*>(source->clone()); |
b75a7d8f A |
614 | } |
615 | } | |
616 | ||
617 | DecimalFormat& | |
618 | DecimalFormat::operator=(const DecimalFormat& rhs) | |
619 | { | |
374ca955 | 620 | if(this != &rhs) { |
57a6839d | 621 | UErrorCode status = U_ZERO_ERROR; |
374ca955 | 622 | NumberFormat::operator=(rhs); |
2ca993e8 A |
623 | if (fImpl == NULL) { |
624 | fImpl = new DecimalFormatImpl(this, *rhs.fImpl, status); | |
625 | } else { | |
626 | fImpl->assign(*rhs.fImpl, status); | |
627 | } | |
57a6839d | 628 | fStaticSets = DecimalFormatStaticSets::getStaticSets(status); |
729e4ab9 | 629 | fStyle = rhs.fStyle; |
51004dcb A |
630 | _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo); |
631 | deleteHashForAffixPattern(); | |
729e4ab9 A |
632 | if (rhs.fAffixPatternsForCurrency) { |
633 | UErrorCode status = U_ZERO_ERROR; | |
729e4ab9 A |
634 | fAffixPatternsForCurrency = initHashForAffixPattern(status); |
635 | copyHashForAffixPattern(rhs.fAffixPatternsForCurrency, | |
636 | fAffixPatternsForCurrency, status); | |
637 | } | |
57a6839d | 638 | } |
2ca993e8 | 639 | |
374ca955 | 640 | return *this; |
b75a7d8f A |
641 | } |
642 | ||
643 | //------------------------------------------------------------------------------ | |
644 | ||
645 | UBool | |
646 | DecimalFormat::operator==(const Format& that) const | |
647 | { | |
648 | if (this == &that) | |
649 | return TRUE; | |
650 | ||
374ca955 | 651 | // NumberFormat::operator== guarantees this cast is safe |
b75a7d8f A |
652 | const DecimalFormat* other = (DecimalFormat*)&that; |
653 | ||
57a6839d A |
654 | return ( |
655 | NumberFormat::operator==(that) && | |
57a6839d | 656 | fBoolFlags.getAll() == other->fBoolFlags.getAll() && |
2ca993e8 | 657 | *fImpl == *other->fImpl); |
57a6839d | 658 | |
b75a7d8f A |
659 | } |
660 | ||
661 | //------------------------------------------------------------------------------ | |
662 | ||
663 | Format* | |
664 | DecimalFormat::clone() const | |
665 | { | |
666 | return new DecimalFormat(*this); | |
667 | } | |
668 | ||
57a6839d A |
669 | |
670 | FixedDecimal | |
671 | DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const { | |
2ca993e8 A |
672 | VisibleDigitsWithExponent digits; |
673 | initVisibleDigitsWithExponent(number, digits, status); | |
57a6839d | 674 | if (U_FAILURE(status)) { |
2ca993e8 | 675 | return FixedDecimal(); |
57a6839d | 676 | } |
2ca993e8 A |
677 | return FixedDecimal(digits.getMantissa()); |
678 | } | |
57a6839d | 679 | |
2ca993e8 A |
680 | VisibleDigitsWithExponent & |
681 | DecimalFormat::initVisibleDigitsWithExponent( | |
682 | double number, | |
683 | VisibleDigitsWithExponent &digits, | |
684 | UErrorCode &status) const { | |
685 | return fImpl->initVisibleDigitsWithExponent(number, digits, status); | |
57a6839d A |
686 | } |
687 | ||
57a6839d A |
688 | FixedDecimal |
689 | DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const { | |
2ca993e8 A |
690 | VisibleDigitsWithExponent digits; |
691 | initVisibleDigitsWithExponent(number, digits, status); | |
57a6839d A |
692 | if (U_FAILURE(status)) { |
693 | return FixedDecimal(); | |
694 | } | |
2ca993e8 A |
695 | return FixedDecimal(digits.getMantissa()); |
696 | } | |
697 | ||
698 | VisibleDigitsWithExponent & | |
699 | DecimalFormat::initVisibleDigitsWithExponent( | |
700 | const Formattable &number, | |
701 | VisibleDigitsWithExponent &digits, | |
702 | UErrorCode &status) const { | |
703 | if (U_FAILURE(status)) { | |
704 | return digits; | |
705 | } | |
57a6839d A |
706 | if (!number.isNumeric()) { |
707 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
2ca993e8 | 708 | return digits; |
57a6839d A |
709 | } |
710 | ||
711 | DigitList *dl = number.getDigitList(); | |
712 | if (dl != NULL) { | |
2ca993e8 A |
713 | DigitList dlCopy(*dl); |
714 | return fImpl->initVisibleDigitsWithExponent( | |
715 | dlCopy, digits, status); | |
57a6839d A |
716 | } |
717 | ||
718 | Formattable::Type type = number.getType(); | |
719 | if (type == Formattable::kDouble || type == Formattable::kLong) { | |
2ca993e8 A |
720 | return fImpl->initVisibleDigitsWithExponent( |
721 | number.getDouble(status), digits, status); | |
57a6839d | 722 | } |
2ca993e8 A |
723 | return fImpl->initVisibleDigitsWithExponent( |
724 | number.getInt64(), digits, status); | |
57a6839d | 725 | } |
57a6839d A |
726 | |
727 | ||
728 | // Create a fixed decimal from a DigitList. | |
729 | // The digit list may be modified. | |
730 | // Internal function only. | |
731 | FixedDecimal | |
732 | DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const { | |
2ca993e8 A |
733 | VisibleDigitsWithExponent digits; |
734 | initVisibleDigitsWithExponent(number, digits, status); | |
735 | if (U_FAILURE(status)) { | |
736 | return FixedDecimal(); | |
57a6839d | 737 | } |
2ca993e8 A |
738 | return FixedDecimal(digits.getMantissa()); |
739 | } | |
57a6839d | 740 | |
2ca993e8 A |
741 | VisibleDigitsWithExponent & |
742 | DecimalFormat::initVisibleDigitsWithExponent( | |
743 | DigitList &number, | |
744 | VisibleDigitsWithExponent &digits, | |
745 | UErrorCode &status) const { | |
746 | return fImpl->initVisibleDigitsWithExponent( | |
747 | number, digits, status); | |
57a6839d A |
748 | } |
749 | ||
750 | ||
b75a7d8f | 751 | //------------------------------------------------------------------------------ |
729e4ab9 | 752 | |
b75a7d8f A |
753 | UnicodeString& |
754 | DecimalFormat::format(int32_t number, | |
755 | UnicodeString& appendTo, | |
756 | FieldPosition& fieldPosition) const | |
374ca955 | 757 | { |
2ca993e8 A |
758 | UErrorCode status = U_ZERO_ERROR; |
759 | return fImpl->format(number, appendTo, fieldPosition, status); | |
374ca955 A |
760 | } |
761 | ||
51004dcb A |
762 | UnicodeString& |
763 | DecimalFormat::format(int32_t number, | |
764 | UnicodeString& appendTo, | |
765 | FieldPosition& fieldPosition, | |
766 | UErrorCode& status) const | |
767 | { | |
2ca993e8 | 768 | return fImpl->format(number, appendTo, fieldPosition, status); |
51004dcb A |
769 | } |
770 | ||
729e4ab9 A |
771 | UnicodeString& |
772 | DecimalFormat::format(int32_t number, | |
773 | UnicodeString& appendTo, | |
774 | FieldPositionIterator* posIter, | |
775 | UErrorCode& status) const | |
776 | { | |
2ca993e8 | 777 | return fImpl->format(number, appendTo, posIter, status); |
729e4ab9 A |
778 | } |
779 | ||
51004dcb | 780 | |
374ca955 | 781 | //------------------------------------------------------------------------------ |
729e4ab9 | 782 | |
374ca955 A |
783 | UnicodeString& |
784 | DecimalFormat::format(int64_t number, | |
785 | UnicodeString& appendTo, | |
786 | FieldPosition& fieldPosition) const | |
51004dcb A |
787 | { |
788 | UErrorCode status = U_ZERO_ERROR; /* ignored */ | |
2ca993e8 | 789 | return fImpl->format(number, appendTo, fieldPosition, status); |
51004dcb A |
790 | } |
791 | ||
792 | UnicodeString& | |
793 | DecimalFormat::format(int64_t number, | |
794 | UnicodeString& appendTo, | |
795 | FieldPosition& fieldPosition, | |
796 | UErrorCode& status) const | |
b75a7d8f | 797 | { |
2ca993e8 | 798 | return fImpl->format(number, appendTo, fieldPosition, status); |
729e4ab9 | 799 | } |
b75a7d8f | 800 | |
729e4ab9 A |
801 | UnicodeString& |
802 | DecimalFormat::format(int64_t number, | |
803 | UnicodeString& appendTo, | |
804 | FieldPositionIterator* posIter, | |
805 | UErrorCode& status) const | |
806 | { | |
2ca993e8 | 807 | return fImpl->format(number, appendTo, posIter, status); |
b75a7d8f | 808 | } |
729e4ab9 | 809 | |
b75a7d8f A |
810 | //------------------------------------------------------------------------------ |
811 | ||
812 | UnicodeString& | |
813 | DecimalFormat::format( double number, | |
814 | UnicodeString& appendTo, | |
815 | FieldPosition& fieldPosition) const | |
816 | { | |
51004dcb | 817 | UErrorCode status = U_ZERO_ERROR; /* ignored */ |
2ca993e8 | 818 | return fImpl->format(number, appendTo, fieldPosition, status); |
51004dcb A |
819 | } |
820 | ||
821 | UnicodeString& | |
822 | DecimalFormat::format( double number, | |
823 | UnicodeString& appendTo, | |
824 | FieldPosition& fieldPosition, | |
825 | UErrorCode& status) const | |
826 | { | |
2ca993e8 | 827 | return fImpl->format(number, appendTo, fieldPosition, status); |
729e4ab9 | 828 | } |
b75a7d8f | 829 | |
729e4ab9 A |
830 | UnicodeString& |
831 | DecimalFormat::format( double number, | |
832 | UnicodeString& appendTo, | |
833 | FieldPositionIterator* posIter, | |
834 | UErrorCode& status) const | |
835 | { | |
2ca993e8 | 836 | return fImpl->format(number, appendTo, posIter, status); |
729e4ab9 A |
837 | } |
838 | ||
839 | //------------------------------------------------------------------------------ | |
840 | ||
841 | ||
842 | UnicodeString& | |
843 | DecimalFormat::format(const StringPiece &number, | |
844 | UnicodeString &toAppendTo, | |
845 | FieldPositionIterator *posIter, | |
846 | UErrorCode &status) const | |
847 | { | |
2ca993e8 A |
848 | return fImpl->format(number, toAppendTo, posIter, status); |
849 | } | |
729e4ab9 A |
850 | |
851 | ||
852 | UnicodeString& | |
853 | DecimalFormat::format(const DigitList &number, | |
854 | UnicodeString &appendTo, | |
855 | FieldPositionIterator *posIter, | |
856 | UErrorCode &status) const { | |
2ca993e8 | 857 | return fImpl->format(number, appendTo, posIter, status); |
729e4ab9 A |
858 | } |
859 | ||
860 | ||
729e4ab9 A |
861 | UnicodeString& |
862 | DecimalFormat::format(const DigitList &number, | |
863 | UnicodeString& appendTo, | |
864 | FieldPosition& pos, | |
865 | UErrorCode &status) const { | |
2ca993e8 | 866 | return fImpl->format(number, appendTo, pos, status); |
b75a7d8f A |
867 | } |
868 | ||
51004dcb | 869 | UnicodeString& |
2ca993e8 A |
870 | DecimalFormat::format(const VisibleDigitsWithExponent &number, |
871 | UnicodeString &appendTo, | |
872 | FieldPositionIterator *posIter, | |
873 | UErrorCode &status) const { | |
874 | return fImpl->format(number, appendTo, posIter, status); | |
b75a7d8f A |
875 | } |
876 | ||
b75a7d8f | 877 | |
b75a7d8f | 878 | UnicodeString& |
2ca993e8 A |
879 | DecimalFormat::format(const VisibleDigitsWithExponent &number, |
880 | UnicodeString& appendTo, | |
881 | FieldPosition& pos, | |
882 | UErrorCode &status) const { | |
883 | return fImpl->format(number, appendTo, pos, status); | |
b75a7d8f A |
884 | } |
885 | ||
2ca993e8 A |
886 | DigitList& |
887 | DecimalFormat::_round(const DigitList& number, DigitList& adjustedNum, UBool& isNegative, UErrorCode& status) const { | |
888 | adjustedNum = number; | |
889 | fImpl->round(adjustedNum, status); | |
890 | isNegative = !adjustedNum.isPositive(); | |
891 | return adjustedNum; | |
b75a7d8f A |
892 | } |
893 | ||
b75a7d8f A |
894 | void |
895 | DecimalFormat::parse(const UnicodeString& text, | |
896 | Formattable& result, | |
374ca955 | 897 | ParsePosition& parsePosition) const { |
4388f060 | 898 | parse(text, result, parsePosition, NULL); |
374ca955 A |
899 | } |
900 | ||
4388f060 A |
901 | CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, |
902 | ParsePosition& pos) const { | |
903 | Formattable parseResult; | |
904 | int32_t start = pos.getIndex(); | |
51004dcb | 905 | UChar curbuf[4] = {}; |
4388f060 A |
906 | parse(text, parseResult, pos, curbuf); |
907 | if (pos.getIndex() != start) { | |
908 | UErrorCode ec = U_ZERO_ERROR; | |
b331163b | 909 | LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec); |
4388f060 A |
910 | if (U_FAILURE(ec)) { |
911 | pos.setIndex(start); // indicate failure | |
912 | } else { | |
913 | return currAmt.orphan(); | |
914 | } | |
915 | } | |
916 | return NULL; | |
374ca955 A |
917 | } |
918 | ||
919 | /** | |
4388f060 | 920 | * Parses the given text as a number, optionally providing a currency amount. |
374ca955 | 921 | * @param text the string to parse |
4388f060 | 922 | * @param result output parameter for the numeric result. |
374ca955 A |
923 | * @param parsePosition input-output position; on input, the |
924 | * position within text to match; must have 0 <= pos.getIndex() < | |
925 | * text.length(); on output, the position after the last matched | |
926 | * character. If the parse fails, the position in unchanged upon | |
927 | * output. | |
4388f060 A |
928 | * @param currency if non-NULL, it should point to a 4-UChar buffer. |
929 | * In this case the text is parsed as a currency format, and the | |
930 | * ISO 4217 code for the parsed currency is put into the buffer. | |
931 | * Otherwise the text is parsed as a non-currency format. | |
374ca955 A |
932 | */ |
933 | void DecimalFormat::parse(const UnicodeString& text, | |
934 | Formattable& result, | |
935 | ParsePosition& parsePosition, | |
4388f060 A |
936 | UChar* currency) const { |
937 | int32_t startIdx, backup; | |
938 | int32_t i = startIdx = backup = parsePosition.getIndex(); | |
b75a7d8f | 939 | |
729e4ab9 A |
940 | // clear any old contents in the result. In particular, clears any DigitList |
941 | // that it may be holding. | |
942 | result.setLong(0); | |
57a6839d A |
943 | if (currency != NULL) { |
944 | for (int32_t ci=0; ci<4; ci++) { | |
945 | currency[ci] = 0; | |
946 | } | |
947 | } | |
729e4ab9 | 948 | |
b75a7d8f | 949 | // Handle NaN as a special case: |
2ca993e8 | 950 | int32_t formatWidth = fImpl->getOldFormatWidth(); |
729e4ab9 | 951 | |
b75a7d8f | 952 | // Skip padding characters, if around prefix |
2ca993e8 A |
953 | if (formatWidth > 0 && ( |
954 | fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix || | |
955 | fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix)) { | |
b75a7d8f A |
956 | i = skipPadding(text, i); |
957 | } | |
729e4ab9 | 958 | |
4388f060 A |
959 | if (isLenient()) { |
960 | // skip any leading whitespace | |
961 | i = backup = skipUWhiteSpace(text, i); | |
46f4442e | 962 | } |
729e4ab9 | 963 | |
b75a7d8f | 964 | // If the text is composed of the representation of NaN, returns NaN.length |
2ca993e8 | 965 | const UnicodeString *nan = &fImpl->getConstSymbol(DecimalFormatSymbols::kNaNSymbol); |
b75a7d8f A |
966 | int32_t nanLen = (text.compare(i, nan->length(), *nan) |
967 | ? 0 : nan->length()); | |
968 | if (nanLen) { | |
969 | i += nanLen; | |
2ca993e8 | 970 | if (formatWidth > 0 && (fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix || fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix)) { |
b75a7d8f A |
971 | i = skipPadding(text, i); |
972 | } | |
973 | parsePosition.setIndex(i); | |
974 | result.setDouble(uprv_getNaN()); | |
975 | return; | |
976 | } | |
729e4ab9 | 977 | |
b75a7d8f A |
978 | // NaN parse failed; start over |
979 | i = backup; | |
46f4442e | 980 | parsePosition.setIndex(i); |
b75a7d8f A |
981 | |
982 | // status is used to record whether a number is infinite. | |
983 | UBool status[fgStatusLength]; | |
51004dcb A |
984 | |
985 | DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer | |
729e4ab9 A |
986 | if (digits == NULL) { |
987 | return; // no way to report error from here. | |
988 | } | |
b75a7d8f | 989 | |
2ca993e8 | 990 | if (fImpl->fMonetary) { |
729e4ab9 A |
991 | if (!parseForCurrency(text, parsePosition, *digits, |
992 | status, currency)) { | |
51004dcb | 993 | return; |
729e4ab9 A |
994 | } |
995 | } else { | |
996 | if (!subparse(text, | |
2ca993e8 A |
997 | &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(), |
998 | &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(), | |
999 | &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(), | |
1000 | &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(), | |
729e4ab9 A |
1001 | FALSE, UCURR_SYMBOL_NAME, |
1002 | parsePosition, *digits, status, currency)) { | |
51004dcb | 1003 | debug("!subparse(...) - rewind"); |
4388f060 | 1004 | parsePosition.setIndex(startIdx); |
729e4ab9 A |
1005 | return; |
1006 | } | |
b75a7d8f A |
1007 | } |
1008 | ||
1009 | // Handle infinity | |
1010 | if (status[fgStatusInfinite]) { | |
1011 | double inf = uprv_getInfinity(); | |
729e4ab9 | 1012 | result.setDouble(digits->isPositive() ? inf : -inf); |
51004dcb | 1013 | // TODO: set the dl to infinity, and let it fall into the code below. |
b75a7d8f A |
1014 | } |
1015 | ||
374ca955 | 1016 | else { |
374ca955 | 1017 | |
2ca993e8 | 1018 | if (!fImpl->fMultiplier.isZero()) { |
729e4ab9 | 1019 | UErrorCode ec = U_ZERO_ERROR; |
2ca993e8 | 1020 | digits->div(fImpl->fMultiplier, ec); |
b75a7d8f | 1021 | } |
729e4ab9 | 1022 | |
2ca993e8 | 1023 | if (fImpl->fScale != 0) { |
51004dcb | 1024 | DigitList ten; |
57a6839d | 1025 | ten.set((int32_t)10); |
2ca993e8 A |
1026 | if (fImpl->fScale > 0) { |
1027 | for (int32_t i = fImpl->fScale; i > 0; i--) { | |
51004dcb A |
1028 | UErrorCode ec = U_ZERO_ERROR; |
1029 | digits->div(ten,ec); | |
1030 | } | |
1031 | } else { | |
2ca993e8 | 1032 | for (int32_t i = fImpl->fScale; i < 0; i++) { |
51004dcb A |
1033 | UErrorCode ec = U_ZERO_ERROR; |
1034 | digits->mult(ten,ec); | |
1035 | } | |
1036 | } | |
1037 | } | |
1038 | ||
729e4ab9 A |
1039 | // Negative zero special case: |
1040 | // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable. | |
1041 | // if not parsing integerOnly, leave as -0, which a double can represent. | |
1042 | if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) { | |
1043 | digits->setPositive(TRUE); | |
b75a7d8f | 1044 | } |
729e4ab9 | 1045 | result.adoptDigitList(digits); |
b75a7d8f | 1046 | } |
b75a7d8f A |
1047 | } |
1048 | ||
1049 | ||
374ca955 | 1050 | |
729e4ab9 A |
1051 | UBool |
1052 | DecimalFormat::parseForCurrency(const UnicodeString& text, | |
1053 | ParsePosition& parsePosition, | |
1054 | DigitList& digits, | |
1055 | UBool* status, | |
1056 | UChar* currency) const { | |
2ca993e8 A |
1057 | UnicodeString positivePrefix; |
1058 | UnicodeString positiveSuffix; | |
1059 | UnicodeString negativePrefix; | |
1060 | UnicodeString negativeSuffix; | |
1061 | fImpl->fPositivePrefixPattern.toString(positivePrefix); | |
1062 | fImpl->fPositiveSuffixPattern.toString(positiveSuffix); | |
1063 | fImpl->fNegativePrefixPattern.toString(negativePrefix); | |
1064 | fImpl->fNegativeSuffixPattern.toString(negativeSuffix); | |
1065 | ||
729e4ab9 A |
1066 | int origPos = parsePosition.getIndex(); |
1067 | int maxPosIndex = origPos; | |
1068 | int maxErrorPos = -1; | |
1069 | // First, parse against current pattern. | |
1070 | // Since current pattern could be set by applyPattern(), | |
1071 | // it could be an arbitrary pattern, and it may not be the one | |
1072 | // defined in current locale. | |
1073 | UBool tmpStatus[fgStatusLength]; | |
1074 | ParsePosition tmpPos(origPos); | |
1075 | DigitList tmpDigitList; | |
1076 | UBool found; | |
4388f060 | 1077 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
729e4ab9 | 1078 | found = subparse(text, |
2ca993e8 A |
1079 | &negativePrefix, &negativeSuffix, |
1080 | &positivePrefix, &positiveSuffix, | |
729e4ab9 A |
1081 | TRUE, UCURR_LONG_NAME, |
1082 | tmpPos, tmpDigitList, tmpStatus, currency); | |
1083 | } else { | |
1084 | found = subparse(text, | |
2ca993e8 A |
1085 | &negativePrefix, &negativeSuffix, |
1086 | &positivePrefix, &positiveSuffix, | |
729e4ab9 A |
1087 | TRUE, UCURR_SYMBOL_NAME, |
1088 | tmpPos, tmpDigitList, tmpStatus, currency); | |
1089 | } | |
1090 | if (found) { | |
1091 | if (tmpPos.getIndex() > maxPosIndex) { | |
1092 | maxPosIndex = tmpPos.getIndex(); | |
1093 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
1094 | status[i] = tmpStatus[i]; | |
1095 | } | |
1096 | digits = tmpDigitList; | |
1097 | } | |
1098 | } else { | |
1099 | maxErrorPos = tmpPos.getErrorIndex(); | |
1100 | } | |
1101 | // Then, parse against affix patterns. | |
1102 | // Those are currency patterns and currency plural patterns. | |
b331163b | 1103 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
1104 | const UHashElement* element = NULL; |
1105 | while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { | |
729e4ab9 A |
1106 | const UHashTok valueTok = element->value; |
1107 | const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer; | |
1108 | UBool tmpStatus[fgStatusLength]; | |
1109 | ParsePosition tmpPos(origPos); | |
1110 | DigitList tmpDigitList; | |
57a6839d A |
1111 | |
1112 | #ifdef FMT_DEBUG | |
1113 | debug("trying affix for currency.."); | |
1114 | affixPtn->dump(); | |
1115 | #endif | |
1116 | ||
729e4ab9 A |
1117 | UBool result = subparse(text, |
1118 | &affixPtn->negPrefixPatternForCurrency, | |
1119 | &affixPtn->negSuffixPatternForCurrency, | |
1120 | &affixPtn->posPrefixPatternForCurrency, | |
1121 | &affixPtn->posSuffixPatternForCurrency, | |
1122 | TRUE, affixPtn->patternType, | |
1123 | tmpPos, tmpDigitList, tmpStatus, currency); | |
1124 | if (result) { | |
1125 | found = true; | |
1126 | if (tmpPos.getIndex() > maxPosIndex) { | |
1127 | maxPosIndex = tmpPos.getIndex(); | |
1128 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
1129 | status[i] = tmpStatus[i]; | |
1130 | } | |
1131 | digits = tmpDigitList; | |
1132 | } | |
1133 | } else { | |
1134 | maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? | |
1135 | tmpPos.getErrorIndex() : maxErrorPos; | |
1136 | } | |
1137 | } | |
1138 | // Finally, parse against simple affix to find the match. | |
1139 | // For example, in TestMonster suite, | |
1140 | // if the to-be-parsed text is "-\u00A40,00". | |
1141 | // complexAffixCompare will not find match, | |
1142 | // since there is no ISO code matches "\u00A4", | |
1143 | // and the parse stops at "\u00A4". | |
1144 | // We will just use simple affix comparison (look for exact match) | |
1145 | // to pass it. | |
57a6839d A |
1146 | // |
1147 | // TODO: We should parse against simple affix first when | |
1148 | // output currency is not requested. After the complex currency | |
1149 | // parsing implementation was introduced, the default currency | |
1150 | // instance parsing slowed down because of the new code flow. | |
1151 | // I filed #10312 - Yoshito | |
729e4ab9 A |
1152 | UBool tmpStatus_2[fgStatusLength]; |
1153 | ParsePosition tmpPos_2(origPos); | |
1154 | DigitList tmpDigitList_2; | |
57a6839d A |
1155 | |
1156 | // Disable complex currency parsing and try it again. | |
729e4ab9 | 1157 | UBool result = subparse(text, |
2ca993e8 A |
1158 | &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(), |
1159 | &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(), | |
1160 | &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(), | |
1161 | &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(), | |
57a6839d | 1162 | FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME, |
729e4ab9 A |
1163 | tmpPos_2, tmpDigitList_2, tmpStatus_2, |
1164 | currency); | |
1165 | if (result) { | |
1166 | if (tmpPos_2.getIndex() > maxPosIndex) { | |
1167 | maxPosIndex = tmpPos_2.getIndex(); | |
1168 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
1169 | status[i] = tmpStatus_2[i]; | |
1170 | } | |
1171 | digits = tmpDigitList_2; | |
1172 | } | |
1173 | found = true; | |
1174 | } else { | |
1175 | maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ? | |
1176 | tmpPos_2.getErrorIndex() : maxErrorPos; | |
1177 | } | |
1178 | ||
1179 | if (!found) { | |
1180 | //parsePosition.setIndex(origPos); | |
1181 | parsePosition.setErrorIndex(maxErrorPos); | |
1182 | } else { | |
1183 | parsePosition.setIndex(maxPosIndex); | |
1184 | parsePosition.setErrorIndex(-1); | |
1185 | } | |
1186 | return found; | |
1187 | } | |
1188 | ||
374ca955 | 1189 | |
b75a7d8f A |
1190 | /** |
1191 | * Parse the given text into a number. The text is parsed beginning at | |
1192 | * parsePosition, until an unparseable character is seen. | |
374ca955 | 1193 | * @param text the string to parse. |
729e4ab9 A |
1194 | * @param negPrefix negative prefix. |
1195 | * @param negSuffix negative suffix. | |
1196 | * @param posPrefix positive prefix. | |
1197 | * @param posSuffix positive suffix. | |
57a6839d | 1198 | * @param complexCurrencyParsing whether it is complex currency parsing or not. |
729e4ab9 | 1199 | * @param type the currency type to parse against, LONG_NAME only or not. |
b75a7d8f | 1200 | * @param parsePosition The position at which to being parsing. Upon |
374ca955 A |
1201 | * return, the first unparsed character. |
1202 | * @param digits the DigitList to set to the parsed value. | |
1203 | * @param status output param containing boolean status flags indicating | |
b75a7d8f | 1204 | * whether the value was infinite and whether it was positive. |
374ca955 A |
1205 | * @param currency return value for parsed currency, for generic |
1206 | * currency parsing mode, or NULL for normal parsing. In generic | |
1207 | * currency parsing mode, any currency is parsed, not just the | |
1208 | * currency that this formatter is set to. | |
b75a7d8f | 1209 | */ |
729e4ab9 A |
1210 | UBool DecimalFormat::subparse(const UnicodeString& text, |
1211 | const UnicodeString* negPrefix, | |
1212 | const UnicodeString* negSuffix, | |
1213 | const UnicodeString* posPrefix, | |
1214 | const UnicodeString* posSuffix, | |
57a6839d | 1215 | UBool complexCurrencyParsing, |
729e4ab9 A |
1216 | int8_t type, |
1217 | ParsePosition& parsePosition, | |
374ca955 A |
1218 | DigitList& digits, UBool* status, |
1219 | UChar* currency) const | |
b75a7d8f | 1220 | { |
729e4ab9 A |
1221 | // The parsing process builds up the number as char string, in the neutral format that |
1222 | // will be acceptable to the decNumber library, then at the end passes that string | |
1223 | // off for conversion to a decNumber. | |
1224 | UErrorCode err = U_ZERO_ERROR; | |
1225 | CharString parsedNum; | |
1226 | digits.setToZero(); | |
1227 | ||
b75a7d8f A |
1228 | int32_t position = parsePosition.getIndex(); |
1229 | int32_t oldStart = position; | |
51004dcb | 1230 | int32_t textLength = text.length(); // One less pointer to follow |
4388f060 | 1231 | UBool strictParse = !isLenient(); |
2ca993e8 A |
1232 | UChar32 zero = fImpl->getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); |
1233 | const UnicodeString *groupingString = &fImpl->getConstSymbol( | |
1234 | !fImpl->fMonetary ? | |
1235 | DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); | |
51004dcb A |
1236 | UChar32 groupingChar = groupingString->char32At(0); |
1237 | int32_t groupingStringLength = groupingString->length(); | |
1238 | int32_t groupingCharLength = U16_LENGTH(groupingChar); | |
1239 | UBool groupingUsed = isGroupingUsed(); | |
1240 | #ifdef FMT_DEBUG | |
1241 | UChar dbgbuf[300]; | |
1242 | UnicodeString s(dbgbuf,0,300);; | |
1243 | s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " ); | |
1244 | #define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); } | |
1245 | DBGAPPD(negPrefix); | |
1246 | DBGAPPD(negSuffix); | |
1247 | DBGAPPD(posPrefix); | |
1248 | DBGAPPD(posSuffix); | |
1249 | debugout(s); | |
51004dcb A |
1250 | #endif |
1251 | ||
1252 | UBool fastParseOk = false; /* TRUE iff fast parse is OK */ | |
1253 | // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */ | |
2ca993e8 | 1254 | if((fImpl->isParseFastpath()) && !fImpl->fMonetary && |
51004dcb A |
1255 | text.length()>0 && |
1256 | text.length()<32 && | |
1257 | (posPrefix==NULL||posPrefix->isEmpty()) && | |
1258 | (posSuffix==NULL||posSuffix->isEmpty()) && | |
1259 | // (negPrefix==NULL||negPrefix->isEmpty()) && | |
1260 | // (negSuffix==NULL||(negSuffix->isEmpty()) ) && | |
1261 | TRUE) { // optimized path | |
1262 | int j=position; | |
1263 | int l=text.length(); | |
1264 | int digitCount=0; | |
1265 | UChar32 ch = text.char32At(j); | |
2ca993e8 | 1266 | const UnicodeString *decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); |
51004dcb A |
1267 | UChar32 decimalChar = 0; |
1268 | UBool intOnly = FALSE; | |
1269 | UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0; | |
1270 | ||
1271 | int32_t decimalCount = decimalString->countChar32(0,3); | |
1272 | if(isParseIntegerOnly()) { | |
1273 | decimalChar = 0; // not allowed | |
1274 | intOnly = TRUE; // Don't look for decimals. | |
1275 | } else if(decimalCount==1) { | |
1276 | decimalChar = decimalString->char32At(0); // Look for this decimal | |
1277 | } else if(decimalCount==0) { | |
1278 | decimalChar=0; // NO decimal set | |
1279 | } else { | |
1280 | j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation. | |
1281 | } | |
b75a7d8f | 1282 | |
51004dcb A |
1283 | #ifdef FMT_DEBUG |
1284 | printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n", | |
1285 | decimalChar, groupingChar, ch, | |
1286 | (intOnly)?'y':'n', | |
1287 | (strictParse)?'y':'n'); | |
1288 | #endif | |
1289 | if(ch==0x002D) { // '-' | |
1290 | j=l+1;//=break - negative number. | |
1291 | ||
1292 | /* | |
1293 | parsedNum.append('-',err); | |
1294 | j+=U16_LENGTH(ch); | |
1295 | if(j<l) ch = text.char32At(j); | |
1296 | */ | |
1297 | } else { | |
1298 | parsedNum.append('+',err); | |
1299 | } | |
1300 | while(j<l) { | |
1301 | int32_t digit = ch - zero; | |
1302 | if(digit >=0 && digit <= 9) { | |
1303 | parsedNum.append((char)(digit + '0'), err); | |
1304 | if((digitCount>0) || digit!=0 || j==(l-1)) { | |
1305 | digitCount++; | |
1306 | } | |
1307 | } else if(ch == 0) { // break out | |
1308 | digitCount=-1; | |
1309 | break; | |
1310 | } else if(ch == decimalChar) { | |
1311 | parsedNum.append((char)('.'), err); | |
1312 | decimalChar=0; // no more decimals. | |
1313 | // fastParseHadDecimal=TRUE; | |
1314 | } else if(ch == lookForGroup) { | |
1315 | // ignore grouping char. No decimals, so it has to be an ignorable grouping sep | |
1316 | } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) { | |
1317 | // parsing integer only and can fall through | |
1318 | } else { | |
1319 | digitCount=-1; // fail - fall through to slow parse | |
1320 | break; | |
1321 | } | |
1322 | j+=U16_LENGTH(ch); | |
1323 | ch = text.char32At(j); // for next | |
1324 | } | |
1325 | if( | |
1326 | ((j==l)||intOnly) // end OR only parsing integer | |
1327 | && (digitCount>0)) { // and have at least one digit | |
51004dcb A |
1328 | fastParseOk=true; // Fast parse OK! |
1329 | ||
1330 | #ifdef SKIP_OPT | |
1331 | debug("SKIP_OPT"); | |
1332 | /* for testing, try it the slow way. also */ | |
1333 | fastParseOk=false; | |
1334 | parsedNum.clear(); | |
1335 | #else | |
1336 | parsePosition.setIndex(position=j); | |
1337 | status[fgStatusInfinite]=false; | |
1338 | #endif | |
1339 | } else { | |
1340 | // was not OK. reset, retry | |
1341 | #ifdef FMT_DEBUG | |
1342 | printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount); | |
1343 | #endif | |
1344 | parsedNum.clear(); | |
1345 | } | |
1346 | } else { | |
1347 | #ifdef FMT_DEBUG | |
1348 | printf("Could not fastpath parse. "); | |
51004dcb A |
1349 | printf("text.length()=%d ", text.length()); |
1350 | printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix); | |
1351 | ||
1352 | printf("\n"); | |
1353 | #endif | |
1354 | } | |
1355 | ||
2ca993e8 A |
1356 | UnicodeString formatPattern; |
1357 | toPattern(formatPattern); | |
1358 | ||
51004dcb A |
1359 | if(!fastParseOk |
1360 | #if UCONFIG_HAVE_PARSEALLINPUT | |
1361 | && fParseAllInput!=UNUM_YES | |
1362 | #endif | |
1363 | ) | |
1364 | { | |
2ca993e8 | 1365 | int32_t formatWidth = fImpl->getOldFormatWidth(); |
b75a7d8f | 1366 | // Match padding before prefix |
2ca993e8 | 1367 | if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { |
b75a7d8f A |
1368 | position = skipPadding(text, position); |
1369 | } | |
1370 | ||
1371 | // Match positive and negative prefixes; prefer longest match. | |
57a6839d A |
1372 | int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency); |
1373 | int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency); | |
b75a7d8f A |
1374 | if (posMatch >= 0 && negMatch >= 0) { |
1375 | if (posMatch > negMatch) { | |
1376 | negMatch = -1; | |
1377 | } else if (negMatch > posMatch) { | |
1378 | posMatch = -1; | |
729e4ab9 | 1379 | } |
b75a7d8f A |
1380 | } |
1381 | if (posMatch >= 0) { | |
1382 | position += posMatch; | |
729e4ab9 | 1383 | parsedNum.append('+', err); |
b75a7d8f A |
1384 | } else if (negMatch >= 0) { |
1385 | position += negMatch; | |
729e4ab9 A |
1386 | parsedNum.append('-', err); |
1387 | } else if (strictParse){ | |
b75a7d8f A |
1388 | parsePosition.setErrorIndex(position); |
1389 | return FALSE; | |
4388f060 A |
1390 | } else { |
1391 | // Temporary set positive. This might be changed after checking suffix | |
1392 | parsedNum.append('+', err); | |
b75a7d8f A |
1393 | } |
1394 | ||
1395 | // Match padding before prefix | |
2ca993e8 | 1396 | if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { |
b75a7d8f A |
1397 | position = skipPadding(text, position); |
1398 | } | |
729e4ab9 | 1399 | |
46f4442e | 1400 | if (! strictParse) { |
4388f060 | 1401 | position = skipUWhiteSpace(text, position); |
46f4442e | 1402 | } |
729e4ab9 | 1403 | |
b75a7d8f | 1404 | // process digits or Inf, find decimal position |
2ca993e8 | 1405 | const UnicodeString *inf = &fImpl->getConstSymbol(DecimalFormatSymbols::kInfinitySymbol); |
b75a7d8f A |
1406 | int32_t infLen = (text.compare(position, inf->length(), *inf) |
1407 | ? 0 : inf->length()); | |
1408 | position += infLen; // infLen is non-zero when it does equal to infinity | |
46f4442e | 1409 | status[fgStatusInfinite] = infLen != 0; |
729e4ab9 | 1410 | |
4388f060 | 1411 | if (infLen != 0) { |
729e4ab9 A |
1412 | parsedNum.append("Infinity", err); |
1413 | } else { | |
b75a7d8f A |
1414 | // We now have a string of digits, possibly with grouping symbols, |
1415 | // and decimal points. We want to process these into a DigitList. | |
1416 | // We don't want to put a bunch of leading zeros into the DigitList | |
1417 | // though, so we keep track of the location of the decimal point, | |
1418 | // put only significant digits into the DigitList, and adjust the | |
1419 | // exponent as needed. | |
1420 | ||
b75a7d8f | 1421 | |
46f4442e | 1422 | UBool strictFail = FALSE; // did we exit with a strict parse failure? |
46f4442e A |
1423 | int32_t lastGroup = -1; // where did we last see a grouping separator? |
1424 | int32_t digitStart = position; | |
2ca993e8 | 1425 | int32_t gs2 = fImpl->fEffGrouping.fGrouping2 == 0 ? fImpl->fEffGrouping.fGrouping : fImpl->fEffGrouping.fGrouping2; |
729e4ab9 | 1426 | |
46f4442e | 1427 | const UnicodeString *decimalString; |
2ca993e8 A |
1428 | if (fImpl->fMonetary) { |
1429 | decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); | |
b75a7d8f | 1430 | } else { |
2ca993e8 | 1431 | decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); |
b75a7d8f | 1432 | } |
46f4442e | 1433 | UChar32 decimalChar = decimalString->char32At(0); |
51004dcb A |
1434 | int32_t decimalStringLength = decimalString->length(); |
1435 | int32_t decimalCharLength = U16_LENGTH(decimalChar); | |
729e4ab9 | 1436 | |
b75a7d8f | 1437 | UBool sawDecimal = FALSE; |
4388f060 A |
1438 | UChar32 sawDecimalChar = 0xFFFF; |
1439 | UBool sawGrouping = FALSE; | |
1440 | UChar32 sawGroupingChar = 0xFFFF; | |
b75a7d8f A |
1441 | UBool sawDigit = FALSE; |
1442 | int32_t backup = -1; | |
1443 | int32_t digit; | |
729e4ab9 | 1444 | |
46f4442e | 1445 | // equivalent grouping and decimal support |
4388f060 A |
1446 | const UnicodeSet *decimalSet = NULL; |
1447 | const UnicodeSet *groupingSet = NULL; | |
729e4ab9 A |
1448 | |
1449 | if (decimalCharLength == decimalStringLength) { | |
4388f060 | 1450 | decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse); |
729e4ab9 A |
1451 | } |
1452 | ||
1453 | if (groupingCharLength == groupingStringLength) { | |
1454 | if (strictParse) { | |
57a6839d | 1455 | groupingSet = fStaticSets->fStrictDefaultGroupingSeparators; |
729e4ab9 | 1456 | } else { |
57a6839d | 1457 | groupingSet = fStaticSets->fDefaultGroupingSeparators; |
46f4442e | 1458 | } |
46f4442e | 1459 | } |
729e4ab9 | 1460 | |
4388f060 A |
1461 | // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized. |
1462 | // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet | |
1463 | // If a character matches decimalSet, don't consider it to be a member of the groupingSet. | |
729e4ab9 | 1464 | |
b75a7d8f A |
1465 | // We have to track digitCount ourselves, because digits.fCount will |
1466 | // pin when the maximum allowable digits is reached. | |
1467 | int32_t digitCount = 0; | |
729e4ab9 | 1468 | int32_t integerDigitCount = 0; |
b75a7d8f A |
1469 | |
1470 | for (; position < textLength; ) | |
1471 | { | |
1472 | UChar32 ch = text.char32At(position); | |
1473 | ||
1474 | /* We recognize all digit ranges, not only the Latin digit range | |
1475 | * '0'..'9'. We do so by using the Character.digit() method, | |
1476 | * which converts a valid Unicode digit to the range 0..9. | |
1477 | * | |
1478 | * The character 'ch' may be a digit. If so, place its value | |
1479 | * from 0 to 9 in 'digit'. First try using the locale digit, | |
1480 | * which may or MAY NOT be a standard Unicode digit range. If | |
1481 | * this fails, try using the standard Unicode digit ranges by | |
729e4ab9 | 1482 | * calling Character.digit(). If this also fails, digit will |
b75a7d8f A |
1483 | * have a value outside the range 0..9. |
1484 | */ | |
1485 | digit = ch - zero; | |
1486 | if (digit < 0 || digit > 9) | |
1487 | { | |
1488 | digit = u_charDigitValue(ch); | |
1489 | } | |
729e4ab9 A |
1490 | |
1491 | // As a last resort, look through the localized digits if the zero digit | |
1492 | // is not a "standard" Unicode digit. | |
1493 | if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) { | |
1494 | digit = 0; | |
1495 | // Already check above (digit = ch - zero) for ch==zero; the only check we need to do here is: | |
1496 | // if \u3007 is treated as 0 for parsing, \u96F6 should be too. Otherwise check for nonzero digits. | |
1497 | if ( zero!=0x3007 || ch!=0x96F6 ) { | |
1498 | for (digit = 1 ; digit < 10 ; digit++ ) { | |
2ca993e8 | 1499 | if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) { |
46f4442e A |
1500 | break; |
1501 | } | |
46f4442e A |
1502 | } |
1503 | } | |
b75a7d8f | 1504 | } |
b75a7d8f | 1505 | |
729e4ab9 A |
1506 | if (digit >= 0 && digit <= 9) |
1507 | { | |
46f4442e A |
1508 | if (strictParse && backup != -1) { |
1509 | // comma followed by digit, so group before comma is a | |
1510 | // secondary group. If there was a group separator | |
1511 | // before that, the group must == the secondary group | |
1512 | // length, else it can be <= the the secondary group | |
1513 | // length. | |
1514 | if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) || | |
1515 | (lastGroup == -1 && position - digitStart - 1 > gs2)) { | |
1516 | strictFail = TRUE; | |
1517 | break; | |
1518 | } | |
729e4ab9 | 1519 | |
46f4442e | 1520 | lastGroup = backup; |
b75a7d8f | 1521 | } |
729e4ab9 A |
1522 | |
1523 | // Cancel out backup setting (see grouping handler below) | |
46f4442e A |
1524 | backup = -1; |
1525 | sawDigit = TRUE; | |
729e4ab9 A |
1526 | |
1527 | // Note: this will append leading zeros | |
1528 | parsedNum.append((char)(digit + '0'), err); | |
1529 | ||
1530 | // count any digit that's not a leading zero | |
1531 | if (digit > 0 || digitCount > 0 || sawDecimal) { | |
1532 | digitCount += 1; | |
1533 | ||
1534 | // count any integer digit that's not a leading zero | |
1535 | if (! sawDecimal) { | |
1536 | integerDigitCount += 1; | |
1537 | } | |
b75a7d8f | 1538 | } |
729e4ab9 | 1539 | |
b75a7d8f A |
1540 | position += U16_LENGTH(ch); |
1541 | } | |
4388f060 A |
1542 | else if (groupingStringLength > 0 && |
1543 | matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet, | |
1544 | decimalChar, decimalSet, | |
51004dcb | 1545 | ch) && groupingUsed) |
b75a7d8f | 1546 | { |
46f4442e A |
1547 | if (sawDecimal) { |
1548 | break; | |
1549 | } | |
729e4ab9 | 1550 | |
46f4442e | 1551 | if (strictParse) { |
729e4ab9 | 1552 | if ( (!sawDigit && groupingSet!=NULL && u_isWhitespace(ch)) || backup != -1 ) { |
2ca993e8 A |
1553 | // We differ from the ICU4J code by allowing a leading group sep in strict mode (for |
1554 | // backward compatibility) as long as it is not one of the breaking whitespace characters | |
1555 | // that is only treated as a group separator because of the equivalence set. If we get | |
1556 | // here it is because the leading sep was such a breaking space, or there were multiple | |
1557 | // group separators in a row. Note that the DecimalFormat documentation says | |
1558 | // "During parsing, grouping separators are ignored" and that was for strict parsing, | |
1559 | // so we may need to further revisit this strictParse restriction to ensure compatibility. | |
1560 | // Also note: u_isWhitespace is true for all Zs/Zl/Zp except the no-break ones: 00A0,2007,202F. | |
1561 | // In CLDR, all locales that have space as a group separator use 00A0 (NBSP). | |
46f4442e A |
1562 | strictFail = TRUE; |
1563 | break; | |
1564 | } | |
1565 | } | |
729e4ab9 | 1566 | |
b75a7d8f A |
1567 | // Ignore grouping characters, if we are using them, but require |
1568 | // that they be followed by a digit. Otherwise we backup and | |
1569 | // reprocess them. | |
1570 | backup = position; | |
46f4442e | 1571 | position += groupingStringLength; |
4388f060 A |
1572 | sawGrouping=TRUE; |
1573 | // Once we see a grouping character, we only accept that grouping character from then on. | |
1574 | sawGroupingChar=ch; | |
b75a7d8f | 1575 | } |
4388f060 | 1576 | else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch)) |
b75a7d8f | 1577 | { |
46f4442e A |
1578 | if (strictParse) { |
1579 | if (backup != -1 || | |
2ca993e8 | 1580 | (lastGroup != -1 && position - lastGroup != fImpl->fEffGrouping.fGrouping + 1)) { |
46f4442e A |
1581 | strictFail = TRUE; |
1582 | break; | |
1583 | } | |
1584 | } | |
729e4ab9 A |
1585 | |
1586 | // If we're only parsing integers, or if we ALREADY saw the | |
b75a7d8f | 1587 | // decimal, then don't parse this one. |
46f4442e | 1588 | if (isParseIntegerOnly() || sawDecimal) { |
4388f060 | 1589 | break; |
46f4442e | 1590 | } |
729e4ab9 A |
1591 | |
1592 | parsedNum.append('.', err); | |
46f4442e | 1593 | position += decimalStringLength; |
b75a7d8f | 1594 | sawDecimal = TRUE; |
4388f060 A |
1595 | // Once we see a decimal character, we only accept that decimal character from then on. |
1596 | sawDecimalChar=ch; | |
1597 | // decimalSet is considered to consist of (ch,ch) | |
b75a7d8f | 1598 | } |
4388f060 | 1599 | else { |
b75a7d8f | 1600 | |
51004dcb | 1601 | if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless.. |
57a6839d | 1602 | isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways |
51004dcb | 1603 | const UnicodeString *tmp; |
2ca993e8 | 1604 | tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); |
51004dcb A |
1605 | // TODO: CASE |
1606 | if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit | |
b75a7d8f | 1607 | { |
51004dcb A |
1608 | // Parse sign, if present |
1609 | int32_t pos = position + tmp->length(); | |
1610 | char exponentSign = '+'; | |
1611 | ||
1612 | if (pos < textLength) | |
b75a7d8f | 1613 | { |
2ca993e8 | 1614 | tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
b75a7d8f A |
1615 | if (!text.compare(pos, tmp->length(), *tmp)) |
1616 | { | |
1617 | pos += tmp->length(); | |
b75a7d8f | 1618 | } |
51004dcb | 1619 | else { |
2ca993e8 | 1620 | tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
51004dcb A |
1621 | if (!text.compare(pos, tmp->length(), *tmp)) |
1622 | { | |
1623 | exponentSign = '-'; | |
1624 | pos += tmp->length(); | |
1625 | } | |
1626 | } | |
b75a7d8f | 1627 | } |
b75a7d8f | 1628 | |
51004dcb A |
1629 | UBool sawExponentDigit = FALSE; |
1630 | while (pos < textLength) { | |
1631 | ch = text[(int32_t)pos]; | |
1632 | digit = ch - zero; | |
b75a7d8f | 1633 | |
51004dcb A |
1634 | if (digit < 0 || digit > 9) { |
1635 | digit = u_charDigitValue(ch); | |
1636 | } | |
1637 | if (0 <= digit && digit <= 9) { | |
1638 | if (!sawExponentDigit) { | |
1639 | parsedNum.append('E', err); | |
1640 | parsedNum.append(exponentSign, err); | |
1641 | sawExponentDigit = TRUE; | |
1642 | } | |
1643 | ++pos; | |
1644 | parsedNum.append((char)(digit + '0'), err); | |
1645 | } else { | |
1646 | break; | |
729e4ab9 | 1647 | } |
b75a7d8f | 1648 | } |
b75a7d8f | 1649 | |
51004dcb A |
1650 | if (sawExponentDigit) { |
1651 | position = pos; // Advance past the exponent | |
1652 | } | |
b75a7d8f | 1653 | |
51004dcb A |
1654 | break; // Whether we fail or succeed, we exit this loop |
1655 | } else { | |
1656 | break; | |
1657 | } | |
1658 | } else { // not parsing exponent | |
b75a7d8f | 1659 | break; |
51004dcb | 1660 | } |
b75a7d8f A |
1661 | } |
1662 | } | |
729e4ab9 | 1663 | |
b331163b A |
1664 | // if we didn't see a decimal and it is required, check to see if the pattern had one |
1665 | if(!sawDecimal && isDecimalPatternMatchRequired()) | |
1666 | { | |
2ca993e8 | 1667 | if(formatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) |
b331163b A |
1668 | { |
1669 | parsePosition.setIndex(oldStart); | |
1670 | parsePosition.setErrorIndex(position); | |
1671 | debug("decimal point match required fail!"); | |
1672 | return FALSE; | |
1673 | } | |
1674 | } | |
1675 | ||
b75a7d8f A |
1676 | if (backup != -1) |
1677 | { | |
1678 | position = backup; | |
1679 | } | |
1680 | ||
46f4442e | 1681 | if (strictParse && !sawDecimal) { |
2ca993e8 | 1682 | if (lastGroup != -1 && position - lastGroup != fImpl->fEffGrouping.fGrouping + 1) { |
46f4442e A |
1683 | strictFail = TRUE; |
1684 | } | |
1685 | } | |
46f4442e A |
1686 | |
1687 | if (strictFail) { | |
4388f060 | 1688 | // only set with strictParse and a grouping separator error |
729e4ab9 | 1689 | |
46f4442e A |
1690 | parsePosition.setIndex(oldStart); |
1691 | parsePosition.setErrorIndex(position); | |
51004dcb | 1692 | debug("strictFail!"); |
46f4442e A |
1693 | return FALSE; |
1694 | } | |
729e4ab9 | 1695 | |
b75a7d8f | 1696 | // If there was no decimal point we have an integer |
b75a7d8f A |
1697 | |
1698 | // If none of the text string was recognized. For example, parse | |
1699 | // "x" with pattern "#0.00" (return index and error index both 0) | |
1700 | // parse "$" with pattern "$#0.00". (return index 0 and error index | |
1701 | // 1). | |
1702 | if (!sawDigit && digitCount == 0) { | |
51004dcb A |
1703 | #ifdef FMT_DEBUG |
1704 | debug("none of text rec"); | |
1705 | printf("position=%d\n",position); | |
1706 | #endif | |
b75a7d8f A |
1707 | parsePosition.setIndex(oldStart); |
1708 | parsePosition.setErrorIndex(oldStart); | |
1709 | return FALSE; | |
1710 | } | |
1711 | } | |
1712 | ||
1713 | // Match padding before suffix | |
2ca993e8 | 1714 | if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { |
b75a7d8f A |
1715 | position = skipPadding(text, position); |
1716 | } | |
1717 | ||
46f4442e | 1718 | int32_t posSuffixMatch = -1, negSuffixMatch = -1; |
729e4ab9 | 1719 | |
b75a7d8f | 1720 | // Match positive and negative suffixes; prefer longest match. |
46f4442e | 1721 | if (posMatch >= 0 || (!strictParse && negMatch < 0)) { |
57a6839d | 1722 | posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency); |
b75a7d8f A |
1723 | } |
1724 | if (negMatch >= 0) { | |
57a6839d | 1725 | negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency); |
b75a7d8f | 1726 | } |
46f4442e A |
1727 | if (posSuffixMatch >= 0 && negSuffixMatch >= 0) { |
1728 | if (posSuffixMatch > negSuffixMatch) { | |
4388f060 | 1729 | negSuffixMatch = -1; |
46f4442e | 1730 | } else if (negSuffixMatch > posSuffixMatch) { |
4388f060 | 1731 | posSuffixMatch = -1; |
729e4ab9 | 1732 | } |
b75a7d8f A |
1733 | } |
1734 | ||
1735 | // Fail if neither or both | |
46f4442e | 1736 | if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) { |
b75a7d8f | 1737 | parsePosition.setErrorIndex(position); |
51004dcb | 1738 | debug("neither or both"); |
b75a7d8f A |
1739 | return FALSE; |
1740 | } | |
1741 | ||
729e4ab9 | 1742 | position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0)); |
b75a7d8f A |
1743 | |
1744 | // Match padding before suffix | |
2ca993e8 | 1745 | if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { |
b75a7d8f A |
1746 | position = skipPadding(text, position); |
1747 | } | |
1748 | ||
1749 | parsePosition.setIndex(position); | |
1750 | ||
729e4ab9 | 1751 | parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-'; |
51004dcb A |
1752 | #ifdef FMT_DEBUG |
1753 | printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err)); | |
1754 | #endif | |
1755 | } /* end SLOW parse */ | |
1756 | if(parsePosition.getIndex() == oldStart) | |
1757 | { | |
1758 | #ifdef FMT_DEBUG | |
1759 | printf(" PP didnt move, err\n"); | |
1760 | #endif | |
1761 | parsePosition.setErrorIndex(position); | |
1762 | return FALSE; | |
1763 | } | |
1764 | #if UCONFIG_HAVE_PARSEALLINPUT | |
1765 | else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength) | |
b75a7d8f | 1766 | { |
51004dcb A |
1767 | #ifdef FMT_DEBUG |
1768 | printf(" PP didnt consume all (UNUM_YES), err\n"); | |
1769 | #endif | |
b75a7d8f A |
1770 | parsePosition.setErrorIndex(position); |
1771 | return FALSE; | |
1772 | } | |
51004dcb A |
1773 | #endif |
1774 | // uint32_t bits = (fastParseOk?kFastpathOk:0) | | |
1775 | // (fastParseHadDecimal?0:kNoDecimal); | |
1776 | //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits); | |
1777 | digits.set(parsedNum.toStringPiece(), | |
1778 | err, | |
1779 | 0//bits | |
1780 | ); | |
729e4ab9 A |
1781 | |
1782 | if (U_FAILURE(err)) { | |
51004dcb A |
1783 | #ifdef FMT_DEBUG |
1784 | printf(" err setting %s\n", u_errorName(err)); | |
1785 | #endif | |
729e4ab9 A |
1786 | parsePosition.setErrorIndex(position); |
1787 | return FALSE; | |
1788 | } | |
b331163b A |
1789 | |
1790 | // check if we missed a required decimal point | |
1791 | if(fastParseOk && isDecimalPatternMatchRequired()) | |
1792 | { | |
2ca993e8 | 1793 | if(formatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) |
b331163b A |
1794 | { |
1795 | parsePosition.setIndex(oldStart); | |
1796 | parsePosition.setErrorIndex(position); | |
1797 | debug("decimal point match required fail!"); | |
1798 | return FALSE; | |
1799 | } | |
1800 | } | |
1801 | ||
1802 | ||
b75a7d8f A |
1803 | return TRUE; |
1804 | } | |
1805 | ||
1806 | /** | |
1807 | * Starting at position, advance past a run of pad characters, if any. | |
1808 | * Return the index of the first character after position that is not a pad | |
1809 | * character. Result is >= position. | |
1810 | */ | |
1811 | int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const { | |
2ca993e8 | 1812 | int32_t padLen = U16_LENGTH(fImpl->fAffixes.fPadChar); |
b75a7d8f | 1813 | while (position < text.length() && |
2ca993e8 | 1814 | text.char32At(position) == fImpl->fAffixes.fPadChar) { |
b75a7d8f A |
1815 | position += padLen; |
1816 | } | |
1817 | return position; | |
1818 | } | |
1819 | ||
1820 | /** | |
1821 | * Return the length matched by the given affix, or -1 if none. | |
1822 | * Runs of white space in the affix, match runs of white space in | |
1823 | * the input. Pattern white space and input white space are | |
1824 | * determined differently; see code. | |
1825 | * @param text input text | |
1826 | * @param pos offset into input at which to begin matching | |
1827 | * @param isNegative | |
1828 | * @param isPrefix | |
729e4ab9 | 1829 | * @param affixPat affix pattern used for currency affix comparison. |
57a6839d | 1830 | * @param complexCurrencyParsing whether it is currency parsing or not |
729e4ab9 | 1831 | * @param type the currency type to parse against, LONG_NAME only or not. |
374ca955 A |
1832 | * @param currency return value for parsed currency, for generic |
1833 | * currency parsing mode, or null for normal parsing. In generic | |
1834 | * currency parsing mode, any currency is parsed, not just the | |
1835 | * currency that this formatter is set to. | |
b75a7d8f A |
1836 | * @return length of input that matches, or -1 if match failure |
1837 | */ | |
1838 | int32_t DecimalFormat::compareAffix(const UnicodeString& text, | |
1839 | int32_t pos, | |
1840 | UBool isNegative, | |
374ca955 | 1841 | UBool isPrefix, |
729e4ab9 | 1842 | const UnicodeString* affixPat, |
57a6839d | 1843 | UBool complexCurrencyParsing, |
729e4ab9 | 1844 | int8_t type, |
46f4442e A |
1845 | UChar* currency) const |
1846 | { | |
1847 | const UnicodeString *patternToCompare; | |
2ca993e8 A |
1848 | if (currency != NULL || |
1849 | (fImpl->fMonetary && complexCurrencyParsing)) { | |
729e4ab9 A |
1850 | |
1851 | if (affixPat != NULL) { | |
1852 | return compareComplexAffix(*affixPat, text, pos, type, currency); | |
46f4442e | 1853 | } |
b75a7d8f | 1854 | } |
729e4ab9 | 1855 | |
46f4442e A |
1856 | if (isNegative) { |
1857 | if (isPrefix) { | |
2ca993e8 | 1858 | patternToCompare = &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(); |
46f4442e A |
1859 | } |
1860 | else { | |
2ca993e8 | 1861 | patternToCompare = &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(); |
46f4442e | 1862 | } |
b75a7d8f | 1863 | } |
46f4442e A |
1864 | else { |
1865 | if (isPrefix) { | |
2ca993e8 | 1866 | patternToCompare = &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(); |
46f4442e A |
1867 | } |
1868 | else { | |
2ca993e8 | 1869 | patternToCompare = &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(); |
46f4442e A |
1870 | } |
1871 | } | |
4388f060 | 1872 | return compareSimpleAffix(*patternToCompare, text, pos, isLenient()); |
b75a7d8f A |
1873 | } |
1874 | ||
57a6839d A |
1875 | UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const { |
1876 | if (lhs == rhs) { | |
1877 | return TRUE; | |
1878 | } | |
1879 | U_ASSERT(fStaticSets != NULL); // should already be loaded | |
1880 | const UnicodeSet *minusSigns = fStaticSets->fMinusSigns; | |
1881 | const UnicodeSet *plusSigns = fStaticSets->fPlusSigns; | |
1882 | return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) || | |
1883 | (plusSigns->contains(lhs) && plusSigns->contains(rhs)); | |
1884 | } | |
1885 | ||
1886 | // check for LRM 0x200E, RLM 0x200F, ALM 0x061C | |
1887 | #define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C) | |
1888 | ||
1889 | #define TRIM_BUFLEN 32 | |
1890 | UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) { | |
1891 | UChar trimBuf[TRIM_BUFLEN]; | |
1892 | int32_t affixLen = affix.length(); | |
1893 | int32_t affixPos, trimLen = 0; | |
1894 | ||
1895 | for (affixPos = 0; affixPos < affixLen; affixPos++) { | |
1896 | UChar c = affix.charAt(affixPos); | |
1897 | if (!IS_BIDI_MARK(c)) { | |
1898 | if (trimLen < TRIM_BUFLEN) { | |
1899 | trimBuf[trimLen++] = c; | |
1900 | } else { | |
1901 | trimLen = 0; | |
1902 | break; | |
1903 | } | |
1904 | } | |
1905 | } | |
1906 | return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix); | |
1907 | } | |
1908 | ||
b75a7d8f A |
1909 | /** |
1910 | * Return the length matched by the given affix, or -1 if none. | |
1911 | * Runs of white space in the affix, match runs of white space in | |
1912 | * the input. Pattern white space and input white space are | |
1913 | * determined differently; see code. | |
1914 | * @param affix pattern string, taken as a literal | |
1915 | * @param input input text | |
1916 | * @param pos offset into input at which to begin matching | |
1917 | * @return length of input that matches, or -1 if match failure | |
1918 | */ | |
1919 | int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, | |
1920 | const UnicodeString& input, | |
46f4442e | 1921 | int32_t pos, |
57a6839d | 1922 | UBool lenient) const { |
b75a7d8f | 1923 | int32_t start = pos; |
57a6839d A |
1924 | UnicodeString trimmedAffix; |
1925 | // For more efficiency we should keep lazily-created trimmed affixes around in | |
1926 | // instance variables instead of trimming each time they are used (the next step) | |
1927 | trimMarksFromAffix(affix, trimmedAffix); | |
1928 | UChar32 affixChar = trimmedAffix.char32At(0); | |
1929 | int32_t affixLength = trimmedAffix.length(); | |
7393aa2f A |
1930 | int32_t inputLength = input.length(); |
1931 | int32_t affixCharLength = U16_LENGTH(affixChar); | |
1932 | UnicodeSet *affixSet; | |
57a6839d A |
1933 | UErrorCode status = U_ZERO_ERROR; |
1934 | ||
1935 | U_ASSERT(fStaticSets != NULL); // should already be loaded | |
729e4ab9 | 1936 | |
57a6839d A |
1937 | if (U_FAILURE(status)) { |
1938 | return -1; | |
1939 | } | |
4388f060 | 1940 | if (!lenient) { |
57a6839d A |
1941 | affixSet = fStaticSets->fStrictDashEquivalents; |
1942 | ||
1943 | // If the trimmedAffix is exactly one character long and that character | |
7393aa2f A |
1944 | // is in the dash set and the very next input character is also |
1945 | // in the dash set, return a match. | |
1946 | if (affixCharLength == affixLength && affixSet->contains(affixChar)) { | |
57a6839d A |
1947 | UChar32 ic = input.char32At(pos); |
1948 | if (affixSet->contains(ic)) { | |
1949 | pos += U16_LENGTH(ic); | |
1950 | pos = skipBidiMarks(input, pos); // skip any trailing bidi marks | |
1951 | return pos - start; | |
7393aa2f A |
1952 | } |
1953 | } | |
729e4ab9 | 1954 | |
4388f060 | 1955 | for (int32_t i = 0; i < affixLength; ) { |
57a6839d | 1956 | UChar32 c = trimmedAffix.char32At(i); |
4388f060 A |
1957 | int32_t len = U16_LENGTH(c); |
1958 | if (PatternProps::isWhiteSpace(c)) { | |
1959 | // We may have a pattern like: \u200F \u0020 | |
1960 | // and input text like: \u200F \u0020 | |
1961 | // Note that U+200F and U+0020 are Pattern_White_Space but only | |
1962 | // U+0020 is UWhiteSpace. So we have to first do a direct | |
1963 | // match of the run of Pattern_White_Space in the pattern, | |
1964 | // then match any extra characters. | |
1965 | UBool literalMatch = FALSE; | |
57a6839d A |
1966 | while (pos < inputLength) { |
1967 | UChar32 ic = input.char32At(pos); | |
1968 | if (ic == c) { | |
1969 | literalMatch = TRUE; | |
1970 | i += len; | |
1971 | pos += len; | |
1972 | if (i == affixLength) { | |
1973 | break; | |
1974 | } | |
1975 | c = trimmedAffix.char32At(i); | |
1976 | len = U16_LENGTH(c); | |
1977 | if (!PatternProps::isWhiteSpace(c)) { | |
1978 | break; | |
1979 | } | |
1980 | } else if (IS_BIDI_MARK(ic)) { | |
1981 | pos ++; // just skip over this input text | |
1982 | } else { | |
4388f060 A |
1983 | break; |
1984 | } | |
1985 | } | |
1986 | ||
1987 | // Advance over run in pattern | |
57a6839d | 1988 | i = skipPatternWhiteSpace(trimmedAffix, i); |
4388f060 A |
1989 | |
1990 | // Advance over run in input text | |
1991 | // Must see at least one white space char in input, | |
57a6839d | 1992 | // unless we've already matched some characters literally. |
4388f060 A |
1993 | int32_t s = pos; |
1994 | pos = skipUWhiteSpace(input, pos); | |
57a6839d | 1995 | if (pos == s && !literalMatch) { |
4388f060 A |
1996 | return -1; |
1997 | } | |
1998 | ||
1999 | // If we skip UWhiteSpace in the input text, we need to skip it in the pattern. | |
2000 | // Otherwise, the previous lines may have skipped over text (such as U+00A0) that | |
57a6839d A |
2001 | // is also in the trimmedAffix. |
2002 | i = skipUWhiteSpace(trimmedAffix, i); | |
4388f060 | 2003 | } else { |
57a6839d A |
2004 | UBool match = FALSE; |
2005 | while (pos < inputLength) { | |
2006 | UChar32 ic = input.char32At(pos); | |
2007 | if (!match && ic == c) { | |
2008 | i += len; | |
2009 | pos += len; | |
2010 | match = TRUE; | |
2011 | } else if (IS_BIDI_MARK(ic)) { | |
2012 | pos++; // just skip over this input text | |
2013 | } else { | |
2014 | break; | |
2015 | } | |
2016 | } | |
2017 | if (!match) { | |
4388f060 A |
2018 | return -1; |
2019 | } | |
2020 | } | |
2021 | } | |
729e4ab9 | 2022 | } else { |
4388f060 | 2023 | UBool match = FALSE; |
57a6839d A |
2024 | |
2025 | affixSet = fStaticSets->fDashEquivalents; | |
729e4ab9 | 2026 | |
7393aa2f | 2027 | if (affixCharLength == affixLength && affixSet->contains(affixChar)) { |
57a6839d A |
2028 | pos = skipUWhiteSpaceAndMarks(input, pos); |
2029 | UChar32 ic = input.char32At(pos); | |
2030 | ||
2031 | if (affixSet->contains(ic)) { | |
2032 | pos += U16_LENGTH(ic); | |
2033 | pos = skipBidiMarks(input, pos); | |
2034 | return pos - start; | |
7393aa2f A |
2035 | } |
2036 | } | |
729e4ab9 | 2037 | |
4388f060 A |
2038 | for (int32_t i = 0; i < affixLength; ) |
2039 | { | |
57a6839d A |
2040 | //i = skipRuleWhiteSpace(trimmedAffix, i); |
2041 | i = skipUWhiteSpace(trimmedAffix, i); | |
2042 | pos = skipUWhiteSpaceAndMarks(input, pos); | |
729e4ab9 | 2043 | |
4388f060 A |
2044 | if (i >= affixLength || pos >= inputLength) { |
2045 | break; | |
2046 | } | |
729e4ab9 | 2047 | |
57a6839d A |
2048 | UChar32 c = trimmedAffix.char32At(i); |
2049 | UChar32 ic = input.char32At(pos); | |
729e4ab9 | 2050 | |
57a6839d | 2051 | if (!equalWithSignCompatibility(ic, c)) { |
4388f060 A |
2052 | return -1; |
2053 | } | |
729e4ab9 | 2054 | |
4388f060 | 2055 | match = TRUE; |
57a6839d A |
2056 | i += U16_LENGTH(c); |
2057 | pos += U16_LENGTH(ic); | |
2058 | pos = skipBidiMarks(input, pos); | |
4388f060 | 2059 | } |
729e4ab9 | 2060 | |
4388f060 A |
2061 | if (affixLength > 0 && ! match) { |
2062 | return -1; | |
2063 | } | |
729e4ab9 | 2064 | } |
b75a7d8f A |
2065 | return pos - start; |
2066 | } | |
2067 | ||
2068 | /** | |
4388f060 | 2069 | * Skip over a run of zero or more Pattern_White_Space characters at |
b75a7d8f A |
2070 | * pos in text. |
2071 | */ | |
4388f060 A |
2072 | int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) { |
2073 | const UChar* s = text.getBuffer(); | |
2074 | return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s); | |
b75a7d8f A |
2075 | } |
2076 | ||
2077 | /** | |
2078 | * Skip over a run of zero or more isUWhiteSpace() characters at pos | |
2079 | * in text. | |
2080 | */ | |
2081 | int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) { | |
2082 | while (pos < text.length()) { | |
2083 | UChar32 c = text.char32At(pos); | |
57a6839d | 2084 | if (!u_isUWhiteSpace(c)) { |
b75a7d8f A |
2085 | break; |
2086 | } | |
2087 | pos += U16_LENGTH(c); | |
2088 | } | |
2089 | return pos; | |
2090 | } | |
2091 | ||
57a6839d A |
2092 | /** |
2093 | * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos | |
2094 | * in text. | |
2095 | */ | |
2096 | int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) { | |
2097 | while (pos < text.length()) { | |
2098 | UChar32 c = text.char32At(pos); | |
2099 | if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM | |
2100 | break; | |
2101 | } | |
2102 | pos += U16_LENGTH(c); | |
2103 | } | |
2104 | return pos; | |
2105 | } | |
2106 | ||
2107 | /** | |
2108 | * Skip over a run of zero or more bidi marks at pos in text. | |
2109 | */ | |
2110 | int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) { | |
2111 | while (pos < text.length()) { | |
2112 | UChar c = text.charAt(pos); | |
2113 | if (!IS_BIDI_MARK(c)) { | |
2114 | break; | |
2115 | } | |
2116 | pos++; | |
2117 | } | |
2118 | return pos; | |
2119 | } | |
2120 | ||
b75a7d8f A |
2121 | /** |
2122 | * Return the length matched by the given affix, or -1 if none. | |
2123 | * @param affixPat pattern string | |
2124 | * @param input input text | |
2125 | * @param pos offset into input at which to begin matching | |
729e4ab9 | 2126 | * @param type the currency type to parse against, LONG_NAME only or not. |
374ca955 A |
2127 | * @param currency return value for parsed currency, for generic |
2128 | * currency parsing mode, or null for normal parsing. In generic | |
2129 | * currency parsing mode, any currency is parsed, not just the | |
2130 | * currency that this formatter is set to. | |
b75a7d8f A |
2131 | * @return length of input that matches, or -1 if match failure |
2132 | */ | |
2133 | int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, | |
2134 | const UnicodeString& text, | |
374ca955 | 2135 | int32_t pos, |
729e4ab9 | 2136 | int8_t type, |
73c04bcf A |
2137 | UChar* currency) const |
2138 | { | |
2139 | int32_t start = pos; | |
2ca993e8 | 2140 | U_ASSERT(currency != NULL || fImpl->fMonetary); |
b75a7d8f | 2141 | |
729e4ab9 A |
2142 | for (int32_t i=0; |
2143 | i<affixPat.length() && pos >= 0; ) { | |
b75a7d8f A |
2144 | UChar32 c = affixPat.char32At(i); |
2145 | i += U16_LENGTH(c); | |
2146 | ||
2147 | if (c == kQuote) { | |
2148 | U_ASSERT(i <= affixPat.length()); | |
2149 | c = affixPat.char32At(i); | |
2150 | i += U16_LENGTH(c); | |
2151 | ||
2152 | const UnicodeString* affix = NULL; | |
2153 | ||
2154 | switch (c) { | |
2155 | case kCurrencySign: { | |
729e4ab9 A |
2156 | // since the currency names in choice format is saved |
2157 | // the same way as other currency names, | |
2158 | // do not need to do currency choice parsing here. | |
2159 | // the general currency parsing parse against all names, | |
2160 | // including names in choice format. | |
b75a7d8f A |
2161 | UBool intl = i<affixPat.length() && |
2162 | affixPat.char32At(i) == kCurrencySign; | |
729e4ab9 A |
2163 | if (intl) { |
2164 | ++i; | |
2165 | } | |
2166 | UBool plural = i<affixPat.length() && | |
2167 | affixPat.char32At(i) == kCurrencySign; | |
2168 | if (plural) { | |
2169 | ++i; | |
2170 | intl = FALSE; | |
2171 | } | |
374ca955 A |
2172 | // Parse generic currency -- anything for which we |
2173 | // have a display name, or any 3-letter ISO code. | |
729e4ab9 A |
2174 | // Try to parse display name for our locale; first |
2175 | // determine our locale. | |
2176 | const char* loc = fCurrencyPluralInfo->getLocale().getName(); | |
2177 | ParsePosition ppos(pos); | |
2178 | UChar curr[4]; | |
2179 | UErrorCode ec = U_ZERO_ERROR; | |
2180 | // Delegate parse of display name => ISO code to Currency | |
2181 | uprv_parseCurrency(loc, text, ppos, type, curr, ec); | |
2182 | ||
2183 | // If parse succeeds, populate currency[0] | |
2184 | if (U_SUCCESS(ec) && ppos.getIndex() != pos) { | |
2185 | if (currency) { | |
374ca955 | 2186 | u_strcpy(currency, curr); |
4388f060 | 2187 | } else { |
729e4ab9 A |
2188 | // The formatter is currency-style but the client has not requested |
2189 | // the value of the parsed currency. In this case, if that value does | |
2190 | // not match the formatter's current value, then the parse fails. | |
2191 | UChar effectiveCurr[4]; | |
2192 | getEffectiveCurrency(effectiveCurr, ec); | |
4388f060 | 2193 | if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) { |
57a6839d A |
2194 | pos = -1; |
2195 | continue; | |
729e4ab9 | 2196 | } |
374ca955 | 2197 | } |
729e4ab9 | 2198 | pos = ppos.getIndex(); |
4388f060 | 2199 | } else if (!isLenient()){ |
729e4ab9 | 2200 | pos = -1; |
b75a7d8f A |
2201 | } |
2202 | continue; | |
2203 | } | |
2204 | case kPatternPercent: | |
2ca993e8 | 2205 | affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPercentSymbol); |
b75a7d8f A |
2206 | break; |
2207 | case kPatternPerMill: | |
2ca993e8 | 2208 | affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); |
b75a7d8f A |
2209 | break; |
2210 | case kPatternPlus: | |
2ca993e8 | 2211 | affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
b75a7d8f A |
2212 | break; |
2213 | case kPatternMinus: | |
2ca993e8 | 2214 | affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
b75a7d8f A |
2215 | break; |
2216 | default: | |
2217 | // fall through to affix!=0 test, which will fail | |
2218 | break; | |
2219 | } | |
2220 | ||
2221 | if (affix != NULL) { | |
2222 | pos = match(text, pos, *affix); | |
2223 | continue; | |
2224 | } | |
2225 | } | |
2226 | ||
2227 | pos = match(text, pos, c); | |
4388f060 A |
2228 | if (PatternProps::isWhiteSpace(c)) { |
2229 | i = skipPatternWhiteSpace(affixPat, i); | |
b75a7d8f A |
2230 | } |
2231 | } | |
73c04bcf | 2232 | return pos - start; |
b75a7d8f A |
2233 | } |
2234 | ||
2235 | /** | |
2236 | * Match a single character at text[pos] and return the index of the | |
2237 | * next character upon success. Return -1 on failure. If | |
4388f060 | 2238 | * ch is a Pattern_White_Space then match a run of white space in text. |
b75a7d8f A |
2239 | */ |
2240 | int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) { | |
4388f060 | 2241 | if (PatternProps::isWhiteSpace(ch)) { |
b75a7d8f A |
2242 | // Advance over run of white space in input text |
2243 | // Must see at least one white space char in input | |
2244 | int32_t s = pos; | |
4388f060 | 2245 | pos = skipPatternWhiteSpace(text, pos); |
b75a7d8f A |
2246 | if (pos == s) { |
2247 | return -1; | |
2248 | } | |
2249 | return pos; | |
2250 | } | |
2251 | return (pos >= 0 && text.char32At(pos) == ch) ? | |
2252 | (pos + U16_LENGTH(ch)) : -1; | |
2253 | } | |
2254 | ||
2255 | /** | |
2256 | * Match a string at text[pos] and return the index of the next | |
2257 | * character upon success. Return -1 on failure. Match a run of | |
2258 | * white space in str with a run of white space in text. | |
2259 | */ | |
2260 | int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) { | |
2261 | for (int32_t i=0; i<str.length() && pos >= 0; ) { | |
2262 | UChar32 ch = str.char32At(i); | |
2263 | i += U16_LENGTH(ch); | |
4388f060 A |
2264 | if (PatternProps::isWhiteSpace(ch)) { |
2265 | i = skipPatternWhiteSpace(str, i); | |
b75a7d8f A |
2266 | } |
2267 | pos = match(text, pos, ch); | |
2268 | } | |
2269 | return pos; | |
2270 | } | |
2271 | ||
46f4442e | 2272 | UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol, |
729e4ab9 | 2273 | UnicodeSet *sset, UChar32 schar) |
46f4442e | 2274 | { |
4388f060 A |
2275 | if (sset != NULL) { |
2276 | return sset->contains(schar); | |
2277 | } | |
729e4ab9 | 2278 | |
4388f060 | 2279 | return text.compare(position, length, symbol) == 0; |
46f4442e A |
2280 | } |
2281 | ||
4388f060 A |
2282 | UBool DecimalFormat::matchDecimal(UChar32 symbolChar, |
2283 | UBool sawDecimal, UChar32 sawDecimalChar, | |
2284 | const UnicodeSet *sset, UChar32 schar) { | |
2285 | if(sawDecimal) { | |
2286 | return schar==sawDecimalChar; | |
2287 | } else if(schar==symbolChar) { | |
2288 | return TRUE; | |
2289 | } else if(sset!=NULL) { | |
2290 | return sset->contains(schar); | |
2291 | } else { | |
2292 | return FALSE; | |
2293 | } | |
2294 | } | |
2295 | ||
2296 | UBool DecimalFormat::matchGrouping(UChar32 groupingChar, | |
2297 | UBool sawGrouping, UChar32 sawGroupingChar, | |
2298 | const UnicodeSet *sset, | |
2299 | UChar32 /*decimalChar*/, const UnicodeSet *decimalSet, | |
2300 | UChar32 schar) { | |
2301 | if(sawGrouping) { | |
2302 | return schar==sawGroupingChar; // previously found | |
2303 | } else if(schar==groupingChar) { | |
2304 | return TRUE; // char from symbols | |
2305 | } else if(sset!=NULL) { | |
2306 | return sset->contains(schar) && // in groupingSet but... | |
2307 | ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet | |
2308 | } else { | |
2309 | return FALSE; | |
2310 | } | |
2311 | } | |
2312 | ||
2313 | ||
729e4ab9 | 2314 | |
b75a7d8f A |
2315 | //------------------------------------------------------------------------------ |
2316 | // Gets the pointer to the localized decimal format symbols | |
2317 | ||
2318 | const DecimalFormatSymbols* | |
2319 | DecimalFormat::getDecimalFormatSymbols() const | |
2320 | { | |
2ca993e8 | 2321 | return &fImpl->getDecimalFormatSymbols(); |
b75a7d8f A |
2322 | } |
2323 | ||
2324 | //------------------------------------------------------------------------------ | |
2325 | // De-owning the current localized symbols and adopt the new symbols. | |
2326 | ||
2327 | void | |
2328 | DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) | |
2329 | { | |
374ca955 A |
2330 | if (symbolsToAdopt == NULL) { |
2331 | return; // do not allow caller to set fSymbols to NULL | |
2332 | } | |
2ca993e8 | 2333 | fImpl->adoptDecimalFormatSymbols(symbolsToAdopt); |
b75a7d8f A |
2334 | } |
2335 | //------------------------------------------------------------------------------ | |
2336 | // Setting the symbols is equlivalent to adopting a newly created localized | |
2337 | // symbols. | |
2338 | ||
2339 | void | |
2340 | DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) | |
2341 | { | |
2342 | adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); | |
2343 | } | |
729e4ab9 | 2344 | |
4388f060 | 2345 | |
729e4ab9 A |
2346 | const CurrencyPluralInfo* |
2347 | DecimalFormat::getCurrencyPluralInfo(void) const | |
2348 | { | |
2349 | return fCurrencyPluralInfo; | |
2350 | } | |
2351 | ||
4388f060 | 2352 | |
729e4ab9 A |
2353 | void |
2354 | DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) | |
2355 | { | |
2356 | if (toAdopt != NULL) { | |
2357 | delete fCurrencyPluralInfo; | |
2358 | fCurrencyPluralInfo = toAdopt; | |
2359 | // re-set currency affix patterns and currency affixes. | |
2ca993e8 | 2360 | if (fImpl->fMonetary) { |
729e4ab9 A |
2361 | UErrorCode status = U_ZERO_ERROR; |
2362 | if (fAffixPatternsForCurrency) { | |
2363 | deleteHashForAffixPattern(); | |
2364 | } | |
2365 | setupCurrencyAffixPatterns(status); | |
729e4ab9 A |
2366 | } |
2367 | } | |
2368 | } | |
2369 | ||
2370 | void | |
2371 | DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) | |
2372 | { | |
2373 | adoptCurrencyPluralInfo(info.clone()); | |
b75a7d8f A |
2374 | } |
2375 | ||
2376 | ||
2377 | //------------------------------------------------------------------------------ | |
2378 | // Gets the positive prefix of the number pattern. | |
729e4ab9 | 2379 | |
b75a7d8f A |
2380 | UnicodeString& |
2381 | DecimalFormat::getPositivePrefix(UnicodeString& result) const | |
2382 | { | |
2ca993e8 | 2383 | return fImpl->getPositivePrefix(result); |
b75a7d8f | 2384 | } |
729e4ab9 | 2385 | |
b75a7d8f A |
2386 | //------------------------------------------------------------------------------ |
2387 | // Sets the positive prefix of the number pattern. | |
729e4ab9 | 2388 | |
b75a7d8f A |
2389 | void |
2390 | DecimalFormat::setPositivePrefix(const UnicodeString& newValue) | |
2391 | { | |
2ca993e8 | 2392 | fImpl->setPositivePrefix(newValue); |
b75a7d8f A |
2393 | } |
2394 | ||
2395 | //------------------------------------------------------------------------------ | |
2396 | // Gets the negative prefix of the number pattern. | |
2397 | ||
2398 | UnicodeString& | |
2399 | DecimalFormat::getNegativePrefix(UnicodeString& result) const | |
2400 | { | |
2ca993e8 | 2401 | return fImpl->getNegativePrefix(result); |
b75a7d8f A |
2402 | } |
2403 | ||
2404 | //------------------------------------------------------------------------------ | |
2405 | // Gets the negative prefix of the number pattern. | |
2406 | ||
2407 | void | |
2408 | DecimalFormat::setNegativePrefix(const UnicodeString& newValue) | |
2409 | { | |
2ca993e8 | 2410 | fImpl->setNegativePrefix(newValue); |
b75a7d8f A |
2411 | } |
2412 | ||
2413 | //------------------------------------------------------------------------------ | |
2414 | // Gets the positive suffix of the number pattern. | |
2415 | ||
2416 | UnicodeString& | |
2417 | DecimalFormat::getPositiveSuffix(UnicodeString& result) const | |
2418 | { | |
2ca993e8 | 2419 | return fImpl->getPositiveSuffix(result); |
b75a7d8f A |
2420 | } |
2421 | ||
2422 | //------------------------------------------------------------------------------ | |
2423 | // Sets the positive suffix of the number pattern. | |
2424 | ||
2425 | void | |
2426 | DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) | |
2427 | { | |
2ca993e8 | 2428 | fImpl->setPositiveSuffix(newValue); |
b75a7d8f A |
2429 | } |
2430 | ||
2431 | //------------------------------------------------------------------------------ | |
2432 | // Gets the negative suffix of the number pattern. | |
2433 | ||
2434 | UnicodeString& | |
2435 | DecimalFormat::getNegativeSuffix(UnicodeString& result) const | |
2436 | { | |
2ca993e8 | 2437 | return fImpl->getNegativeSuffix(result); |
b75a7d8f A |
2438 | } |
2439 | ||
2440 | //------------------------------------------------------------------------------ | |
2441 | // Sets the negative suffix of the number pattern. | |
2442 | ||
2443 | void | |
2444 | DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) | |
2445 | { | |
2ca993e8 | 2446 | fImpl->setNegativeSuffix(newValue); |
b75a7d8f A |
2447 | } |
2448 | ||
2449 | //------------------------------------------------------------------------------ | |
2450 | // Gets the multiplier of the number pattern. | |
729e4ab9 A |
2451 | // Multipliers are stored as decimal numbers (DigitLists) because that |
2452 | // is the most convenient for muliplying or dividing the numbers to be formatted. | |
2453 | // A NULL multiplier implies one, and the scaling operations are skipped. | |
b75a7d8f | 2454 | |
729e4ab9 A |
2455 | int32_t |
2456 | DecimalFormat::getMultiplier() const | |
b75a7d8f | 2457 | { |
2ca993e8 | 2458 | return fImpl->getMultiplier(); |
b75a7d8f A |
2459 | } |
2460 | ||
2461 | //------------------------------------------------------------------------------ | |
2462 | // Sets the multiplier of the number pattern. | |
2463 | void | |
2464 | DecimalFormat::setMultiplier(int32_t newValue) | |
2465 | { | |
2ca993e8 | 2466 | fImpl->setMultiplier(newValue); |
b75a7d8f A |
2467 | } |
2468 | ||
2469 | /** | |
2470 | * Get the rounding increment. | |
2471 | * @return A positive rounding increment, or 0.0 if rounding | |
2472 | * is not in effect. | |
2473 | * @see #setRoundingIncrement | |
2474 | * @see #getRoundingMode | |
2475 | * @see #setRoundingMode | |
2476 | */ | |
374ca955 | 2477 | double DecimalFormat::getRoundingIncrement() const { |
2ca993e8 | 2478 | return fImpl->getRoundingIncrement(); |
b75a7d8f A |
2479 | } |
2480 | ||
2481 | /** | |
2482 | * Set the rounding increment. This method also controls whether | |
2483 | * rounding is enabled. | |
2484 | * @param newValue A positive rounding increment, or 0.0 to disable rounding. | |
2485 | * Negative increments are equivalent to 0.0. | |
2486 | * @see #getRoundingIncrement | |
2487 | * @see #getRoundingMode | |
2488 | * @see #setRoundingMode | |
2489 | */ | |
2490 | void DecimalFormat::setRoundingIncrement(double newValue) { | |
2ca993e8 | 2491 | fImpl->setRoundingIncrement(newValue); |
b75a7d8f A |
2492 | } |
2493 | ||
2494 | /** | |
2495 | * Get the rounding mode. | |
2496 | * @return A rounding mode | |
2497 | * @see #setRoundingIncrement | |
2498 | * @see #getRoundingIncrement | |
2499 | * @see #setRoundingMode | |
2500 | */ | |
374ca955 | 2501 | DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const { |
2ca993e8 | 2502 | return fImpl->getRoundingMode(); |
b75a7d8f A |
2503 | } |
2504 | ||
2505 | /** | |
2506 | * Set the rounding mode. This has no effect unless the rounding | |
2507 | * increment is greater than zero. | |
2508 | * @param roundingMode A rounding mode | |
2509 | * @see #setRoundingIncrement | |
2510 | * @see #getRoundingIncrement | |
2511 | * @see #getRoundingMode | |
2512 | */ | |
2513 | void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { | |
2ca993e8 | 2514 | fImpl->setRoundingMode(roundingMode); |
b75a7d8f A |
2515 | } |
2516 | ||
2517 | /** | |
2518 | * Get the width to which the output of <code>format()</code> is padded. | |
2519 | * @return the format width, or zero if no padding is in effect | |
2520 | * @see #setFormatWidth | |
2521 | * @see #getPadCharacter | |
2522 | * @see #setPadCharacter | |
2523 | * @see #getPadPosition | |
2524 | * @see #setPadPosition | |
2525 | */ | |
374ca955 | 2526 | int32_t DecimalFormat::getFormatWidth() const { |
2ca993e8 | 2527 | return fImpl->getFormatWidth(); |
b75a7d8f A |
2528 | } |
2529 | ||
2530 | /** | |
2531 | * Set the width to which the output of <code>format()</code> is padded. | |
2532 | * This method also controls whether padding is enabled. | |
2533 | * @param width the width to which to pad the result of | |
2534 | * <code>format()</code>, or zero to disable padding. A negative | |
2535 | * width is equivalent to 0. | |
2536 | * @see #getFormatWidth | |
2537 | * @see #getPadCharacter | |
2538 | * @see #setPadCharacter | |
2539 | * @see #getPadPosition | |
2540 | * @see #setPadPosition | |
2541 | */ | |
2542 | void DecimalFormat::setFormatWidth(int32_t width) { | |
2ca993e8 A |
2543 | int32_t formatWidth = (width > 0) ? width : 0; |
2544 | fImpl->setFormatWidth(formatWidth); | |
b75a7d8f A |
2545 | } |
2546 | ||
374ca955 | 2547 | UnicodeString DecimalFormat::getPadCharacterString() const { |
2ca993e8 | 2548 | return UnicodeString(fImpl->getPadCharacter()); |
b75a7d8f A |
2549 | } |
2550 | ||
b75a7d8f | 2551 | void DecimalFormat::setPadCharacter(const UnicodeString &padChar) { |
2ca993e8 | 2552 | UChar pad; |
b75a7d8f | 2553 | if (padChar.length() > 0) { |
2ca993e8 | 2554 | pad = padChar.char32At(0); |
b75a7d8f A |
2555 | } |
2556 | else { | |
2ca993e8 | 2557 | pad = kDefaultPad; |
b75a7d8f | 2558 | } |
2ca993e8 A |
2559 | fImpl->setPadCharacter(pad); |
2560 | } | |
2561 | ||
2562 | static DecimalFormat::EPadPosition fromPadPosition(DigitAffixesAndPadding::EPadPosition padPos) { | |
2563 | switch (padPos) { | |
2564 | case DigitAffixesAndPadding::kPadBeforePrefix: | |
2565 | return DecimalFormat::kPadBeforePrefix; | |
2566 | case DigitAffixesAndPadding::kPadAfterPrefix: | |
2567 | return DecimalFormat::kPadAfterPrefix; | |
2568 | case DigitAffixesAndPadding::kPadBeforeSuffix: | |
2569 | return DecimalFormat::kPadBeforeSuffix; | |
2570 | case DigitAffixesAndPadding::kPadAfterSuffix: | |
2571 | return DecimalFormat::kPadAfterSuffix; | |
2572 | default: | |
2573 | U_ASSERT(FALSE); | |
2574 | break; | |
2575 | } | |
2576 | return DecimalFormat::kPadBeforePrefix; | |
b75a7d8f A |
2577 | } |
2578 | ||
2579 | /** | |
2580 | * Get the position at which padding will take place. This is the location | |
2581 | * at which padding will be inserted if the result of <code>format()</code> | |
2582 | * is shorter than the format width. | |
2583 | * @return the pad position, one of <code>kPadBeforePrefix</code>, | |
2584 | * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or | |
2585 | * <code>kPadAfterSuffix</code>. | |
2586 | * @see #setFormatWidth | |
2587 | * @see #getFormatWidth | |
2588 | * @see #setPadCharacter | |
2589 | * @see #getPadCharacter | |
2590 | * @see #setPadPosition | |
2591 | * @see #kPadBeforePrefix | |
2592 | * @see #kPadAfterPrefix | |
2593 | * @see #kPadBeforeSuffix | |
2594 | * @see #kPadAfterSuffix | |
2595 | */ | |
374ca955 | 2596 | DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const { |
2ca993e8 A |
2597 | return fromPadPosition(fImpl->getPadPosition()); |
2598 | } | |
2599 | ||
2600 | static DigitAffixesAndPadding::EPadPosition toPadPosition(DecimalFormat::EPadPosition padPos) { | |
2601 | switch (padPos) { | |
2602 | case DecimalFormat::kPadBeforePrefix: | |
2603 | return DigitAffixesAndPadding::kPadBeforePrefix; | |
2604 | case DecimalFormat::kPadAfterPrefix: | |
2605 | return DigitAffixesAndPadding::kPadAfterPrefix; | |
2606 | case DecimalFormat::kPadBeforeSuffix: | |
2607 | return DigitAffixesAndPadding::kPadBeforeSuffix; | |
2608 | case DecimalFormat::kPadAfterSuffix: | |
2609 | return DigitAffixesAndPadding::kPadAfterSuffix; | |
2610 | default: | |
2611 | U_ASSERT(FALSE); | |
2612 | break; | |
2613 | } | |
2614 | return DigitAffixesAndPadding::kPadBeforePrefix; | |
b75a7d8f A |
2615 | } |
2616 | ||
2617 | /** | |
2618 | * <strong><font face=helvetica color=red>NEW</font></strong> | |
2619 | * Set the position at which padding will take place. This is the location | |
2620 | * at which padding will be inserted if the result of <code>format()</code> | |
2621 | * is shorter than the format width. This has no effect unless padding is | |
2622 | * enabled. | |
2623 | * @param padPos the pad position, one of <code>kPadBeforePrefix</code>, | |
2624 | * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or | |
2625 | * <code>kPadAfterSuffix</code>. | |
2626 | * @see #setFormatWidth | |
2627 | * @see #getFormatWidth | |
2628 | * @see #setPadCharacter | |
2629 | * @see #getPadCharacter | |
2630 | * @see #getPadPosition | |
2631 | * @see #kPadBeforePrefix | |
2632 | * @see #kPadAfterPrefix | |
2633 | * @see #kPadBeforeSuffix | |
2634 | * @see #kPadAfterSuffix | |
2635 | */ | |
2636 | void DecimalFormat::setPadPosition(EPadPosition padPos) { | |
2ca993e8 | 2637 | fImpl->setPadPosition(toPadPosition(padPos)); |
b75a7d8f A |
2638 | } |
2639 | ||
2640 | /** | |
2641 | * Return whether or not scientific notation is used. | |
2642 | * @return TRUE if this object formats and parses scientific notation | |
2643 | * @see #setScientificNotation | |
2644 | * @see #getMinimumExponentDigits | |
2645 | * @see #setMinimumExponentDigits | |
2646 | * @see #isExponentSignAlwaysShown | |
2647 | * @see #setExponentSignAlwaysShown | |
2648 | */ | |
57a6839d | 2649 | UBool DecimalFormat::isScientificNotation() const { |
2ca993e8 | 2650 | return fImpl->isScientificNotation(); |
b75a7d8f A |
2651 | } |
2652 | ||
2653 | /** | |
2654 | * Set whether or not scientific notation is used. | |
2655 | * @param useScientific TRUE if this object formats and parses scientific | |
2656 | * notation | |
2657 | * @see #isScientificNotation | |
2658 | * @see #getMinimumExponentDigits | |
2659 | * @see #setMinimumExponentDigits | |
2660 | * @see #isExponentSignAlwaysShown | |
2661 | * @see #setExponentSignAlwaysShown | |
2662 | */ | |
2663 | void DecimalFormat::setScientificNotation(UBool useScientific) { | |
2ca993e8 | 2664 | fImpl->setScientificNotation(useScientific); |
b75a7d8f A |
2665 | } |
2666 | ||
2667 | /** | |
2668 | * Return the minimum exponent digits that will be shown. | |
2669 | * @return the minimum exponent digits that will be shown | |
2670 | * @see #setScientificNotation | |
2671 | * @see #isScientificNotation | |
2672 | * @see #setMinimumExponentDigits | |
2673 | * @see #isExponentSignAlwaysShown | |
2674 | * @see #setExponentSignAlwaysShown | |
2675 | */ | |
374ca955 | 2676 | int8_t DecimalFormat::getMinimumExponentDigits() const { |
2ca993e8 | 2677 | return fImpl->getMinimumExponentDigits(); |
b75a7d8f A |
2678 | } |
2679 | ||
2680 | /** | |
2681 | * Set the minimum exponent digits that will be shown. This has no | |
2682 | * effect unless scientific notation is in use. | |
2683 | * @param minExpDig a value >= 1 indicating the fewest exponent digits | |
2684 | * that will be shown. Values less than 1 will be treated as 1. | |
2685 | * @see #setScientificNotation | |
2686 | * @see #isScientificNotation | |
2687 | * @see #getMinimumExponentDigits | |
2688 | * @see #isExponentSignAlwaysShown | |
2689 | * @see #setExponentSignAlwaysShown | |
2690 | */ | |
2691 | void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { | |
2ca993e8 A |
2692 | int32_t minExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1); |
2693 | fImpl->setMinimumExponentDigits(minExponentDigits); | |
b75a7d8f A |
2694 | } |
2695 | ||
2696 | /** | |
2697 | * Return whether the exponent sign is always shown. | |
2698 | * @return TRUE if the exponent is always prefixed with either the | |
2699 | * localized minus sign or the localized plus sign, false if only negative | |
2700 | * exponents are prefixed with the localized minus sign. | |
2701 | * @see #setScientificNotation | |
2702 | * @see #isScientificNotation | |
2703 | * @see #setMinimumExponentDigits | |
2704 | * @see #getMinimumExponentDigits | |
2705 | * @see #setExponentSignAlwaysShown | |
2706 | */ | |
57a6839d | 2707 | UBool DecimalFormat::isExponentSignAlwaysShown() const { |
2ca993e8 | 2708 | return fImpl->isExponentSignAlwaysShown(); |
b75a7d8f A |
2709 | } |
2710 | ||
2711 | /** | |
2712 | * Set whether the exponent sign is always shown. This has no effect | |
2713 | * unless scientific notation is in use. | |
2714 | * @param expSignAlways TRUE if the exponent is always prefixed with either | |
2715 | * the localized minus sign or the localized plus sign, false if only | |
2716 | * negative exponents are prefixed with the localized minus sign. | |
2717 | * @see #setScientificNotation | |
2718 | * @see #isScientificNotation | |
2719 | * @see #setMinimumExponentDigits | |
2720 | * @see #getMinimumExponentDigits | |
2721 | * @see #isExponentSignAlwaysShown | |
2722 | */ | |
2723 | void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { | |
2ca993e8 | 2724 | fImpl->setExponentSignAlwaysShown(expSignAlways); |
b75a7d8f A |
2725 | } |
2726 | ||
2727 | //------------------------------------------------------------------------------ | |
2728 | // Gets the grouping size of the number pattern. For example, thousand or 10 | |
2729 | // thousand groupings. | |
729e4ab9 | 2730 | |
b75a7d8f A |
2731 | int32_t |
2732 | DecimalFormat::getGroupingSize() const | |
2733 | { | |
2ca993e8 | 2734 | return fImpl->getGroupingSize(); |
b75a7d8f | 2735 | } |
729e4ab9 | 2736 | |
b75a7d8f A |
2737 | //------------------------------------------------------------------------------ |
2738 | // Gets the grouping size of the number pattern. | |
729e4ab9 | 2739 | |
b75a7d8f A |
2740 | void |
2741 | DecimalFormat::setGroupingSize(int32_t newValue) | |
2742 | { | |
2ca993e8 | 2743 | fImpl->setGroupingSize(newValue); |
b75a7d8f A |
2744 | } |
2745 | ||
2746 | //------------------------------------------------------------------------------ | |
2747 | ||
2748 | int32_t | |
2749 | DecimalFormat::getSecondaryGroupingSize() const | |
2750 | { | |
2ca993e8 | 2751 | return fImpl->getSecondaryGroupingSize(); |
b75a7d8f A |
2752 | } |
2753 | ||
2754 | //------------------------------------------------------------------------------ | |
2755 | ||
2756 | void | |
2757 | DecimalFormat::setSecondaryGroupingSize(int32_t newValue) | |
2758 | { | |
2ca993e8 A |
2759 | fImpl->setSecondaryGroupingSize(newValue); |
2760 | } | |
2761 | ||
2762 | //------------------------------------------------------------------------------ | |
2763 | ||
2764 | int32_t | |
2765 | DecimalFormat::getMinimumGroupingDigits() const | |
2766 | { | |
2767 | return fImpl->getMinimumGroupingDigits(); | |
2768 | } | |
2769 | ||
2770 | //------------------------------------------------------------------------------ | |
2771 | ||
2772 | void | |
2773 | DecimalFormat::setMinimumGroupingDigits(int32_t newValue) | |
2774 | { | |
2775 | fImpl->setMinimumGroupingDigits(newValue); | |
b75a7d8f A |
2776 | } |
2777 | ||
2778 | //------------------------------------------------------------------------------ | |
2779 | // Checks if to show the decimal separator. | |
2780 | ||
2781 | UBool | |
2782 | DecimalFormat::isDecimalSeparatorAlwaysShown() const | |
2783 | { | |
2ca993e8 | 2784 | return fImpl->isDecimalSeparatorAlwaysShown(); |
b75a7d8f A |
2785 | } |
2786 | ||
2787 | //------------------------------------------------------------------------------ | |
2788 | // Sets to always show the decimal separator. | |
2789 | ||
2790 | void | |
2791 | DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) | |
2792 | { | |
2ca993e8 | 2793 | fImpl->setDecimalSeparatorAlwaysShown(newValue); |
b75a7d8f A |
2794 | } |
2795 | ||
b331163b A |
2796 | //------------------------------------------------------------------------------ |
2797 | // Checks if decimal point pattern match is required | |
2798 | UBool | |
2799 | DecimalFormat::isDecimalPatternMatchRequired(void) const | |
2800 | { | |
2801 | return fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED); | |
2802 | } | |
2803 | ||
2804 | //------------------------------------------------------------------------------ | |
2805 | // Checks if decimal point pattern match is required | |
2806 | ||
2807 | void | |
2808 | DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) | |
2809 | { | |
2810 | fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue); | |
2811 | } | |
2812 | ||
2813 | ||
b75a7d8f A |
2814 | //------------------------------------------------------------------------------ |
2815 | // Emits the pattern of this DecimalFormat instance. | |
2816 | ||
2817 | UnicodeString& | |
2818 | DecimalFormat::toPattern(UnicodeString& result) const | |
2819 | { | |
2ca993e8 | 2820 | return fImpl->toPattern(result); |
b75a7d8f A |
2821 | } |
2822 | ||
2823 | //------------------------------------------------------------------------------ | |
2824 | // Emits the localized pattern this DecimalFormat instance. | |
2825 | ||
2826 | UnicodeString& | |
2827 | DecimalFormat::toLocalizedPattern(UnicodeString& result) const | |
2828 | { | |
2ca993e8 A |
2829 | // toLocalizedPattern is deprecated, so we just make it the same as |
2830 | // toPattern. | |
2831 | return fImpl->toPattern(result); | |
b75a7d8f A |
2832 | } |
2833 | ||
2834 | //------------------------------------------------------------------------------ | |
2835 | ||
2836 | void | |
2837 | DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) | |
2838 | { | |
2ca993e8 A |
2839 | if (pattern.indexOf(kCurrencySign) != -1) { |
2840 | handleCurrencySignInPattern(status); | |
2841 | } | |
2842 | fImpl->applyPattern(pattern, status); | |
b75a7d8f A |
2843 | } |
2844 | ||
2845 | //------------------------------------------------------------------------------ | |
2846 | ||
2847 | void | |
2848 | DecimalFormat::applyPattern(const UnicodeString& pattern, | |
729e4ab9 | 2849 | UParseError& parseError, |
b75a7d8f A |
2850 | UErrorCode& status) |
2851 | { | |
2ca993e8 A |
2852 | if (pattern.indexOf(kCurrencySign) != -1) { |
2853 | handleCurrencySignInPattern(status); | |
2854 | } | |
2855 | fImpl->applyPattern(pattern, parseError, status); | |
b75a7d8f A |
2856 | } |
2857 | //------------------------------------------------------------------------------ | |
2858 | ||
2859 | void | |
2860 | DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status) | |
2861 | { | |
2ca993e8 A |
2862 | if (pattern.indexOf(kCurrencySign) != -1) { |
2863 | handleCurrencySignInPattern(status); | |
2864 | } | |
2865 | fImpl->applyLocalizedPattern(pattern, status); | |
b75a7d8f A |
2866 | } |
2867 | ||
2868 | //------------------------------------------------------------------------------ | |
2869 | ||
2870 | void | |
2871 | DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, | |
2872 | UParseError& parseError, | |
2873 | UErrorCode& status) | |
2874 | { | |
729e4ab9 | 2875 | if (pattern.indexOf(kCurrencySign) != -1) { |
2ca993e8 | 2876 | handleCurrencySignInPattern(status); |
b75a7d8f | 2877 | } |
2ca993e8 | 2878 | fImpl->applyLocalizedPattern(pattern, parseError, status); |
b75a7d8f A |
2879 | } |
2880 | ||
2ca993e8 | 2881 | //------------------------------------------------------------------------------ |
729e4ab9 | 2882 | |
b75a7d8f A |
2883 | /** |
2884 | * Sets the maximum number of digits allowed in the integer portion of a | |
57a6839d | 2885 | * number. |
b75a7d8f A |
2886 | * @see NumberFormat#setMaximumIntegerDigits |
2887 | */ | |
2888 | void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { | |
2ca993e8 A |
2889 | newValue = _min(newValue, gDefaultMaxIntegerDigits); |
2890 | NumberFormat::setMaximumIntegerDigits(newValue); | |
2891 | fImpl->updatePrecision(); | |
b75a7d8f A |
2892 | } |
2893 | ||
2894 | /** | |
2895 | * Sets the minimum number of digits allowed in the integer portion of a | |
2896 | * number. This override limits the integer digit count to 309. | |
2897 | * @see NumberFormat#setMinimumIntegerDigits | |
2898 | */ | |
2899 | void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { | |
2ca993e8 A |
2900 | newValue = _min(newValue, kDoubleIntegerDigits); |
2901 | NumberFormat::setMinimumIntegerDigits(newValue); | |
2902 | fImpl->updatePrecision(); | |
b75a7d8f A |
2903 | } |
2904 | ||
2905 | /** | |
2906 | * Sets the maximum number of digits allowed in the fraction portion of a | |
2907 | * number. This override limits the fraction digit count to 340. | |
2908 | * @see NumberFormat#setMaximumFractionDigits | |
2909 | */ | |
2910 | void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { | |
2ca993e8 A |
2911 | newValue = _min(newValue, kDoubleFractionDigits); |
2912 | NumberFormat::setMaximumFractionDigits(newValue); | |
2913 | fImpl->updatePrecision(); | |
b75a7d8f A |
2914 | } |
2915 | ||
2916 | /** | |
2917 | * Sets the minimum number of digits allowed in the fraction portion of a | |
2918 | * number. This override limits the fraction digit count to 340. | |
2919 | * @see NumberFormat#setMinimumFractionDigits | |
2920 | */ | |
2921 | void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { | |
2ca993e8 A |
2922 | newValue = _min(newValue, kDoubleFractionDigits); |
2923 | NumberFormat::setMinimumFractionDigits(newValue); | |
2924 | fImpl->updatePrecision(); | |
b75a7d8f A |
2925 | } |
2926 | ||
374ca955 | 2927 | int32_t DecimalFormat::getMinimumSignificantDigits() const { |
2ca993e8 | 2928 | return fImpl->getMinimumSignificantDigits(); |
374ca955 A |
2929 | } |
2930 | ||
2931 | int32_t DecimalFormat::getMaximumSignificantDigits() const { | |
2ca993e8 | 2932 | return fImpl->getMaximumSignificantDigits(); |
374ca955 A |
2933 | } |
2934 | ||
2935 | void DecimalFormat::setMinimumSignificantDigits(int32_t min) { | |
2936 | if (min < 1) { | |
729e4ab9 | 2937 | min = 1; |
374ca955 A |
2938 | } |
2939 | // pin max sig dig to >= min | |
2ca993e8 A |
2940 | int32_t max = _max(fImpl->fMaxSigDigits, min); |
2941 | fImpl->setMinMaxSignificantDigits(min, max); | |
374ca955 A |
2942 | } |
2943 | ||
2944 | void DecimalFormat::setMaximumSignificantDigits(int32_t max) { | |
2945 | if (max < 1) { | |
2946 | max = 1; | |
2947 | } | |
2948 | // pin min sig dig to 1..max | |
2ca993e8 A |
2949 | U_ASSERT(fImpl->fMinSigDigits >= 1); |
2950 | int32_t min = _min(fImpl->fMinSigDigits, max); | |
2951 | fImpl->setMinMaxSignificantDigits(min, max); | |
374ca955 A |
2952 | } |
2953 | ||
2954 | UBool DecimalFormat::areSignificantDigitsUsed() const { | |
2ca993e8 | 2955 | return fImpl->areSignificantDigitsUsed(); |
374ca955 A |
2956 | } |
2957 | ||
2958 | void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { | |
2ca993e8 | 2959 | fImpl->setSignificantDigitsUsed(useSignificantDigits); |
729e4ab9 A |
2960 | } |
2961 | ||
2962 | void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { | |
2963 | // set the currency before compute affixes to get the right currency names | |
2964 | NumberFormat::setCurrency(theCurrency, ec); | |
2ca993e8 | 2965 | fImpl->updateCurrency(ec); |
b75a7d8f A |
2966 | } |
2967 | ||
b331163b | 2968 | void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){ |
2ca993e8 | 2969 | fImpl->setCurrencyUsage(newContext, *ec); |
b331163b A |
2970 | } |
2971 | ||
2972 | UCurrencyUsage DecimalFormat::getCurrencyUsage() const { | |
2ca993e8 | 2973 | return fImpl->getCurrencyUsage(); |
b331163b A |
2974 | } |
2975 | ||
374ca955 A |
2976 | // Deprecated variant with no UErrorCode parameter |
2977 | void DecimalFormat::setCurrency(const UChar* theCurrency) { | |
2978 | UErrorCode ec = U_ZERO_ERROR; | |
2979 | setCurrency(theCurrency, ec); | |
2980 | } | |
2981 | ||
46f4442e | 2982 | void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { |
2ca993e8 | 2983 | if (fImpl->fSymbols == NULL) { |
46f4442e A |
2984 | ec = U_MEMORY_ALLOCATION_ERROR; |
2985 | return; | |
2986 | } | |
2987 | ec = U_ZERO_ERROR; | |
374ca955 A |
2988 | const UChar* c = getCurrency(); |
2989 | if (*c == 0) { | |
2990 | const UnicodeString &intl = | |
2ca993e8 | 2991 | fImpl->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); |
374ca955 A |
2992 | c = intl.getBuffer(); // ok for intl to go out of scope |
2993 | } | |
2994 | u_strncpy(result, c, 3); | |
2995 | result[3] = 0; | |
2996 | } | |
2997 | ||
729e4ab9 A |
2998 | Hashtable* |
2999 | DecimalFormat::initHashForAffixPattern(UErrorCode& status) { | |
3000 | if ( U_FAILURE(status) ) { | |
3001 | return NULL; | |
3002 | } | |
3003 | Hashtable* hTable; | |
3004 | if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { | |
3005 | status = U_MEMORY_ALLOCATION_ERROR; | |
3006 | return NULL; | |
3007 | } | |
3008 | if ( U_FAILURE(status) ) { | |
3009 | delete hTable; | |
3010 | return NULL; | |
3011 | } | |
3012 | hTable->setValueComparator(decimfmtAffixPatternValueComparator); | |
3013 | return hTable; | |
3014 | } | |
3015 | ||
729e4ab9 A |
3016 | void |
3017 | DecimalFormat::deleteHashForAffixPattern() | |
3018 | { | |
3019 | if ( fAffixPatternsForCurrency == NULL ) { | |
3020 | return; | |
3021 | } | |
b331163b | 3022 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
3023 | const UHashElement* element = NULL; |
3024 | while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { | |
729e4ab9 A |
3025 | const UHashTok valueTok = element->value; |
3026 | const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; | |
3027 | delete value; | |
3028 | } | |
3029 | delete fAffixPatternsForCurrency; | |
3030 | fAffixPatternsForCurrency = NULL; | |
3031 | } | |
3032 | ||
3033 | ||
3034 | void | |
3035 | DecimalFormat::copyHashForAffixPattern(const Hashtable* source, | |
3036 | Hashtable* target, | |
3037 | UErrorCode& status) { | |
3038 | if ( U_FAILURE(status) ) { | |
3039 | return; | |
3040 | } | |
b331163b | 3041 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
3042 | const UHashElement* element = NULL; |
3043 | if ( source ) { | |
3044 | while ( (element = source->nextElement(pos)) != NULL ) { | |
3045 | const UHashTok keyTok = element->key; | |
3046 | const UnicodeString* key = (UnicodeString*)keyTok.pointer; | |
3047 | const UHashTok valueTok = element->value; | |
3048 | const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; | |
3049 | AffixPatternsForCurrency* copy = new AffixPatternsForCurrency( | |
3050 | value->negPrefixPatternForCurrency, | |
3051 | value->negSuffixPatternForCurrency, | |
3052 | value->posPrefixPatternForCurrency, | |
3053 | value->posSuffixPatternForCurrency, | |
3054 | value->patternType); | |
3055 | target->put(UnicodeString(*key), copy, status); | |
3056 | if ( U_FAILURE(status) ) { | |
3057 | return; | |
3058 | } | |
3059 | } | |
3060 | } | |
3061 | } | |
3062 | ||
57a6839d A |
3063 | void |
3064 | DecimalFormat::setGroupingUsed(UBool newValue) { | |
3065 | NumberFormat::setGroupingUsed(newValue); | |
2ca993e8 | 3066 | fImpl->updateGrouping(); |
57a6839d A |
3067 | } |
3068 | ||
57a6839d A |
3069 | void |
3070 | DecimalFormat::setParseIntegerOnly(UBool newValue) { | |
3071 | NumberFormat::setParseIntegerOnly(newValue); | |
57a6839d A |
3072 | } |
3073 | ||
57a6839d A |
3074 | void |
3075 | DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) { | |
3076 | NumberFormat::setContext(value, status); | |
57a6839d A |
3077 | } |
3078 | ||
51004dcb A |
3079 | DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr, |
3080 | int32_t newValue, | |
3081 | UErrorCode &status) { | |
3082 | if(U_FAILURE(status)) return *this; | |
3083 | ||
3084 | switch(attr) { | |
3085 | case UNUM_LENIENT_PARSE: | |
3086 | setLenient(newValue!=0); | |
3087 | break; | |
3088 | ||
3089 | case UNUM_PARSE_INT_ONLY: | |
3090 | setParseIntegerOnly(newValue!=0); | |
3091 | break; | |
3092 | ||
3093 | case UNUM_GROUPING_USED: | |
3094 | setGroupingUsed(newValue!=0); | |
3095 | break; | |
3096 | ||
3097 | case UNUM_DECIMAL_ALWAYS_SHOWN: | |
3098 | setDecimalSeparatorAlwaysShown(newValue!=0); | |
3099 | break; | |
3100 | ||
3101 | case UNUM_MAX_INTEGER_DIGITS: | |
3102 | setMaximumIntegerDigits(newValue); | |
3103 | break; | |
3104 | ||
3105 | case UNUM_MIN_INTEGER_DIGITS: | |
3106 | setMinimumIntegerDigits(newValue); | |
3107 | break; | |
3108 | ||
3109 | case UNUM_INTEGER_DIGITS: | |
3110 | setMinimumIntegerDigits(newValue); | |
3111 | setMaximumIntegerDigits(newValue); | |
3112 | break; | |
3113 | ||
3114 | case UNUM_MAX_FRACTION_DIGITS: | |
3115 | setMaximumFractionDigits(newValue); | |
3116 | break; | |
3117 | ||
3118 | case UNUM_MIN_FRACTION_DIGITS: | |
3119 | setMinimumFractionDigits(newValue); | |
3120 | break; | |
3121 | ||
3122 | case UNUM_FRACTION_DIGITS: | |
3123 | setMinimumFractionDigits(newValue); | |
3124 | setMaximumFractionDigits(newValue); | |
3125 | break; | |
3126 | ||
3127 | case UNUM_SIGNIFICANT_DIGITS_USED: | |
3128 | setSignificantDigitsUsed(newValue!=0); | |
3129 | break; | |
3130 | ||
3131 | case UNUM_MAX_SIGNIFICANT_DIGITS: | |
3132 | setMaximumSignificantDigits(newValue); | |
3133 | break; | |
3134 | ||
3135 | case UNUM_MIN_SIGNIFICANT_DIGITS: | |
3136 | setMinimumSignificantDigits(newValue); | |
3137 | break; | |
3138 | ||
3139 | case UNUM_MULTIPLIER: | |
3140 | setMultiplier(newValue); | |
3141 | break; | |
3142 | ||
3143 | case UNUM_GROUPING_SIZE: | |
3144 | setGroupingSize(newValue); | |
3145 | break; | |
3146 | ||
3147 | case UNUM_ROUNDING_MODE: | |
3148 | setRoundingMode((DecimalFormat::ERoundingMode)newValue); | |
3149 | break; | |
3150 | ||
3151 | case UNUM_FORMAT_WIDTH: | |
3152 | setFormatWidth(newValue); | |
3153 | break; | |
3154 | ||
3155 | case UNUM_PADDING_POSITION: | |
3156 | /** The position at which padding will take place. */ | |
3157 | setPadPosition((DecimalFormat::EPadPosition)newValue); | |
3158 | break; | |
3159 | ||
3160 | case UNUM_SECONDARY_GROUPING_SIZE: | |
3161 | setSecondaryGroupingSize(newValue); | |
3162 | break; | |
3163 | ||
3164 | #if UCONFIG_HAVE_PARSEALLINPUT | |
3165 | case UNUM_PARSE_ALL_INPUT: | |
3166 | setParseAllInput((UNumberFormatAttributeValue)newValue); | |
3167 | break; | |
3168 | #endif | |
3169 | ||
3170 | /* These are stored in fBoolFlags */ | |
3171 | case UNUM_PARSE_NO_EXPONENT: | |
3172 | case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: | |
b331163b | 3173 | case UNUM_PARSE_DECIMAL_MARK_REQUIRED: |
51004dcb A |
3174 | if(!fBoolFlags.isValidValue(newValue)) { |
3175 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
3176 | } else { | |
2ca993e8 A |
3177 | if (attr == UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS) { |
3178 | fImpl->setFailIfMoreThanMaxDigits((UBool) newValue); | |
3179 | } | |
51004dcb A |
3180 | fBoolFlags.set(attr, newValue); |
3181 | } | |
3182 | break; | |
3183 | ||
3184 | case UNUM_SCALE: | |
2ca993e8 | 3185 | fImpl->setScale(newValue); |
51004dcb A |
3186 | break; |
3187 | ||
b331163b A |
3188 | case UNUM_CURRENCY_USAGE: |
3189 | setCurrencyUsage((UCurrencyUsage)newValue, &status); | |
2ca993e8 A |
3190 | break; |
3191 | ||
3192 | case UNUM_MINIMUM_GROUPING_DIGITS: | |
3193 | setMinimumGroupingDigits(newValue); | |
3194 | break; | |
b331163b | 3195 | |
51004dcb A |
3196 | default: |
3197 | status = U_UNSUPPORTED_ERROR; | |
3198 | break; | |
3199 | } | |
3200 | return *this; | |
3201 | } | |
3202 | ||
3203 | int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr, | |
3204 | UErrorCode &status ) const { | |
3205 | if(U_FAILURE(status)) return -1; | |
3206 | switch(attr) { | |
3207 | case UNUM_LENIENT_PARSE: | |
3208 | return isLenient(); | |
3209 | ||
3210 | case UNUM_PARSE_INT_ONLY: | |
3211 | return isParseIntegerOnly(); | |
3212 | ||
3213 | case UNUM_GROUPING_USED: | |
3214 | return isGroupingUsed(); | |
3215 | ||
3216 | case UNUM_DECIMAL_ALWAYS_SHOWN: | |
3217 | return isDecimalSeparatorAlwaysShown(); | |
3218 | ||
3219 | case UNUM_MAX_INTEGER_DIGITS: | |
3220 | return getMaximumIntegerDigits(); | |
3221 | ||
3222 | case UNUM_MIN_INTEGER_DIGITS: | |
3223 | return getMinimumIntegerDigits(); | |
3224 | ||
3225 | case UNUM_INTEGER_DIGITS: | |
3226 | // TBD: what should this return? | |
3227 | return getMinimumIntegerDigits(); | |
3228 | ||
3229 | case UNUM_MAX_FRACTION_DIGITS: | |
3230 | return getMaximumFractionDigits(); | |
3231 | ||
3232 | case UNUM_MIN_FRACTION_DIGITS: | |
3233 | return getMinimumFractionDigits(); | |
3234 | ||
3235 | case UNUM_FRACTION_DIGITS: | |
3236 | // TBD: what should this return? | |
3237 | return getMinimumFractionDigits(); | |
3238 | ||
3239 | case UNUM_SIGNIFICANT_DIGITS_USED: | |
3240 | return areSignificantDigitsUsed(); | |
3241 | ||
3242 | case UNUM_MAX_SIGNIFICANT_DIGITS: | |
3243 | return getMaximumSignificantDigits(); | |
3244 | ||
3245 | case UNUM_MIN_SIGNIFICANT_DIGITS: | |
3246 | return getMinimumSignificantDigits(); | |
3247 | ||
3248 | case UNUM_MULTIPLIER: | |
3249 | return getMultiplier(); | |
3250 | ||
3251 | case UNUM_GROUPING_SIZE: | |
3252 | return getGroupingSize(); | |
3253 | ||
3254 | case UNUM_ROUNDING_MODE: | |
3255 | return getRoundingMode(); | |
3256 | ||
3257 | case UNUM_FORMAT_WIDTH: | |
3258 | return getFormatWidth(); | |
3259 | ||
3260 | case UNUM_PADDING_POSITION: | |
3261 | return getPadPosition(); | |
3262 | ||
3263 | case UNUM_SECONDARY_GROUPING_SIZE: | |
3264 | return getSecondaryGroupingSize(); | |
3265 | ||
3266 | /* These are stored in fBoolFlags */ | |
3267 | case UNUM_PARSE_NO_EXPONENT: | |
3268 | case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: | |
b331163b | 3269 | case UNUM_PARSE_DECIMAL_MARK_REQUIRED: |
51004dcb A |
3270 | return fBoolFlags.get(attr); |
3271 | ||
3272 | case UNUM_SCALE: | |
2ca993e8 | 3273 | return fImpl->fScale; |
51004dcb | 3274 | |
b331163b | 3275 | case UNUM_CURRENCY_USAGE: |
2ca993e8 A |
3276 | return fImpl->getCurrencyUsage(); |
3277 | ||
3278 | case UNUM_MINIMUM_GROUPING_DIGITS: | |
3279 | return getMinimumGroupingDigits(); | |
b331163b | 3280 | |
51004dcb A |
3281 | default: |
3282 | status = U_UNSUPPORTED_ERROR; | |
3283 | break; | |
3284 | } | |
729e4ab9 | 3285 | |
51004dcb A |
3286 | return -1; /* undefined */ |
3287 | } | |
3288 | ||
3289 | #if UCONFIG_HAVE_PARSEALLINPUT | |
3290 | void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) { | |
3291 | fParseAllInput = value; | |
51004dcb A |
3292 | } |
3293 | #endif | |
729e4ab9 | 3294 | |
b75a7d8f A |
3295 | U_NAMESPACE_END |
3296 | ||
3297 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
3298 | ||
3299 | //eof |