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