]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
b331163b | 3 | * Copyright (C) 1997-2015, International Business Machines Corporation and * |
b75a7d8f A |
4 | * others. All Rights Reserved. * |
5 | ******************************************************************************* | |
6 | * | |
7 | * File DECIMFMT.CPP | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 02/19/97 aliu Converted from java. | |
13 | * 03/20/97 clhuang Implemented with new APIs. | |
14 | * 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it. | |
15 | * 04/3/97 aliu Rewrote parsing and formatting completely, and | |
16 | * cleaned up and debugged. Actually works now. | |
17 | * Implemented NAN and INF handling, for both parsing | |
18 | * and formatting. Extensive testing & debugging. | |
19 | * 04/10/97 aliu Modified to compile on AIX. | |
20 | * 04/16/97 aliu Rewrote to use DigitList, which has been resurrected. | |
21 | * Changed DigitCount to int per code review. | |
22 | * 07/09/97 helena Made ParsePosition into a class. | |
23 | * 08/26/97 aliu Extensive changes to applyPattern; completely | |
24 | * rewritten from the Java. | |
25 | * 09/09/97 aliu Ported over support for exponential formats. | |
26 | * 07/20/98 stephen JDK 1.2 sync up. | |
27 | * Various instances of '0' replaced with 'NULL' | |
28 | * Check for grouping size in subFormat() | |
29 | * Brought subParse() in line with Java 1.2 | |
30 | * Added method appendAffix() | |
31 | * 08/24/1998 srl Removed Mutex calls. This is not a thread safe class! | |
32 | * 02/22/99 stephen Removed character literals for EBCDIC safety | |
33 | * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes | |
34 | * 06/28/99 stephen Fixed bugs in toPattern(). | |
729e4ab9 | 35 | * 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad, |
b75a7d8f A |
36 | * fPadPosition |
37 | ******************************************************************************** | |
38 | */ | |
729e4ab9 | 39 | |
b75a7d8f A |
40 | #include "unicode/utypes.h" |
41 | ||
42 | #if !UCONFIG_NO_FORMATTING | |
43 | ||
729e4ab9 | 44 | #include "fphdlimp.h" |
b75a7d8f A |
45 | #include "unicode/decimfmt.h" |
46 | #include "unicode/choicfmt.h" | |
47 | #include "unicode/ucurr.h" | |
48 | #include "unicode/ustring.h" | |
49 | #include "unicode/dcfmtsym.h" | |
374ca955 | 50 | #include "unicode/ures.h" |
b75a7d8f | 51 | #include "unicode/uchar.h" |
46f4442e | 52 | #include "unicode/uniset.h" |
374ca955 | 53 | #include "unicode/curramt.h" |
729e4ab9 A |
54 | #include "unicode/currpinf.h" |
55 | #include "unicode/plurrule.h" | |
4388f060 A |
56 | #include "unicode/utf16.h" |
57 | #include "unicode/numsys.h" | |
58 | #include "unicode/localpointer.h" | |
59 | #include "uresimp.h" | |
374ca955 | 60 | #include "ucurrimp.h" |
729e4ab9 A |
61 | #include "charstr.h" |
62 | #include "cmemory.h" | |
4388f060 | 63 | #include "patternprops.h" |
b75a7d8f | 64 | #include "digitlst.h" |
b75a7d8f A |
65 | #include "cstring.h" |
66 | #include "umutex.h" | |
67 | #include "uassert.h" | |
374ca955 | 68 | #include "putilimp.h" |
729e4ab9 A |
69 | #include <math.h> |
70 | #include "hash.h" | |
4388f060 | 71 | #include "decfmtst.h" |
51004dcb | 72 | #include "dcfmtimp.h" |
57a6839d A |
73 | #include "plurrule_impl.h" |
74 | #include "decimalformatpattern.h" | |
b331163b | 75 | #include "fmtableimp.h" |
729e4ab9 | 76 | |
51004dcb A |
77 | /* |
78 | * On certain platforms, round is a macro defined in math.h | |
79 | * This undefine is to avoid conflict between the macro and | |
80 | * the function defined below. | |
81 | */ | |
82 | #ifdef round | |
83 | #undef round | |
84 | #endif | |
b75a7d8f | 85 | |
57a6839d | 86 | |
b75a7d8f A |
87 | U_NAMESPACE_BEGIN |
88 | ||
57a6839d A |
89 | #ifdef FMT_DEBUG |
90 | #include <stdio.h> | |
91 | static void _debugout(const char *f, int l, const UnicodeString& s) { | |
92 | char buf[2000]; | |
93 | s.extract((int32_t) 0, s.length(), buf, "utf-8"); | |
94 | printf("%s:%d: %s\n", f,l, buf); | |
95 | } | |
96 | #define debugout(x) _debugout(__FILE__,__LINE__,x) | |
97 | #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x); | |
98 | static const UnicodeString dbg_null("<NULL>",""); | |
99 | #define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null)) | |
100 | #else | |
101 | #define debugout(x) | |
102 | #define debug(x) | |
103 | #endif | |
104 | ||
105 | ||
51004dcb A |
106 | |
107 | /* == Fastpath calculation. == | |
108 | */ | |
109 | #if UCONFIG_FORMAT_FASTPATHS_49 | |
110 | inline DecimalFormatInternal& internalData(uint8_t *reserved) { | |
111 | return *reinterpret_cast<DecimalFormatInternal*>(reserved); | |
112 | } | |
113 | inline const DecimalFormatInternal& internalData(const uint8_t *reserved) { | |
114 | return *reinterpret_cast<const DecimalFormatInternal*>(reserved); | |
115 | } | |
116 | #else | |
117 | #endif | |
118 | ||
729e4ab9 A |
119 | /* For currency parsing purose, |
120 | * Need to remember all prefix patterns and suffix patterns of | |
121 | * every currency format pattern, | |
122 | * including the pattern of default currecny style | |
123 | * and plural currency style. And the patterns are set through applyPattern. | |
124 | */ | |
125 | struct AffixPatternsForCurrency : public UMemory { | |
126 | // negative prefix pattern | |
127 | UnicodeString negPrefixPatternForCurrency; | |
128 | // negative suffix pattern | |
129 | UnicodeString negSuffixPatternForCurrency; | |
130 | // positive prefix pattern | |
131 | UnicodeString posPrefixPatternForCurrency; | |
132 | // positive suffix pattern | |
133 | UnicodeString posSuffixPatternForCurrency; | |
134 | int8_t patternType; | |
135 | ||
136 | AffixPatternsForCurrency(const UnicodeString& negPrefix, | |
137 | const UnicodeString& negSuffix, | |
138 | const UnicodeString& posPrefix, | |
139 | const UnicodeString& posSuffix, | |
140 | int8_t type) { | |
141 | negPrefixPatternForCurrency = negPrefix; | |
142 | negSuffixPatternForCurrency = negSuffix; | |
143 | posPrefixPatternForCurrency = posPrefix; | |
144 | posSuffixPatternForCurrency = posSuffix; | |
145 | patternType = type; | |
146 | } | |
57a6839d A |
147 | #ifdef FMT_DEBUG |
148 | void dump() const { | |
149 | debugout( UnicodeString("AffixPatternsForCurrency( -=\"") + | |
150 | negPrefixPatternForCurrency + (UnicodeString)"\"/\"" + | |
151 | negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" + | |
152 | posPrefixPatternForCurrency + (UnicodeString)"\"/\"" + | |
153 | posSuffixPatternForCurrency + (UnicodeString)"\" )"); | |
154 | } | |
155 | #endif | |
729e4ab9 A |
156 | }; |
157 | ||
158 | /* affix for currency formatting when the currency sign in the pattern | |
159 | * equals to 3, such as the pattern contains 3 currency sign or | |
160 | * the formatter style is currency plural format style. | |
161 | */ | |
162 | struct AffixesForCurrency : public UMemory { | |
163 | // negative prefix | |
164 | UnicodeString negPrefixForCurrency; | |
165 | // negative suffix | |
166 | UnicodeString negSuffixForCurrency; | |
167 | // positive prefix | |
168 | UnicodeString posPrefixForCurrency; | |
169 | // positive suffix | |
170 | UnicodeString posSuffixForCurrency; | |
171 | ||
172 | int32_t formatWidth; | |
173 | ||
174 | AffixesForCurrency(const UnicodeString& negPrefix, | |
175 | const UnicodeString& negSuffix, | |
176 | const UnicodeString& posPrefix, | |
177 | const UnicodeString& posSuffix) { | |
178 | negPrefixForCurrency = negPrefix; | |
179 | negSuffixForCurrency = negSuffix; | |
180 | posPrefixForCurrency = posPrefix; | |
181 | posSuffixForCurrency = posSuffix; | |
182 | } | |
57a6839d A |
183 | #ifdef FMT_DEBUG |
184 | void dump() const { | |
185 | debugout( UnicodeString("AffixesForCurrency( -=\"") + | |
186 | negPrefixForCurrency + (UnicodeString)"\"/\"" + | |
187 | negSuffixForCurrency + (UnicodeString)"\" +=\"" + | |
188 | posPrefixForCurrency + (UnicodeString)"\"/\"" + | |
189 | posSuffixForCurrency + (UnicodeString)"\" )"); | |
190 | } | |
191 | #endif | |
729e4ab9 A |
192 | }; |
193 | ||
194 | U_CDECL_BEGIN | |
195 | ||
196 | /** | |
197 | * @internal ICU 4.2 | |
198 | */ | |
199 | static UBool U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2); | |
200 | ||
201 | /** | |
202 | * @internal ICU 4.2 | |
203 | */ | |
204 | static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2); | |
205 | ||
206 | ||
207 | static UBool | |
208 | U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2) { | |
209 | const AffixesForCurrency* affix_1 = | |
210 | (AffixesForCurrency*)val1.pointer; | |
211 | const AffixesForCurrency* affix_2 = | |
212 | (AffixesForCurrency*)val2.pointer; | |
213 | return affix_1->negPrefixForCurrency == affix_2->negPrefixForCurrency && | |
214 | affix_1->negSuffixForCurrency == affix_2->negSuffixForCurrency && | |
215 | affix_1->posPrefixForCurrency == affix_2->posPrefixForCurrency && | |
216 | affix_1->posSuffixForCurrency == affix_2->posSuffixForCurrency; | |
217 | } | |
218 | ||
219 | ||
220 | static UBool | |
221 | U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) { | |
222 | const AffixPatternsForCurrency* affix_1 = | |
223 | (AffixPatternsForCurrency*)val1.pointer; | |
224 | const AffixPatternsForCurrency* affix_2 = | |
225 | (AffixPatternsForCurrency*)val2.pointer; | |
226 | return affix_1->negPrefixPatternForCurrency == | |
227 | affix_2->negPrefixPatternForCurrency && | |
228 | affix_1->negSuffixPatternForCurrency == | |
229 | affix_2->negSuffixPatternForCurrency && | |
230 | affix_1->posPrefixPatternForCurrency == | |
231 | affix_2->posPrefixPatternForCurrency && | |
232 | affix_1->posSuffixPatternForCurrency == | |
233 | affix_2->posSuffixPatternForCurrency && | |
234 | affix_1->patternType == affix_2->patternType; | |
235 | } | |
236 | ||
237 | U_CDECL_END | |
238 | ||
b75a7d8f | 239 | |
4388f060 | 240 | |
46f4442e | 241 | |
b75a7d8f A |
242 | // ***************************************************************************** |
243 | // class DecimalFormat | |
244 | // ***************************************************************************** | |
245 | ||
374ca955 | 246 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat) |
b75a7d8f A |
247 | |
248 | // Constants for characters used in programmatic (unlocalized) patterns. | |
374ca955 A |
249 | #define kPatternZeroDigit ((UChar)0x0030) /*'0'*/ |
250 | #define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/ | |
251 | #define kPatternGroupingSeparator ((UChar)0x002C) /*','*/ | |
252 | #define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/ | |
253 | #define kPatternPerMill ((UChar)0x2030) | |
254 | #define kPatternPercent ((UChar)0x0025) /*'%'*/ | |
255 | #define kPatternDigit ((UChar)0x0023) /*'#'*/ | |
256 | #define kPatternSeparator ((UChar)0x003B) /*';'*/ | |
257 | #define kPatternExponent ((UChar)0x0045) /*'E'*/ | |
258 | #define kPatternPlus ((UChar)0x002B) /*'+'*/ | |
259 | #define kPatternMinus ((UChar)0x002D) /*'-'*/ | |
260 | #define kPatternPadEscape ((UChar)0x002A) /*'*'*/ | |
261 | #define kQuote ((UChar)0x0027) /*'\''*/ | |
262 | /** | |
263 | * The CURRENCY_SIGN is the standard Unicode symbol for currency. It | |
264 | * is used in patterns and substitued with either the currency symbol, | |
265 | * or if it is doubled, with the international currency symbol. If the | |
266 | * CURRENCY_SIGN is seen in a pattern, then the decimal separator is | |
267 | * replaced with the monetary decimal separator. | |
268 | */ | |
269 | #define kCurrencySign ((UChar)0x00A4) | |
270 | #define kDefaultPad ((UChar)0x0020) /* */ | |
b75a7d8f A |
271 | |
272 | const int32_t DecimalFormat::kDoubleIntegerDigits = 309; | |
273 | const int32_t DecimalFormat::kDoubleFractionDigits = 340; | |
274 | ||
374ca955 A |
275 | const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8; |
276 | ||
b75a7d8f A |
277 | /** |
278 | * These are the tags we expect to see in normal resource bundle files associated | |
279 | * with a locale. | |
280 | */ | |
729e4ab9 A |
281 | const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used |
282 | static const char fgNumberElements[]="NumberElements"; | |
283 | static const char fgLatn[]="latn"; | |
284 | static const char fgPatterns[]="patterns"; | |
285 | static const char fgDecimalFormat[]="decimalFormat"; | |
286 | static const char fgCurrencyFormat[]="currencyFormat"; | |
57a6839d | 287 | |
729e4ab9 | 288 | static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0}; |
b75a7d8f | 289 | |
374ca955 A |
290 | inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; } |
291 | inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; } | |
b75a7d8f | 292 | |
57a6839d A |
293 | static void copyString(const UnicodeString& src, UBool isBogus, UnicodeString *& dest, UErrorCode &status) { |
294 | if (U_FAILURE(status)) { | |
295 | return; | |
296 | } | |
297 | if (isBogus) { | |
298 | delete dest; | |
299 | dest = NULL; | |
300 | } else { | |
301 | if (dest != NULL) { | |
302 | *dest = src; | |
303 | } else { | |
304 | dest = new UnicodeString(src); | |
305 | if (dest == NULL) { | |
306 | status = U_MEMORY_ALLOCATION_ERROR; | |
307 | return; | |
308 | } | |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | ||
b75a7d8f A |
314 | //------------------------------------------------------------------------------ |
315 | // Constructs a DecimalFormat instance in the default locale. | |
729e4ab9 A |
316 | |
317 | DecimalFormat::DecimalFormat(UErrorCode& status) { | |
57a6839d | 318 | init(); |
b75a7d8f A |
319 | UParseError parseError; |
320 | construct(status, parseError); | |
321 | } | |
322 | ||
323 | //------------------------------------------------------------------------------ | |
324 | // Constructs a DecimalFormat instance with the specified number format | |
325 | // pattern in the default locale. | |
326 | ||
327 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
729e4ab9 | 328 | UErrorCode& status) { |
57a6839d | 329 | init(); |
b75a7d8f A |
330 | UParseError parseError; |
331 | construct(status, parseError, &pattern); | |
332 | } | |
333 | ||
334 | //------------------------------------------------------------------------------ | |
335 | // Constructs a DecimalFormat instance with the specified number format | |
336 | // pattern and the number format symbols in the default locale. The | |
337 | // created instance owns the symbols. | |
338 | ||
339 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
340 | DecimalFormatSymbols* symbolsToAdopt, | |
729e4ab9 | 341 | UErrorCode& status) { |
57a6839d | 342 | init(); |
b75a7d8f A |
343 | UParseError parseError; |
344 | if (symbolsToAdopt == NULL) | |
345 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
346 | construct(status, parseError, &pattern, symbolsToAdopt); | |
347 | } | |
729e4ab9 | 348 | |
b75a7d8f A |
349 | DecimalFormat::DecimalFormat( const UnicodeString& pattern, |
350 | DecimalFormatSymbols* symbolsToAdopt, | |
351 | UParseError& parseErr, | |
729e4ab9 | 352 | UErrorCode& status) { |
57a6839d | 353 | init(); |
b75a7d8f A |
354 | if (symbolsToAdopt == NULL) |
355 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
356 | construct(status,parseErr, &pattern, symbolsToAdopt); | |
357 | } | |
729e4ab9 | 358 | |
b75a7d8f A |
359 | //------------------------------------------------------------------------------ |
360 | // Constructs a DecimalFormat instance with the specified number format | |
361 | // pattern and the number format symbols in the default locale. The | |
362 | // created instance owns the clone of the symbols. | |
729e4ab9 | 363 | |
b75a7d8f A |
364 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
365 | const DecimalFormatSymbols& symbols, | |
729e4ab9 | 366 | UErrorCode& status) { |
57a6839d | 367 | init(); |
b75a7d8f A |
368 | UParseError parseError; |
369 | construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols)); | |
370 | } | |
371 | ||
729e4ab9 A |
372 | //------------------------------------------------------------------------------ |
373 | // Constructs a DecimalFormat instance with the specified number format | |
374 | // pattern, the number format symbols, and the number format style. | |
375 | // The created instance owns the clone of the symbols. | |
376 | ||
377 | DecimalFormat::DecimalFormat(const UnicodeString& pattern, | |
378 | DecimalFormatSymbols* symbolsToAdopt, | |
4388f060 | 379 | UNumberFormatStyle style, |
729e4ab9 | 380 | UErrorCode& status) { |
57a6839d | 381 | init(); |
729e4ab9 A |
382 | fStyle = style; |
383 | UParseError parseError; | |
384 | construct(status, parseError, &pattern, symbolsToAdopt); | |
385 | } | |
386 | ||
387 | //----------------------------------------------------------------------------- | |
388 | // Common DecimalFormat initialization. | |
389 | // Put all fields of an uninitialized object into a known state. | |
390 | // Common code, shared by all constructors. | |
57a6839d A |
391 | // Can not fail. Leave the object in good enough shape that the destructor |
392 | // or assignment operator can run successfully. | |
729e4ab9 | 393 | void |
57a6839d | 394 | DecimalFormat::init() { |
729e4ab9 A |
395 | fPosPrefixPattern = 0; |
396 | fPosSuffixPattern = 0; | |
397 | fNegPrefixPattern = 0; | |
398 | fNegSuffixPattern = 0; | |
399 | fCurrencyChoice = 0; | |
400 | fMultiplier = NULL; | |
51004dcb | 401 | fScale = 0; |
729e4ab9 A |
402 | fGroupingSize = 0; |
403 | fGroupingSize2 = 0; | |
404 | fDecimalSeparatorAlwaysShown = FALSE; | |
405 | fSymbols = NULL; | |
406 | fUseSignificantDigits = FALSE; | |
407 | fMinSignificantDigits = 1; | |
408 | fMaxSignificantDigits = 6; | |
409 | fUseExponentialNotation = FALSE; | |
410 | fMinExponentDigits = 0; | |
411 | fExponentSignAlwaysShown = FALSE; | |
51004dcb | 412 | fBoolFlags.clear(); |
729e4ab9 A |
413 | fRoundingIncrement = 0; |
414 | fRoundingMode = kRoundHalfEven; | |
415 | fPad = 0; | |
416 | fFormatWidth = 0; | |
417 | fPadPosition = kPadBeforePrefix; | |
4388f060 | 418 | fStyle = UNUM_DECIMAL; |
57a6839d | 419 | fCurrencySignCount = fgCurrencySignCountZero; |
729e4ab9 A |
420 | fAffixPatternsForCurrency = NULL; |
421 | fAffixesForCurrency = NULL; | |
422 | fPluralAffixesForCurrency = NULL; | |
423 | fCurrencyPluralInfo = NULL; | |
b331163b | 424 | fCurrencyUsage = UCURR_USAGE_STANDARD; |
51004dcb A |
425 | #if UCONFIG_HAVE_PARSEALLINPUT |
426 | fParseAllInput = UNUM_MAYBE; | |
427 | #endif | |
428 | ||
429 | #if UCONFIG_FORMAT_FASTPATHS_49 | |
430 | DecimalFormatInternal &data = internalData(fReserved); | |
431 | data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later. | |
432 | data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later. | |
433 | #endif | |
57a6839d | 434 | fStaticSets = NULL; |
729e4ab9 A |
435 | } |
436 | ||
b75a7d8f A |
437 | //------------------------------------------------------------------------------ |
438 | // Constructs a DecimalFormat instance with the specified number format | |
439 | // pattern and the number format symbols in the desired locale. The | |
440 | // created instance owns the symbols. | |
441 | ||
442 | void | |
57a6839d | 443 | DecimalFormat::construct(UErrorCode& status, |
b75a7d8f A |
444 | UParseError& parseErr, |
445 | const UnicodeString* pattern, | |
446 | DecimalFormatSymbols* symbolsToAdopt) | |
447 | { | |
448 | fSymbols = symbolsToAdopt; // Do this BEFORE aborting on status failure!!! | |
b75a7d8f | 449 | fRoundingIncrement = NULL; |
b75a7d8f A |
450 | fRoundingMode = kRoundHalfEven; |
451 | fPad = kPatternPadEscape; | |
452 | fPadPosition = kPadBeforePrefix; | |
453 | if (U_FAILURE(status)) | |
454 | return; | |
455 | ||
456 | fPosPrefixPattern = fPosSuffixPattern = NULL; | |
457 | fNegPrefixPattern = fNegSuffixPattern = NULL; | |
729e4ab9 | 458 | setMultiplier(1); |
b75a7d8f A |
459 | fGroupingSize = 3; |
460 | fGroupingSize2 = 0; | |
461 | fDecimalSeparatorAlwaysShown = FALSE; | |
b75a7d8f A |
462 | fUseExponentialNotation = FALSE; |
463 | fMinExponentDigits = 0; | |
464 | ||
465 | if (fSymbols == NULL) | |
466 | { | |
467 | fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status); | |
b75a7d8f A |
468 | if (fSymbols == 0) { |
469 | status = U_MEMORY_ALLOCATION_ERROR; | |
470 | return; | |
471 | } | |
472 | } | |
57a6839d A |
473 | fStaticSets = DecimalFormatStaticSets::getStaticSets(status); |
474 | if (U_FAILURE(status)) { | |
475 | return; | |
476 | } | |
4388f060 A |
477 | UErrorCode nsStatus = U_ZERO_ERROR; |
478 | NumberingSystem *ns = NumberingSystem::createInstance(nsStatus); | |
479 | if (U_FAILURE(nsStatus)) { | |
480 | status = nsStatus; | |
481 | return; | |
482 | } | |
b75a7d8f A |
483 | |
484 | UnicodeString str; | |
485 | // Uses the default locale's number format pattern if there isn't | |
486 | // one specified. | |
487 | if (pattern == NULL) | |
488 | { | |
374ca955 | 489 | int32_t len = 0; |
4388f060 A |
490 | UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status); |
491 | ||
492 | UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status); | |
493 | resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status); | |
494 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); | |
495 | const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); | |
496 | if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) { | |
497 | status = U_ZERO_ERROR; | |
498 | resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status); | |
499 | resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status); | |
500 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); | |
501 | resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); | |
502 | } | |
374ca955 | 503 | str.setTo(TRUE, resStr, len); |
b75a7d8f | 504 | pattern = &str; |
374ca955 | 505 | ures_close(resource); |
4388f060 | 506 | ures_close(top); |
b75a7d8f A |
507 | } |
508 | ||
4388f060 A |
509 | delete ns; |
510 | ||
b75a7d8f A |
511 | if (U_FAILURE(status)) |
512 | { | |
513 | return; | |
514 | } | |
515 | ||
374ca955 A |
516 | if (pattern->indexOf((UChar)kCurrencySign) >= 0) { |
517 | // If it looks like we are going to use a currency pattern | |
518 | // then do the time consuming lookup. | |
73c04bcf | 519 | setCurrencyForSymbols(); |
b75a7d8f | 520 | } else { |
729e4ab9 A |
521 | setCurrencyInternally(NULL, status); |
522 | } | |
523 | ||
524 | const UnicodeString* patternUsed; | |
525 | UnicodeString currencyPluralPatternForOther; | |
526 | // apply pattern | |
4388f060 | 527 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
729e4ab9 A |
528 | fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status); |
529 | if (U_FAILURE(status)) { | |
530 | return; | |
531 | } | |
532 | ||
533 | // the pattern used in format is not fixed until formatting, | |
534 | // in which, the number is known and | |
535 | // will be used to pick the right pattern based on plural count. | |
536 | // Here, set the pattern as the pattern of plural count == "other". | |
537 | // For most locale, the patterns are probably the same for all | |
538 | // plural count. If not, the right pattern need to be re-applied | |
539 | // during format. | |
4388f060 | 540 | fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther); |
729e4ab9 A |
541 | patternUsed = ¤cyPluralPatternForOther; |
542 | // TODO: not needed? | |
543 | setCurrencyForSymbols(); | |
544 | ||
545 | } else { | |
546 | patternUsed = pattern; | |
547 | } | |
548 | ||
549 | if (patternUsed->indexOf(kCurrencySign) != -1) { | |
550 | // initialize for currency, not only for plural format, | |
551 | // but also for mix parsing | |
552 | if (fCurrencyPluralInfo == NULL) { | |
553 | fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status); | |
554 | if (U_FAILURE(status)) { | |
555 | return; | |
556 | } | |
557 | } | |
558 | // need it for mix parsing | |
559 | setupCurrencyAffixPatterns(status); | |
560 | // expanded affixes for plural names | |
4388f060 | 561 | if (patternUsed->indexOf(fgTripleCurrencySign, 3, 0) != -1) { |
729e4ab9 A |
562 | setupCurrencyAffixes(*patternUsed, TRUE, TRUE, status); |
563 | } | |
564 | } | |
565 | ||
566 | applyPatternWithoutExpandAffix(*patternUsed,FALSE, parseErr, status); | |
567 | ||
568 | // expand affixes | |
569 | if (fCurrencySignCount != fgCurrencySignCountInPluralFormat) { | |
570 | expandAffixAdjustWidth(NULL); | |
b75a7d8f A |
571 | } |
572 | ||
73c04bcf A |
573 | // If it was a currency format, apply the appropriate rounding by |
574 | // resetting the currency. NOTE: this copies fCurrency on top of itself. | |
57a6839d | 575 | if (fCurrencySignCount != fgCurrencySignCountZero) { |
729e4ab9 | 576 | setCurrencyInternally(getCurrency(), status); |
b75a7d8f | 577 | } |
51004dcb A |
578 | #if UCONFIG_FORMAT_FASTPATHS_49 |
579 | DecimalFormatInternal &data = internalData(fReserved); | |
580 | data.fFastFormatStatus = kFastpathNO; // allow it to be calculated | |
581 | data.fFastParseStatus = kFastpathNO; // allow it to be calculated | |
582 | handleChanged(); | |
583 | #endif | |
b75a7d8f A |
584 | } |
585 | ||
729e4ab9 A |
586 | |
587 | void | |
588 | DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) { | |
589 | if (U_FAILURE(status)) { | |
590 | return; | |
591 | } | |
592 | UParseError parseErr; | |
593 | fAffixPatternsForCurrency = initHashForAffixPattern(status); | |
594 | if (U_FAILURE(status)) { | |
595 | return; | |
596 | } | |
597 | ||
4388f060 A |
598 | NumberingSystem *ns = NumberingSystem::createInstance(fSymbols->getLocale(),status); |
599 | if (U_FAILURE(status)) { | |
600 | return; | |
601 | } | |
602 | ||
729e4ab9 A |
603 | // Save the default currency patterns of this locale. |
604 | // Here, chose onlyApplyPatternWithoutExpandAffix without | |
605 | // expanding the affix patterns into affixes. | |
606 | UnicodeString currencyPattern; | |
607 | UErrorCode error = U_ZERO_ERROR; | |
608 | ||
609 | UResourceBundle *resource = ures_open(NULL, fSymbols->getLocale().getName(), &error); | |
4388f060 A |
610 | UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error); |
611 | resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error); | |
612 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); | |
729e4ab9 | 613 | int32_t patLen = 0; |
4388f060 A |
614 | const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); |
615 | if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) { | |
616 | error = U_ZERO_ERROR; | |
617 | resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error); | |
618 | resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); | |
619 | patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); | |
620 | } | |
621 | ures_close(numElements); | |
729e4ab9 | 622 | ures_close(resource); |
4388f060 | 623 | delete ns; |
729e4ab9 A |
624 | |
625 | if (U_SUCCESS(error)) { | |
626 | applyPatternWithoutExpandAffix(UnicodeString(patResStr, patLen), false, | |
627 | parseErr, status); | |
628 | AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( | |
629 | *fNegPrefixPattern, | |
630 | *fNegSuffixPattern, | |
631 | *fPosPrefixPattern, | |
632 | *fPosSuffixPattern, | |
633 | UCURR_SYMBOL_NAME); | |
4388f060 | 634 | fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status); |
729e4ab9 A |
635 | } |
636 | ||
637 | // save the unique currency plural patterns of this locale. | |
638 | Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern; | |
639 | const UHashElement* element = NULL; | |
b331163b | 640 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
641 | Hashtable pluralPatternSet; |
642 | while ((element = pluralPtn->nextElement(pos)) != NULL) { | |
643 | const UHashTok valueTok = element->value; | |
644 | const UnicodeString* value = (UnicodeString*)valueTok.pointer; | |
645 | const UHashTok keyTok = element->key; | |
646 | const UnicodeString* key = (UnicodeString*)keyTok.pointer; | |
647 | if (pluralPatternSet.geti(*value) != 1) { | |
648 | pluralPatternSet.puti(*value, 1, status); | |
649 | applyPatternWithoutExpandAffix(*value, false, parseErr, status); | |
650 | AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( | |
651 | *fNegPrefixPattern, | |
652 | *fNegSuffixPattern, | |
653 | *fPosPrefixPattern, | |
654 | *fPosSuffixPattern, | |
655 | UCURR_LONG_NAME); | |
656 | fAffixPatternsForCurrency->put(*key, affixPtn, status); | |
657 | } | |
658 | } | |
659 | } | |
660 | ||
661 | ||
662 | void | |
663 | DecimalFormat::setupCurrencyAffixes(const UnicodeString& pattern, | |
664 | UBool setupForCurrentPattern, | |
665 | UBool setupForPluralPattern, | |
666 | UErrorCode& status) { | |
667 | if (U_FAILURE(status)) { | |
668 | return; | |
669 | } | |
670 | UParseError parseErr; | |
671 | if (setupForCurrentPattern) { | |
672 | if (fAffixesForCurrency) { | |
673 | deleteHashForAffix(fAffixesForCurrency); | |
674 | } | |
675 | fAffixesForCurrency = initHashForAffix(status); | |
676 | if (U_SUCCESS(status)) { | |
677 | applyPatternWithoutExpandAffix(pattern, false, parseErr, status); | |
678 | const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules(); | |
679 | StringEnumeration* keywords = pluralRules->getKeywords(status); | |
680 | if (U_SUCCESS(status)) { | |
4388f060 A |
681 | const UnicodeString* pluralCount; |
682 | while ((pluralCount = keywords->snext(status)) != NULL) { | |
729e4ab9 | 683 | if ( U_SUCCESS(status) ) { |
4388f060 | 684 | expandAffixAdjustWidth(pluralCount); |
729e4ab9 A |
685 | AffixesForCurrency* affix = new AffixesForCurrency( |
686 | fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix); | |
4388f060 | 687 | fAffixesForCurrency->put(*pluralCount, affix, status); |
729e4ab9 A |
688 | } |
689 | } | |
690 | } | |
691 | delete keywords; | |
692 | } | |
693 | } | |
694 | ||
695 | if (U_FAILURE(status)) { | |
696 | return; | |
697 | } | |
698 | ||
699 | if (setupForPluralPattern) { | |
700 | if (fPluralAffixesForCurrency) { | |
701 | deleteHashForAffix(fPluralAffixesForCurrency); | |
702 | } | |
703 | fPluralAffixesForCurrency = initHashForAffix(status); | |
704 | if (U_SUCCESS(status)) { | |
705 | const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules(); | |
706 | StringEnumeration* keywords = pluralRules->getKeywords(status); | |
707 | if (U_SUCCESS(status)) { | |
4388f060 A |
708 | const UnicodeString* pluralCount; |
709 | while ((pluralCount = keywords->snext(status)) != NULL) { | |
729e4ab9 | 710 | if ( U_SUCCESS(status) ) { |
729e4ab9 | 711 | UnicodeString ptn; |
4388f060 A |
712 | fCurrencyPluralInfo->getCurrencyPluralPattern(*pluralCount, ptn); |
713 | applyPatternInternally(*pluralCount, ptn, false, parseErr, status); | |
729e4ab9 A |
714 | AffixesForCurrency* affix = new AffixesForCurrency( |
715 | fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix); | |
4388f060 | 716 | fPluralAffixesForCurrency->put(*pluralCount, affix, status); |
729e4ab9 A |
717 | } |
718 | } | |
719 | } | |
720 | delete keywords; | |
721 | } | |
722 | } | |
723 | } | |
724 | ||
725 | ||
b75a7d8f A |
726 | //------------------------------------------------------------------------------ |
727 | ||
728 | DecimalFormat::~DecimalFormat() | |
729 | { | |
b75a7d8f A |
730 | delete fPosPrefixPattern; |
731 | delete fPosSuffixPattern; | |
732 | delete fNegPrefixPattern; | |
733 | delete fNegSuffixPattern; | |
734 | delete fCurrencyChoice; | |
729e4ab9 | 735 | delete fMultiplier; |
b75a7d8f A |
736 | delete fSymbols; |
737 | delete fRoundingIncrement; | |
729e4ab9 A |
738 | deleteHashForAffixPattern(); |
739 | deleteHashForAffix(fAffixesForCurrency); | |
740 | deleteHashForAffix(fPluralAffixesForCurrency); | |
741 | delete fCurrencyPluralInfo; | |
b75a7d8f A |
742 | } |
743 | ||
744 | //------------------------------------------------------------------------------ | |
745 | // copy constructor | |
746 | ||
729e4ab9 A |
747 | DecimalFormat::DecimalFormat(const DecimalFormat &source) : |
748 | NumberFormat(source) { | |
57a6839d | 749 | init(); |
b75a7d8f A |
750 | *this = source; |
751 | } | |
752 | ||
753 | //------------------------------------------------------------------------------ | |
754 | // assignment operator | |
b75a7d8f | 755 | |
51004dcb A |
756 | template <class T> |
757 | static void _copy_ptr(T** pdest, const T* source) { | |
b75a7d8f A |
758 | if (source == NULL) { |
759 | delete *pdest; | |
760 | *pdest = NULL; | |
761 | } else if (*pdest == NULL) { | |
51004dcb A |
762 | *pdest = new T(*source); |
763 | } else { | |
764 | **pdest = *source; | |
765 | } | |
766 | } | |
767 | ||
768 | template <class T> | |
769 | static void _clone_ptr(T** pdest, const T* source) { | |
770 | delete *pdest; | |
771 | if (source == NULL) { | |
772 | *pdest = NULL; | |
b75a7d8f | 773 | } else { |
51004dcb | 774 | *pdest = static_cast<T*>(source->clone()); |
b75a7d8f A |
775 | } |
776 | } | |
777 | ||
778 | DecimalFormat& | |
779 | DecimalFormat::operator=(const DecimalFormat& rhs) | |
780 | { | |
374ca955 | 781 | if(this != &rhs) { |
57a6839d | 782 | UErrorCode status = U_ZERO_ERROR; |
374ca955 | 783 | NumberFormat::operator=(rhs); |
57a6839d | 784 | fStaticSets = DecimalFormatStaticSets::getStaticSets(status); |
374ca955 A |
785 | fPositivePrefix = rhs.fPositivePrefix; |
786 | fPositiveSuffix = rhs.fPositiveSuffix; | |
787 | fNegativePrefix = rhs.fNegativePrefix; | |
788 | fNegativeSuffix = rhs.fNegativeSuffix; | |
51004dcb A |
789 | _copy_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern); |
790 | _copy_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern); | |
791 | _copy_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern); | |
792 | _copy_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern); | |
793 | _clone_ptr(&fCurrencyChoice, rhs.fCurrencyChoice); | |
729e4ab9 | 794 | setRoundingIncrement(rhs.getRoundingIncrement()); |
03115e54 | 795 | fRoundingMode = rhs.fRoundingMode; |
729e4ab9 | 796 | setMultiplier(rhs.getMultiplier()); |
374ca955 A |
797 | fGroupingSize = rhs.fGroupingSize; |
798 | fGroupingSize2 = rhs.fGroupingSize2; | |
799 | fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown; | |
51004dcb | 800 | _copy_ptr(&fSymbols, rhs.fSymbols); |
374ca955 A |
801 | fUseExponentialNotation = rhs.fUseExponentialNotation; |
802 | fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown; | |
51004dcb | 803 | fBoolFlags = rhs.fBoolFlags; |
374ca955 | 804 | /*Bertrand A. D. Update 98.03.17*/ |
729e4ab9 | 805 | fCurrencySignCount = rhs.fCurrencySignCount; |
374ca955 A |
806 | /*end of Update*/ |
807 | fMinExponentDigits = rhs.fMinExponentDigits; | |
729e4ab9 | 808 | |
374ca955 A |
809 | /* sfb 990629 */ |
810 | fFormatWidth = rhs.fFormatWidth; | |
811 | fPad = rhs.fPad; | |
812 | fPadPosition = rhs.fPadPosition; | |
813 | /* end sfb */ | |
814 | fMinSignificantDigits = rhs.fMinSignificantDigits; | |
815 | fMaxSignificantDigits = rhs.fMaxSignificantDigits; | |
816 | fUseSignificantDigits = rhs.fUseSignificantDigits; | |
729e4ab9 | 817 | fFormatPattern = rhs.fFormatPattern; |
b331163b | 818 | fCurrencyUsage = rhs.fCurrencyUsage; |
729e4ab9 | 819 | fStyle = rhs.fStyle; |
51004dcb A |
820 | _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo); |
821 | deleteHashForAffixPattern(); | |
729e4ab9 A |
822 | if (rhs.fAffixPatternsForCurrency) { |
823 | UErrorCode status = U_ZERO_ERROR; | |
729e4ab9 A |
824 | fAffixPatternsForCurrency = initHashForAffixPattern(status); |
825 | copyHashForAffixPattern(rhs.fAffixPatternsForCurrency, | |
826 | fAffixPatternsForCurrency, status); | |
827 | } | |
51004dcb | 828 | deleteHashForAffix(fAffixesForCurrency); |
729e4ab9 A |
829 | if (rhs.fAffixesForCurrency) { |
830 | UErrorCode status = U_ZERO_ERROR; | |
729e4ab9 A |
831 | fAffixesForCurrency = initHashForAffixPattern(status); |
832 | copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, status); | |
833 | } | |
51004dcb | 834 | deleteHashForAffix(fPluralAffixesForCurrency); |
729e4ab9 A |
835 | if (rhs.fPluralAffixesForCurrency) { |
836 | UErrorCode status = U_ZERO_ERROR; | |
729e4ab9 A |
837 | fPluralAffixesForCurrency = initHashForAffixPattern(status); |
838 | copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status); | |
839 | } | |
51004dcb | 840 | #if UCONFIG_FORMAT_FASTPATHS_49 |
57a6839d A |
841 | DecimalFormatInternal &data = internalData(fReserved); |
842 | const DecimalFormatInternal &rhsData = internalData(rhs.fReserved); | |
843 | data = rhsData; | |
51004dcb | 844 | #endif |
57a6839d | 845 | } |
374ca955 | 846 | return *this; |
b75a7d8f A |
847 | } |
848 | ||
849 | //------------------------------------------------------------------------------ | |
850 | ||
851 | UBool | |
852 | DecimalFormat::operator==(const Format& that) const | |
853 | { | |
854 | if (this == &that) | |
855 | return TRUE; | |
856 | ||
374ca955 | 857 | // NumberFormat::operator== guarantees this cast is safe |
b75a7d8f A |
858 | const DecimalFormat* other = (DecimalFormat*)&that; |
859 | ||
860 | #ifdef FMT_DEBUG | |
861 | // This code makes it easy to determine why two format objects that should | |
862 | // be equal aren't. | |
863 | UBool first = TRUE; | |
864 | if (!NumberFormat::operator==(that)) { | |
865 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
866 | debug("NumberFormat::!="); | |
729e4ab9 | 867 | } else { |
b75a7d8f A |
868 | if (!((fPosPrefixPattern == other->fPosPrefixPattern && // both null |
869 | fPositivePrefix == other->fPositivePrefix) | |
870 | || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && | |
871 | *fPosPrefixPattern == *other->fPosPrefixPattern))) { | |
872 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
873 | debug("Pos Prefix !="); | |
874 | } | |
875 | if (!((fPosSuffixPattern == other->fPosSuffixPattern && // both null | |
876 | fPositiveSuffix == other->fPositiveSuffix) | |
877 | || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && | |
878 | *fPosSuffixPattern == *other->fPosSuffixPattern))) { | |
879 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
880 | debug("Pos Suffix !="); | |
881 | } | |
882 | if (!((fNegPrefixPattern == other->fNegPrefixPattern && // both null | |
883 | fNegativePrefix == other->fNegativePrefix) | |
884 | || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && | |
885 | *fNegPrefixPattern == *other->fNegPrefixPattern))) { | |
886 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
887 | debug("Neg Prefix "); | |
888 | if (fNegPrefixPattern == NULL) { | |
889 | debug("NULL("); | |
890 | debugout(fNegativePrefix); | |
891 | debug(")"); | |
892 | } else { | |
893 | debugout(*fNegPrefixPattern); | |
894 | } | |
895 | debug(" != "); | |
896 | if (other->fNegPrefixPattern == NULL) { | |
897 | debug("NULL("); | |
898 | debugout(other->fNegativePrefix); | |
899 | debug(")"); | |
900 | } else { | |
901 | debugout(*other->fNegPrefixPattern); | |
902 | } | |
903 | } | |
904 | if (!((fNegSuffixPattern == other->fNegSuffixPattern && // both null | |
905 | fNegativeSuffix == other->fNegativeSuffix) | |
906 | || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && | |
907 | *fNegSuffixPattern == *other->fNegSuffixPattern))) { | |
908 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
909 | debug("Neg Suffix "); | |
910 | if (fNegSuffixPattern == NULL) { | |
911 | debug("NULL("); | |
912 | debugout(fNegativeSuffix); | |
913 | debug(")"); | |
914 | } else { | |
915 | debugout(*fNegSuffixPattern); | |
916 | } | |
917 | debug(" != "); | |
918 | if (other->fNegSuffixPattern == NULL) { | |
919 | debug("NULL("); | |
920 | debugout(other->fNegativeSuffix); | |
921 | debug(")"); | |
922 | } else { | |
923 | debugout(*other->fNegSuffixPattern); | |
924 | } | |
925 | } | |
926 | if (!((fRoundingIncrement == other->fRoundingIncrement) // both null | |
927 | || (fRoundingIncrement != NULL && | |
928 | other->fRoundingIncrement != NULL && | |
929 | *fRoundingIncrement == *other->fRoundingIncrement))) { | |
930 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
931 | debug("Rounding Increment !="); | |
932 | } | |
57a6839d A |
933 | if (fRoundingMode != other->fRoundingMode) { |
934 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
935 | printf("Rounding Mode %d != %d", (int)fRoundingMode, (int)other->fRoundingMode); | |
936 | } | |
729e4ab9 | 937 | if (getMultiplier() != other->getMultiplier()) { |
b75a7d8f | 938 | if (first) { printf("[ "); first = FALSE; } |
729e4ab9 | 939 | printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier()); |
b75a7d8f A |
940 | } |
941 | if (fGroupingSize != other->fGroupingSize) { | |
942 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
943 | printf("Grouping Size %ld != %ld", fGroupingSize, other->fGroupingSize); | |
944 | } | |
945 | if (fGroupingSize2 != other->fGroupingSize2) { | |
946 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
947 | printf("Secondary Grouping Size %ld != %ld", fGroupingSize2, other->fGroupingSize2); | |
948 | } | |
949 | if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) { | |
950 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
57a6839d | 951 | printf("fDecimalSeparatorAlwaysShown %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown); |
b75a7d8f A |
952 | } |
953 | if (fUseExponentialNotation != other->fUseExponentialNotation) { | |
954 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
57a6839d A |
955 | debug("fUseExponentialNotation !="); |
956 | } | |
957 | if (fUseExponentialNotation && | |
958 | fMinExponentDigits != other->fMinExponentDigits) { | |
959 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
960 | debug("fMinExponentDigits !="); | |
961 | } | |
962 | if (fUseExponentialNotation && | |
963 | fExponentSignAlwaysShown != other->fExponentSignAlwaysShown) { | |
964 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
965 | debug("fExponentSignAlwaysShown !="); | |
b75a7d8f | 966 | } |
57a6839d | 967 | if (fBoolFlags.getAll() != other->fBoolFlags.getAll()) { |
b75a7d8f | 968 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
57a6839d | 969 | debug("fBoolFlags !="); |
b75a7d8f A |
970 | } |
971 | if (*fSymbols != *(other->fSymbols)) { | |
972 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
973 | debug("Symbols !="); | |
974 | } | |
374ca955 | 975 | // TODO Add debug stuff for significant digits here |
729e4ab9 | 976 | if (fUseSignificantDigits != other->fUseSignificantDigits) { |
57a6839d | 977 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
729e4ab9 A |
978 | debug("fUseSignificantDigits !="); |
979 | } | |
980 | if (fUseSignificantDigits && | |
981 | fMinSignificantDigits != other->fMinSignificantDigits) { | |
57a6839d | 982 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
729e4ab9 A |
983 | debug("fMinSignificantDigits !="); |
984 | } | |
985 | if (fUseSignificantDigits && | |
986 | fMaxSignificantDigits != other->fMaxSignificantDigits) { | |
57a6839d | 987 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
729e4ab9 A |
988 | debug("fMaxSignificantDigits !="); |
989 | } | |
57a6839d A |
990 | if (fFormatWidth != other->fFormatWidth) { |
991 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
992 | debug("fFormatWidth !="); | |
993 | } | |
994 | if (fPad != other->fPad) { | |
995 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
996 | debug("fPad !="); | |
997 | } | |
998 | if (fPadPosition != other->fPadPosition) { | |
999 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
1000 | debug("fPadPosition !="); | |
1001 | } | |
1002 | if (fStyle == UNUM_CURRENCY_PLURAL && | |
1003 | fStyle != other->fStyle) | |
1004 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
1005 | debug("fStyle !="); | |
1006 | } | |
1007 | if (fStyle == UNUM_CURRENCY_PLURAL && | |
1008 | fFormatPattern != other->fFormatPattern) { | |
1009 | if (first) { printf("[ "); first = FALSE; } else { printf(", "); } | |
1010 | debug("fFormatPattern !="); | |
1011 | } | |
729e4ab9 | 1012 | |
b75a7d8f | 1013 | if (!first) { printf(" ]"); } |
729e4ab9 A |
1014 | if (fCurrencySignCount != other->fCurrencySignCount) { |
1015 | debug("fCurrencySignCount !="); | |
1016 | } | |
1017 | if (fCurrencyPluralInfo == other->fCurrencyPluralInfo) { | |
1018 | debug("fCurrencyPluralInfo == "); | |
1019 | if (fCurrencyPluralInfo == NULL) { | |
1020 | debug("fCurrencyPluralInfo == NULL"); | |
1021 | } | |
1022 | } | |
1023 | if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL && | |
1024 | *fCurrencyPluralInfo != *(other->fCurrencyPluralInfo)) { | |
1025 | debug("fCurrencyPluralInfo !="); | |
1026 | } | |
1027 | if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo == NULL || | |
1028 | fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo != NULL) { | |
1029 | debug("fCurrencyPluralInfo one NULL, the other not"); | |
1030 | } | |
1031 | if (fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo == NULL) { | |
1032 | debug("fCurrencyPluralInfo == "); | |
1033 | } | |
1034 | } | |
b75a7d8f A |
1035 | #endif |
1036 | ||
57a6839d A |
1037 | return ( |
1038 | NumberFormat::operator==(that) && | |
1039 | ||
1040 | ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ? | |
1041 | (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) : | |
1042 | (((fPosPrefixPattern == other->fPosPrefixPattern && // both null | |
1043 | fPositivePrefix == other->fPositivePrefix) | |
1044 | || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && | |
1045 | *fPosPrefixPattern == *other->fPosPrefixPattern)) && | |
1046 | ((fPosSuffixPattern == other->fPosSuffixPattern && // both null | |
1047 | fPositiveSuffix == other->fPositiveSuffix) | |
1048 | || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && | |
1049 | *fPosSuffixPattern == *other->fPosSuffixPattern)) && | |
1050 | ((fNegPrefixPattern == other->fNegPrefixPattern && // both null | |
1051 | fNegativePrefix == other->fNegativePrefix) | |
1052 | || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && | |
1053 | *fNegPrefixPattern == *other->fNegPrefixPattern)) && | |
1054 | ((fNegSuffixPattern == other->fNegSuffixPattern && // both null | |
1055 | fNegativeSuffix == other->fNegativeSuffix) | |
1056 | || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && | |
1057 | *fNegSuffixPattern == *other->fNegSuffixPattern)))) && | |
1058 | ||
1059 | ((fRoundingIncrement == other->fRoundingIncrement) // both null | |
1060 | || (fRoundingIncrement != NULL && | |
1061 | other->fRoundingIncrement != NULL && | |
1062 | *fRoundingIncrement == *other->fRoundingIncrement)) && | |
1063 | ||
1064 | fRoundingMode == other->fRoundingMode && | |
729e4ab9 | 1065 | getMultiplier() == other->getMultiplier() && |
b75a7d8f A |
1066 | fGroupingSize == other->fGroupingSize && |
1067 | fGroupingSize2 == other->fGroupingSize2 && | |
1068 | fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown && | |
1069 | fUseExponentialNotation == other->fUseExponentialNotation && | |
57a6839d | 1070 | |
b75a7d8f | 1071 | (!fUseExponentialNotation || |
57a6839d A |
1072 | (fMinExponentDigits == other->fMinExponentDigits && fExponentSignAlwaysShown == other->fExponentSignAlwaysShown)) && |
1073 | ||
1074 | fBoolFlags.getAll() == other->fBoolFlags.getAll() && | |
374ca955 A |
1075 | *fSymbols == *(other->fSymbols) && |
1076 | fUseSignificantDigits == other->fUseSignificantDigits && | |
57a6839d | 1077 | |
374ca955 | 1078 | (!fUseSignificantDigits || |
57a6839d A |
1079 | (fMinSignificantDigits == other->fMinSignificantDigits && fMaxSignificantDigits == other->fMaxSignificantDigits)) && |
1080 | ||
1081 | fFormatWidth == other->fFormatWidth && | |
1082 | fPad == other->fPad && | |
1083 | fPadPosition == other->fPadPosition && | |
1084 | ||
1085 | (fStyle != UNUM_CURRENCY_PLURAL || | |
1086 | (fStyle == other->fStyle && fFormatPattern == other->fFormatPattern)) && | |
1087 | ||
729e4ab9 | 1088 | fCurrencySignCount == other->fCurrencySignCount && |
57a6839d | 1089 | |
729e4ab9 A |
1090 | ((fCurrencyPluralInfo == other->fCurrencyPluralInfo && |
1091 | fCurrencyPluralInfo == NULL) || | |
1092 | (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL && | |
b331163b A |
1093 | *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))) && |
1094 | ||
1095 | fCurrencyUsage == other->fCurrencyUsage | |
57a6839d A |
1096 | |
1097 | // depending on other settings we may also need to compare | |
1098 | // fCurrencyChoice (mostly deprecated?), | |
1099 | // fAffixesForCurrency & fPluralAffixesForCurrency (only relevant in some cases) | |
1100 | ); | |
b75a7d8f A |
1101 | } |
1102 | ||
1103 | //------------------------------------------------------------------------------ | |
1104 | ||
1105 | Format* | |
1106 | DecimalFormat::clone() const | |
1107 | { | |
1108 | return new DecimalFormat(*this); | |
1109 | } | |
1110 | ||
57a6839d A |
1111 | |
1112 | FixedDecimal | |
1113 | DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const { | |
1114 | FixedDecimal result; | |
1115 | ||
1116 | if (U_FAILURE(status)) { | |
1117 | return result; | |
1118 | } | |
1119 | ||
1120 | if (uprv_isNaN(number) || uprv_isPositiveInfinity(fabs(number))) { | |
1121 | // For NaN and Infinity the state of the formatter is ignored. | |
1122 | result.init(number); | |
1123 | return result; | |
1124 | } | |
1125 | ||
1126 | if (fMultiplier == NULL && fScale == 0 && fRoundingIncrement == 0 && areSignificantDigitsUsed() == FALSE && | |
1127 | result.quickInit(number) && result.visibleDecimalDigitCount <= getMaximumFractionDigits()) { | |
1128 | // Fast Path. Construction of an exact FixedDecimal directly from the double, without passing | |
1129 | // through a DigitList, was successful, and the formatter is doing nothing tricky with rounding. | |
1130 | // printf("getFixedDecimal(%g): taking fast path.\n", number); | |
1131 | result.adjustForMinFractionDigits(getMinimumFractionDigits()); | |
1132 | } else { | |
1133 | // Slow path. Create a DigitList, and have this formatter round it according to the | |
1134 | // requirements of the format, and fill the fixedDecimal from that. | |
1135 | DigitList digits; | |
1136 | digits.set(number); | |
1137 | result = getFixedDecimal(digits, status); | |
1138 | } | |
1139 | return result; | |
1140 | } | |
1141 | ||
57a6839d A |
1142 | FixedDecimal |
1143 | DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const { | |
1144 | if (U_FAILURE(status)) { | |
1145 | return FixedDecimal(); | |
1146 | } | |
1147 | if (!number.isNumeric()) { | |
1148 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
1149 | return FixedDecimal(); | |
1150 | } | |
1151 | ||
1152 | DigitList *dl = number.getDigitList(); | |
1153 | if (dl != NULL) { | |
1154 | DigitList clonedDL(*dl); | |
1155 | return getFixedDecimal(clonedDL, status); | |
1156 | } | |
1157 | ||
1158 | Formattable::Type type = number.getType(); | |
1159 | if (type == Formattable::kDouble || type == Formattable::kLong) { | |
1160 | return getFixedDecimal(number.getDouble(status), status); | |
1161 | } | |
1162 | ||
b331163b A |
1163 | if (type == Formattable::kInt64 && number.getInt64() <= MAX_INT64_IN_DOUBLE && |
1164 | number.getInt64() >= -MAX_INT64_IN_DOUBLE) { | |
1165 | return getFixedDecimal(number.getDouble(status), status); | |
57a6839d A |
1166 | } |
1167 | ||
1168 | // The only case left is type==int64_t, with a value with more digits than a double can represent. | |
1169 | // Any formattable originating as a big decimal will have had a pre-existing digit list. | |
1170 | // Any originating as a double or int32 will have been handled as a double. | |
1171 | ||
1172 | U_ASSERT(type == Formattable::kInt64); | |
1173 | DigitList digits; | |
1174 | digits.set(number.getInt64()); | |
1175 | return getFixedDecimal(digits, status); | |
1176 | } | |
57a6839d A |
1177 | |
1178 | ||
1179 | // Create a fixed decimal from a DigitList. | |
1180 | // The digit list may be modified. | |
1181 | // Internal function only. | |
1182 | FixedDecimal | |
1183 | DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const { | |
1184 | // Round the number according to the requirements of this Format. | |
1185 | FixedDecimal result; | |
1186 | _round(number, number, result.isNegative, status); | |
1187 | ||
1188 | // The int64_t fields in FixedDecimal can easily overflow. | |
1189 | // In deciding what to discard in this event, consider that fixedDecimal | |
1190 | // is being used only with PluralRules, and those rules mostly look at least significant | |
1191 | // few digits of the integer part, and whether the fraction part is zero or not. | |
1192 | // | |
1193 | // So, in case of overflow when filling in the fields of the FixedDecimal object, | |
1194 | // for the integer part, discard the most significant digits. | |
1195 | // for the fraction part, discard the least significant digits, | |
1196 | // don't truncate the fraction value to zero. | |
1197 | // For simplicity, the int64_t fields are limited to 18 decimal digits, even | |
1198 | // though they could hold most (but not all) 19 digit values. | |
1199 | ||
1200 | // Integer Digits. | |
1201 | int32_t di = number.getDecimalAt()-18; // Take at most 18 digits. | |
1202 | if (di < 0) { | |
1203 | di = 0; | |
1204 | } | |
1205 | result.intValue = 0; | |
1206 | for (; di<number.getDecimalAt(); di++) { | |
1207 | result.intValue = result.intValue * 10 + (number.getDigit(di) & 0x0f); | |
1208 | } | |
1209 | if (result.intValue == 0 && number.getDecimalAt()-18 > 0) { | |
1210 | // The number is something like 100000000000000000000000. | |
1211 | // More than 18 digits integer digits, but the least significant 18 are all zero. | |
1212 | // We don't want to return zero as the int part, but want to keep zeros | |
1213 | // for several of the least significant digits. | |
1214 | result.intValue = 100000000000000000LL; | |
1215 | } | |
1216 | ||
1217 | // Fraction digits. | |
1218 | result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = result.visibleDecimalDigitCount = 0; | |
1219 | for (di = number.getDecimalAt(); di < number.getCount(); di++) { | |
1220 | result.visibleDecimalDigitCount++; | |
1221 | if (result.decimalDigits < 100000000000000000LL) { | |
1222 | // 9223372036854775807 Largest 64 bit signed integer | |
1223 | int32_t digitVal = number.getDigit(di) & 0x0f; // getDigit() returns a char, '0'-'9'. | |
1224 | result.decimalDigits = result.decimalDigits * 10 + digitVal; | |
1225 | if (digitVal > 0) { | |
1226 | result.decimalDigitsWithoutTrailingZeros = result.decimalDigits; | |
1227 | } | |
1228 | } | |
1229 | } | |
1230 | ||
1231 | result.hasIntegerValue = (result.decimalDigits == 0); | |
1232 | ||
1233 | // Trailing fraction zeros. The format specification may require more trailing | |
1234 | // zeros than the numeric value. Add any such on now. | |
1235 | ||
1236 | int32_t minFractionDigits; | |
1237 | if (areSignificantDigitsUsed()) { | |
1238 | minFractionDigits = getMinimumSignificantDigits() - number.getDecimalAt(); | |
1239 | if (minFractionDigits < 0) { | |
1240 | minFractionDigits = 0; | |
1241 | } | |
1242 | } else { | |
1243 | minFractionDigits = getMinimumFractionDigits(); | |
1244 | } | |
1245 | result.adjustForMinFractionDigits(minFractionDigits); | |
1246 | ||
1247 | return result; | |
1248 | } | |
1249 | ||
1250 | ||
b75a7d8f | 1251 | //------------------------------------------------------------------------------ |
729e4ab9 | 1252 | |
b75a7d8f A |
1253 | UnicodeString& |
1254 | DecimalFormat::format(int32_t number, | |
1255 | UnicodeString& appendTo, | |
1256 | FieldPosition& fieldPosition) const | |
374ca955 A |
1257 | { |
1258 | return format((int64_t)number, appendTo, fieldPosition); | |
1259 | } | |
1260 | ||
51004dcb A |
1261 | UnicodeString& |
1262 | DecimalFormat::format(int32_t number, | |
1263 | UnicodeString& appendTo, | |
1264 | FieldPosition& fieldPosition, | |
1265 | UErrorCode& status) const | |
1266 | { | |
1267 | return format((int64_t)number, appendTo, fieldPosition, status); | |
1268 | } | |
1269 | ||
729e4ab9 A |
1270 | UnicodeString& |
1271 | DecimalFormat::format(int32_t number, | |
1272 | UnicodeString& appendTo, | |
1273 | FieldPositionIterator* posIter, | |
1274 | UErrorCode& status) const | |
1275 | { | |
1276 | return format((int64_t)number, appendTo, posIter, status); | |
1277 | } | |
1278 | ||
51004dcb A |
1279 | |
1280 | #if UCONFIG_FORMAT_FASTPATHS_49 | |
1281 | void DecimalFormat::handleChanged() { | |
1282 | DecimalFormatInternal &data = internalData(fReserved); | |
1283 | ||
1284 | if(data.fFastFormatStatus == kFastpathUNKNOWN || data.fFastParseStatus == kFastpathUNKNOWN) { | |
1285 | return; // still constructing. Wait. | |
1286 | } | |
1287 | ||
1288 | data.fFastParseStatus = data.fFastFormatStatus = kFastpathNO; | |
1289 | ||
1290 | #if UCONFIG_HAVE_PARSEALLINPUT | |
1291 | if(fParseAllInput == UNUM_NO) { | |
1292 | debug("No Parse fastpath: fParseAllInput==UNUM_NO"); | |
1293 | } else | |
1294 | #endif | |
1295 | if (fFormatWidth!=0) { | |
1296 | debug("No Parse fastpath: fFormatWidth"); | |
1297 | } else if(fPositivePrefix.length()>0) { | |
1298 | debug("No Parse fastpath: positive prefix"); | |
1299 | } else if(fPositiveSuffix.length()>0) { | |
1300 | debug("No Parse fastpath: positive suffix"); | |
1301 | } else if(fNegativePrefix.length()>1 | |
1302 | || ((fNegativePrefix.length()==1) && (fNegativePrefix.charAt(0)!=0x002D))) { | |
1303 | debug("No Parse fastpath: negative prefix that isn't '-'"); | |
1304 | } else if(fNegativeSuffix.length()>0) { | |
1305 | debug("No Parse fastpath: negative suffix"); | |
1306 | } else { | |
1307 | data.fFastParseStatus = kFastpathYES; | |
1308 | debug("parse fastpath: YES"); | |
1309 | } | |
1310 | ||
b331163b | 1311 | if(fUseExponentialNotation) { |
51004dcb A |
1312 | debug("No format fastpath: fUseExponentialNotation"); |
1313 | } else if(fFormatWidth!=0) { | |
1314 | debug("No format fastpath: fFormatWidth!=0"); | |
1315 | } else if(fMinSignificantDigits!=1) { | |
1316 | debug("No format fastpath: fMinSignificantDigits!=1"); | |
1317 | } else if(fMultiplier!=NULL) { | |
1318 | debug("No format fastpath: fMultiplier!=NULL"); | |
1319 | } else if(fScale!=0) { | |
1320 | debug("No format fastpath: fScale!=0"); | |
1321 | } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) { | |
1322 | debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)"); | |
1323 | } else if(fDecimalSeparatorAlwaysShown) { | |
1324 | debug("No format fastpath: fDecimalSeparatorAlwaysShown"); | |
1325 | } else if(getMinimumFractionDigits()>0) { | |
1326 | debug("No format fastpath: fMinFractionDigits>0"); | |
57a6839d A |
1327 | } else if(fCurrencySignCount != fgCurrencySignCountZero) { |
1328 | debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero"); | |
51004dcb A |
1329 | } else if(fRoundingIncrement!=0) { |
1330 | debug("No format fastpath: fRoundingIncrement!=0"); | |
b331163b A |
1331 | } else if (fGroupingSize!=0 && isGroupingUsed()) { |
1332 | debug("Maybe format fastpath: fGroupingSize!=0 and grouping is used"); | |
1333 | #ifdef FMT_DEBUG | |
1334 | printf("groupingsize=%d\n", fGroupingSize); | |
1335 | #endif | |
1336 | ||
1337 | if (getMinimumIntegerDigits() <= fGroupingSize) { | |
1338 | data.fFastFormatStatus = kFastpathMAYBE; | |
1339 | } | |
1340 | } else if(fGroupingSize2!=0 && isGroupingUsed()) { | |
1341 | debug("No format fastpath: fGroupingSize2!=0"); | |
51004dcb A |
1342 | } else { |
1343 | data.fFastFormatStatus = kFastpathYES; | |
1344 | debug("format:kFastpathYES!"); | |
1345 | } | |
1346 | ||
1347 | ||
1348 | } | |
1349 | #endif | |
374ca955 | 1350 | //------------------------------------------------------------------------------ |
729e4ab9 | 1351 | |
374ca955 A |
1352 | UnicodeString& |
1353 | DecimalFormat::format(int64_t number, | |
1354 | UnicodeString& appendTo, | |
1355 | FieldPosition& fieldPosition) const | |
51004dcb A |
1356 | { |
1357 | UErrorCode status = U_ZERO_ERROR; /* ignored */ | |
1358 | FieldPositionOnlyHandler handler(fieldPosition); | |
1359 | return _format(number, appendTo, handler, status); | |
1360 | } | |
1361 | ||
1362 | UnicodeString& | |
1363 | DecimalFormat::format(int64_t number, | |
1364 | UnicodeString& appendTo, | |
1365 | FieldPosition& fieldPosition, | |
1366 | UErrorCode& status) const | |
b75a7d8f | 1367 | { |
729e4ab9 | 1368 | FieldPositionOnlyHandler handler(fieldPosition); |
51004dcb | 1369 | return _format(number, appendTo, handler, status); |
729e4ab9 | 1370 | } |
b75a7d8f | 1371 | |
729e4ab9 A |
1372 | UnicodeString& |
1373 | DecimalFormat::format(int64_t number, | |
1374 | UnicodeString& appendTo, | |
1375 | FieldPositionIterator* posIter, | |
1376 | UErrorCode& status) const | |
1377 | { | |
1378 | FieldPositionIteratorHandler handler(posIter, status); | |
51004dcb | 1379 | return _format(number, appendTo, handler, status); |
729e4ab9 | 1380 | } |
b75a7d8f | 1381 | |
729e4ab9 A |
1382 | UnicodeString& |
1383 | DecimalFormat::_format(int64_t number, | |
1384 | UnicodeString& appendTo, | |
51004dcb A |
1385 | FieldPositionHandler& handler, |
1386 | UErrorCode &status) const | |
729e4ab9 | 1387 | { |
51004dcb A |
1388 | // Bottleneck function for formatting int64_t |
1389 | if (U_FAILURE(status)) { | |
1390 | return appendTo; | |
1391 | } | |
1392 | ||
1393 | #if UCONFIG_FORMAT_FASTPATHS_49 | |
1394 | // const UnicodeString *posPrefix = fPosPrefixPattern; | |
1395 | // const UnicodeString *posSuffix = fPosSuffixPattern; | |
1396 | // const UnicodeString *negSuffix = fNegSuffixPattern; | |
1397 | ||
1398 | const DecimalFormatInternal &data = internalData(fReserved); | |
1399 | ||
1400 | #ifdef FMT_DEBUG | |
1401 | data.dump(); | |
1402 | printf("fastpath? [%d]\n", number); | |
1403 | #endif | |
1404 | ||
b331163b A |
1405 | if( data.fFastFormatStatus==kFastpathYES || |
1406 | data.fFastFormatStatus==kFastpathMAYBE) { | |
1407 | int32_t noGroupingThreshold = 0; | |
51004dcb A |
1408 | |
1409 | #define kZero 0x0030 | |
1410 | const int32_t MAX_IDX = MAX_DIGITS+2; | |
1411 | UChar outputStr[MAX_IDX]; | |
1412 | int32_t destIdx = MAX_IDX; | |
1413 | outputStr[--destIdx] = 0; // term | |
1414 | ||
b331163b A |
1415 | if (data.fFastFormatStatus==kFastpathMAYBE) { |
1416 | noGroupingThreshold = destIdx - fGroupingSize; | |
1417 | } | |
51004dcb A |
1418 | int64_t n = number; |
1419 | if (number < 1) { | |
1420 | // Negative numbers are slightly larger than positive | |
1421 | // output the first digit (or the leading zero) | |
1422 | outputStr[--destIdx] = (-(n % 10) + kZero); | |
1423 | n /= -10; | |
1424 | } | |
1425 | // get any remaining digits | |
1426 | while (n > 0) { | |
b331163b A |
1427 | if (destIdx == noGroupingThreshold) { |
1428 | goto slowPath; | |
1429 | } | |
51004dcb A |
1430 | outputStr[--destIdx] = (n % 10) + kZero; |
1431 | n /= 10; | |
1432 | } | |
51004dcb A |
1433 | |
1434 | // Slide the number to the start of the output str | |
1435 | U_ASSERT(destIdx >= 0); | |
1436 | int32_t length = MAX_IDX - destIdx -1; | |
b331163b A |
1437 | /*int32_t prefixLen = */ appendAffix(appendTo, static_cast<double>(number), handler, number<0, TRUE); |
1438 | ||
1439 | // This will be at least 0 even if it was set to a negative number. | |
51004dcb A |
1440 | int32_t maxIntDig = getMaximumIntegerDigits(); |
1441 | int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits | |
1442 | ||
1443 | if(length>maxIntDig && fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) { | |
1444 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
1445 | } | |
1446 | ||
b331163b A |
1447 | int32_t minDigits = getMinimumIntegerDigits(); |
1448 | ||
1449 | // We always want at least one digit, even if it is just a 0. | |
1450 | int32_t prependZero = (minDigits < 1 ? 1 : minDigits) - destlength; | |
51004dcb A |
1451 | |
1452 | #ifdef FMT_DEBUG | |
1453 | printf("prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d\n", prependZero, length, getMinimumIntegerDigits(), maxIntDig, destlength, length-destlength); | |
1454 | #endif | |
1455 | int32_t intBegin = appendTo.length(); | |
1456 | ||
1457 | while((prependZero--)>0) { | |
1458 | appendTo.append((UChar)0x0030); // '0' | |
1459 | } | |
1460 | ||
1461 | appendTo.append(outputStr+destIdx+ | |
1462 | (length-destlength), // skip any leading digits | |
1463 | destlength); | |
1464 | handler.addAttribute(kIntegerField, intBegin, appendTo.length()); | |
1465 | ||
b331163b | 1466 | /*int32_t suffixLen =*/ appendAffix(appendTo, static_cast<double>(number), handler, number<0, FALSE); |
51004dcb A |
1467 | |
1468 | //outputStr[length]=0; | |
1469 | ||
1470 | #ifdef FMT_DEBUG | |
1471 | printf("Writing [%s] length [%d] max %d for [%d]\n", outputStr+destIdx, length, MAX_IDX, number); | |
1472 | #endif | |
1473 | ||
1474 | #undef kZero | |
1475 | ||
1476 | return appendTo; | |
1477 | } // end fastpath | |
1478 | #endif | |
b331163b | 1479 | slowPath: |
51004dcb A |
1480 | |
1481 | // Else the slow way - via DigitList | |
729e4ab9 A |
1482 | DigitList digits; |
1483 | digits.set(number); | |
1484 | return _format(digits, appendTo, handler, status); | |
b75a7d8f | 1485 | } |
729e4ab9 | 1486 | |
b75a7d8f A |
1487 | //------------------------------------------------------------------------------ |
1488 | ||
1489 | UnicodeString& | |
1490 | DecimalFormat::format( double number, | |
1491 | UnicodeString& appendTo, | |
1492 | FieldPosition& fieldPosition) const | |
1493 | { | |
51004dcb | 1494 | UErrorCode status = U_ZERO_ERROR; /* ignored */ |
729e4ab9 | 1495 | FieldPositionOnlyHandler handler(fieldPosition); |
51004dcb A |
1496 | return _format(number, appendTo, handler, status); |
1497 | } | |
1498 | ||
1499 | UnicodeString& | |
1500 | DecimalFormat::format( double number, | |
1501 | UnicodeString& appendTo, | |
1502 | FieldPosition& fieldPosition, | |
1503 | UErrorCode& status) const | |
1504 | { | |
1505 | FieldPositionOnlyHandler handler(fieldPosition); | |
1506 | return _format(number, appendTo, handler, status); | |
729e4ab9 | 1507 | } |
b75a7d8f | 1508 | |
729e4ab9 A |
1509 | UnicodeString& |
1510 | DecimalFormat::format( double number, | |
1511 | UnicodeString& appendTo, | |
1512 | FieldPositionIterator* posIter, | |
1513 | UErrorCode& status) const | |
1514 | { | |
1515 | FieldPositionIteratorHandler handler(posIter, status); | |
51004dcb | 1516 | return _format(number, appendTo, handler, status); |
729e4ab9 A |
1517 | } |
1518 | ||
1519 | UnicodeString& | |
1520 | DecimalFormat::_format( double number, | |
1521 | UnicodeString& appendTo, | |
51004dcb A |
1522 | FieldPositionHandler& handler, |
1523 | UErrorCode &status) const | |
729e4ab9 | 1524 | { |
51004dcb A |
1525 | if (U_FAILURE(status)) { |
1526 | return appendTo; | |
1527 | } | |
b75a7d8f A |
1528 | // Special case for NaN, sets the begin and end index to be the |
1529 | // the string length of localized name of NaN. | |
729e4ab9 | 1530 | // TODO: let NaNs go through DigitList. |
b75a7d8f A |
1531 | if (uprv_isNaN(number)) |
1532 | { | |
729e4ab9 A |
1533 | int begin = appendTo.length(); |
1534 | appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol); | |
1535 | ||
1536 | handler.addAttribute(kIntegerField, begin, appendTo.length()); | |
1537 | ||
1538 | addPadding(appendTo, handler, 0, 0); | |
1539 | return appendTo; | |
1540 | } | |
1541 | ||
729e4ab9 A |
1542 | DigitList digits; |
1543 | digits.set(number); | |
1544 | _format(digits, appendTo, handler, status); | |
1545 | // No way to return status from here. | |
1546 | return appendTo; | |
1547 | } | |
1548 | ||
1549 | //------------------------------------------------------------------------------ | |
1550 | ||
1551 | ||
1552 | UnicodeString& | |
1553 | DecimalFormat::format(const StringPiece &number, | |
1554 | UnicodeString &toAppendTo, | |
1555 | FieldPositionIterator *posIter, | |
1556 | UErrorCode &status) const | |
1557 | { | |
51004dcb A |
1558 | #if UCONFIG_FORMAT_FASTPATHS_49 |
1559 | // don't bother if the int64 path is not optimized | |
1560 | int32_t len = number.length(); | |
1561 | ||
1562 | if(len>0&&len<10) { /* 10 or more digits may not be an int64 */ | |
1563 | const char *data = number.data(); | |
1564 | int64_t num = 0; | |
1565 | UBool neg = FALSE; | |
1566 | UBool ok = TRUE; | |
1567 | ||
1568 | int32_t start = 0; | |
1569 | ||
1570 | if(data[start]=='+') { | |
1571 | start++; | |
1572 | } else if(data[start]=='-') { | |
1573 | neg=TRUE; | |
1574 | start++; | |
1575 | } | |
1576 | ||
1577 | int32_t place = 1; /* 1, 10, ... */ | |
1578 | for(int32_t i=len-1;i>=start;i--) { | |
1579 | if(data[i]>='0'&&data[i]<='9') { | |
1580 | num+=place*(int64_t)(data[i]-'0'); | |
1581 | } else { | |
1582 | ok=FALSE; | |
1583 | break; | |
1584 | } | |
1585 | place *= 10; | |
1586 | } | |
1587 | ||
1588 | if(ok) { | |
1589 | if(neg) { | |
1590 | num = -num;// add minus bit | |
1591 | } | |
1592 | // format as int64_t | |
1593 | return format(num, toAppendTo, posIter, status); | |
1594 | } | |
1595 | // else fall through | |
1596 | } | |
1597 | #endif | |
1598 | ||
729e4ab9 A |
1599 | DigitList dnum; |
1600 | dnum.set(number, status); | |
1601 | if (U_FAILURE(status)) { | |
1602 | return toAppendTo; | |
1603 | } | |
1604 | FieldPositionIteratorHandler handler(posIter, status); | |
1605 | _format(dnum, toAppendTo, handler, status); | |
1606 | return toAppendTo; | |
1607 | } | |
1608 | ||
1609 | ||
1610 | UnicodeString& | |
1611 | DecimalFormat::format(const DigitList &number, | |
1612 | UnicodeString &appendTo, | |
1613 | FieldPositionIterator *posIter, | |
1614 | UErrorCode &status) const { | |
1615 | FieldPositionIteratorHandler handler(posIter, status); | |
1616 | _format(number, appendTo, handler, status); | |
1617 | return appendTo; | |
1618 | } | |
1619 | ||
1620 | ||
1621 | ||
1622 | UnicodeString& | |
1623 | DecimalFormat::format(const DigitList &number, | |
1624 | UnicodeString& appendTo, | |
1625 | FieldPosition& pos, | |
1626 | UErrorCode &status) const { | |
1627 | FieldPositionOnlyHandler handler(pos); | |
1628 | _format(number, appendTo, handler, status); | |
1629 | return appendTo; | |
1630 | } | |
b75a7d8f | 1631 | |
51004dcb A |
1632 | DigitList& |
1633 | DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& isNegative, UErrorCode &status) const { | |
1634 | if (U_FAILURE(status)) { | |
1635 | return adjustedNum; | |
1636 | } | |
57a6839d A |
1637 | |
1638 | // note: number and adjustedNum may refer to the same DigitList, in cases where a copy | |
1639 | // is not needed by the caller. | |
1640 | ||
51004dcb A |
1641 | adjustedNum = number; |
1642 | isNegative = false; | |
1643 | if (number.isNaN()) { | |
1644 | return adjustedNum; | |
b75a7d8f A |
1645 | } |
1646 | ||
46f4442e A |
1647 | // Do this BEFORE checking to see if value is infinite or negative! Sets the |
1648 | // begin and end index to be length of the string composed of | |
1649 | // localized name of Infinite and the positive/negative localized | |
1650 | // signs. | |
1651 | ||
729e4ab9 A |
1652 | adjustedNum.setRoundingMode(fRoundingMode); |
1653 | if (fMultiplier != NULL) { | |
1654 | adjustedNum.mult(*fMultiplier, status); | |
51004dcb A |
1655 | if (U_FAILURE(status)) { |
1656 | return adjustedNum; | |
1657 | } | |
729e4ab9 | 1658 | } |
46f4442e | 1659 | |
51004dcb A |
1660 | if (fScale != 0) { |
1661 | DigitList ten; | |
57a6839d | 1662 | ten.set((int32_t)10); |
51004dcb A |
1663 | if (fScale > 0) { |
1664 | for (int32_t i = fScale ; i > 0 ; i--) { | |
1665 | adjustedNum.mult(ten, status); | |
1666 | if (U_FAILURE(status)) { | |
1667 | return adjustedNum; | |
1668 | } | |
1669 | } | |
1670 | } else { | |
1671 | for (int32_t i = fScale ; i < 0 ; i++) { | |
1672 | adjustedNum.div(ten, status); | |
1673 | if (U_FAILURE(status)) { | |
1674 | return adjustedNum; | |
1675 | } | |
1676 | } | |
1677 | } | |
1678 | } | |
1679 | ||
1680 | /* | |
729e4ab9 A |
1681 | * Note: sign is important for zero as well as non-zero numbers. |
1682 | * Proper detection of -0.0 is needed to deal with the | |
b75a7d8f A |
1683 | * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. |
1684 | */ | |
51004dcb | 1685 | isNegative = !adjustedNum.isPositive(); |
b75a7d8f | 1686 | |
b75a7d8f | 1687 | // Apply rounding after multiplier |
51004dcb | 1688 | |
4388f060 | 1689 | adjustedNum.fContext.status &= ~DEC_Inexact; |
b75a7d8f | 1690 | if (fRoundingIncrement != NULL) { |
729e4ab9 A |
1691 | adjustedNum.div(*fRoundingIncrement, status); |
1692 | adjustedNum.toIntegralValue(); | |
1693 | adjustedNum.mult(*fRoundingIncrement, status); | |
1694 | adjustedNum.trim(); | |
51004dcb A |
1695 | if (U_FAILURE(status)) { |
1696 | return adjustedNum; | |
1697 | } | |
b75a7d8f | 1698 | } |
4388f060 A |
1699 | if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) { |
1700 | status = U_FORMAT_INEXACT_ERROR; | |
51004dcb | 1701 | return adjustedNum; |
4388f060 | 1702 | } |
b75a7d8f | 1703 | |
729e4ab9 | 1704 | if (adjustedNum.isInfinite()) { |
51004dcb | 1705 | return adjustedNum; |
b75a7d8f A |
1706 | } |
1707 | ||
729e4ab9 A |
1708 | if (fUseExponentialNotation || areSignificantDigitsUsed()) { |
1709 | int32_t sigDigits = precision(); | |
1710 | if (sigDigits > 0) { | |
1711 | adjustedNum.round(sigDigits); | |
57a6839d A |
1712 | // Travis Keep (21/2/2014): Calling round on a digitList does not necessarily |
1713 | // preserve the sign of that digit list. Preserving the sign is especially | |
1714 | // important when formatting -0.0 for instance. Not preserving the sign seems | |
1715 | // like a bug because I cannot think of any case where the sign would actually | |
1716 | // have to change when rounding. For now, we preserve the sign by setting the | |
1717 | // positive attribute directly. | |
1718 | adjustedNum.setPositive(!isNegative); | |
b75a7d8f | 1719 | } |
729e4ab9 A |
1720 | } else { |
1721 | // Fixed point format. Round to a set number of fraction digits. | |
1722 | int32_t numFractionDigits = precision(); | |
1723 | adjustedNum.roundFixedPoint(numFractionDigits); | |
b75a7d8f | 1724 | } |
4388f060 A |
1725 | if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) { |
1726 | status = U_FORMAT_INEXACT_ERROR; | |
51004dcb | 1727 | return adjustedNum; |
4388f060 | 1728 | } |
51004dcb | 1729 | return adjustedNum; |
b75a7d8f A |
1730 | } |
1731 | ||
51004dcb A |
1732 | UnicodeString& |
1733 | DecimalFormat::_format(const DigitList &number, | |
1734 | UnicodeString& appendTo, | |
1735 | FieldPositionHandler& handler, | |
1736 | UErrorCode &status) const | |
1737 | { | |
1738 | if (U_FAILURE(status)) { | |
1739 | return appendTo; | |
1740 | } | |
1741 | ||
1742 | // Special case for NaN, sets the begin and end index to be the | |
1743 | // the string length of localized name of NaN. | |
1744 | if (number.isNaN()) | |
1745 | { | |
1746 | int begin = appendTo.length(); | |
1747 | appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol); | |
1748 | ||
1749 | handler.addAttribute(kIntegerField, begin, appendTo.length()); | |
1750 | ||
1751 | addPadding(appendTo, handler, 0, 0); | |
1752 | return appendTo; | |
1753 | } | |
1754 | ||
1755 | DigitList adjustedNum; | |
1756 | UBool isNegative; | |
1757 | _round(number, adjustedNum, isNegative, status); | |
1758 | if (U_FAILURE(status)) { | |
1759 | return appendTo; | |
1760 | } | |
1761 | ||
1762 | // Special case for INFINITE, | |
1763 | if (adjustedNum.isInfinite()) { | |
1764 | int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE); | |
1765 | ||
1766 | int begin = appendTo.length(); | |
1767 | appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol); | |
1768 | ||
1769 | handler.addAttribute(kIntegerField, begin, appendTo.length()); | |
1770 | ||
1771 | int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE); | |
1772 | ||
1773 | addPadding(appendTo, handler, prefixLen, suffixLen); | |
1774 | return appendTo; | |
1775 | } | |
1776 | return subformat(appendTo, handler, adjustedNum, FALSE, status); | |
1777 | } | |
729e4ab9 | 1778 | |
b75a7d8f A |
1779 | /** |
1780 | * Return true if a grouping separator belongs at the given | |
1781 | * position, based on whether grouping is in use and the values of | |
1782 | * the primary and secondary grouping interval. | |
1783 | * @param pos the number of integer digits to the right of | |
1784 | * the current position. Zero indicates the position after the | |
1785 | * rightmost integer digit. | |
1786 | * @return true if a grouping character belongs at the current | |
1787 | * position. | |
1788 | */ | |
1789 | UBool DecimalFormat::isGroupingPosition(int32_t pos) const { | |
1790 | UBool result = FALSE; | |
1791 | if (isGroupingUsed() && (pos > 0) && (fGroupingSize > 0)) { | |
1792 | if ((fGroupingSize2 > 0) && (pos > fGroupingSize)) { | |
1793 | result = ((pos - fGroupingSize) % fGroupingSize2) == 0; | |
1794 | } else { | |
1795 | result = pos % fGroupingSize == 0; | |
1796 | } | |
1797 | } | |
1798 | return result; | |
1799 | } | |
1800 | ||
1801 | //------------------------------------------------------------------------------ | |
1802 | ||
1803 | /** | |
729e4ab9 | 1804 | * Complete the formatting of a finite number. On entry, the DigitList must |
b75a7d8f A |
1805 | * be filled in with the correct digits. |
1806 | */ | |
1807 | UnicodeString& | |
1808 | DecimalFormat::subformat(UnicodeString& appendTo, | |
729e4ab9 | 1809 | FieldPositionHandler& handler, |
b75a7d8f | 1810 | DigitList& digits, |
51004dcb A |
1811 | UBool isInteger, |
1812 | UErrorCode& status) const | |
b75a7d8f | 1813 | { |
729e4ab9 A |
1814 | // char zero = '0'; |
1815 | // DigitList returns digits as '0' thru '9', so we will need to | |
1816 | // always need to subtract the character 0 to get the numeric value to use for indexing. | |
1817 | ||
1818 | UChar32 localizedDigits[10]; | |
1819 | localizedDigits[0] = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); | |
1820 | localizedDigits[1] = getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0); | |
1821 | localizedDigits[2] = getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0); | |
1822 | localizedDigits[3] = getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0); | |
1823 | localizedDigits[4] = getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0); | |
1824 | localizedDigits[5] = getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0); | |
1825 | localizedDigits[6] = getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0); | |
1826 | localizedDigits[7] = getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0); | |
1827 | localizedDigits[8] = getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0); | |
1828 | localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0); | |
1829 | ||
73c04bcf | 1830 | const UnicodeString *grouping ; |
57a6839d | 1831 | if(fCurrencySignCount == fgCurrencySignCountZero) { |
73c04bcf | 1832 | grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); |
57a6839d A |
1833 | }else{ |
1834 | grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); | |
73c04bcf | 1835 | } |
b75a7d8f | 1836 | const UnicodeString *decimal; |
57a6839d | 1837 | if(fCurrencySignCount == fgCurrencySignCountZero) { |
b75a7d8f | 1838 | decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); |
57a6839d A |
1839 | } else { |
1840 | decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); | |
b75a7d8f | 1841 | } |
374ca955 | 1842 | UBool useSigDig = areSignificantDigitsUsed(); |
b75a7d8f A |
1843 | int32_t maxIntDig = getMaximumIntegerDigits(); |
1844 | int32_t minIntDig = getMinimumIntegerDigits(); | |
1845 | ||
b75a7d8f A |
1846 | // Appends the prefix. |
1847 | double doubleValue = digits.getDouble(); | |
729e4ab9 | 1848 | int32_t prefixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), TRUE); |
b75a7d8f A |
1849 | |
1850 | if (fUseExponentialNotation) | |
1851 | { | |
729e4ab9 A |
1852 | int currentLength = appendTo.length(); |
1853 | int intBegin = currentLength; | |
1854 | int intEnd = -1; | |
1855 | int fracBegin = -1; | |
b75a7d8f | 1856 | |
374ca955 A |
1857 | int32_t minFracDig = 0; |
1858 | if (useSigDig) { | |
1859 | maxIntDig = minIntDig = 1; | |
1860 | minFracDig = getMinimumSignificantDigits() - 1; | |
1861 | } else { | |
1862 | minFracDig = getMinimumFractionDigits(); | |
1863 | if (maxIntDig > kMaxScientificIntegerDigits) { | |
1864 | maxIntDig = 1; | |
1865 | if (maxIntDig < minIntDig) { | |
1866 | maxIntDig = minIntDig; | |
1867 | } | |
1868 | } | |
1869 | if (maxIntDig > minIntDig) { | |
1870 | minIntDig = 1; | |
1871 | } | |
1872 | } | |
1873 | ||
b75a7d8f A |
1874 | // Minimum integer digits are handled in exponential format by |
1875 | // adjusting the exponent. For example, 0.01234 with 3 minimum | |
1876 | // integer digits is "123.4E-4". | |
1877 | ||
1878 | // Maximum integer digits are interpreted as indicating the | |
1879 | // repeating range. This is useful for engineering notation, in | |
1880 | // which the exponent is restricted to a multiple of 3. For | |
1881 | // example, 0.01234 with 3 maximum integer digits is "12.34e-3". | |
1882 | // If maximum integer digits are defined and are larger than | |
1883 | // minimum integer digits, then minimum integer digits are | |
1884 | // ignored. | |
729e4ab9 A |
1885 | digits.reduce(); // Removes trailing zero digits. |
1886 | int32_t exponent = digits.getDecimalAt(); | |
b75a7d8f A |
1887 | if (maxIntDig > 1 && maxIntDig != minIntDig) { |
1888 | // A exponent increment is defined; adjust to it. | |
1889 | exponent = (exponent > 0) ? (exponent - 1) / maxIntDig | |
1890 | : (exponent / maxIntDig) - 1; | |
1891 | exponent *= maxIntDig; | |
1892 | } else { | |
1893 | // No exponent increment is defined; use minimum integer digits. | |
1894 | // If none is specified, as in "#E0", generate 1 integer digit. | |
374ca955 | 1895 | exponent -= (minIntDig > 0 || minFracDig > 0) |
b75a7d8f A |
1896 | ? minIntDig : 1; |
1897 | } | |
1898 | ||
1899 | // We now output a minimum number of digits, and more if there | |
1900 | // are more digits, up to the maximum number of digits. We | |
1901 | // place the decimal point after the "integer" digits, which | |
1902 | // are the first (decimalAt - exponent) digits. | |
374ca955 | 1903 | int32_t minimumDigits = minIntDig + minFracDig; |
b75a7d8f A |
1904 | // The number of integer digits is handled specially if the number |
1905 | // is zero, since then there may be no digits. | |
1906 | int32_t integerDigits = digits.isZero() ? minIntDig : | |
729e4ab9 A |
1907 | digits.getDecimalAt() - exponent; |
1908 | int32_t totalDigits = digits.getCount(); | |
b75a7d8f A |
1909 | if (minimumDigits > totalDigits) |
1910 | totalDigits = minimumDigits; | |
1911 | if (integerDigits > totalDigits) | |
1912 | totalDigits = integerDigits; | |
1913 | ||
1914 | // totalDigits records total number of digits needs to be processed | |
1915 | int32_t i; | |
1916 | for (i=0; i<totalDigits; ++i) | |
1917 | { | |
1918 | if (i == integerDigits) | |
1919 | { | |
729e4ab9 A |
1920 | intEnd = appendTo.length(); |
1921 | handler.addAttribute(kIntegerField, intBegin, intEnd); | |
b75a7d8f A |
1922 | |
1923 | appendTo += *decimal; | |
1924 | ||
729e4ab9 A |
1925 | fracBegin = appendTo.length(); |
1926 | handler.addAttribute(kDecimalSeparatorField, fracBegin - 1, fracBegin); | |
b75a7d8f A |
1927 | } |
1928 | // Restores the digit character or pads the buffer with zeros. | |
729e4ab9 A |
1929 | UChar32 c = (UChar32)((i < digits.getCount()) ? |
1930 | localizedDigits[digits.getDigitValue(i)] : | |
1931 | localizedDigits[0]); | |
b75a7d8f A |
1932 | appendTo += c; |
1933 | } | |
1934 | ||
729e4ab9 A |
1935 | currentLength = appendTo.length(); |
1936 | ||
1937 | if (intEnd < 0) { | |
1938 | handler.addAttribute(kIntegerField, intBegin, currentLength); | |
b75a7d8f | 1939 | } |
729e4ab9 A |
1940 | if (fracBegin > 0) { |
1941 | handler.addAttribute(kFractionField, fracBegin, currentLength); | |
b75a7d8f A |
1942 | } |
1943 | ||
1944 | // The exponent is output using the pattern-specified minimum | |
1945 | // exponent digits. There is no maximum limit to the exponent | |
1946 | // digits, since truncating the exponent would appendTo in an | |
1947 | // unacceptable inaccuracy. | |
1948 | appendTo += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); | |
1949 | ||
729e4ab9 A |
1950 | handler.addAttribute(kExponentSymbolField, currentLength, appendTo.length()); |
1951 | currentLength = appendTo.length(); | |
1952 | ||
b75a7d8f A |
1953 | // For zero values, we force the exponent to zero. We |
1954 | // must do this here, and not earlier, because the value | |
1955 | // is used to determine integer digit count above. | |
1956 | if (digits.isZero()) | |
1957 | exponent = 0; | |
1958 | ||
1959 | if (exponent < 0) { | |
1960 | appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
729e4ab9 | 1961 | handler.addAttribute(kExponentSignField, currentLength, appendTo.length()); |
b75a7d8f A |
1962 | } else if (fExponentSignAlwaysShown) { |
1963 | appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); | |
729e4ab9 | 1964 | handler.addAttribute(kExponentSignField, currentLength, appendTo.length()); |
b75a7d8f A |
1965 | } |
1966 | ||
729e4ab9 A |
1967 | currentLength = appendTo.length(); |
1968 | ||
b75a7d8f A |
1969 | DigitList expDigits; |
1970 | expDigits.set(exponent); | |
374ca955 A |
1971 | { |
1972 | int expDig = fMinExponentDigits; | |
1973 | if (fUseExponentialNotation && expDig < 1) { | |
1974 | expDig = 1; | |
1975 | } | |
729e4ab9 A |
1976 | for (i=expDigits.getDecimalAt(); i<expDig; ++i) |
1977 | appendTo += (localizedDigits[0]); | |
374ca955 | 1978 | } |
729e4ab9 | 1979 | for (i=0; i<expDigits.getDecimalAt(); ++i) |
b75a7d8f | 1980 | { |
729e4ab9 A |
1981 | UChar32 c = (UChar32)((i < expDigits.getCount()) ? |
1982 | localizedDigits[expDigits.getDigitValue(i)] : | |
1983 | localizedDigits[0]); | |
b75a7d8f A |
1984 | appendTo += c; |
1985 | } | |
729e4ab9 A |
1986 | |
1987 | handler.addAttribute(kExponentField, currentLength, appendTo.length()); | |
b75a7d8f A |
1988 | } |
1989 | else // Not using exponential notation | |
1990 | { | |
729e4ab9 A |
1991 | int currentLength = appendTo.length(); |
1992 | int intBegin = currentLength; | |
b75a7d8f | 1993 | |
374ca955 A |
1994 | int32_t sigCount = 0; |
1995 | int32_t minSigDig = getMinimumSignificantDigits(); | |
1996 | int32_t maxSigDig = getMaximumSignificantDigits(); | |
1997 | if (!useSigDig) { | |
1998 | minSigDig = 0; | |
1999 | maxSigDig = INT32_MAX; | |
2000 | } | |
2001 | ||
b75a7d8f A |
2002 | // Output the integer portion. Here 'count' is the total |
2003 | // number of integer digits we will display, including both | |
2004 | // leading zeros required to satisfy getMinimumIntegerDigits, | |
2005 | // and actual digits present in the number. | |
374ca955 | 2006 | int32_t count = useSigDig ? |
729e4ab9 A |
2007 | _max(1, digits.getDecimalAt()) : minIntDig; |
2008 | if (digits.getDecimalAt() > 0 && count < digits.getDecimalAt()) { | |
2009 | count = digits.getDecimalAt(); | |
374ca955 | 2010 | } |
b75a7d8f A |
2011 | |
2012 | // Handle the case where getMaximumIntegerDigits() is smaller | |
2013 | // than the real number of integer digits. If this is so, we | |
2014 | // output the least significant max integer digits. For example, | |
2015 | // the value 1997 printed with 2 max integer digits is just "97". | |
2016 | ||
374ca955 A |
2017 | int32_t digitIndex = 0; // Index into digitList.fDigits[] |
2018 | if (count > maxIntDig && maxIntDig >= 0) { | |
b75a7d8f | 2019 | count = maxIntDig; |
729e4ab9 | 2020 | digitIndex = digits.getDecimalAt() - count; |
51004dcb A |
2021 | if(fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) { |
2022 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
2023 | } | |
b75a7d8f A |
2024 | } |
2025 | ||
2026 | int32_t sizeBeforeIntegerPart = appendTo.length(); | |
2027 | ||
2028 | int32_t i; | |
2029 | for (i=count-1; i>=0; --i) | |
2030 | { | |
729e4ab9 | 2031 | if (i < digits.getDecimalAt() && digitIndex < digits.getCount() && |
374ca955 | 2032 | sigCount < maxSigDig) { |
b75a7d8f | 2033 | // Output a real digit |
729e4ab9 | 2034 | appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)]; |
374ca955 | 2035 | ++sigCount; |
b75a7d8f A |
2036 | } |
2037 | else | |
2038 | { | |
374ca955 | 2039 | // Output a zero (leading or trailing) |
729e4ab9 | 2040 | appendTo += localizedDigits[0]; |
374ca955 A |
2041 | if (sigCount > 0) { |
2042 | ++sigCount; | |
2043 | } | |
b75a7d8f A |
2044 | } |
2045 | ||
2046 | // Output grouping separator if necessary. | |
2047 | if (isGroupingPosition(i)) { | |
729e4ab9 | 2048 | currentLength = appendTo.length(); |
b75a7d8f | 2049 | appendTo.append(*grouping); |
729e4ab9 | 2050 | handler.addAttribute(kGroupingSeparatorField, currentLength, appendTo.length()); |
b75a7d8f A |
2051 | } |
2052 | } | |
2053 | ||
57a6839d A |
2054 | // This handles the special case of formatting 0. For zero only, we count the |
2055 | // zero to the left of the decimal point as one signficant digit. Ordinarily we | |
2056 | // do not count any leading 0's as significant. If the number we are formatting | |
2057 | // is not zero, then either sigCount or digits.getCount() will be non-zero. | |
2058 | if (sigCount == 0 && digits.getCount() == 0) { | |
2059 | sigCount = 1; | |
2060 | } | |
2061 | ||
729e4ab9 A |
2062 | // TODO(dlf): this looks like it was a bug, we marked the int field as ending |
2063 | // before the zero was generated. | |
b75a7d8f | 2064 | // Record field information for caller. |
729e4ab9 A |
2065 | // if (fieldPosition.getField() == NumberFormat::kIntegerField) |
2066 | // fieldPosition.setEndIndex(appendTo.length()); | |
b75a7d8f A |
2067 | |
2068 | // Determine whether or not there are any printable fractional | |
2069 | // digits. If we've used up the digits we know there aren't. | |
729e4ab9 | 2070 | UBool fractionPresent = (!isInteger && digitIndex < digits.getCount()) || |
374ca955 | 2071 | (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0)); |
b75a7d8f A |
2072 | |
2073 | // If there is no fraction present, and we haven't printed any | |
2074 | // integer digits, then print a zero. Otherwise we won't print | |
2075 | // _any_ digits, and we won't be able to parse this string. | |
2076 | if (!fractionPresent && appendTo.length() == sizeBeforeIntegerPart) | |
729e4ab9 A |
2077 | appendTo += localizedDigits[0]; |
2078 | ||
2079 | currentLength = appendTo.length(); | |
2080 | handler.addAttribute(kIntegerField, intBegin, currentLength); | |
b75a7d8f A |
2081 | |
2082 | // Output the decimal separator if we always do so. | |
729e4ab9 | 2083 | if (fDecimalSeparatorAlwaysShown || fractionPresent) { |
b75a7d8f | 2084 | appendTo += *decimal; |
729e4ab9 A |
2085 | handler.addAttribute(kDecimalSeparatorField, currentLength, appendTo.length()); |
2086 | currentLength = appendTo.length(); | |
2087 | } | |
b75a7d8f | 2088 | |
729e4ab9 | 2089 | int fracBegin = currentLength; |
b75a7d8f | 2090 | |
374ca955 A |
2091 | count = useSigDig ? INT32_MAX : getMaximumFractionDigits(); |
2092 | if (useSigDig && (sigCount == maxSigDig || | |
729e4ab9 | 2093 | (sigCount >= minSigDig && digitIndex == digits.getCount()))) { |
374ca955 A |
2094 | count = 0; |
2095 | } | |
2096 | ||
2097 | for (i=0; i < count; ++i) { | |
2098 | // Here is where we escape from the loop. We escape | |
2099 | // if we've output the maximum fraction digits | |
2100 | // (specified in the for expression above). We also | |
2101 | // stop when we've output the minimum digits and | |
2102 | // either: we have an integer, so there is no | |
2103 | // fractional stuff to display, or we're out of | |
2104 | // significant digits. | |
2105 | if (!useSigDig && i >= getMinimumFractionDigits() && | |
729e4ab9 | 2106 | (isInteger || digitIndex >= digits.getCount())) { |
374ca955 | 2107 | break; |
b75a7d8f | 2108 | } |
b75a7d8f | 2109 | |
374ca955 A |
2110 | // Output leading fractional zeros. These are zeros |
2111 | // that come after the decimal but before any | |
2112 | // significant digits. These are only output if | |
2113 | // abs(number being formatted) < 1.0. | |
729e4ab9 A |
2114 | if (-1-i > (digits.getDecimalAt()-1)) { |
2115 | appendTo += localizedDigits[0]; | |
374ca955 A |
2116 | continue; |
2117 | } | |
2118 | ||
2119 | // Output a digit, if we have any precision left, or a | |
2120 | // zero if we don't. We don't want to output noise digits. | |
729e4ab9 A |
2121 | if (!isInteger && digitIndex < digits.getCount()) { |
2122 | appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)]; | |
374ca955 | 2123 | } else { |
729e4ab9 | 2124 | appendTo += localizedDigits[0]; |
374ca955 A |
2125 | } |
2126 | ||
2127 | // If we reach the maximum number of significant | |
2128 | // digits, or if we output all the real digits and | |
2129 | // reach the minimum, then we are done. | |
2130 | ++sigCount; | |
2131 | if (useSigDig && | |
2132 | (sigCount == maxSigDig || | |
729e4ab9 | 2133 | (digitIndex == digits.getCount() && sigCount >= minSigDig))) { |
374ca955 | 2134 | break; |
b75a7d8f A |
2135 | } |
2136 | } | |
2137 | ||
729e4ab9 | 2138 | handler.addAttribute(kFractionField, fracBegin, appendTo.length()); |
b75a7d8f A |
2139 | } |
2140 | ||
729e4ab9 | 2141 | int32_t suffixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), FALSE); |
b75a7d8f | 2142 | |
729e4ab9 | 2143 | addPadding(appendTo, handler, prefixLen, suffixLen); |
b75a7d8f A |
2144 | return appendTo; |
2145 | } | |
2146 | ||
2147 | /** | |
2148 | * Inserts the character fPad as needed to expand result to fFormatWidth. | |
2149 | * @param result the string to be padded | |
2150 | */ | |
2151 | void DecimalFormat::addPadding(UnicodeString& appendTo, | |
729e4ab9 | 2152 | FieldPositionHandler& handler, |
b75a7d8f A |
2153 | int32_t prefixLen, |
2154 | int32_t suffixLen) const | |
2155 | { | |
2156 | if (fFormatWidth > 0) { | |
2157 | int32_t len = fFormatWidth - appendTo.length(); | |
2158 | if (len > 0) { | |
2159 | UnicodeString padding; | |
2160 | for (int32_t i=0; i<len; ++i) { | |
2161 | padding += fPad; | |
2162 | } | |
2163 | switch (fPadPosition) { | |
2164 | case kPadAfterPrefix: | |
2165 | appendTo.insert(prefixLen, padding); | |
2166 | break; | |
2167 | case kPadBeforePrefix: | |
2168 | appendTo.insert(0, padding); | |
2169 | break; | |
2170 | case kPadBeforeSuffix: | |
2171 | appendTo.insert(appendTo.length() - suffixLen, padding); | |
2172 | break; | |
2173 | case kPadAfterSuffix: | |
2174 | appendTo += padding; | |
2175 | break; | |
2176 | } | |
729e4ab9 A |
2177 | if (fPadPosition == kPadBeforePrefix || fPadPosition == kPadAfterPrefix) { |
2178 | handler.shiftLast(len); | |
b75a7d8f A |
2179 | } |
2180 | } | |
2181 | } | |
2182 | } | |
2183 | ||
2184 | //------------------------------------------------------------------------------ | |
729e4ab9 | 2185 | |
b75a7d8f A |
2186 | void |
2187 | DecimalFormat::parse(const UnicodeString& text, | |
2188 | Formattable& result, | |
374ca955 | 2189 | ParsePosition& parsePosition) const { |
4388f060 | 2190 | parse(text, result, parsePosition, NULL); |
374ca955 A |
2191 | } |
2192 | ||
4388f060 A |
2193 | CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, |
2194 | ParsePosition& pos) const { | |
2195 | Formattable parseResult; | |
2196 | int32_t start = pos.getIndex(); | |
51004dcb | 2197 | UChar curbuf[4] = {}; |
4388f060 A |
2198 | parse(text, parseResult, pos, curbuf); |
2199 | if (pos.getIndex() != start) { | |
2200 | UErrorCode ec = U_ZERO_ERROR; | |
b331163b | 2201 | LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec); |
4388f060 A |
2202 | if (U_FAILURE(ec)) { |
2203 | pos.setIndex(start); // indicate failure | |
2204 | } else { | |
2205 | return currAmt.orphan(); | |
2206 | } | |
2207 | } | |
2208 | return NULL; | |
374ca955 A |
2209 | } |
2210 | ||
2211 | /** | |
4388f060 | 2212 | * Parses the given text as a number, optionally providing a currency amount. |
374ca955 | 2213 | * @param text the string to parse |
4388f060 | 2214 | * @param result output parameter for the numeric result. |
374ca955 A |
2215 | * @param parsePosition input-output position; on input, the |
2216 | * position within text to match; must have 0 <= pos.getIndex() < | |
2217 | * text.length(); on output, the position after the last matched | |
2218 | * character. If the parse fails, the position in unchanged upon | |
2219 | * output. | |
4388f060 A |
2220 | * @param currency if non-NULL, it should point to a 4-UChar buffer. |
2221 | * In this case the text is parsed as a currency format, and the | |
2222 | * ISO 4217 code for the parsed currency is put into the buffer. | |
2223 | * Otherwise the text is parsed as a non-currency format. | |
374ca955 A |
2224 | */ |
2225 | void DecimalFormat::parse(const UnicodeString& text, | |
2226 | Formattable& result, | |
2227 | ParsePosition& parsePosition, | |
4388f060 A |
2228 | UChar* currency) const { |
2229 | int32_t startIdx, backup; | |
2230 | int32_t i = startIdx = backup = parsePosition.getIndex(); | |
b75a7d8f | 2231 | |
729e4ab9 A |
2232 | // clear any old contents in the result. In particular, clears any DigitList |
2233 | // that it may be holding. | |
2234 | result.setLong(0); | |
57a6839d A |
2235 | if (currency != NULL) { |
2236 | for (int32_t ci=0; ci<4; ci++) { | |
2237 | currency[ci] = 0; | |
2238 | } | |
2239 | } | |
729e4ab9 | 2240 | |
b75a7d8f | 2241 | // Handle NaN as a special case: |
729e4ab9 | 2242 | |
b75a7d8f A |
2243 | // Skip padding characters, if around prefix |
2244 | if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix || | |
2245 | fPadPosition == kPadAfterPrefix)) { | |
2246 | i = skipPadding(text, i); | |
2247 | } | |
729e4ab9 | 2248 | |
4388f060 A |
2249 | if (isLenient()) { |
2250 | // skip any leading whitespace | |
2251 | i = backup = skipUWhiteSpace(text, i); | |
46f4442e | 2252 | } |
729e4ab9 | 2253 | |
b75a7d8f A |
2254 | // If the text is composed of the representation of NaN, returns NaN.length |
2255 | const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol); | |
2256 | int32_t nanLen = (text.compare(i, nan->length(), *nan) | |
2257 | ? 0 : nan->length()); | |
2258 | if (nanLen) { | |
2259 | i += nanLen; | |
2260 | if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix || | |
2261 | fPadPosition == kPadAfterSuffix)) { | |
2262 | i = skipPadding(text, i); | |
2263 | } | |
2264 | parsePosition.setIndex(i); | |
2265 | result.setDouble(uprv_getNaN()); | |
2266 | return; | |
2267 | } | |
729e4ab9 | 2268 | |
b75a7d8f A |
2269 | // NaN parse failed; start over |
2270 | i = backup; | |
46f4442e | 2271 | parsePosition.setIndex(i); |
b75a7d8f A |
2272 | |
2273 | // status is used to record whether a number is infinite. | |
2274 | UBool status[fgStatusLength]; | |
51004dcb A |
2275 | |
2276 | DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer | |
729e4ab9 A |
2277 | if (digits == NULL) { |
2278 | return; // no way to report error from here. | |
2279 | } | |
b75a7d8f | 2280 | |
57a6839d | 2281 | if (fCurrencySignCount != fgCurrencySignCountZero) { |
729e4ab9 A |
2282 | if (!parseForCurrency(text, parsePosition, *digits, |
2283 | status, currency)) { | |
51004dcb | 2284 | return; |
729e4ab9 A |
2285 | } |
2286 | } else { | |
2287 | if (!subparse(text, | |
2288 | fNegPrefixPattern, fNegSuffixPattern, | |
2289 | fPosPrefixPattern, fPosSuffixPattern, | |
2290 | FALSE, UCURR_SYMBOL_NAME, | |
2291 | parsePosition, *digits, status, currency)) { | |
51004dcb | 2292 | debug("!subparse(...) - rewind"); |
4388f060 | 2293 | parsePosition.setIndex(startIdx); |
729e4ab9 A |
2294 | return; |
2295 | } | |
b75a7d8f A |
2296 | } |
2297 | ||
2298 | // Handle infinity | |
2299 | if (status[fgStatusInfinite]) { | |
2300 | double inf = uprv_getInfinity(); | |
729e4ab9 | 2301 | result.setDouble(digits->isPositive() ? inf : -inf); |
51004dcb | 2302 | // TODO: set the dl to infinity, and let it fall into the code below. |
b75a7d8f A |
2303 | } |
2304 | ||
374ca955 | 2305 | else { |
374ca955 | 2306 | |
729e4ab9 A |
2307 | if (fMultiplier != NULL) { |
2308 | UErrorCode ec = U_ZERO_ERROR; | |
2309 | digits->div(*fMultiplier, ec); | |
b75a7d8f | 2310 | } |
729e4ab9 | 2311 | |
51004dcb A |
2312 | if (fScale != 0) { |
2313 | DigitList ten; | |
57a6839d | 2314 | ten.set((int32_t)10); |
51004dcb A |
2315 | if (fScale > 0) { |
2316 | for (int32_t i = fScale; i > 0; i--) { | |
2317 | UErrorCode ec = U_ZERO_ERROR; | |
2318 | digits->div(ten,ec); | |
2319 | } | |
2320 | } else { | |
2321 | for (int32_t i = fScale; i < 0; i++) { | |
2322 | UErrorCode ec = U_ZERO_ERROR; | |
2323 | digits->mult(ten,ec); | |
2324 | } | |
2325 | } | |
2326 | } | |
2327 | ||
729e4ab9 A |
2328 | // Negative zero special case: |
2329 | // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable. | |
2330 | // if not parsing integerOnly, leave as -0, which a double can represent. | |
2331 | if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) { | |
2332 | digits->setPositive(TRUE); | |
b75a7d8f | 2333 | } |
729e4ab9 | 2334 | result.adoptDigitList(digits); |
b75a7d8f | 2335 | } |
b75a7d8f A |
2336 | } |
2337 | ||
2338 | ||
374ca955 | 2339 | |
729e4ab9 A |
2340 | UBool |
2341 | DecimalFormat::parseForCurrency(const UnicodeString& text, | |
2342 | ParsePosition& parsePosition, | |
2343 | DigitList& digits, | |
2344 | UBool* status, | |
2345 | UChar* currency) const { | |
2346 | int origPos = parsePosition.getIndex(); | |
2347 | int maxPosIndex = origPos; | |
2348 | int maxErrorPos = -1; | |
2349 | // First, parse against current pattern. | |
2350 | // Since current pattern could be set by applyPattern(), | |
2351 | // it could be an arbitrary pattern, and it may not be the one | |
2352 | // defined in current locale. | |
2353 | UBool tmpStatus[fgStatusLength]; | |
2354 | ParsePosition tmpPos(origPos); | |
2355 | DigitList tmpDigitList; | |
2356 | UBool found; | |
4388f060 | 2357 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
729e4ab9 A |
2358 | found = subparse(text, |
2359 | fNegPrefixPattern, fNegSuffixPattern, | |
2360 | fPosPrefixPattern, fPosSuffixPattern, | |
2361 | TRUE, UCURR_LONG_NAME, | |
2362 | tmpPos, tmpDigitList, tmpStatus, currency); | |
2363 | } else { | |
2364 | found = subparse(text, | |
2365 | fNegPrefixPattern, fNegSuffixPattern, | |
2366 | fPosPrefixPattern, fPosSuffixPattern, | |
2367 | TRUE, UCURR_SYMBOL_NAME, | |
2368 | tmpPos, tmpDigitList, tmpStatus, currency); | |
2369 | } | |
2370 | if (found) { | |
2371 | if (tmpPos.getIndex() > maxPosIndex) { | |
2372 | maxPosIndex = tmpPos.getIndex(); | |
2373 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
2374 | status[i] = tmpStatus[i]; | |
2375 | } | |
2376 | digits = tmpDigitList; | |
2377 | } | |
2378 | } else { | |
2379 | maxErrorPos = tmpPos.getErrorIndex(); | |
2380 | } | |
2381 | // Then, parse against affix patterns. | |
2382 | // Those are currency patterns and currency plural patterns. | |
b331163b | 2383 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
2384 | const UHashElement* element = NULL; |
2385 | while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { | |
729e4ab9 A |
2386 | const UHashTok valueTok = element->value; |
2387 | const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer; | |
2388 | UBool tmpStatus[fgStatusLength]; | |
2389 | ParsePosition tmpPos(origPos); | |
2390 | DigitList tmpDigitList; | |
57a6839d A |
2391 | |
2392 | #ifdef FMT_DEBUG | |
2393 | debug("trying affix for currency.."); | |
2394 | affixPtn->dump(); | |
2395 | #endif | |
2396 | ||
729e4ab9 A |
2397 | UBool result = subparse(text, |
2398 | &affixPtn->negPrefixPatternForCurrency, | |
2399 | &affixPtn->negSuffixPatternForCurrency, | |
2400 | &affixPtn->posPrefixPatternForCurrency, | |
2401 | &affixPtn->posSuffixPatternForCurrency, | |
2402 | TRUE, affixPtn->patternType, | |
2403 | tmpPos, tmpDigitList, tmpStatus, currency); | |
2404 | if (result) { | |
2405 | found = true; | |
2406 | if (tmpPos.getIndex() > maxPosIndex) { | |
2407 | maxPosIndex = tmpPos.getIndex(); | |
2408 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
2409 | status[i] = tmpStatus[i]; | |
2410 | } | |
2411 | digits = tmpDigitList; | |
2412 | } | |
2413 | } else { | |
2414 | maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? | |
2415 | tmpPos.getErrorIndex() : maxErrorPos; | |
2416 | } | |
2417 | } | |
2418 | // Finally, parse against simple affix to find the match. | |
2419 | // For example, in TestMonster suite, | |
2420 | // if the to-be-parsed text is "-\u00A40,00". | |
2421 | // complexAffixCompare will not find match, | |
2422 | // since there is no ISO code matches "\u00A4", | |
2423 | // and the parse stops at "\u00A4". | |
2424 | // We will just use simple affix comparison (look for exact match) | |
2425 | // to pass it. | |
57a6839d A |
2426 | // |
2427 | // TODO: We should parse against simple affix first when | |
2428 | // output currency is not requested. After the complex currency | |
2429 | // parsing implementation was introduced, the default currency | |
2430 | // instance parsing slowed down because of the new code flow. | |
2431 | // I filed #10312 - Yoshito | |
729e4ab9 A |
2432 | UBool tmpStatus_2[fgStatusLength]; |
2433 | ParsePosition tmpPos_2(origPos); | |
2434 | DigitList tmpDigitList_2; | |
57a6839d A |
2435 | |
2436 | // Disable complex currency parsing and try it again. | |
729e4ab9 A |
2437 | UBool result = subparse(text, |
2438 | &fNegativePrefix, &fNegativeSuffix, | |
2439 | &fPositivePrefix, &fPositiveSuffix, | |
57a6839d | 2440 | FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME, |
729e4ab9 A |
2441 | tmpPos_2, tmpDigitList_2, tmpStatus_2, |
2442 | currency); | |
2443 | if (result) { | |
2444 | if (tmpPos_2.getIndex() > maxPosIndex) { | |
2445 | maxPosIndex = tmpPos_2.getIndex(); | |
2446 | for (int32_t i = 0; i < fgStatusLength; ++i) { | |
2447 | status[i] = tmpStatus_2[i]; | |
2448 | } | |
2449 | digits = tmpDigitList_2; | |
2450 | } | |
2451 | found = true; | |
2452 | } else { | |
2453 | maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ? | |
2454 | tmpPos_2.getErrorIndex() : maxErrorPos; | |
2455 | } | |
2456 | ||
2457 | if (!found) { | |
2458 | //parsePosition.setIndex(origPos); | |
2459 | parsePosition.setErrorIndex(maxErrorPos); | |
2460 | } else { | |
2461 | parsePosition.setIndex(maxPosIndex); | |
2462 | parsePosition.setErrorIndex(-1); | |
2463 | } | |
2464 | return found; | |
2465 | } | |
2466 | ||
374ca955 | 2467 | |
b75a7d8f A |
2468 | /** |
2469 | * Parse the given text into a number. The text is parsed beginning at | |
2470 | * parsePosition, until an unparseable character is seen. | |
374ca955 | 2471 | * @param text the string to parse. |
729e4ab9 A |
2472 | * @param negPrefix negative prefix. |
2473 | * @param negSuffix negative suffix. | |
2474 | * @param posPrefix positive prefix. | |
2475 | * @param posSuffix positive suffix. | |
57a6839d | 2476 | * @param complexCurrencyParsing whether it is complex currency parsing or not. |
729e4ab9 | 2477 | * @param type the currency type to parse against, LONG_NAME only or not. |
b75a7d8f | 2478 | * @param parsePosition The position at which to being parsing. Upon |
374ca955 A |
2479 | * return, the first unparsed character. |
2480 | * @param digits the DigitList to set to the parsed value. | |
2481 | * @param status output param containing boolean status flags indicating | |
b75a7d8f | 2482 | * whether the value was infinite and whether it was positive. |
374ca955 A |
2483 | * @param currency return value for parsed currency, for generic |
2484 | * currency parsing mode, or NULL for normal parsing. In generic | |
2485 | * currency parsing mode, any currency is parsed, not just the | |
2486 | * currency that this formatter is set to. | |
b75a7d8f | 2487 | */ |
729e4ab9 A |
2488 | UBool DecimalFormat::subparse(const UnicodeString& text, |
2489 | const UnicodeString* negPrefix, | |
2490 | const UnicodeString* negSuffix, | |
2491 | const UnicodeString* posPrefix, | |
2492 | const UnicodeString* posSuffix, | |
57a6839d | 2493 | UBool complexCurrencyParsing, |
729e4ab9 A |
2494 | int8_t type, |
2495 | ParsePosition& parsePosition, | |
374ca955 A |
2496 | DigitList& digits, UBool* status, |
2497 | UChar* currency) const | |
b75a7d8f | 2498 | { |
729e4ab9 A |
2499 | // The parsing process builds up the number as char string, in the neutral format that |
2500 | // will be acceptable to the decNumber library, then at the end passes that string | |
2501 | // off for conversion to a decNumber. | |
2502 | UErrorCode err = U_ZERO_ERROR; | |
2503 | CharString parsedNum; | |
2504 | digits.setToZero(); | |
2505 | ||
b75a7d8f A |
2506 | int32_t position = parsePosition.getIndex(); |
2507 | int32_t oldStart = position; | |
51004dcb | 2508 | int32_t textLength = text.length(); // One less pointer to follow |
4388f060 | 2509 | UBool strictParse = !isLenient(); |
51004dcb | 2510 | UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); |
57a6839d A |
2511 | const UnicodeString *groupingString = &getConstSymbol(fCurrencySignCount == fgCurrencySignCountZero ? |
2512 | DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); | |
51004dcb A |
2513 | UChar32 groupingChar = groupingString->char32At(0); |
2514 | int32_t groupingStringLength = groupingString->length(); | |
2515 | int32_t groupingCharLength = U16_LENGTH(groupingChar); | |
2516 | UBool groupingUsed = isGroupingUsed(); | |
2517 | #ifdef FMT_DEBUG | |
2518 | UChar dbgbuf[300]; | |
2519 | UnicodeString s(dbgbuf,0,300);; | |
2520 | s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " ); | |
2521 | #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 ")); } | |
2522 | DBGAPPD(negPrefix); | |
2523 | DBGAPPD(negSuffix); | |
2524 | DBGAPPD(posPrefix); | |
2525 | DBGAPPD(posSuffix); | |
2526 | debugout(s); | |
2527 | printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(), negPrefix!=NULL?negPrefix->length():-1); | |
2528 | #endif | |
2529 | ||
2530 | UBool fastParseOk = false; /* TRUE iff fast parse is OK */ | |
2531 | // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */ | |
2532 | const DecimalFormatInternal &data = internalData(fReserved); | |
2533 | if((data.fFastParseStatus==kFastpathYES) && | |
57a6839d | 2534 | fCurrencySignCount == fgCurrencySignCountZero && |
51004dcb A |
2535 | // (negPrefix!=NULL&&negPrefix->isEmpty()) || |
2536 | text.length()>0 && | |
2537 | text.length()<32 && | |
2538 | (posPrefix==NULL||posPrefix->isEmpty()) && | |
2539 | (posSuffix==NULL||posSuffix->isEmpty()) && | |
2540 | // (negPrefix==NULL||negPrefix->isEmpty()) && | |
2541 | // (negSuffix==NULL||(negSuffix->isEmpty()) ) && | |
2542 | TRUE) { // optimized path | |
2543 | int j=position; | |
2544 | int l=text.length(); | |
2545 | int digitCount=0; | |
2546 | UChar32 ch = text.char32At(j); | |
2547 | const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); | |
2548 | UChar32 decimalChar = 0; | |
2549 | UBool intOnly = FALSE; | |
2550 | UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0; | |
2551 | ||
2552 | int32_t decimalCount = decimalString->countChar32(0,3); | |
2553 | if(isParseIntegerOnly()) { | |
2554 | decimalChar = 0; // not allowed | |
2555 | intOnly = TRUE; // Don't look for decimals. | |
2556 | } else if(decimalCount==1) { | |
2557 | decimalChar = decimalString->char32At(0); // Look for this decimal | |
2558 | } else if(decimalCount==0) { | |
2559 | decimalChar=0; // NO decimal set | |
2560 | } else { | |
2561 | j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation. | |
2562 | } | |
b75a7d8f | 2563 | |
51004dcb A |
2564 | #ifdef FMT_DEBUG |
2565 | printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n", | |
2566 | decimalChar, groupingChar, ch, | |
2567 | (intOnly)?'y':'n', | |
2568 | (strictParse)?'y':'n'); | |
2569 | #endif | |
2570 | if(ch==0x002D) { // '-' | |
2571 | j=l+1;//=break - negative number. | |
2572 | ||
2573 | /* | |
2574 | parsedNum.append('-',err); | |
2575 | j+=U16_LENGTH(ch); | |
2576 | if(j<l) ch = text.char32At(j); | |
2577 | */ | |
2578 | } else { | |
2579 | parsedNum.append('+',err); | |
2580 | } | |
2581 | while(j<l) { | |
2582 | int32_t digit = ch - zero; | |
2583 | if(digit >=0 && digit <= 9) { | |
2584 | parsedNum.append((char)(digit + '0'), err); | |
2585 | if((digitCount>0) || digit!=0 || j==(l-1)) { | |
2586 | digitCount++; | |
2587 | } | |
2588 | } else if(ch == 0) { // break out | |
2589 | digitCount=-1; | |
2590 | break; | |
2591 | } else if(ch == decimalChar) { | |
2592 | parsedNum.append((char)('.'), err); | |
2593 | decimalChar=0; // no more decimals. | |
2594 | // fastParseHadDecimal=TRUE; | |
2595 | } else if(ch == lookForGroup) { | |
2596 | // ignore grouping char. No decimals, so it has to be an ignorable grouping sep | |
2597 | } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) { | |
2598 | // parsing integer only and can fall through | |
2599 | } else { | |
2600 | digitCount=-1; // fail - fall through to slow parse | |
2601 | break; | |
2602 | } | |
2603 | j+=U16_LENGTH(ch); | |
2604 | ch = text.char32At(j); // for next | |
2605 | } | |
2606 | if( | |
2607 | ((j==l)||intOnly) // end OR only parsing integer | |
2608 | && (digitCount>0)) { // and have at least one digit | |
2609 | #ifdef FMT_DEBUG | |
2610 | printf("PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2); | |
2611 | #endif | |
2612 | fastParseOk=true; // Fast parse OK! | |
2613 | ||
2614 | #ifdef SKIP_OPT | |
2615 | debug("SKIP_OPT"); | |
2616 | /* for testing, try it the slow way. also */ | |
2617 | fastParseOk=false; | |
2618 | parsedNum.clear(); | |
2619 | #else | |
2620 | parsePosition.setIndex(position=j); | |
2621 | status[fgStatusInfinite]=false; | |
2622 | #endif | |
2623 | } else { | |
2624 | // was not OK. reset, retry | |
2625 | #ifdef FMT_DEBUG | |
2626 | printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount); | |
2627 | #endif | |
2628 | parsedNum.clear(); | |
2629 | } | |
2630 | } else { | |
2631 | #ifdef FMT_DEBUG | |
2632 | printf("Could not fastpath parse. "); | |
2633 | printf("fFormatWidth=%d ", fFormatWidth); | |
2634 | printf("text.length()=%d ", text.length()); | |
2635 | printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix); | |
2636 | ||
2637 | printf("\n"); | |
2638 | #endif | |
2639 | } | |
2640 | ||
2641 | if(!fastParseOk | |
2642 | #if UCONFIG_HAVE_PARSEALLINPUT | |
2643 | && fParseAllInput!=UNUM_YES | |
2644 | #endif | |
2645 | ) | |
2646 | { | |
b75a7d8f A |
2647 | // Match padding before prefix |
2648 | if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) { | |
2649 | position = skipPadding(text, position); | |
2650 | } | |
2651 | ||
2652 | // Match positive and negative prefixes; prefer longest match. | |
57a6839d A |
2653 | int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency); |
2654 | int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency); | |
b75a7d8f A |
2655 | if (posMatch >= 0 && negMatch >= 0) { |
2656 | if (posMatch > negMatch) { | |
2657 | negMatch = -1; | |
2658 | } else if (negMatch > posMatch) { | |
2659 | posMatch = -1; | |
729e4ab9 | 2660 | } |
b75a7d8f A |
2661 | } |
2662 | if (posMatch >= 0) { | |
2663 | position += posMatch; | |
729e4ab9 | 2664 | parsedNum.append('+', err); |
b75a7d8f A |
2665 | } else if (negMatch >= 0) { |
2666 | position += negMatch; | |
729e4ab9 A |
2667 | parsedNum.append('-', err); |
2668 | } else if (strictParse){ | |
b75a7d8f A |
2669 | parsePosition.setErrorIndex(position); |
2670 | return FALSE; | |
4388f060 A |
2671 | } else { |
2672 | // Temporary set positive. This might be changed after checking suffix | |
2673 | parsedNum.append('+', err); | |
b75a7d8f A |
2674 | } |
2675 | ||
2676 | // Match padding before prefix | |
2677 | if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) { | |
2678 | position = skipPadding(text, position); | |
2679 | } | |
729e4ab9 | 2680 | |
46f4442e | 2681 | if (! strictParse) { |
4388f060 | 2682 | position = skipUWhiteSpace(text, position); |
46f4442e | 2683 | } |
729e4ab9 | 2684 | |
b75a7d8f A |
2685 | // process digits or Inf, find decimal position |
2686 | const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySymbol); | |
2687 | int32_t infLen = (text.compare(position, inf->length(), *inf) | |
2688 | ? 0 : inf->length()); | |
2689 | position += infLen; // infLen is non-zero when it does equal to infinity | |
46f4442e | 2690 | status[fgStatusInfinite] = infLen != 0; |
729e4ab9 | 2691 | |
4388f060 | 2692 | if (infLen != 0) { |
729e4ab9 A |
2693 | parsedNum.append("Infinity", err); |
2694 | } else { | |
b75a7d8f A |
2695 | // We now have a string of digits, possibly with grouping symbols, |
2696 | // and decimal points. We want to process these into a DigitList. | |
2697 | // We don't want to put a bunch of leading zeros into the DigitList | |
2698 | // though, so we keep track of the location of the decimal point, | |
2699 | // put only significant digits into the DigitList, and adjust the | |
2700 | // exponent as needed. | |
2701 | ||
b75a7d8f | 2702 | |
46f4442e | 2703 | UBool strictFail = FALSE; // did we exit with a strict parse failure? |
46f4442e A |
2704 | int32_t lastGroup = -1; // where did we last see a grouping separator? |
2705 | int32_t digitStart = position; | |
2706 | int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2; | |
729e4ab9 | 2707 | |
46f4442e | 2708 | const UnicodeString *decimalString; |
57a6839d | 2709 | if (fCurrencySignCount != fgCurrencySignCountZero) { |
4388f060 | 2710 | decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); |
b75a7d8f | 2711 | } else { |
4388f060 | 2712 | decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); |
b75a7d8f | 2713 | } |
46f4442e | 2714 | UChar32 decimalChar = decimalString->char32At(0); |
51004dcb A |
2715 | int32_t decimalStringLength = decimalString->length(); |
2716 | int32_t decimalCharLength = U16_LENGTH(decimalChar); | |
729e4ab9 | 2717 | |
b75a7d8f | 2718 | UBool sawDecimal = FALSE; |
4388f060 A |
2719 | UChar32 sawDecimalChar = 0xFFFF; |
2720 | UBool sawGrouping = FALSE; | |
2721 | UChar32 sawGroupingChar = 0xFFFF; | |
b75a7d8f A |
2722 | UBool sawDigit = FALSE; |
2723 | int32_t backup = -1; | |
2724 | int32_t digit; | |
729e4ab9 | 2725 | |
46f4442e | 2726 | // equivalent grouping and decimal support |
4388f060 A |
2727 | const UnicodeSet *decimalSet = NULL; |
2728 | const UnicodeSet *groupingSet = NULL; | |
729e4ab9 A |
2729 | |
2730 | if (decimalCharLength == decimalStringLength) { | |
4388f060 | 2731 | decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse); |
729e4ab9 A |
2732 | } |
2733 | ||
2734 | if (groupingCharLength == groupingStringLength) { | |
2735 | if (strictParse) { | |
57a6839d | 2736 | groupingSet = fStaticSets->fStrictDefaultGroupingSeparators; |
729e4ab9 | 2737 | } else { |
57a6839d | 2738 | groupingSet = fStaticSets->fDefaultGroupingSeparators; |
46f4442e | 2739 | } |
46f4442e | 2740 | } |
729e4ab9 | 2741 | |
4388f060 A |
2742 | // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized. |
2743 | // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet | |
2744 | // If a character matches decimalSet, don't consider it to be a member of the groupingSet. | |
729e4ab9 | 2745 | |
b75a7d8f A |
2746 | // We have to track digitCount ourselves, because digits.fCount will |
2747 | // pin when the maximum allowable digits is reached. | |
2748 | int32_t digitCount = 0; | |
729e4ab9 | 2749 | int32_t integerDigitCount = 0; |
b75a7d8f A |
2750 | |
2751 | for (; position < textLength; ) | |
2752 | { | |
2753 | UChar32 ch = text.char32At(position); | |
2754 | ||
2755 | /* We recognize all digit ranges, not only the Latin digit range | |
2756 | * '0'..'9'. We do so by using the Character.digit() method, | |
2757 | * which converts a valid Unicode digit to the range 0..9. | |
2758 | * | |
2759 | * The character 'ch' may be a digit. If so, place its value | |
2760 | * from 0 to 9 in 'digit'. First try using the locale digit, | |
2761 | * which may or MAY NOT be a standard Unicode digit range. If | |
2762 | * this fails, try using the standard Unicode digit ranges by | |
729e4ab9 | 2763 | * calling Character.digit(). If this also fails, digit will |
b75a7d8f A |
2764 | * have a value outside the range 0..9. |
2765 | */ | |
2766 | digit = ch - zero; | |
2767 | if (digit < 0 || digit > 9) | |
2768 | { | |
2769 | digit = u_charDigitValue(ch); | |
2770 | } | |
729e4ab9 A |
2771 | |
2772 | // As a last resort, look through the localized digits if the zero digit | |
2773 | // is not a "standard" Unicode digit. | |
2774 | if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) { | |
2775 | digit = 0; | |
2776 | // Already check above (digit = ch - zero) for ch==zero; the only check we need to do here is: | |
2777 | // if \u3007 is treated as 0 for parsing, \u96F6 should be too. Otherwise check for nonzero digits. | |
2778 | if ( zero!=0x3007 || ch!=0x96F6 ) { | |
2779 | for (digit = 1 ; digit < 10 ; digit++ ) { | |
2780 | if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) { | |
46f4442e A |
2781 | break; |
2782 | } | |
46f4442e A |
2783 | } |
2784 | } | |
b75a7d8f | 2785 | } |
b75a7d8f | 2786 | |
729e4ab9 A |
2787 | if (digit >= 0 && digit <= 9) |
2788 | { | |
46f4442e A |
2789 | if (strictParse && backup != -1) { |
2790 | // comma followed by digit, so group before comma is a | |
2791 | // secondary group. If there was a group separator | |
2792 | // before that, the group must == the secondary group | |
2793 | // length, else it can be <= the the secondary group | |
2794 | // length. | |
2795 | if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) || | |
2796 | (lastGroup == -1 && position - digitStart - 1 > gs2)) { | |
2797 | strictFail = TRUE; | |
2798 | break; | |
2799 | } | |
729e4ab9 | 2800 | |
46f4442e | 2801 | lastGroup = backup; |
b75a7d8f | 2802 | } |
729e4ab9 A |
2803 | |
2804 | // Cancel out backup setting (see grouping handler below) | |
46f4442e A |
2805 | backup = -1; |
2806 | sawDigit = TRUE; | |
729e4ab9 A |
2807 | |
2808 | // Note: this will append leading zeros | |
2809 | parsedNum.append((char)(digit + '0'), err); | |
2810 | ||
2811 | // count any digit that's not a leading zero | |
2812 | if (digit > 0 || digitCount > 0 || sawDecimal) { | |
2813 | digitCount += 1; | |
2814 | ||
2815 | // count any integer digit that's not a leading zero | |
2816 | if (! sawDecimal) { | |
2817 | integerDigitCount += 1; | |
2818 | } | |
b75a7d8f | 2819 | } |
729e4ab9 | 2820 | |
b75a7d8f A |
2821 | position += U16_LENGTH(ch); |
2822 | } | |
4388f060 A |
2823 | else if (groupingStringLength > 0 && |
2824 | matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet, | |
2825 | decimalChar, decimalSet, | |
51004dcb | 2826 | ch) && groupingUsed) |
b75a7d8f | 2827 | { |
46f4442e A |
2828 | if (sawDecimal) { |
2829 | break; | |
2830 | } | |
729e4ab9 | 2831 | |
46f4442e | 2832 | if (strictParse) { |
729e4ab9 A |
2833 | if ( (!sawDigit && groupingSet!=NULL && u_isWhitespace(ch)) || backup != -1 ) { |
2834 | // We differ from the ICU4J code by allowing a leading group sep in strict mode (for | |
2835 | // backward compatibility) as long as it is not one of the breaking whitespace characters | |
2836 | // that is only treated as a group separator because of the equivalence set. If we get | |
2837 | // here it is because the leading sep was such a breaking space, or there were multiple | |
2838 | // group separators in a row. Note that the DecimalFormat documentation says | |
2839 | // "During parsing, grouping separators are ignored" and that was for strict parsing, | |
2840 | // so we may need to further revisit this strictParse restriction to ensure compatibility. | |
2841 | // Also note: u_isWhitespace is true for all Zs/Zl/Zp except the no-break ones: 00A0,2007,202F. | |
2842 | // In CLDR, all locales that have space as a group separator use 00A0 (NBSP). | |
46f4442e A |
2843 | strictFail = TRUE; |
2844 | break; | |
2845 | } | |
2846 | } | |
729e4ab9 | 2847 | |
b75a7d8f A |
2848 | // Ignore grouping characters, if we are using them, but require |
2849 | // that they be followed by a digit. Otherwise we backup and | |
2850 | // reprocess them. | |
2851 | backup = position; | |
46f4442e | 2852 | position += groupingStringLength; |
4388f060 A |
2853 | sawGrouping=TRUE; |
2854 | // Once we see a grouping character, we only accept that grouping character from then on. | |
2855 | sawGroupingChar=ch; | |
b75a7d8f | 2856 | } |
4388f060 | 2857 | else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch)) |
b75a7d8f | 2858 | { |
46f4442e A |
2859 | if (strictParse) { |
2860 | if (backup != -1 || | |
2861 | (lastGroup != -1 && position - lastGroup != fGroupingSize + 1)) { | |
2862 | strictFail = TRUE; | |
2863 | break; | |
2864 | } | |
2865 | } | |
729e4ab9 A |
2866 | |
2867 | // If we're only parsing integers, or if we ALREADY saw the | |
b75a7d8f | 2868 | // decimal, then don't parse this one. |
46f4442e | 2869 | if (isParseIntegerOnly() || sawDecimal) { |
4388f060 | 2870 | break; |
46f4442e | 2871 | } |
729e4ab9 A |
2872 | |
2873 | parsedNum.append('.', err); | |
46f4442e | 2874 | position += decimalStringLength; |
b75a7d8f | 2875 | sawDecimal = TRUE; |
4388f060 A |
2876 | // Once we see a decimal character, we only accept that decimal character from then on. |
2877 | sawDecimalChar=ch; | |
2878 | // decimalSet is considered to consist of (ch,ch) | |
b75a7d8f | 2879 | } |
4388f060 | 2880 | else { |
b75a7d8f | 2881 | |
51004dcb | 2882 | if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless.. |
57a6839d | 2883 | isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways |
51004dcb A |
2884 | const UnicodeString *tmp; |
2885 | tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); | |
2886 | // TODO: CASE | |
2887 | if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit | |
b75a7d8f | 2888 | { |
51004dcb A |
2889 | // Parse sign, if present |
2890 | int32_t pos = position + tmp->length(); | |
2891 | char exponentSign = '+'; | |
2892 | ||
2893 | if (pos < textLength) | |
b75a7d8f | 2894 | { |
51004dcb | 2895 | tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
b75a7d8f A |
2896 | if (!text.compare(pos, tmp->length(), *tmp)) |
2897 | { | |
2898 | pos += tmp->length(); | |
b75a7d8f | 2899 | } |
51004dcb A |
2900 | else { |
2901 | tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
2902 | if (!text.compare(pos, tmp->length(), *tmp)) | |
2903 | { | |
2904 | exponentSign = '-'; | |
2905 | pos += tmp->length(); | |
2906 | } | |
2907 | } | |
b75a7d8f | 2908 | } |
b75a7d8f | 2909 | |
51004dcb A |
2910 | UBool sawExponentDigit = FALSE; |
2911 | while (pos < textLength) { | |
2912 | ch = text[(int32_t)pos]; | |
2913 | digit = ch - zero; | |
b75a7d8f | 2914 | |
51004dcb A |
2915 | if (digit < 0 || digit > 9) { |
2916 | digit = u_charDigitValue(ch); | |
2917 | } | |
2918 | if (0 <= digit && digit <= 9) { | |
2919 | if (!sawExponentDigit) { | |
2920 | parsedNum.append('E', err); | |
2921 | parsedNum.append(exponentSign, err); | |
2922 | sawExponentDigit = TRUE; | |
2923 | } | |
2924 | ++pos; | |
2925 | parsedNum.append((char)(digit + '0'), err); | |
2926 | } else { | |
2927 | break; | |
729e4ab9 | 2928 | } |
b75a7d8f | 2929 | } |
b75a7d8f | 2930 | |
51004dcb A |
2931 | if (sawExponentDigit) { |
2932 | position = pos; // Advance past the exponent | |
2933 | } | |
b75a7d8f | 2934 | |
51004dcb A |
2935 | break; // Whether we fail or succeed, we exit this loop |
2936 | } else { | |
2937 | break; | |
2938 | } | |
2939 | } else { // not parsing exponent | |
b75a7d8f | 2940 | break; |
51004dcb | 2941 | } |
b75a7d8f A |
2942 | } |
2943 | } | |
729e4ab9 | 2944 | |
b331163b A |
2945 | // if we didn't see a decimal and it is required, check to see if the pattern had one |
2946 | if(!sawDecimal && isDecimalPatternMatchRequired()) | |
2947 | { | |
2948 | if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) | |
2949 | { | |
2950 | parsePosition.setIndex(oldStart); | |
2951 | parsePosition.setErrorIndex(position); | |
2952 | debug("decimal point match required fail!"); | |
2953 | return FALSE; | |
2954 | } | |
2955 | } | |
2956 | ||
b75a7d8f A |
2957 | if (backup != -1) |
2958 | { | |
2959 | position = backup; | |
2960 | } | |
2961 | ||
46f4442e A |
2962 | if (strictParse && !sawDecimal) { |
2963 | if (lastGroup != -1 && position - lastGroup != fGroupingSize + 1) { | |
2964 | strictFail = TRUE; | |
2965 | } | |
2966 | } | |
46f4442e A |
2967 | |
2968 | if (strictFail) { | |
4388f060 | 2969 | // only set with strictParse and a grouping separator error |
729e4ab9 | 2970 | |
46f4442e A |
2971 | parsePosition.setIndex(oldStart); |
2972 | parsePosition.setErrorIndex(position); | |
51004dcb | 2973 | debug("strictFail!"); |
46f4442e A |
2974 | return FALSE; |
2975 | } | |
729e4ab9 | 2976 | |
b75a7d8f | 2977 | // If there was no decimal point we have an integer |
b75a7d8f A |
2978 | |
2979 | // If none of the text string was recognized. For example, parse | |
2980 | // "x" with pattern "#0.00" (return index and error index both 0) | |
2981 | // parse "$" with pattern "$#0.00". (return index 0 and error index | |
2982 | // 1). | |
2983 | if (!sawDigit && digitCount == 0) { | |
51004dcb A |
2984 | #ifdef FMT_DEBUG |
2985 | debug("none of text rec"); | |
2986 | printf("position=%d\n",position); | |
2987 | #endif | |
b75a7d8f A |
2988 | parsePosition.setIndex(oldStart); |
2989 | parsePosition.setErrorIndex(oldStart); | |
2990 | return FALSE; | |
2991 | } | |
2992 | } | |
2993 | ||
2994 | // Match padding before suffix | |
2995 | if (fFormatWidth > 0 && fPadPosition == kPadBeforeSuffix) { | |
2996 | position = skipPadding(text, position); | |
2997 | } | |
2998 | ||
46f4442e | 2999 | int32_t posSuffixMatch = -1, negSuffixMatch = -1; |
729e4ab9 | 3000 | |
b75a7d8f | 3001 | // Match positive and negative suffixes; prefer longest match. |
46f4442e | 3002 | if (posMatch >= 0 || (!strictParse && negMatch < 0)) { |
57a6839d | 3003 | posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency); |
b75a7d8f A |
3004 | } |
3005 | if (negMatch >= 0) { | |
57a6839d | 3006 | negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency); |
b75a7d8f | 3007 | } |
46f4442e A |
3008 | if (posSuffixMatch >= 0 && negSuffixMatch >= 0) { |
3009 | if (posSuffixMatch > negSuffixMatch) { | |
4388f060 | 3010 | negSuffixMatch = -1; |
46f4442e | 3011 | } else if (negSuffixMatch > posSuffixMatch) { |
4388f060 | 3012 | posSuffixMatch = -1; |
729e4ab9 | 3013 | } |
b75a7d8f A |
3014 | } |
3015 | ||
3016 | // Fail if neither or both | |
46f4442e | 3017 | if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) { |
b75a7d8f | 3018 | parsePosition.setErrorIndex(position); |
51004dcb | 3019 | debug("neither or both"); |
b75a7d8f A |
3020 | return FALSE; |
3021 | } | |
3022 | ||
729e4ab9 | 3023 | position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0)); |
b75a7d8f A |
3024 | |
3025 | // Match padding before suffix | |
3026 | if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) { | |
3027 | position = skipPadding(text, position); | |
3028 | } | |
3029 | ||
3030 | parsePosition.setIndex(position); | |
3031 | ||
729e4ab9 | 3032 | parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-'; |
51004dcb A |
3033 | #ifdef FMT_DEBUG |
3034 | printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err)); | |
3035 | #endif | |
3036 | } /* end SLOW parse */ | |
3037 | if(parsePosition.getIndex() == oldStart) | |
3038 | { | |
3039 | #ifdef FMT_DEBUG | |
3040 | printf(" PP didnt move, err\n"); | |
3041 | #endif | |
3042 | parsePosition.setErrorIndex(position); | |
3043 | return FALSE; | |
3044 | } | |
3045 | #if UCONFIG_HAVE_PARSEALLINPUT | |
3046 | else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength) | |
b75a7d8f | 3047 | { |
51004dcb A |
3048 | #ifdef FMT_DEBUG |
3049 | printf(" PP didnt consume all (UNUM_YES), err\n"); | |
3050 | #endif | |
b75a7d8f A |
3051 | parsePosition.setErrorIndex(position); |
3052 | return FALSE; | |
3053 | } | |
51004dcb A |
3054 | #endif |
3055 | // uint32_t bits = (fastParseOk?kFastpathOk:0) | | |
3056 | // (fastParseHadDecimal?0:kNoDecimal); | |
3057 | //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits); | |
3058 | digits.set(parsedNum.toStringPiece(), | |
3059 | err, | |
3060 | 0//bits | |
3061 | ); | |
729e4ab9 A |
3062 | |
3063 | if (U_FAILURE(err)) { | |
51004dcb A |
3064 | #ifdef FMT_DEBUG |
3065 | printf(" err setting %s\n", u_errorName(err)); | |
3066 | #endif | |
729e4ab9 A |
3067 | parsePosition.setErrorIndex(position); |
3068 | return FALSE; | |
3069 | } | |
b331163b A |
3070 | |
3071 | // check if we missed a required decimal point | |
3072 | if(fastParseOk && isDecimalPatternMatchRequired()) | |
3073 | { | |
3074 | if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) | |
3075 | { | |
3076 | parsePosition.setIndex(oldStart); | |
3077 | parsePosition.setErrorIndex(position); | |
3078 | debug("decimal point match required fail!"); | |
3079 | return FALSE; | |
3080 | } | |
3081 | } | |
3082 | ||
3083 | ||
b75a7d8f A |
3084 | return TRUE; |
3085 | } | |
3086 | ||
3087 | /** | |
3088 | * Starting at position, advance past a run of pad characters, if any. | |
3089 | * Return the index of the first character after position that is not a pad | |
3090 | * character. Result is >= position. | |
3091 | */ | |
3092 | int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const { | |
3093 | int32_t padLen = U16_LENGTH(fPad); | |
3094 | while (position < text.length() && | |
3095 | text.char32At(position) == fPad) { | |
3096 | position += padLen; | |
3097 | } | |
3098 | return position; | |
3099 | } | |
3100 | ||
3101 | /** | |
3102 | * Return the length matched by the given affix, or -1 if none. | |
3103 | * Runs of white space in the affix, match runs of white space in | |
3104 | * the input. Pattern white space and input white space are | |
3105 | * determined differently; see code. | |
3106 | * @param text input text | |
3107 | * @param pos offset into input at which to begin matching | |
3108 | * @param isNegative | |
3109 | * @param isPrefix | |
729e4ab9 | 3110 | * @param affixPat affix pattern used for currency affix comparison. |
57a6839d | 3111 | * @param complexCurrencyParsing whether it is currency parsing or not |
729e4ab9 | 3112 | * @param type the currency type to parse against, LONG_NAME only or not. |
374ca955 A |
3113 | * @param currency return value for parsed currency, for generic |
3114 | * currency parsing mode, or null for normal parsing. In generic | |
3115 | * currency parsing mode, any currency is parsed, not just the | |
3116 | * currency that this formatter is set to. | |
b75a7d8f A |
3117 | * @return length of input that matches, or -1 if match failure |
3118 | */ | |
3119 | int32_t DecimalFormat::compareAffix(const UnicodeString& text, | |
3120 | int32_t pos, | |
3121 | UBool isNegative, | |
374ca955 | 3122 | UBool isPrefix, |
729e4ab9 | 3123 | const UnicodeString* affixPat, |
57a6839d | 3124 | UBool complexCurrencyParsing, |
729e4ab9 | 3125 | int8_t type, |
46f4442e A |
3126 | UChar* currency) const |
3127 | { | |
3128 | const UnicodeString *patternToCompare; | |
729e4ab9 | 3129 | if (fCurrencyChoice != NULL || currency != NULL || |
57a6839d | 3130 | (fCurrencySignCount != fgCurrencySignCountZero && complexCurrencyParsing)) { |
729e4ab9 A |
3131 | |
3132 | if (affixPat != NULL) { | |
3133 | return compareComplexAffix(*affixPat, text, pos, type, currency); | |
46f4442e | 3134 | } |
b75a7d8f | 3135 | } |
729e4ab9 | 3136 | |
46f4442e A |
3137 | if (isNegative) { |
3138 | if (isPrefix) { | |
3139 | patternToCompare = &fNegativePrefix; | |
3140 | } | |
3141 | else { | |
3142 | patternToCompare = &fNegativeSuffix; | |
3143 | } | |
b75a7d8f | 3144 | } |
46f4442e A |
3145 | else { |
3146 | if (isPrefix) { | |
3147 | patternToCompare = &fPositivePrefix; | |
3148 | } | |
3149 | else { | |
3150 | patternToCompare = &fPositiveSuffix; | |
3151 | } | |
3152 | } | |
4388f060 | 3153 | return compareSimpleAffix(*patternToCompare, text, pos, isLenient()); |
b75a7d8f A |
3154 | } |
3155 | ||
57a6839d A |
3156 | UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const { |
3157 | if (lhs == rhs) { | |
3158 | return TRUE; | |
3159 | } | |
3160 | U_ASSERT(fStaticSets != NULL); // should already be loaded | |
3161 | const UnicodeSet *minusSigns = fStaticSets->fMinusSigns; | |
3162 | const UnicodeSet *plusSigns = fStaticSets->fPlusSigns; | |
3163 | return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) || | |
3164 | (plusSigns->contains(lhs) && plusSigns->contains(rhs)); | |
3165 | } | |
3166 | ||
3167 | // check for LRM 0x200E, RLM 0x200F, ALM 0x061C | |
3168 | #define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C) | |
3169 | ||
3170 | #define TRIM_BUFLEN 32 | |
3171 | UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) { | |
3172 | UChar trimBuf[TRIM_BUFLEN]; | |
3173 | int32_t affixLen = affix.length(); | |
3174 | int32_t affixPos, trimLen = 0; | |
3175 | ||
3176 | for (affixPos = 0; affixPos < affixLen; affixPos++) { | |
3177 | UChar c = affix.charAt(affixPos); | |
3178 | if (!IS_BIDI_MARK(c)) { | |
3179 | if (trimLen < TRIM_BUFLEN) { | |
3180 | trimBuf[trimLen++] = c; | |
3181 | } else { | |
3182 | trimLen = 0; | |
3183 | break; | |
3184 | } | |
3185 | } | |
3186 | } | |
3187 | return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix); | |
3188 | } | |
3189 | ||
b75a7d8f A |
3190 | /** |
3191 | * Return the length matched by the given affix, or -1 if none. | |
3192 | * Runs of white space in the affix, match runs of white space in | |
3193 | * the input. Pattern white space and input white space are | |
3194 | * determined differently; see code. | |
3195 | * @param affix pattern string, taken as a literal | |
3196 | * @param input input text | |
3197 | * @param pos offset into input at which to begin matching | |
3198 | * @return length of input that matches, or -1 if match failure | |
3199 | */ | |
3200 | int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, | |
3201 | const UnicodeString& input, | |
46f4442e | 3202 | int32_t pos, |
57a6839d | 3203 | UBool lenient) const { |
b75a7d8f | 3204 | int32_t start = pos; |
57a6839d A |
3205 | UnicodeString trimmedAffix; |
3206 | // For more efficiency we should keep lazily-created trimmed affixes around in | |
3207 | // instance variables instead of trimming each time they are used (the next step) | |
3208 | trimMarksFromAffix(affix, trimmedAffix); | |
3209 | UChar32 affixChar = trimmedAffix.char32At(0); | |
3210 | int32_t affixLength = trimmedAffix.length(); | |
7393aa2f A |
3211 | int32_t inputLength = input.length(); |
3212 | int32_t affixCharLength = U16_LENGTH(affixChar); | |
3213 | UnicodeSet *affixSet; | |
57a6839d A |
3214 | UErrorCode status = U_ZERO_ERROR; |
3215 | ||
3216 | U_ASSERT(fStaticSets != NULL); // should already be loaded | |
729e4ab9 | 3217 | |
57a6839d A |
3218 | if (U_FAILURE(status)) { |
3219 | return -1; | |
3220 | } | |
4388f060 | 3221 | if (!lenient) { |
57a6839d A |
3222 | affixSet = fStaticSets->fStrictDashEquivalents; |
3223 | ||
3224 | // If the trimmedAffix is exactly one character long and that character | |
7393aa2f A |
3225 | // is in the dash set and the very next input character is also |
3226 | // in the dash set, return a match. | |
3227 | if (affixCharLength == affixLength && affixSet->contains(affixChar)) { | |
57a6839d A |
3228 | UChar32 ic = input.char32At(pos); |
3229 | if (affixSet->contains(ic)) { | |
3230 | pos += U16_LENGTH(ic); | |
3231 | pos = skipBidiMarks(input, pos); // skip any trailing bidi marks | |
3232 | return pos - start; | |
7393aa2f A |
3233 | } |
3234 | } | |
729e4ab9 | 3235 | |
4388f060 | 3236 | for (int32_t i = 0; i < affixLength; ) { |
57a6839d | 3237 | UChar32 c = trimmedAffix.char32At(i); |
4388f060 A |
3238 | int32_t len = U16_LENGTH(c); |
3239 | if (PatternProps::isWhiteSpace(c)) { | |
3240 | // We may have a pattern like: \u200F \u0020 | |
3241 | // and input text like: \u200F \u0020 | |
3242 | // Note that U+200F and U+0020 are Pattern_White_Space but only | |
3243 | // U+0020 is UWhiteSpace. So we have to first do a direct | |
3244 | // match of the run of Pattern_White_Space in the pattern, | |
3245 | // then match any extra characters. | |
3246 | UBool literalMatch = FALSE; | |
57a6839d A |
3247 | while (pos < inputLength) { |
3248 | UChar32 ic = input.char32At(pos); | |
3249 | if (ic == c) { | |
3250 | literalMatch = TRUE; | |
3251 | i += len; | |
3252 | pos += len; | |
3253 | if (i == affixLength) { | |
3254 | break; | |
3255 | } | |
3256 | c = trimmedAffix.char32At(i); | |
3257 | len = U16_LENGTH(c); | |
3258 | if (!PatternProps::isWhiteSpace(c)) { | |
3259 | break; | |
3260 | } | |
3261 | } else if (IS_BIDI_MARK(ic)) { | |
3262 | pos ++; // just skip over this input text | |
3263 | } else { | |
4388f060 A |
3264 | break; |
3265 | } | |
3266 | } | |
3267 | ||
3268 | // Advance over run in pattern | |
57a6839d | 3269 | i = skipPatternWhiteSpace(trimmedAffix, i); |
4388f060 A |
3270 | |
3271 | // Advance over run in input text | |
3272 | // Must see at least one white space char in input, | |
57a6839d | 3273 | // unless we've already matched some characters literally. |
4388f060 A |
3274 | int32_t s = pos; |
3275 | pos = skipUWhiteSpace(input, pos); | |
57a6839d | 3276 | if (pos == s && !literalMatch) { |
4388f060 A |
3277 | return -1; |
3278 | } | |
3279 | ||
3280 | // If we skip UWhiteSpace in the input text, we need to skip it in the pattern. | |
3281 | // Otherwise, the previous lines may have skipped over text (such as U+00A0) that | |
57a6839d A |
3282 | // is also in the trimmedAffix. |
3283 | i = skipUWhiteSpace(trimmedAffix, i); | |
4388f060 | 3284 | } else { |
57a6839d A |
3285 | UBool match = FALSE; |
3286 | while (pos < inputLength) { | |
3287 | UChar32 ic = input.char32At(pos); | |
3288 | if (!match && ic == c) { | |
3289 | i += len; | |
3290 | pos += len; | |
3291 | match = TRUE; | |
3292 | } else if (IS_BIDI_MARK(ic)) { | |
3293 | pos++; // just skip over this input text | |
3294 | } else { | |
3295 | break; | |
3296 | } | |
3297 | } | |
3298 | if (!match) { | |
4388f060 A |
3299 | return -1; |
3300 | } | |
3301 | } | |
3302 | } | |
729e4ab9 | 3303 | } else { |
4388f060 | 3304 | UBool match = FALSE; |
57a6839d A |
3305 | |
3306 | affixSet = fStaticSets->fDashEquivalents; | |
729e4ab9 | 3307 | |
7393aa2f | 3308 | if (affixCharLength == affixLength && affixSet->contains(affixChar)) { |
57a6839d A |
3309 | pos = skipUWhiteSpaceAndMarks(input, pos); |
3310 | UChar32 ic = input.char32At(pos); | |
3311 | ||
3312 | if (affixSet->contains(ic)) { | |
3313 | pos += U16_LENGTH(ic); | |
3314 | pos = skipBidiMarks(input, pos); | |
3315 | return pos - start; | |
7393aa2f A |
3316 | } |
3317 | } | |
729e4ab9 | 3318 | |
4388f060 A |
3319 | for (int32_t i = 0; i < affixLength; ) |
3320 | { | |
57a6839d A |
3321 | //i = skipRuleWhiteSpace(trimmedAffix, i); |
3322 | i = skipUWhiteSpace(trimmedAffix, i); | |
3323 | pos = skipUWhiteSpaceAndMarks(input, pos); | |
729e4ab9 | 3324 | |
4388f060 A |
3325 | if (i >= affixLength || pos >= inputLength) { |
3326 | break; | |
3327 | } | |
729e4ab9 | 3328 | |
57a6839d A |
3329 | UChar32 c = trimmedAffix.char32At(i); |
3330 | UChar32 ic = input.char32At(pos); | |
729e4ab9 | 3331 | |
57a6839d | 3332 | if (!equalWithSignCompatibility(ic, c)) { |
4388f060 A |
3333 | return -1; |
3334 | } | |
729e4ab9 | 3335 | |
4388f060 | 3336 | match = TRUE; |
57a6839d A |
3337 | i += U16_LENGTH(c); |
3338 | pos += U16_LENGTH(ic); | |
3339 | pos = skipBidiMarks(input, pos); | |
4388f060 | 3340 | } |
729e4ab9 | 3341 | |
4388f060 A |
3342 | if (affixLength > 0 && ! match) { |
3343 | return -1; | |
3344 | } | |
729e4ab9 | 3345 | } |
b75a7d8f A |
3346 | return pos - start; |
3347 | } | |
3348 | ||
3349 | /** | |
4388f060 | 3350 | * Skip over a run of zero or more Pattern_White_Space characters at |
b75a7d8f A |
3351 | * pos in text. |
3352 | */ | |
4388f060 A |
3353 | int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) { |
3354 | const UChar* s = text.getBuffer(); | |
3355 | return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s); | |
b75a7d8f A |
3356 | } |
3357 | ||
3358 | /** | |
3359 | * Skip over a run of zero or more isUWhiteSpace() characters at pos | |
3360 | * in text. | |
3361 | */ | |
3362 | int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) { | |
3363 | while (pos < text.length()) { | |
3364 | UChar32 c = text.char32At(pos); | |
57a6839d | 3365 | if (!u_isUWhiteSpace(c)) { |
b75a7d8f A |
3366 | break; |
3367 | } | |
3368 | pos += U16_LENGTH(c); | |
3369 | } | |
3370 | return pos; | |
3371 | } | |
3372 | ||
57a6839d A |
3373 | /** |
3374 | * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos | |
3375 | * in text. | |
3376 | */ | |
3377 | int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) { | |
3378 | while (pos < text.length()) { | |
3379 | UChar32 c = text.char32At(pos); | |
3380 | if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM | |
3381 | break; | |
3382 | } | |
3383 | pos += U16_LENGTH(c); | |
3384 | } | |
3385 | return pos; | |
3386 | } | |
3387 | ||
3388 | /** | |
3389 | * Skip over a run of zero or more bidi marks at pos in text. | |
3390 | */ | |
3391 | int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) { | |
3392 | while (pos < text.length()) { | |
3393 | UChar c = text.charAt(pos); | |
3394 | if (!IS_BIDI_MARK(c)) { | |
3395 | break; | |
3396 | } | |
3397 | pos++; | |
3398 | } | |
3399 | return pos; | |
3400 | } | |
3401 | ||
b75a7d8f A |
3402 | /** |
3403 | * Return the length matched by the given affix, or -1 if none. | |
3404 | * @param affixPat pattern string | |
3405 | * @param input input text | |
3406 | * @param pos offset into input at which to begin matching | |
729e4ab9 | 3407 | * @param type the currency type to parse against, LONG_NAME only or not. |
374ca955 A |
3408 | * @param currency return value for parsed currency, for generic |
3409 | * currency parsing mode, or null for normal parsing. In generic | |
3410 | * currency parsing mode, any currency is parsed, not just the | |
3411 | * currency that this formatter is set to. | |
b75a7d8f A |
3412 | * @return length of input that matches, or -1 if match failure |
3413 | */ | |
3414 | int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, | |
3415 | const UnicodeString& text, | |
374ca955 | 3416 | int32_t pos, |
729e4ab9 | 3417 | int8_t type, |
73c04bcf A |
3418 | UChar* currency) const |
3419 | { | |
3420 | int32_t start = pos; | |
374ca955 | 3421 | U_ASSERT(currency != NULL || |
729e4ab9 | 3422 | (fCurrencyChoice != NULL && *getCurrency() != 0) || |
57a6839d | 3423 | fCurrencySignCount != fgCurrencySignCountZero); |
b75a7d8f | 3424 | |
729e4ab9 A |
3425 | for (int32_t i=0; |
3426 | i<affixPat.length() && pos >= 0; ) { | |
b75a7d8f A |
3427 | UChar32 c = affixPat.char32At(i); |
3428 | i += U16_LENGTH(c); | |
3429 | ||
3430 | if (c == kQuote) { | |
3431 | U_ASSERT(i <= affixPat.length()); | |
3432 | c = affixPat.char32At(i); | |
3433 | i += U16_LENGTH(c); | |
3434 | ||
3435 | const UnicodeString* affix = NULL; | |
3436 | ||
3437 | switch (c) { | |
3438 | case kCurrencySign: { | |
729e4ab9 A |
3439 | // since the currency names in choice format is saved |
3440 | // the same way as other currency names, | |
3441 | // do not need to do currency choice parsing here. | |
3442 | // the general currency parsing parse against all names, | |
3443 | // including names in choice format. | |
b75a7d8f A |
3444 | UBool intl = i<affixPat.length() && |
3445 | affixPat.char32At(i) == kCurrencySign; | |
729e4ab9 A |
3446 | if (intl) { |
3447 | ++i; | |
3448 | } | |
3449 | UBool plural = i<affixPat.length() && | |
3450 | affixPat.char32At(i) == kCurrencySign; | |
3451 | if (plural) { | |
3452 | ++i; | |
3453 | intl = FALSE; | |
3454 | } | |
374ca955 A |
3455 | // Parse generic currency -- anything for which we |
3456 | // have a display name, or any 3-letter ISO code. | |
729e4ab9 A |
3457 | // Try to parse display name for our locale; first |
3458 | // determine our locale. | |
3459 | const char* loc = fCurrencyPluralInfo->getLocale().getName(); | |
3460 | ParsePosition ppos(pos); | |
3461 | UChar curr[4]; | |
3462 | UErrorCode ec = U_ZERO_ERROR; | |
3463 | // Delegate parse of display name => ISO code to Currency | |
3464 | uprv_parseCurrency(loc, text, ppos, type, curr, ec); | |
3465 | ||
3466 | // If parse succeeds, populate currency[0] | |
3467 | if (U_SUCCESS(ec) && ppos.getIndex() != pos) { | |
3468 | if (currency) { | |
374ca955 | 3469 | u_strcpy(currency, curr); |
4388f060 | 3470 | } else { |
729e4ab9 A |
3471 | // The formatter is currency-style but the client has not requested |
3472 | // the value of the parsed currency. In this case, if that value does | |
3473 | // not match the formatter's current value, then the parse fails. | |
3474 | UChar effectiveCurr[4]; | |
3475 | getEffectiveCurrency(effectiveCurr, ec); | |
4388f060 | 3476 | if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) { |
57a6839d A |
3477 | pos = -1; |
3478 | continue; | |
729e4ab9 | 3479 | } |
374ca955 | 3480 | } |
729e4ab9 | 3481 | pos = ppos.getIndex(); |
4388f060 | 3482 | } else if (!isLenient()){ |
729e4ab9 | 3483 | pos = -1; |
b75a7d8f A |
3484 | } |
3485 | continue; | |
3486 | } | |
3487 | case kPatternPercent: | |
3488 | affix = &getConstSymbol(DecimalFormatSymbols::kPercentSymbol); | |
3489 | break; | |
3490 | case kPatternPerMill: | |
3491 | affix = &getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); | |
3492 | break; | |
3493 | case kPatternPlus: | |
3494 | affix = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); | |
3495 | break; | |
3496 | case kPatternMinus: | |
3497 | affix = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
3498 | break; | |
3499 | default: | |
3500 | // fall through to affix!=0 test, which will fail | |
3501 | break; | |
3502 | } | |
3503 | ||
3504 | if (affix != NULL) { | |
3505 | pos = match(text, pos, *affix); | |
3506 | continue; | |
3507 | } | |
3508 | } | |
3509 | ||
3510 | pos = match(text, pos, c); | |
4388f060 A |
3511 | if (PatternProps::isWhiteSpace(c)) { |
3512 | i = skipPatternWhiteSpace(affixPat, i); | |
b75a7d8f A |
3513 | } |
3514 | } | |
73c04bcf | 3515 | return pos - start; |
b75a7d8f A |
3516 | } |
3517 | ||
3518 | /** | |
3519 | * Match a single character at text[pos] and return the index of the | |
3520 | * next character upon success. Return -1 on failure. If | |
4388f060 | 3521 | * ch is a Pattern_White_Space then match a run of white space in text. |
b75a7d8f A |
3522 | */ |
3523 | int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) { | |
4388f060 | 3524 | if (PatternProps::isWhiteSpace(ch)) { |
b75a7d8f A |
3525 | // Advance over run of white space in input text |
3526 | // Must see at least one white space char in input | |
3527 | int32_t s = pos; | |
4388f060 | 3528 | pos = skipPatternWhiteSpace(text, pos); |
b75a7d8f A |
3529 | if (pos == s) { |
3530 | return -1; | |
3531 | } | |
3532 | return pos; | |
3533 | } | |
3534 | return (pos >= 0 && text.char32At(pos) == ch) ? | |
3535 | (pos + U16_LENGTH(ch)) : -1; | |
3536 | } | |
3537 | ||
3538 | /** | |
3539 | * Match a string at text[pos] and return the index of the next | |
3540 | * character upon success. Return -1 on failure. Match a run of | |
3541 | * white space in str with a run of white space in text. | |
3542 | */ | |
3543 | int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) { | |
3544 | for (int32_t i=0; i<str.length() && pos >= 0; ) { | |
3545 | UChar32 ch = str.char32At(i); | |
3546 | i += U16_LENGTH(ch); | |
4388f060 A |
3547 | if (PatternProps::isWhiteSpace(ch)) { |
3548 | i = skipPatternWhiteSpace(str, i); | |
b75a7d8f A |
3549 | } |
3550 | pos = match(text, pos, ch); | |
3551 | } | |
3552 | return pos; | |
3553 | } | |
3554 | ||
46f4442e | 3555 | UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol, |
729e4ab9 | 3556 | UnicodeSet *sset, UChar32 schar) |
46f4442e | 3557 | { |
4388f060 A |
3558 | if (sset != NULL) { |
3559 | return sset->contains(schar); | |
3560 | } | |
729e4ab9 | 3561 | |
4388f060 | 3562 | return text.compare(position, length, symbol) == 0; |
46f4442e A |
3563 | } |
3564 | ||
4388f060 A |
3565 | UBool DecimalFormat::matchDecimal(UChar32 symbolChar, |
3566 | UBool sawDecimal, UChar32 sawDecimalChar, | |
3567 | const UnicodeSet *sset, UChar32 schar) { | |
3568 | if(sawDecimal) { | |
3569 | return schar==sawDecimalChar; | |
3570 | } else if(schar==symbolChar) { | |
3571 | return TRUE; | |
3572 | } else if(sset!=NULL) { | |
3573 | return sset->contains(schar); | |
3574 | } else { | |
3575 | return FALSE; | |
3576 | } | |
3577 | } | |
3578 | ||
3579 | UBool DecimalFormat::matchGrouping(UChar32 groupingChar, | |
3580 | UBool sawGrouping, UChar32 sawGroupingChar, | |
3581 | const UnicodeSet *sset, | |
3582 | UChar32 /*decimalChar*/, const UnicodeSet *decimalSet, | |
3583 | UChar32 schar) { | |
3584 | if(sawGrouping) { | |
3585 | return schar==sawGroupingChar; // previously found | |
3586 | } else if(schar==groupingChar) { | |
3587 | return TRUE; // char from symbols | |
3588 | } else if(sset!=NULL) { | |
3589 | return sset->contains(schar) && // in groupingSet but... | |
3590 | ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet | |
3591 | } else { | |
3592 | return FALSE; | |
3593 | } | |
3594 | } | |
3595 | ||
3596 | ||
729e4ab9 | 3597 | |
b75a7d8f A |
3598 | //------------------------------------------------------------------------------ |
3599 | // Gets the pointer to the localized decimal format symbols | |
3600 | ||
3601 | const DecimalFormatSymbols* | |
3602 | DecimalFormat::getDecimalFormatSymbols() const | |
3603 | { | |
3604 | return fSymbols; | |
3605 | } | |
3606 | ||
3607 | //------------------------------------------------------------------------------ | |
3608 | // De-owning the current localized symbols and adopt the new symbols. | |
3609 | ||
3610 | void | |
3611 | DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) | |
3612 | { | |
374ca955 A |
3613 | if (symbolsToAdopt == NULL) { |
3614 | return; // do not allow caller to set fSymbols to NULL | |
3615 | } | |
3616 | ||
3617 | UBool sameSymbols = FALSE; | |
3618 | if (fSymbols != NULL) { | |
3619 | sameSymbols = (UBool)(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) == | |
3620 | symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) && | |
3621 | getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == | |
3622 | symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); | |
b75a7d8f | 3623 | delete fSymbols; |
374ca955 | 3624 | } |
b75a7d8f A |
3625 | |
3626 | fSymbols = symbolsToAdopt; | |
374ca955 A |
3627 | if (!sameSymbols) { |
3628 | // If the currency symbols are the same, there is no need to recalculate. | |
3629 | setCurrencyForSymbols(); | |
3630 | } | |
729e4ab9 | 3631 | expandAffixes(NULL); |
51004dcb A |
3632 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3633 | handleChanged(); | |
3634 | #endif | |
b75a7d8f A |
3635 | } |
3636 | //------------------------------------------------------------------------------ | |
3637 | // Setting the symbols is equlivalent to adopting a newly created localized | |
3638 | // symbols. | |
3639 | ||
3640 | void | |
3641 | DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) | |
3642 | { | |
3643 | adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); | |
51004dcb A |
3644 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3645 | handleChanged(); | |
3646 | #endif | |
b75a7d8f | 3647 | } |
729e4ab9 | 3648 | |
4388f060 | 3649 | |
729e4ab9 A |
3650 | const CurrencyPluralInfo* |
3651 | DecimalFormat::getCurrencyPluralInfo(void) const | |
3652 | { | |
3653 | return fCurrencyPluralInfo; | |
3654 | } | |
3655 | ||
4388f060 | 3656 | |
729e4ab9 A |
3657 | void |
3658 | DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) | |
3659 | { | |
3660 | if (toAdopt != NULL) { | |
3661 | delete fCurrencyPluralInfo; | |
3662 | fCurrencyPluralInfo = toAdopt; | |
3663 | // re-set currency affix patterns and currency affixes. | |
57a6839d | 3664 | if (fCurrencySignCount != fgCurrencySignCountZero) { |
729e4ab9 A |
3665 | UErrorCode status = U_ZERO_ERROR; |
3666 | if (fAffixPatternsForCurrency) { | |
3667 | deleteHashForAffixPattern(); | |
3668 | } | |
3669 | setupCurrencyAffixPatterns(status); | |
3670 | if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) { | |
3671 | // only setup the affixes of the plural pattern. | |
3672 | setupCurrencyAffixes(fFormatPattern, FALSE, TRUE, status); | |
3673 | } | |
3674 | } | |
3675 | } | |
51004dcb A |
3676 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3677 | handleChanged(); | |
3678 | #endif | |
729e4ab9 A |
3679 | } |
3680 | ||
3681 | void | |
3682 | DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) | |
3683 | { | |
3684 | adoptCurrencyPluralInfo(info.clone()); | |
51004dcb A |
3685 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3686 | handleChanged(); | |
3687 | #endif | |
729e4ab9 A |
3688 | } |
3689 | ||
3690 | ||
b75a7d8f A |
3691 | /** |
3692 | * Update the currency object to match the symbols. This method | |
3693 | * is used only when the caller has passed in a symbols object | |
3694 | * that may not be the default object for its locale. | |
3695 | */ | |
3696 | void | |
3697 | DecimalFormat::setCurrencyForSymbols() { | |
3698 | /*Bug 4212072 | |
3699 | Update the affix strings accroding to symbols in order to keep | |
3700 | the affix strings up to date. | |
3701 | [Richard/GCL] | |
3702 | */ | |
3703 | ||
3704 | // With the introduction of the Currency object, the currency | |
3705 | // symbols in the DFS object are ignored. For backward | |
3706 | // compatibility, we check any explicitly set DFS object. If it | |
3707 | // is a default symbols object for its locale, we change the | |
3708 | // currency object to one for that locale. If it is custom, | |
3709 | // we set the currency to null. | |
3710 | UErrorCode ec = U_ZERO_ERROR; | |
374ca955 A |
3711 | const UChar* c = NULL; |
3712 | const char* loc = fSymbols->getLocale().getName(); | |
729e4ab9 | 3713 | UChar intlCurrencySymbol[4]; |
374ca955 A |
3714 | ucurr_forLocale(loc, intlCurrencySymbol, 4, &ec); |
3715 | UnicodeString currencySymbol; | |
3716 | ||
3717 | uprv_getStaticCurrencyName(intlCurrencySymbol, loc, currencySymbol, ec); | |
3718 | if (U_SUCCESS(ec) | |
3719 | && getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) == currencySymbol | |
4388f060 | 3720 | && getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == UnicodeString(intlCurrencySymbol)) |
374ca955 A |
3721 | { |
3722 | // Trap an error in mapping locale to currency. If we can't | |
3723 | // map, then don't fail and set the currency to "". | |
3724 | c = intlCurrencySymbol; | |
b75a7d8f | 3725 | } |
374ca955 | 3726 | ec = U_ZERO_ERROR; // reset local error code! |
729e4ab9 | 3727 | setCurrencyInternally(c, ec); |
51004dcb A |
3728 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3729 | handleChanged(); | |
3730 | #endif | |
b75a7d8f A |
3731 | } |
3732 | ||
3733 | ||
3734 | //------------------------------------------------------------------------------ | |
3735 | // Gets the positive prefix of the number pattern. | |
729e4ab9 | 3736 | |
b75a7d8f A |
3737 | UnicodeString& |
3738 | DecimalFormat::getPositivePrefix(UnicodeString& result) const | |
3739 | { | |
3740 | result = fPositivePrefix; | |
3741 | return result; | |
3742 | } | |
729e4ab9 | 3743 | |
b75a7d8f A |
3744 | //------------------------------------------------------------------------------ |
3745 | // Sets the positive prefix of the number pattern. | |
729e4ab9 | 3746 | |
b75a7d8f A |
3747 | void |
3748 | DecimalFormat::setPositivePrefix(const UnicodeString& newValue) | |
3749 | { | |
3750 | fPositivePrefix = newValue; | |
3751 | delete fPosPrefixPattern; | |
3752 | fPosPrefixPattern = 0; | |
51004dcb A |
3753 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3754 | handleChanged(); | |
3755 | #endif | |
b75a7d8f A |
3756 | } |
3757 | ||
3758 | //------------------------------------------------------------------------------ | |
3759 | // Gets the negative prefix of the number pattern. | |
3760 | ||
3761 | UnicodeString& | |
3762 | DecimalFormat::getNegativePrefix(UnicodeString& result) const | |
3763 | { | |
3764 | result = fNegativePrefix; | |
3765 | return result; | |
3766 | } | |
3767 | ||
3768 | //------------------------------------------------------------------------------ | |
3769 | // Gets the negative prefix of the number pattern. | |
3770 | ||
3771 | void | |
3772 | DecimalFormat::setNegativePrefix(const UnicodeString& newValue) | |
3773 | { | |
3774 | fNegativePrefix = newValue; | |
3775 | delete fNegPrefixPattern; | |
3776 | fNegPrefixPattern = 0; | |
51004dcb A |
3777 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3778 | handleChanged(); | |
3779 | #endif | |
b75a7d8f A |
3780 | } |
3781 | ||
3782 | //------------------------------------------------------------------------------ | |
3783 | // Gets the positive suffix of the number pattern. | |
3784 | ||
3785 | UnicodeString& | |
3786 | DecimalFormat::getPositiveSuffix(UnicodeString& result) const | |
3787 | { | |
3788 | result = fPositiveSuffix; | |
3789 | return result; | |
3790 | } | |
3791 | ||
3792 | //------------------------------------------------------------------------------ | |
3793 | // Sets the positive suffix of the number pattern. | |
3794 | ||
3795 | void | |
3796 | DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) | |
3797 | { | |
3798 | fPositiveSuffix = newValue; | |
3799 | delete fPosSuffixPattern; | |
3800 | fPosSuffixPattern = 0; | |
51004dcb A |
3801 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3802 | handleChanged(); | |
3803 | #endif | |
b75a7d8f A |
3804 | } |
3805 | ||
3806 | //------------------------------------------------------------------------------ | |
3807 | // Gets the negative suffix of the number pattern. | |
3808 | ||
3809 | UnicodeString& | |
3810 | DecimalFormat::getNegativeSuffix(UnicodeString& result) const | |
3811 | { | |
3812 | result = fNegativeSuffix; | |
3813 | return result; | |
3814 | } | |
3815 | ||
3816 | //------------------------------------------------------------------------------ | |
3817 | // Sets the negative suffix of the number pattern. | |
3818 | ||
3819 | void | |
3820 | DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) | |
3821 | { | |
3822 | fNegativeSuffix = newValue; | |
3823 | delete fNegSuffixPattern; | |
3824 | fNegSuffixPattern = 0; | |
51004dcb A |
3825 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3826 | handleChanged(); | |
3827 | #endif | |
b75a7d8f A |
3828 | } |
3829 | ||
3830 | //------------------------------------------------------------------------------ | |
3831 | // Gets the multiplier of the number pattern. | |
729e4ab9 A |
3832 | // Multipliers are stored as decimal numbers (DigitLists) because that |
3833 | // is the most convenient for muliplying or dividing the numbers to be formatted. | |
3834 | // A NULL multiplier implies one, and the scaling operations are skipped. | |
b75a7d8f | 3835 | |
729e4ab9 A |
3836 | int32_t |
3837 | DecimalFormat::getMultiplier() const | |
b75a7d8f | 3838 | { |
729e4ab9 A |
3839 | if (fMultiplier == NULL) { |
3840 | return 1; | |
3841 | } else { | |
3842 | return fMultiplier->getLong(); | |
3843 | } | |
b75a7d8f A |
3844 | } |
3845 | ||
3846 | //------------------------------------------------------------------------------ | |
3847 | // Sets the multiplier of the number pattern. | |
3848 | void | |
3849 | DecimalFormat::setMultiplier(int32_t newValue) | |
3850 | { | |
46f4442e A |
3851 | // if (newValue == 0) { |
3852 | // throw new IllegalArgumentException("Bad multiplier: " + newValue); | |
3853 | // } | |
729e4ab9 A |
3854 | if (newValue == 0) { |
3855 | newValue = 1; // one being the benign default value for a multiplier. | |
3856 | } | |
3857 | if (newValue == 1) { | |
3858 | delete fMultiplier; | |
3859 | fMultiplier = NULL; | |
3860 | } else { | |
3861 | if (fMultiplier == NULL) { | |
3862 | fMultiplier = new DigitList; | |
3863 | } | |
3864 | if (fMultiplier != NULL) { | |
3865 | fMultiplier->set(newValue); | |
3866 | } | |
46f4442e | 3867 | } |
51004dcb A |
3868 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3869 | handleChanged(); | |
3870 | #endif | |
b75a7d8f A |
3871 | } |
3872 | ||
3873 | /** | |
3874 | * Get the rounding increment. | |
3875 | * @return A positive rounding increment, or 0.0 if rounding | |
3876 | * is not in effect. | |
3877 | * @see #setRoundingIncrement | |
3878 | * @see #getRoundingMode | |
3879 | * @see #setRoundingMode | |
3880 | */ | |
374ca955 | 3881 | double DecimalFormat::getRoundingIncrement() const { |
729e4ab9 A |
3882 | if (fRoundingIncrement == NULL) { |
3883 | return 0.0; | |
3884 | } else { | |
3885 | return fRoundingIncrement->getDouble(); | |
3886 | } | |
b75a7d8f A |
3887 | } |
3888 | ||
3889 | /** | |
3890 | * Set the rounding increment. This method also controls whether | |
3891 | * rounding is enabled. | |
3892 | * @param newValue A positive rounding increment, or 0.0 to disable rounding. | |
3893 | * Negative increments are equivalent to 0.0. | |
3894 | * @see #getRoundingIncrement | |
3895 | * @see #getRoundingMode | |
3896 | * @see #setRoundingMode | |
3897 | */ | |
3898 | void DecimalFormat::setRoundingIncrement(double newValue) { | |
3899 | if (newValue > 0.0) { | |
3900 | if (fRoundingIncrement == NULL) { | |
3901 | fRoundingIncrement = new DigitList(); | |
3902 | } | |
46f4442e | 3903 | if (fRoundingIncrement != NULL) { |
729e4ab9 | 3904 | fRoundingIncrement->set(newValue); |
46f4442e A |
3905 | return; |
3906 | } | |
729e4ab9 | 3907 | } |
46f4442e A |
3908 | // These statements are executed if newValue is less than 0.0 |
3909 | // or fRoundingIncrement could not be created. | |
3910 | delete fRoundingIncrement; | |
3911 | fRoundingIncrement = NULL; | |
51004dcb A |
3912 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3913 | handleChanged(); | |
3914 | #endif | |
b75a7d8f A |
3915 | } |
3916 | ||
3917 | /** | |
3918 | * Get the rounding mode. | |
3919 | * @return A rounding mode | |
3920 | * @see #setRoundingIncrement | |
3921 | * @see #getRoundingIncrement | |
3922 | * @see #setRoundingMode | |
3923 | */ | |
374ca955 | 3924 | DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const { |
b75a7d8f A |
3925 | return fRoundingMode; |
3926 | } | |
3927 | ||
3928 | /** | |
3929 | * Set the rounding mode. This has no effect unless the rounding | |
3930 | * increment is greater than zero. | |
3931 | * @param roundingMode A rounding mode | |
3932 | * @see #setRoundingIncrement | |
3933 | * @see #getRoundingIncrement | |
3934 | * @see #getRoundingMode | |
3935 | */ | |
3936 | void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { | |
3937 | fRoundingMode = roundingMode; | |
51004dcb A |
3938 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3939 | handleChanged(); | |
3940 | #endif | |
b75a7d8f A |
3941 | } |
3942 | ||
3943 | /** | |
3944 | * Get the width to which the output of <code>format()</code> is padded. | |
3945 | * @return the format width, or zero if no padding is in effect | |
3946 | * @see #setFormatWidth | |
3947 | * @see #getPadCharacter | |
3948 | * @see #setPadCharacter | |
3949 | * @see #getPadPosition | |
3950 | * @see #setPadPosition | |
3951 | */ | |
374ca955 | 3952 | int32_t DecimalFormat::getFormatWidth() const { |
b75a7d8f A |
3953 | return fFormatWidth; |
3954 | } | |
3955 | ||
3956 | /** | |
3957 | * Set the width to which the output of <code>format()</code> is padded. | |
3958 | * This method also controls whether padding is enabled. | |
3959 | * @param width the width to which to pad the result of | |
3960 | * <code>format()</code>, or zero to disable padding. A negative | |
3961 | * width is equivalent to 0. | |
3962 | * @see #getFormatWidth | |
3963 | * @see #getPadCharacter | |
3964 | * @see #setPadCharacter | |
3965 | * @see #getPadPosition | |
3966 | * @see #setPadPosition | |
3967 | */ | |
3968 | void DecimalFormat::setFormatWidth(int32_t width) { | |
3969 | fFormatWidth = (width > 0) ? width : 0; | |
51004dcb A |
3970 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3971 | handleChanged(); | |
3972 | #endif | |
b75a7d8f A |
3973 | } |
3974 | ||
374ca955 | 3975 | UnicodeString DecimalFormat::getPadCharacterString() const { |
4388f060 | 3976 | return UnicodeString(fPad); |
b75a7d8f A |
3977 | } |
3978 | ||
b75a7d8f A |
3979 | void DecimalFormat::setPadCharacter(const UnicodeString &padChar) { |
3980 | if (padChar.length() > 0) { | |
3981 | fPad = padChar.char32At(0); | |
3982 | } | |
3983 | else { | |
3984 | fPad = kDefaultPad; | |
3985 | } | |
51004dcb A |
3986 | #if UCONFIG_FORMAT_FASTPATHS_49 |
3987 | handleChanged(); | |
3988 | #endif | |
b75a7d8f A |
3989 | } |
3990 | ||
3991 | /** | |
3992 | * Get the position at which padding will take place. This is the location | |
3993 | * at which padding will be inserted if the result of <code>format()</code> | |
3994 | * is shorter than the format width. | |
3995 | * @return the pad position, one of <code>kPadBeforePrefix</code>, | |
3996 | * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or | |
3997 | * <code>kPadAfterSuffix</code>. | |
3998 | * @see #setFormatWidth | |
3999 | * @see #getFormatWidth | |
4000 | * @see #setPadCharacter | |
4001 | * @see #getPadCharacter | |
4002 | * @see #setPadPosition | |
4003 | * @see #kPadBeforePrefix | |
4004 | * @see #kPadAfterPrefix | |
4005 | * @see #kPadBeforeSuffix | |
4006 | * @see #kPadAfterSuffix | |
4007 | */ | |
374ca955 | 4008 | DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const { |
b75a7d8f A |
4009 | return fPadPosition; |
4010 | } | |
4011 | ||
4012 | /** | |
4013 | * <strong><font face=helvetica color=red>NEW</font></strong> | |
4014 | * Set the position at which padding will take place. This is the location | |
4015 | * at which padding will be inserted if the result of <code>format()</code> | |
4016 | * is shorter than the format width. This has no effect unless padding is | |
4017 | * enabled. | |
4018 | * @param padPos the pad position, one of <code>kPadBeforePrefix</code>, | |
4019 | * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or | |
4020 | * <code>kPadAfterSuffix</code>. | |
4021 | * @see #setFormatWidth | |
4022 | * @see #getFormatWidth | |
4023 | * @see #setPadCharacter | |
4024 | * @see #getPadCharacter | |
4025 | * @see #getPadPosition | |
4026 | * @see #kPadBeforePrefix | |
4027 | * @see #kPadAfterPrefix | |
4028 | * @see #kPadBeforeSuffix | |
4029 | * @see #kPadAfterSuffix | |
4030 | */ | |
4031 | void DecimalFormat::setPadPosition(EPadPosition padPos) { | |
4032 | fPadPosition = padPos; | |
51004dcb A |
4033 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4034 | handleChanged(); | |
4035 | #endif | |
b75a7d8f A |
4036 | } |
4037 | ||
4038 | /** | |
4039 | * Return whether or not scientific notation is used. | |
4040 | * @return TRUE if this object formats and parses scientific notation | |
4041 | * @see #setScientificNotation | |
4042 | * @see #getMinimumExponentDigits | |
4043 | * @see #setMinimumExponentDigits | |
4044 | * @see #isExponentSignAlwaysShown | |
4045 | * @see #setExponentSignAlwaysShown | |
4046 | */ | |
57a6839d | 4047 | UBool DecimalFormat::isScientificNotation() const { |
b75a7d8f A |
4048 | return fUseExponentialNotation; |
4049 | } | |
4050 | ||
4051 | /** | |
4052 | * Set whether or not scientific notation is used. | |
4053 | * @param useScientific TRUE if this object formats and parses scientific | |
4054 | * notation | |
4055 | * @see #isScientificNotation | |
4056 | * @see #getMinimumExponentDigits | |
4057 | * @see #setMinimumExponentDigits | |
4058 | * @see #isExponentSignAlwaysShown | |
4059 | * @see #setExponentSignAlwaysShown | |
4060 | */ | |
4061 | void DecimalFormat::setScientificNotation(UBool useScientific) { | |
4062 | fUseExponentialNotation = useScientific; | |
51004dcb A |
4063 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4064 | handleChanged(); | |
4065 | #endif | |
b75a7d8f A |
4066 | } |
4067 | ||
4068 | /** | |
4069 | * Return the minimum exponent digits that will be shown. | |
4070 | * @return the minimum exponent digits that will be shown | |
4071 | * @see #setScientificNotation | |
4072 | * @see #isScientificNotation | |
4073 | * @see #setMinimumExponentDigits | |
4074 | * @see #isExponentSignAlwaysShown | |
4075 | * @see #setExponentSignAlwaysShown | |
4076 | */ | |
374ca955 | 4077 | int8_t DecimalFormat::getMinimumExponentDigits() const { |
b75a7d8f A |
4078 | return fMinExponentDigits; |
4079 | } | |
4080 | ||
4081 | /** | |
4082 | * Set the minimum exponent digits that will be shown. This has no | |
4083 | * effect unless scientific notation is in use. | |
4084 | * @param minExpDig a value >= 1 indicating the fewest exponent digits | |
4085 | * that will be shown. Values less than 1 will be treated as 1. | |
4086 | * @see #setScientificNotation | |
4087 | * @see #isScientificNotation | |
4088 | * @see #getMinimumExponentDigits | |
4089 | * @see #isExponentSignAlwaysShown | |
4090 | * @see #setExponentSignAlwaysShown | |
4091 | */ | |
4092 | void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { | |
4093 | fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1); | |
51004dcb A |
4094 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4095 | handleChanged(); | |
4096 | #endif | |
b75a7d8f A |
4097 | } |
4098 | ||
4099 | /** | |
4100 | * Return whether the exponent sign is always shown. | |
4101 | * @return TRUE if the exponent is always prefixed with either the | |
4102 | * localized minus sign or the localized plus sign, false if only negative | |
4103 | * exponents are prefixed with the localized minus sign. | |
4104 | * @see #setScientificNotation | |
4105 | * @see #isScientificNotation | |
4106 | * @see #setMinimumExponentDigits | |
4107 | * @see #getMinimumExponentDigits | |
4108 | * @see #setExponentSignAlwaysShown | |
4109 | */ | |
57a6839d | 4110 | UBool DecimalFormat::isExponentSignAlwaysShown() const { |
b75a7d8f A |
4111 | return fExponentSignAlwaysShown; |
4112 | } | |
4113 | ||
4114 | /** | |
4115 | * Set whether the exponent sign is always shown. This has no effect | |
4116 | * unless scientific notation is in use. | |
4117 | * @param expSignAlways TRUE if the exponent is always prefixed with either | |
4118 | * the localized minus sign or the localized plus sign, false if only | |
4119 | * negative exponents are prefixed with the localized minus sign. | |
4120 | * @see #setScientificNotation | |
4121 | * @see #isScientificNotation | |
4122 | * @see #setMinimumExponentDigits | |
4123 | * @see #getMinimumExponentDigits | |
4124 | * @see #isExponentSignAlwaysShown | |
4125 | */ | |
4126 | void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { | |
4127 | fExponentSignAlwaysShown = expSignAlways; | |
51004dcb A |
4128 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4129 | handleChanged(); | |
4130 | #endif | |
b75a7d8f A |
4131 | } |
4132 | ||
4133 | //------------------------------------------------------------------------------ | |
4134 | // Gets the grouping size of the number pattern. For example, thousand or 10 | |
4135 | // thousand groupings. | |
729e4ab9 | 4136 | |
b75a7d8f A |
4137 | int32_t |
4138 | DecimalFormat::getGroupingSize() const | |
4139 | { | |
08b89b0a | 4140 | return isGroupingUsed() ? fGroupingSize : 0; |
b75a7d8f | 4141 | } |
729e4ab9 | 4142 | |
b75a7d8f A |
4143 | //------------------------------------------------------------------------------ |
4144 | // Gets the grouping size of the number pattern. | |
729e4ab9 | 4145 | |
b75a7d8f A |
4146 | void |
4147 | DecimalFormat::setGroupingSize(int32_t newValue) | |
4148 | { | |
4149 | fGroupingSize = newValue; | |
51004dcb A |
4150 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4151 | handleChanged(); | |
4152 | #endif | |
b75a7d8f A |
4153 | } |
4154 | ||
4155 | //------------------------------------------------------------------------------ | |
4156 | ||
4157 | int32_t | |
4158 | DecimalFormat::getSecondaryGroupingSize() const | |
4159 | { | |
4160 | return fGroupingSize2; | |
4161 | } | |
4162 | ||
4163 | //------------------------------------------------------------------------------ | |
4164 | ||
4165 | void | |
4166 | DecimalFormat::setSecondaryGroupingSize(int32_t newValue) | |
4167 | { | |
4168 | fGroupingSize2 = newValue; | |
51004dcb A |
4169 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4170 | handleChanged(); | |
4171 | #endif | |
b75a7d8f A |
4172 | } |
4173 | ||
4174 | //------------------------------------------------------------------------------ | |
4175 | // Checks if to show the decimal separator. | |
4176 | ||
4177 | UBool | |
4178 | DecimalFormat::isDecimalSeparatorAlwaysShown() const | |
4179 | { | |
4180 | return fDecimalSeparatorAlwaysShown; | |
4181 | } | |
4182 | ||
4183 | //------------------------------------------------------------------------------ | |
4184 | // Sets to always show the decimal separator. | |
4185 | ||
4186 | void | |
4187 | DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) | |
4188 | { | |
4189 | fDecimalSeparatorAlwaysShown = newValue; | |
51004dcb A |
4190 | #if UCONFIG_FORMAT_FASTPATHS_49 |
4191 | handleChanged(); | |
4192 | #endif | |
b75a7d8f A |
4193 | } |
4194 | ||
b331163b A |
4195 | //------------------------------------------------------------------------------ |
4196 | // Checks if decimal point pattern match is required | |
4197 | UBool | |
4198 | DecimalFormat::isDecimalPatternMatchRequired(void) const | |
4199 | { | |
4200 | return fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED); | |
4201 | } | |
4202 | ||
4203 | //------------------------------------------------------------------------------ | |
4204 | // Checks if decimal point pattern match is required | |
4205 | ||
4206 | void | |
4207 | DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) | |
4208 | { | |
4209 | fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue); | |
4210 | } | |
4211 | ||
4212 | ||
b75a7d8f A |
4213 | //------------------------------------------------------------------------------ |
4214 | // Emits the pattern of this DecimalFormat instance. | |
4215 | ||
4216 | UnicodeString& | |
4217 | DecimalFormat::toPattern(UnicodeString& result) const | |
4218 | { | |
4219 | return toPattern(result, FALSE); | |
4220 | } | |
4221 | ||
4222 | //------------------------------------------------------------------------------ | |
4223 | // Emits the localized pattern this DecimalFormat instance. | |
4224 | ||
4225 | UnicodeString& | |
4226 | DecimalFormat::toLocalizedPattern(UnicodeString& result) const | |
4227 | { | |
4228 | return toPattern(result, TRUE); | |
4229 | } | |
4230 | ||
4231 | //------------------------------------------------------------------------------ | |
4232 | /** | |
4233 | * Expand the affix pattern strings into the expanded affix strings. If any | |
4234 | * affix pattern string is null, do not expand it. This method should be | |
4235 | * called any time the symbols or the affix patterns change in order to keep | |
4236 | * the expanded affix strings up to date. | |
729e4ab9 A |
4237 | * This method also will be called before formatting if format currency |
4238 | * plural names, since the plural name is not a static one, it is | |
4239 | * based on the currency plural count, the affix will be known only | |
4240 | * after the currency plural count is know. | |
4241 | * In which case, the parameter | |
4242 | * 'pluralCount' will be a non-null currency plural count. | |
4243 | * In all other cases, the 'pluralCount' is null, which means it is not needed. | |
b75a7d8f | 4244 | */ |
729e4ab9 A |
4245 | void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) { |
4246 | FieldPositionHandler none; | |
b75a7d8f | 4247 | if (fPosPrefixPattern != 0) { |
729e4ab9 | 4248 | expandAffix(*fPosPrefixPattern, fPositivePrefix, 0, none, FALSE, pluralCount); |
b75a7d8f A |
4249 | } |
4250 | if (fPosSuffixPattern != 0) { | |
729e4ab9 | 4251 | expandAffix(*fPosSuffixPattern, fPositiveSuffix, 0, none, FALSE, pluralCount); |
b75a7d8f A |
4252 | } |
4253 | if (fNegPrefixPattern != 0) { | |
729e4ab9 | 4254 | expandAffix(*fNegPrefixPattern, fNegativePrefix, 0, none, FALSE, pluralCount); |
b75a7d8f A |
4255 | } |
4256 | if (fNegSuffixPattern != 0) { | |
729e4ab9 | 4257 | expandAffix(*fNegSuffixPattern, fNegativeSuffix, 0, none, FALSE, pluralCount); |
b75a7d8f A |
4258 | } |
4259 | #ifdef FMT_DEBUG | |
4260 | UnicodeString s; | |
51004dcb A |
4261 | s.append(UnicodeString("[")) |
4262 | .append(DEREFSTR(fPosPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fPosSuffixPattern)) | |
4263 | .append((UnicodeString)";") .append(DEREFSTR(fNegPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fNegSuffixPattern)) | |
4264 | .append((UnicodeString)"]->[") | |
4265 | .append(fPositivePrefix).append((UnicodeString)"|").append(fPositiveSuffix) | |
4266 | .append((UnicodeString)";") .append(fNegativePrefix).append((UnicodeString)"|").append(fNegativeSuffix) | |
4267 | .append((UnicodeString)"]\n"); | |
b75a7d8f A |
4268 | debugout(s); |
4269 | #endif | |
4270 | } | |
4271 | ||
4272 | /** | |
4273 | * Expand an affix pattern into an affix string. All characters in the | |
4274 | * pattern are literal unless prefixed by kQuote. The following characters | |
4275 | * after kQuote are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, | |
4276 | * PATTERN_MINUS, and kCurrencySign. If kCurrencySign is doubled (kQuote + | |
4277 | * kCurrencySign + kCurrencySign), it is interpreted as an international | |
729e4ab9 A |
4278 | * currency sign. If CURRENCY_SIGN is tripled, it is interpreted as |
4279 | * currency plural long names, such as "US Dollars". | |
4280 | * Any other character after a kQuote represents itself. | |
b75a7d8f A |
4281 | * kQuote must be followed by another character; kQuote may not occur by |
4282 | * itself at the end of the pattern. | |
4283 | * | |
4284 | * This method is used in two distinct ways. First, it is used to expand | |
4285 | * the stored affix patterns into actual affixes. For this usage, doFormat | |
4286 | * must be false. Second, it is used to expand the stored affix patterns | |
4287 | * given a specific number (doFormat == true), for those rare cases in | |
4288 | * which a currency format references a ChoiceFormat (e.g., en_IN display | |
4289 | * name for INR). The number itself is taken from digitList. | |
4290 | * | |
4291 | * When used in the first way, this method has a side effect: It sets | |
4292 | * currencyChoice to a ChoiceFormat object, if the currency's display name | |
4293 | * in this locale is a ChoiceFormat pattern (very rare). It only does this | |
4294 | * if currencyChoice is null to start with. | |
4295 | * | |
4296 | * @param pattern the non-null, fPossibly empty pattern | |
4297 | * @param affix string to receive the expanded equivalent of pattern. | |
4298 | * Previous contents are deleted. | |
4299 | * @param doFormat if false, then the pattern will be expanded, and if a | |
4300 | * currency symbol is encountered that expands to a ChoiceFormat, the | |
4301 | * currencyChoice member variable will be initialized if it is null. If | |
4302 | * doFormat is true, then it is assumed that the currencyChoice has been | |
4303 | * created, and it will be used to format the value in digitList. | |
729e4ab9 A |
4304 | * @param pluralCount the plural count. It is only used for currency |
4305 | * plural format. In which case, it is the plural | |
4306 | * count of the currency amount. For example, | |
4307 | * in en_US, it is the singular "one", or the plural | |
4308 | * "other". For all other cases, it is null, and | |
4309 | * is not being used. | |
b75a7d8f A |
4310 | */ |
4311 | void DecimalFormat::expandAffix(const UnicodeString& pattern, | |
4312 | UnicodeString& affix, | |
4313 | double number, | |
729e4ab9 A |
4314 | FieldPositionHandler& handler, |
4315 | UBool doFormat, | |
4316 | const UnicodeString* pluralCount) const { | |
b75a7d8f A |
4317 | affix.remove(); |
4318 | for (int i=0; i<pattern.length(); ) { | |
4319 | UChar32 c = pattern.char32At(i); | |
4320 | i += U16_LENGTH(c); | |
4321 | if (c == kQuote) { | |
4322 | c = pattern.char32At(i); | |
4323 | i += U16_LENGTH(c); | |
729e4ab9 | 4324 | int beginIdx = affix.length(); |
b75a7d8f A |
4325 | switch (c) { |
4326 | case kCurrencySign: { | |
4327 | // As of ICU 2.2 we use the currency object, and | |
4328 | // ignore the currency symbols in the DFS, unless | |
4329 | // we have a null currency object. This occurs if | |
4330 | // resurrecting a pre-2.2 object or if the user | |
4331 | // sets a custom DFS. | |
4332 | UBool intl = i<pattern.length() && | |
4333 | pattern.char32At(i) == kCurrencySign; | |
729e4ab9 | 4334 | UBool plural = FALSE; |
b75a7d8f A |
4335 | if (intl) { |
4336 | ++i; | |
729e4ab9 A |
4337 | plural = i<pattern.length() && |
4338 | pattern.char32At(i) == kCurrencySign; | |
4339 | if (plural) { | |
4340 | intl = FALSE; | |
4341 | ++i; | |
4342 | } | |
b75a7d8f A |
4343 | } |
4344 | const UChar* currencyUChars = getCurrency(); | |
4345 | if (currencyUChars[0] != 0) { | |
4346 | UErrorCode ec = U_ZERO_ERROR; | |
729e4ab9 A |
4347 | if (plural && pluralCount != NULL) { |
4348 | // plural name is only needed when pluralCount != null, | |
4349 | // which means when formatting currency plural names. | |
4350 | // For other cases, pluralCount == null, | |
4351 | // and plural names are not needed. | |
4352 | int32_t len; | |
4388f060 A |
4353 | CharString pluralCountChar; |
4354 | pluralCountChar.appendInvariantChars(*pluralCount, ec); | |
729e4ab9 A |
4355 | UBool isChoiceFormat; |
4356 | const UChar* s = ucurr_getPluralName(currencyUChars, | |
4357 | fSymbols != NULL ? fSymbols->getLocale().getName() : | |
4358 | Locale::getDefault().getName(), &isChoiceFormat, | |
4388f060 | 4359 | pluralCountChar.data(), &len, &ec); |
729e4ab9 A |
4360 | affix += UnicodeString(s, len); |
4361 | handler.addAttribute(kCurrencyField, beginIdx, affix.length()); | |
4362 | } else if(intl) { | |
4388f060 | 4363 | affix.append(currencyUChars, -1); |
729e4ab9 | 4364 | handler.addAttribute(kCurrencyField, beginIdx, affix.length()); |
b75a7d8f A |
4365 | } else { |
4366 | int32_t len; | |
4367 | UBool isChoiceFormat; | |
46f4442e | 4368 | // If fSymbols is NULL, use default locale |
729e4ab9 A |
4369 | const UChar* s = ucurr_getName(currencyUChars, |
4370 | fSymbols != NULL ? fSymbols->getLocale().getName() : Locale::getDefault().getName(), | |
4371 | UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec); | |
b75a7d8f A |
4372 | if (isChoiceFormat) { |
4373 | // Two modes here: If doFormat is false, we set up | |
4374 | // currencyChoice. If doFormat is true, we use the | |
4375 | // previously created currencyChoice to format the | |
4376 | // value in digitList. | |
4377 | if (!doFormat) { | |
4378 | // If the currency is handled by a ChoiceFormat, | |
4379 | // then we're not going to use the expanded | |
4380 | // patterns. Instantiate the ChoiceFormat and | |
4381 | // return. | |
4382 | if (fCurrencyChoice == NULL) { | |
4383 | // TODO Replace double-check with proper thread-safe code | |
4388f060 | 4384 | ChoiceFormat* fmt = new ChoiceFormat(UnicodeString(s), ec); |
b75a7d8f A |
4385 | if (U_SUCCESS(ec)) { |
4386 | umtx_lock(NULL); | |
4387 | if (fCurrencyChoice == NULL) { | |
4388 | // Cast away const | |
4389 | ((DecimalFormat*)this)->fCurrencyChoice = fmt; | |
4390 | fmt = NULL; | |
4391 | } | |
4392 | umtx_unlock(NULL); | |
4393 | delete fmt; | |
4394 | } | |
4395 | } | |
4396 | // We could almost return null or "" here, since the | |
4397 | // expanded affixes are almost not used at all | |
4398 | // in this situation. However, one method -- | |
4399 | // toPattern() -- still does use the expanded | |
4400 | // affixes, in order to set up a padding | |
4401 | // pattern. We use the CURRENCY_SIGN as a | |
4402 | // placeholder. | |
4403 | affix.append(kCurrencySign); | |
4404 | } else { | |
4405 | if (fCurrencyChoice != NULL) { | |
4406 | FieldPosition pos(0); // ignored | |
4407 | if (number < 0) { | |
4408 | number = -number; | |
4409 | } | |
4410 | fCurrencyChoice->format(number, affix, pos); | |
4411 | } else { | |
4412 | // We only arrive here if the currency choice | |
4413 | // format in the locale data is INVALID. | |
4388f060 | 4414 | affix.append(currencyUChars, -1); |
729e4ab9 | 4415 | handler.addAttribute(kCurrencyField, beginIdx, affix.length()); |
b75a7d8f A |
4416 | } |
4417 | } | |
4418 | continue; | |
4419 | } | |
4420 | affix += UnicodeString(s, len); | |
729e4ab9 | 4421 | handler.addAttribute(kCurrencyField, beginIdx, affix.length()); |
b75a7d8f A |
4422 | } |
4423 | } else { | |
4424 | if(intl) { | |
4425 | affix += getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); | |
4426 | } else { | |
4427 | affix += getConstSymbol(DecimalFormatSymbols::kCurrencySymbol); | |
4428 | } | |
729e4ab9 | 4429 | handler.addAttribute(kCurrencyField, beginIdx, affix.length()); |
b75a7d8f A |
4430 | } |
4431 | break; | |
4432 | } | |
4433 | case kPatternPercent: | |
4434 | affix += getConstSymbol(DecimalFormatSymbols::kPercentSymbol); | |
729e4ab9 | 4435 | handler.addAttribute(kPercentField, beginIdx, affix.length()); |
b75a7d8f A |
4436 | break; |
4437 | case kPatternPerMill: | |
4438 | affix += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); | |
729e4ab9 | 4439 | handler.addAttribute(kPermillField, beginIdx, affix.length()); |
b75a7d8f A |
4440 | break; |
4441 | case kPatternPlus: | |
4442 | affix += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); | |
729e4ab9 | 4443 | handler.addAttribute(kSignField, beginIdx, affix.length()); |
b75a7d8f A |
4444 | break; |
4445 | case kPatternMinus: | |
4446 | affix += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
729e4ab9 | 4447 | handler.addAttribute(kSignField, beginIdx, affix.length()); |
b75a7d8f A |
4448 | break; |
4449 | default: | |
4450 | affix.append(c); | |
4451 | break; | |
4452 | } | |
4453 | } | |
4454 | else { | |
4455 | affix.append(c); | |
4456 | } | |
4457 | } | |
4458 | } | |
4459 | ||
4460 | /** | |
4461 | * Append an affix to the given StringBuffer. | |
4462 | * @param buf buffer to append to | |
4463 | * @param isNegative | |
4464 | * @param isPrefix | |
4465 | */ | |
4466 | int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number, | |
729e4ab9 | 4467 | FieldPositionHandler& handler, |
b75a7d8f | 4468 | UBool isNegative, UBool isPrefix) const { |
729e4ab9 A |
4469 | // plural format precedes choice format |
4470 | if (fCurrencyChoice != 0 && | |
4471 | fCurrencySignCount != fgCurrencySignCountInPluralFormat) { | |
46f4442e | 4472 | const UnicodeString* affixPat; |
b75a7d8f A |
4473 | if (isPrefix) { |
4474 | affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern; | |
4475 | } else { | |
4476 | affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern; | |
4477 | } | |
46f4442e A |
4478 | if (affixPat) { |
4479 | UnicodeString affixBuf; | |
729e4ab9 | 4480 | expandAffix(*affixPat, affixBuf, number, handler, TRUE, NULL); |
46f4442e A |
4481 | buf.append(affixBuf); |
4482 | return affixBuf.length(); | |
4483 | } | |
4484 | // else someone called a function that reset the pattern. | |
b75a7d8f | 4485 | } |
729e4ab9 | 4486 | |
46f4442e | 4487 | const UnicodeString* affix; |
729e4ab9 | 4488 | if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) { |
57a6839d A |
4489 | // TODO: get an accurate count of visible fraction digits. |
4490 | UnicodeString pluralCount; | |
4491 | int32_t minFractionDigits = this->getMinimumFractionDigits(); | |
4492 | if (minFractionDigits > 0) { | |
4493 | FixedDecimal ni(number, this->getMinimumFractionDigits()); | |
4494 | pluralCount = fCurrencyPluralInfo->getPluralRules()->select(ni); | |
4495 | } else { | |
4496 | pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number); | |
4497 | } | |
729e4ab9 | 4498 | AffixesForCurrency* oneSet; |
4388f060 | 4499 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
729e4ab9 A |
4500 | oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount); |
4501 | } else { | |
4502 | oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount); | |
4503 | } | |
4504 | if (isPrefix) { | |
4505 | affix = isNegative ? &oneSet->negPrefixForCurrency : | |
4506 | &oneSet->posPrefixForCurrency; | |
4507 | } else { | |
4508 | affix = isNegative ? &oneSet->negSuffixForCurrency : | |
4509 | &oneSet->posSuffixForCurrency; | |
4510 | } | |
b75a7d8f | 4511 | } else { |
729e4ab9 A |
4512 | if (isPrefix) { |
4513 | affix = isNegative ? &fNegativePrefix : &fPositivePrefix; | |
4514 | } else { | |
4515 | affix = isNegative ? &fNegativeSuffix : &fPositiveSuffix; | |
4516 | } | |
b75a7d8f | 4517 | } |
729e4ab9 A |
4518 | |
4519 | int32_t begin = (int) buf.length(); | |
4520 | ||
b75a7d8f | 4521 | buf.append(*affix); |
729e4ab9 A |
4522 | |
4523 | if (handler.isRecording()) { | |
4524 | int32_t offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol)); | |
4525 | if (offset > -1) { | |
4526 | UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kCurrencySymbol); | |
4527 | handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length()); | |
4528 | } | |
4529 | ||
4530 | offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); | |
4531 | if (offset > -1) { | |
4532 | UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); | |
4533 | handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length()); | |
4534 | } | |
4535 | ||
4536 | offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)); | |
4537 | if (offset > -1) { | |
4538 | UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
4539 | handler.addAttribute(kSignField, begin + offset, begin + offset + aff.length()); | |
4540 | } | |
4541 | ||
4542 | offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol)); | |
4543 | if (offset > -1) { | |
4544 | UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPercentSymbol); | |
4545 | handler.addAttribute(kPercentField, begin + offset, begin + offset + aff.length()); | |
4546 | } | |
4547 | ||
4548 | offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol)); | |
4549 | if (offset > -1) { | |
4550 | UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); | |
4551 | handler.addAttribute(kPermillField, begin + offset, begin + offset + aff.length()); | |
4552 | } | |
4553 | } | |
b75a7d8f A |
4554 | return affix->length(); |
4555 | } | |
4556 | ||
4557 | /** | |
4558 | * Appends an affix pattern to the given StringBuffer, quoting special | |
4559 | * characters as needed. Uses the internal affix pattern, if that exists, | |
4560 | * or the literal affix, if the internal affix pattern is null. The | |
4561 | * appended string will generate the same affix pattern (or literal affix) | |
4562 | * when passed to toPattern(). | |
4563 | * | |
4564 | * @param appendTo the affix string is appended to this | |
4565 | * @param affixPattern a pattern such as fPosPrefixPattern; may be null | |
4566 | * @param expAffix a corresponding expanded affix, such as fPositivePrefix. | |
4567 | * Ignored unless affixPattern is null. If affixPattern is null, then | |
4568 | * expAffix is appended as a literal affix. | |
4569 | * @param localized true if the appended pattern should contain localized | |
4570 | * pattern characters; otherwise, non-localized pattern chars are appended | |
4571 | */ | |
4572 | void DecimalFormat::appendAffixPattern(UnicodeString& appendTo, | |
4573 | const UnicodeString* affixPattern, | |
4574 | const UnicodeString& expAffix, | |
4575 | UBool localized) const { | |
4576 | if (affixPattern == 0) { | |
4577 | appendAffixPattern(appendTo, expAffix, localized); | |
4578 | } else { | |
4579 | int i; | |
4580 | for (int pos=0; pos<affixPattern->length(); pos=i) { | |
4581 | i = affixPattern->indexOf(kQuote, pos); | |
4582 | if (i < 0) { | |
4583 | UnicodeString s; | |
4584 | affixPattern->extractBetween(pos, affixPattern->length(), s); | |
4585 | appendAffixPattern(appendTo, s, localized); | |
4586 | break; | |
4587 | } | |
4588 | if (i > pos) { | |
4589 | UnicodeString s; | |
4590 | affixPattern->extractBetween(pos, i, s); | |
4591 | appendAffixPattern(appendTo, s, localized); | |
4592 | } | |
4593 | UChar32 c = affixPattern->char32At(++i); | |
4594 | ++i; | |
4595 | if (c == kQuote) { | |
4596 | appendTo.append(c).append(c); | |
4597 | // Fall through and append another kQuote below | |
4598 | } else if (c == kCurrencySign && | |
4599 | i<affixPattern->length() && | |
4600 | affixPattern->char32At(i) == kCurrencySign) { | |
4601 | ++i; | |
4602 | appendTo.append(c).append(c); | |
4603 | } else if (localized) { | |
4604 | switch (c) { | |
4605 | case kPatternPercent: | |
4606 | appendTo += getConstSymbol(DecimalFormatSymbols::kPercentSymbol); | |
4607 | break; | |
4608 | case kPatternPerMill: | |
4609 | appendTo += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); | |
4610 | break; | |
4611 | case kPatternPlus: | |
4612 | appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); | |
4613 | break; | |
4614 | case kPatternMinus: | |
4615 | appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); | |
4616 | break; | |
4617 | default: | |
4618 | appendTo.append(c); | |
4619 | } | |
4620 | } else { | |
4621 | appendTo.append(c); | |
4622 | } | |
4623 | } | |
4624 | } | |
4625 | } | |
4626 | ||
4627 | /** | |
4628 | * Append an affix to the given StringBuffer, using quotes if | |
4629 | * there are special characters. Single quotes themselves must be | |
4630 | * escaped in either case. | |
4631 | */ | |
4632 | void | |
4633 | DecimalFormat::appendAffixPattern(UnicodeString& appendTo, | |
4634 | const UnicodeString& affix, | |
4635 | UBool localized) const { | |
4636 | UBool needQuote; | |
4637 | if(localized) { | |
4638 | needQuote = affix.indexOf(getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) >= 0 | |
4639 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) >= 0 | |
4640 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) >= 0 | |
4641 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol)) >= 0 | |
4642 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol)) >= 0 | |
4643 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDigitSymbol)) >= 0 | |
4644 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) >= 0 | |
4645 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol)) >= 0 | |
4646 | || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) >= 0 | |
4647 | || affix.indexOf(kCurrencySign) >= 0; | |
4648 | } | |
4649 | else { | |
4650 | needQuote = affix.indexOf(kPatternZeroDigit) >= 0 | |
4651 | || affix.indexOf(kPatternGroupingSeparator) >= 0 | |
4652 | || affix.indexOf(kPatternDecimalSeparator) >= 0 | |
4653 | || affix.indexOf(kPatternPercent) >= 0 | |
4654 | || affix.indexOf(kPatternPerMill) >= 0 | |
4655 | || affix.indexOf(kPatternDigit) >= 0 | |
4656 | || affix.indexOf(kPatternSeparator) >= 0 | |
4657 | || affix.indexOf(kPatternExponent) >= 0 | |
4658 | || affix.indexOf(kPatternPlus) >= 0 | |
4659 | || affix.indexOf(kPatternMinus) >= 0 | |
4660 | || affix.indexOf(kCurrencySign) >= 0; | |
4661 | } | |
4662 | if (needQuote) | |
4663 | appendTo += (UChar)0x0027 /*'\''*/; | |
4664 | if (affix.indexOf((UChar)0x0027 /*'\''*/) < 0) | |
4665 | appendTo += affix; | |
4666 | else { | |
4667 | for (int32_t j = 0; j < affix.length(); ) { | |
4668 | UChar32 c = affix.char32At(j); | |
4669 | j += U16_LENGTH(c); | |
4670 | appendTo += c; | |
4671 | if (c == 0x0027 /*'\''*/) | |
4672 | appendTo += c; | |
4673 | } | |
4674 | } | |
4675 | if (needQuote) | |
4676 | appendTo += (UChar)0x0027 /*'\''*/; | |
4677 | } | |
4678 | ||
4679 | //------------------------------------------------------------------------------ | |
4680 | ||
b75a7d8f A |
4681 | UnicodeString& |
4682 | DecimalFormat::toPattern(UnicodeString& result, UBool localized) const | |
4683 | { | |
4388f060 | 4684 | if (fStyle == UNUM_CURRENCY_PLURAL) { |
729e4ab9 A |
4685 | // the prefix or suffix pattern might not be defined yet, |
4686 | // so they can not be synthesized, | |
4687 | // instead, get them directly. | |
4688 | // but it might not be the actual pattern used in formatting. | |
4689 | // the actual pattern used in formatting depends on the | |
4690 | // formatted number's plural count. | |
4691 | result = fFormatPattern; | |
4692 | return result; | |
4693 | } | |
b75a7d8f | 4694 | result.remove(); |
374ca955 | 4695 | UChar32 zero, sigDigit = kPatternSignificantDigit; |
b75a7d8f A |
4696 | UnicodeString digit, group; |
4697 | int32_t i; | |
4698 | int32_t roundingDecimalPos = 0; // Pos of decimal in roundingDigits | |
4699 | UnicodeString roundingDigits; | |
4700 | int32_t padPos = (fFormatWidth > 0) ? fPadPosition : -1; | |
4701 | UnicodeString padSpec; | |
374ca955 | 4702 | UBool useSigDig = areSignificantDigitsUsed(); |
b75a7d8f A |
4703 | |
4704 | if (localized) { | |
4705 | digit.append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol)); | |
4706 | group.append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)); | |
4707 | zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); | |
374ca955 A |
4708 | if (useSigDig) { |
4709 | sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0); | |
4710 | } | |
b75a7d8f A |
4711 | } |
4712 | else { | |
4713 | digit.append((UChar)kPatternDigit); | |
4714 | group.append((UChar)kPatternGroupingSeparator); | |
4715 | zero = (UChar32)kPatternZeroDigit; | |
4716 | } | |
4717 | if (fFormatWidth > 0) { | |
4718 | if (localized) { | |
4719 | padSpec.append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol)); | |
4720 | } | |
4721 | else { | |
4722 | padSpec.append((UChar)kPatternPadEscape); | |
4723 | } | |
4724 | padSpec.append(fPad); | |
4725 | } | |
4726 | if (fRoundingIncrement != NULL) { | |
729e4ab9 A |
4727 | for(i=0; i<fRoundingIncrement->getCount(); ++i) { |
4728 | roundingDigits.append(zero+(fRoundingIncrement->getDigitValue(i))); // Convert to Unicode digit | |
b75a7d8f | 4729 | } |
729e4ab9 | 4730 | roundingDecimalPos = fRoundingIncrement->getDecimalAt(); |
b75a7d8f A |
4731 | } |
4732 | for (int32_t part=0; part<2; ++part) { | |
4733 | if (padPos == kPadBeforePrefix) { | |
4734 | result.append(padSpec); | |
4735 | } | |
4736 | appendAffixPattern(result, | |
4737 | (part==0 ? fPosPrefixPattern : fNegPrefixPattern), | |
4738 | (part==0 ? fPositivePrefix : fNegativePrefix), | |
4739 | localized); | |
4740 | if (padPos == kPadAfterPrefix && ! padSpec.isEmpty()) { | |
4741 | result.append(padSpec); | |
4742 | } | |
4743 | int32_t sub0Start = result.length(); | |
374ca955 | 4744 | int32_t g = isGroupingUsed() ? _max(0, fGroupingSize) : 0; |
b75a7d8f A |
4745 | if (g > 0 && fGroupingSize2 > 0 && fGroupingSize2 != fGroupingSize) { |
4746 | g += fGroupingSize2; | |
4747 | } | |
374ca955 A |
4748 | int32_t maxDig = 0, minDig = 0, maxSigDig = 0; |
4749 | if (useSigDig) { | |
4750 | minDig = getMinimumSignificantDigits(); | |
4751 | maxDig = maxSigDig = getMaximumSignificantDigits(); | |
4752 | } else { | |
4753 | minDig = getMinimumIntegerDigits(); | |
4754 | maxDig = getMaximumIntegerDigits(); | |
4755 | } | |
4756 | if (fUseExponentialNotation) { | |
4757 | if (maxDig > kMaxScientificIntegerDigits) { | |
4758 | maxDig = 1; | |
4759 | } | |
4760 | } else if (useSigDig) { | |
4761 | maxDig = _max(maxDig, g+1); | |
4762 | } else { | |
4763 | maxDig = _max(_max(g, getMinimumIntegerDigits()), | |
4764 | roundingDecimalPos) + 1; | |
4765 | } | |
4766 | for (i = maxDig; i > 0; --i) { | |
4767 | if (!fUseExponentialNotation && i<maxDig && | |
b75a7d8f A |
4768 | isGroupingPosition(i)) { |
4769 | result.append(group); | |
4770 | } | |
374ca955 A |
4771 | if (useSigDig) { |
4772 | // #@,@### (maxSigDig == 5, minSigDig == 2) | |
4773 | // 65 4321 (1-based pos, count from the right) | |
4774 | // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig) | |
4775 | // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig | |
4776 | if (maxSigDig >= i && i > (maxSigDig - minDig)) { | |
4777 | result.append(sigDigit); | |
4778 | } else { | |
4779 | result.append(digit); | |
4780 | } | |
4781 | } else { | |
4782 | if (! roundingDigits.isEmpty()) { | |
4783 | int32_t pos = roundingDecimalPos - i; | |
4784 | if (pos >= 0 && pos < roundingDigits.length()) { | |
4785 | result.append((UChar) (roundingDigits.char32At(pos) - kPatternZeroDigit + zero)); | |
4786 | continue; | |
4787 | } | |
4788 | } | |
4789 | if (i<=minDig) { | |
4790 | result.append(zero); | |
4791 | } else { | |
4792 | result.append(digit); | |
b75a7d8f | 4793 | } |
b75a7d8f A |
4794 | } |
4795 | } | |
374ca955 A |
4796 | if (!useSigDig) { |
4797 | if (getMaximumFractionDigits() > 0 || fDecimalSeparatorAlwaysShown) { | |
4798 | if (localized) { | |
4799 | result += getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); | |
4800 | } | |
4801 | else { | |
4802 | result.append((UChar)kPatternDecimalSeparator); | |
4803 | } | |
b75a7d8f | 4804 | } |
374ca955 A |
4805 | int32_t pos = roundingDecimalPos; |
4806 | for (i = 0; i < getMaximumFractionDigits(); ++i) { | |
4807 | if (! roundingDigits.isEmpty() && pos < roundingDigits.length()) { | |
4808 | if (pos < 0) { | |
4809 | result.append(zero); | |
4810 | } | |
4811 | else { | |
4812 | result.append((UChar)(roundingDigits.char32At(pos) - kPatternZeroDigit + zero)); | |
4813 | } | |
4814 | ++pos; | |
4815 | continue; | |
4816 | } | |
4817 | if (i<getMinimumFractionDigits()) { | |
b75a7d8f A |
4818 | result.append(zero); |
4819 | } | |
4820 | else { | |
374ca955 | 4821 | result.append(digit); |
b75a7d8f | 4822 | } |
b75a7d8f A |
4823 | } |
4824 | } | |
4825 | if (fUseExponentialNotation) { | |
4826 | if (localized) { | |
4827 | result += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); | |
4828 | } | |
4829 | else { | |
4830 | result.append((UChar)kPatternExponent); | |
4831 | } | |
4832 | if (fExponentSignAlwaysShown) { | |
4833 | if (localized) { | |
4834 | result += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); | |
4835 | } | |
4836 | else { | |
4837 | result.append((UChar)kPatternPlus); | |
4838 | } | |
4839 | } | |
4840 | for (i=0; i<fMinExponentDigits; ++i) { | |
4841 | result.append(zero); | |
4842 | } | |
4843 | } | |
4844 | if (! padSpec.isEmpty() && !fUseExponentialNotation) { | |
4845 | int32_t add = fFormatWidth - result.length() + sub0Start | |
4846 | - ((part == 0) | |
4847 | ? fPositivePrefix.length() + fPositiveSuffix.length() | |
4848 | : fNegativePrefix.length() + fNegativeSuffix.length()); | |
4849 | while (add > 0) { | |
4850 | result.insert(sub0Start, digit); | |
374ca955 | 4851 | ++maxDig; |
b75a7d8f A |
4852 | --add; |
4853 | // Only add a grouping separator if we have at least | |
4854 | // 2 additional characters to be added, so we don't | |
4855 | // end up with ",###". | |
374ca955 | 4856 | if (add>1 && isGroupingPosition(maxDig)) { |
b75a7d8f | 4857 | result.insert(sub0Start, group); |
729e4ab9 | 4858 | --add; |
b75a7d8f A |
4859 | } |
4860 | } | |
4861 | } | |
4862 | if (fPadPosition == kPadBeforeSuffix && ! padSpec.isEmpty()) { | |
4863 | result.append(padSpec); | |
4864 | } | |
4865 | if (part == 0) { | |
4866 | appendAffixPattern(result, fPosSuffixPattern, fPositiveSuffix, localized); | |
4867 | if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) { | |
4868 | result.append(padSpec); | |
4869 | } | |
4870 | UBool isDefault = FALSE; | |
4871 | if ((fNegSuffixPattern == fPosSuffixPattern && // both null | |
4872 | fNegativeSuffix == fPositiveSuffix) | |
4873 | || (fNegSuffixPattern != 0 && fPosSuffixPattern != 0 && | |
4874 | *fNegSuffixPattern == *fPosSuffixPattern)) | |
4875 | { | |
4876 | if (fNegPrefixPattern != NULL && fPosPrefixPattern != NULL) | |
4877 | { | |
4878 | int32_t length = fPosPrefixPattern->length(); | |
4879 | isDefault = fNegPrefixPattern->length() == (length+2) && | |
4880 | (*fNegPrefixPattern)[(int32_t)0] == kQuote && | |
4881 | (*fNegPrefixPattern)[(int32_t)1] == kPatternMinus && | |
4882 | fNegPrefixPattern->compare(2, length, *fPosPrefixPattern, 0, length) == 0; | |
4883 | } | |
4884 | if (!isDefault && | |
4885 | fNegPrefixPattern == NULL && fPosPrefixPattern == NULL) | |
4886 | { | |
4887 | int32_t length = fPositivePrefix.length(); | |
4888 | isDefault = fNegativePrefix.length() == (length+1) && | |
4889 | fNegativePrefix.compare(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) == 0 && | |
4890 | fNegativePrefix.compare(1, length, fPositivePrefix, 0, length) == 0; | |
4891 | } | |
4892 | } | |
4893 | if (isDefault) { | |
4894 | break; // Don't output default negative subpattern | |
4895 | } else { | |
4896 | if (localized) { | |
4897 | result += getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); | |
4898 | } | |
4899 | else { | |
4900 | result.append((UChar)kPatternSeparator); | |
4901 | } | |
4902 | } | |
4903 | } else { | |
4904 | appendAffixPattern(result, fNegSuffixPattern, fNegativeSuffix, localized); | |
4905 | if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) { | |
4906 | result.append(padSpec); | |
4907 | } | |
4908 | } | |
4909 | } | |
4910 | ||
4911 | return result; | |
4912 | } | |
4913 | ||
4914 | //------------------------------------------------------------------------------ | |
4915 | ||
4916 | void | |
4917 | DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) | |
4918 | { | |
4919 | UParseError parseError; | |
4920 | applyPattern(pattern, FALSE, parseError, status); | |
4921 | } | |
4922 | ||
4923 | //------------------------------------------------------------------------------ | |
4924 | ||
4925 | void | |
4926 | DecimalFormat::applyPattern(const UnicodeString& pattern, | |
729e4ab9 | 4927 | UParseError& parseError, |
b75a7d8f A |
4928 | UErrorCode& status) |
4929 | { | |
4930 | applyPattern(pattern, FALSE, parseError, status); | |
4931 | } | |
4932 | //------------------------------------------------------------------------------ | |
4933 | ||
4934 | void | |
4935 | DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status) | |
4936 | { | |
4937 | UParseError parseError; | |
4938 | applyPattern(pattern, TRUE,parseError,status); | |
4939 | } | |
4940 | ||
4941 | //------------------------------------------------------------------------------ | |
4942 | ||
4943 | void | |
4944 | DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, | |
4945 | UParseError& parseError, | |
4946 | UErrorCode& status) | |
4947 | { | |
4948 | applyPattern(pattern, TRUE,parseError,status); | |
4949 | } | |
4950 | ||
4951 | //------------------------------------------------------------------------------ | |
4952 | ||
4953 | void | |
729e4ab9 A |
4954 | DecimalFormat::applyPatternWithoutExpandAffix(const UnicodeString& pattern, |
4955 | UBool localized, | |
4956 | UParseError& parseError, | |
4957 | UErrorCode& status) | |
b75a7d8f A |
4958 | { |
4959 | if (U_FAILURE(status)) | |
4960 | { | |
4961 | return; | |
4962 | } | |
57a6839d | 4963 | DecimalFormatPatternParser patternParser; |
b75a7d8f | 4964 | if (localized) { |
57a6839d | 4965 | patternParser.useSymbols(*fSymbols); |
b75a7d8f | 4966 | } |
57a6839d A |
4967 | fFormatPattern = pattern; |
4968 | DecimalFormatPattern out; | |
4969 | patternParser.applyPatternWithoutExpandAffix( | |
4970 | pattern, | |
4971 | out, | |
4972 | parseError, | |
4973 | status); | |
4974 | if (U_FAILURE(status)) { | |
4975 | return; | |
4976 | } | |
4977 | ||
4978 | setMinimumIntegerDigits(out.fMinimumIntegerDigits); | |
4979 | setMaximumIntegerDigits(out.fMaximumIntegerDigits); | |
4980 | setMinimumFractionDigits(out.fMinimumFractionDigits); | |
4981 | setMaximumFractionDigits(out.fMaximumFractionDigits); | |
4982 | setSignificantDigitsUsed(out.fUseSignificantDigits); | |
4983 | if (out.fUseSignificantDigits) { | |
4984 | setMinimumSignificantDigits(out.fMinimumSignificantDigits); | |
4985 | setMaximumSignificantDigits(out.fMaximumSignificantDigits); | |
4986 | } | |
4987 | fUseExponentialNotation = out.fUseExponentialNotation; | |
4988 | if (out.fUseExponentialNotation) { | |
4989 | fMinExponentDigits = out.fMinExponentDigits; | |
4990 | } | |
4991 | fExponentSignAlwaysShown = out.fExponentSignAlwaysShown; | |
4992 | fCurrencySignCount = out.fCurrencySignCount; | |
4993 | setGroupingUsed(out.fGroupingUsed); | |
4994 | if (out.fGroupingUsed) { | |
4995 | fGroupingSize = out.fGroupingSize; | |
4996 | fGroupingSize2 = out.fGroupingSize2; | |
4997 | } | |
4998 | setMultiplier(out.fMultiplier); | |
4999 | fDecimalSeparatorAlwaysShown = out.fDecimalSeparatorAlwaysShown; | |
5000 | fFormatWidth = out.fFormatWidth; | |
5001 | if (out.fRoundingIncrementUsed) { | |
5002 | if (fRoundingIncrement != NULL) { | |
5003 | *fRoundingIncrement = out.fRoundingIncrement; | |
b75a7d8f | 5004 | } else { |
57a6839d | 5005 | fRoundingIncrement = new DigitList(out.fRoundingIncrement); |
b75a7d8f | 5006 | /* test for NULL */ |
57a6839d A |
5007 | if (fRoundingIncrement == NULL) { |
5008 | status = U_MEMORY_ALLOCATION_ERROR; | |
5009 | return; | |
b75a7d8f A |
5010 | } |
5011 | } | |
57a6839d | 5012 | } else { |
b75a7d8f A |
5013 | setRoundingIncrement(0.0); |
5014 | } | |
57a6839d A |
5015 | fPad = out.fPad; |
5016 | switch (out.fPadPosition) { | |
5017 | case DecimalFormatPattern::kPadBeforePrefix: | |
5018 | fPadPosition = kPadBeforePrefix; | |
5019 | break; | |
5020 | case DecimalFormatPattern::kPadAfterPrefix: | |
5021 | fPadPosition = kPadAfterPrefix; | |
5022 | break; | |
5023 | case DecimalFormatPattern::kPadBeforeSuffix: | |
5024 | fPadPosition = kPadBeforeSuffix; | |
5025 | break; | |
5026 | case DecimalFormatPattern::kPadAfterSuffix: | |
5027 | fPadPosition = kPadAfterSuffix; | |
5028 | break; | |
b75a7d8f | 5029 | } |
57a6839d A |
5030 | copyString(out.fNegPrefixPattern, out.fNegPatternsBogus, fNegPrefixPattern, status); |
5031 | copyString(out.fNegSuffixPattern, out.fNegPatternsBogus, fNegSuffixPattern, status); | |
5032 | copyString(out.fPosPrefixPattern, out.fPosPatternsBogus, fPosPrefixPattern, status); | |
5033 | copyString(out.fPosSuffixPattern, out.fPosPatternsBogus, fPosSuffixPattern, status); | |
729e4ab9 A |
5034 | } |
5035 | ||
5036 | ||
5037 | void | |
5038 | DecimalFormat::expandAffixAdjustWidth(const UnicodeString* pluralCount) { | |
5039 | expandAffixes(pluralCount); | |
b75a7d8f A |
5040 | if (fFormatWidth > 0) { |
5041 | // Finish computing format width (see above) | |
729e4ab9 A |
5042 | // TODO: how to handle fFormatWidth, |
5043 | // need to save in f(Plural)AffixesForCurrecy? | |
5044 | fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length(); | |
5045 | } | |
5046 | } | |
5047 | ||
5048 | ||
5049 | void | |
5050 | DecimalFormat::applyPattern(const UnicodeString& pattern, | |
5051 | UBool localized, | |
5052 | UParseError& parseError, | |
5053 | UErrorCode& status) | |
5054 | { | |
5055 | // do the following re-set first. since they change private data by | |
5056 | // apply pattern again. | |
5057 | if (pattern.indexOf(kCurrencySign) != -1) { | |
5058 | if (fCurrencyPluralInfo == NULL) { | |
5059 | // initialize currencyPluralInfo if needed | |
5060 | fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status); | |
5061 | } | |
5062 | if (fAffixPatternsForCurrency == NULL) { | |
5063 | setupCurrencyAffixPatterns(status); | |
5064 | } | |
4388f060 | 5065 | if (pattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) { |
729e4ab9 A |
5066 | // only setup the affixes of the current pattern. |
5067 | setupCurrencyAffixes(pattern, TRUE, FALSE, status); | |
5068 | } | |
b75a7d8f | 5069 | } |
729e4ab9 A |
5070 | applyPatternWithoutExpandAffix(pattern, localized, parseError, status); |
5071 | expandAffixAdjustWidth(NULL); | |
51004dcb A |
5072 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5073 | handleChanged(); | |
5074 | #endif | |
729e4ab9 A |
5075 | } |
5076 | ||
5077 | ||
5078 | void | |
5079 | DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount, | |
5080 | const UnicodeString& pattern, | |
5081 | UBool localized, | |
5082 | UParseError& parseError, | |
5083 | UErrorCode& status) { | |
5084 | applyPatternWithoutExpandAffix(pattern, localized, parseError, status); | |
5085 | expandAffixAdjustWidth(&pluralCount); | |
51004dcb A |
5086 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5087 | handleChanged(); | |
5088 | #endif | |
b75a7d8f A |
5089 | } |
5090 | ||
729e4ab9 | 5091 | |
b75a7d8f A |
5092 | /** |
5093 | * Sets the maximum number of digits allowed in the integer portion of a | |
57a6839d | 5094 | * number. |
b75a7d8f A |
5095 | * @see NumberFormat#setMaximumIntegerDigits |
5096 | */ | |
5097 | void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { | |
57a6839d | 5098 | NumberFormat::setMaximumIntegerDigits(_min(newValue, gDefaultMaxIntegerDigits)); |
51004dcb A |
5099 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5100 | handleChanged(); | |
5101 | #endif | |
b75a7d8f A |
5102 | } |
5103 | ||
5104 | /** | |
5105 | * Sets the minimum number of digits allowed in the integer portion of a | |
5106 | * number. This override limits the integer digit count to 309. | |
5107 | * @see NumberFormat#setMinimumIntegerDigits | |
5108 | */ | |
5109 | void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { | |
374ca955 | 5110 | NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits)); |
51004dcb A |
5111 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5112 | handleChanged(); | |
5113 | #endif | |
b75a7d8f A |
5114 | } |
5115 | ||
5116 | /** | |
5117 | * Sets the maximum number of digits allowed in the fraction portion of a | |
5118 | * number. This override limits the fraction digit count to 340. | |
5119 | * @see NumberFormat#setMaximumFractionDigits | |
5120 | */ | |
5121 | void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { | |
374ca955 | 5122 | NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits)); |
51004dcb A |
5123 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5124 | handleChanged(); | |
5125 | #endif | |
b75a7d8f A |
5126 | } |
5127 | ||
5128 | /** | |
5129 | * Sets the minimum number of digits allowed in the fraction portion of a | |
5130 | * number. This override limits the fraction digit count to 340. | |
5131 | * @see NumberFormat#setMinimumFractionDigits | |
5132 | */ | |
5133 | void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { | |
374ca955 | 5134 | NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits)); |
51004dcb A |
5135 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5136 | handleChanged(); | |
5137 | #endif | |
b75a7d8f A |
5138 | } |
5139 | ||
374ca955 A |
5140 | int32_t DecimalFormat::getMinimumSignificantDigits() const { |
5141 | return fMinSignificantDigits; | |
5142 | } | |
5143 | ||
5144 | int32_t DecimalFormat::getMaximumSignificantDigits() const { | |
5145 | return fMaxSignificantDigits; | |
5146 | } | |
5147 | ||
5148 | void DecimalFormat::setMinimumSignificantDigits(int32_t min) { | |
5149 | if (min < 1) { | |
729e4ab9 | 5150 | min = 1; |
374ca955 A |
5151 | } |
5152 | // pin max sig dig to >= min | |
5153 | int32_t max = _max(fMaxSignificantDigits, min); | |
5154 | fMinSignificantDigits = min; | |
5155 | fMaxSignificantDigits = max; | |
57a6839d | 5156 | fUseSignificantDigits = TRUE; |
51004dcb A |
5157 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5158 | handleChanged(); | |
5159 | #endif | |
374ca955 A |
5160 | } |
5161 | ||
5162 | void DecimalFormat::setMaximumSignificantDigits(int32_t max) { | |
5163 | if (max < 1) { | |
5164 | max = 1; | |
5165 | } | |
5166 | // pin min sig dig to 1..max | |
5167 | U_ASSERT(fMinSignificantDigits >= 1); | |
5168 | int32_t min = _min(fMinSignificantDigits, max); | |
5169 | fMinSignificantDigits = min; | |
5170 | fMaxSignificantDigits = max; | |
57a6839d | 5171 | fUseSignificantDigits = TRUE; |
51004dcb A |
5172 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5173 | handleChanged(); | |
5174 | #endif | |
374ca955 A |
5175 | } |
5176 | ||
5177 | UBool DecimalFormat::areSignificantDigitsUsed() const { | |
5178 | return fUseSignificantDigits; | |
5179 | } | |
5180 | ||
5181 | void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { | |
5182 | fUseSignificantDigits = useSignificantDigits; | |
51004dcb A |
5183 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5184 | handleChanged(); | |
5185 | #endif | |
374ca955 A |
5186 | } |
5187 | ||
729e4ab9 A |
5188 | void DecimalFormat::setCurrencyInternally(const UChar* theCurrency, |
5189 | UErrorCode& ec) { | |
b75a7d8f A |
5190 | // If we are a currency format, then modify our affixes to |
5191 | // encode the currency symbol for the given currency in our | |
5192 | // locale, and adjust the decimal digits and rounding for the | |
5193 | // given currency. | |
5194 | ||
374ca955 A |
5195 | // Note: The code is ordered so that this object is *not changed* |
5196 | // until we are sure we are going to succeed. | |
729e4ab9 | 5197 | |
374ca955 A |
5198 | // NULL or empty currency is *legal* and indicates no currency. |
5199 | UBool isCurr = (theCurrency && *theCurrency); | |
5200 | ||
5201 | double rounding = 0.0; | |
5202 | int32_t frac = 0; | |
57a6839d | 5203 | if (fCurrencySignCount != fgCurrencySignCountZero && isCurr) { |
b331163b A |
5204 | rounding = ucurr_getRoundingIncrementForUsage(theCurrency, fCurrencyUsage, &ec); |
5205 | frac = ucurr_getDefaultFractionDigitsForUsage(theCurrency, fCurrencyUsage, &ec); | |
374ca955 | 5206 | } |
729e4ab9 | 5207 | |
374ca955 A |
5208 | NumberFormat::setCurrency(theCurrency, ec); |
5209 | if (U_FAILURE(ec)) return; | |
b75a7d8f | 5210 | |
57a6839d | 5211 | if (fCurrencySignCount != fgCurrencySignCountZero) { |
374ca955 A |
5212 | // NULL or empty currency is *legal* and indicates no currency. |
5213 | if (isCurr) { | |
5214 | setRoundingIncrement(rounding); | |
5215 | setMinimumFractionDigits(frac); | |
5216 | setMaximumFractionDigits(frac); | |
b75a7d8f | 5217 | } |
729e4ab9 A |
5218 | expandAffixes(NULL); |
5219 | } | |
51004dcb A |
5220 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5221 | handleChanged(); | |
5222 | #endif | |
729e4ab9 A |
5223 | } |
5224 | ||
5225 | void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { | |
5226 | // set the currency before compute affixes to get the right currency names | |
5227 | NumberFormat::setCurrency(theCurrency, ec); | |
4388f060 | 5228 | if (fFormatPattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) { |
729e4ab9 A |
5229 | UnicodeString savedPtn = fFormatPattern; |
5230 | setupCurrencyAffixes(fFormatPattern, TRUE, TRUE, ec); | |
5231 | UParseError parseErr; | |
5232 | applyPattern(savedPtn, FALSE, parseErr, ec); | |
b75a7d8f | 5233 | } |
729e4ab9 A |
5234 | // set the currency after apply pattern to get the correct rounding/fraction |
5235 | setCurrencyInternally(theCurrency, ec); | |
51004dcb A |
5236 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5237 | handleChanged(); | |
5238 | #endif | |
b75a7d8f A |
5239 | } |
5240 | ||
b331163b A |
5241 | void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){ |
5242 | fCurrencyUsage = newContext; | |
5243 | ||
5244 | const UChar* theCurrency = getCurrency(); | |
5245 | ||
5246 | // We set rounding/digit based on currency context | |
5247 | if(theCurrency){ | |
5248 | double rounding = ucurr_getRoundingIncrementForUsage(theCurrency, fCurrencyUsage, ec); | |
5249 | int32_t frac = ucurr_getDefaultFractionDigitsForUsage(theCurrency, fCurrencyUsage, ec); | |
5250 | ||
5251 | if (U_SUCCESS(*ec)) { | |
5252 | setRoundingIncrement(rounding); | |
5253 | setMinimumFractionDigits(frac); | |
5254 | setMaximumFractionDigits(frac); | |
5255 | } | |
5256 | } | |
5257 | } | |
5258 | ||
5259 | UCurrencyUsage DecimalFormat::getCurrencyUsage() const { | |
5260 | return fCurrencyUsage; | |
5261 | } | |
5262 | ||
374ca955 A |
5263 | // Deprecated variant with no UErrorCode parameter |
5264 | void DecimalFormat::setCurrency(const UChar* theCurrency) { | |
5265 | UErrorCode ec = U_ZERO_ERROR; | |
5266 | setCurrency(theCurrency, ec); | |
51004dcb A |
5267 | #if UCONFIG_FORMAT_FASTPATHS_49 |
5268 | handleChanged(); | |
5269 | #endif | |
374ca955 A |
5270 | } |
5271 | ||
46f4442e A |
5272 | void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { |
5273 | if (fSymbols == NULL) { | |
5274 | ec = U_MEMORY_ALLOCATION_ERROR; | |
5275 | return; | |
5276 | } | |
5277 | ec = U_ZERO_ERROR; | |
374ca955 A |
5278 | const UChar* c = getCurrency(); |
5279 | if (*c == 0) { | |
5280 | const UnicodeString &intl = | |
5281 | fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); | |
5282 | c = intl.getBuffer(); // ok for intl to go out of scope | |
5283 | } | |
5284 | u_strncpy(result, c, 3); | |
5285 | result[3] = 0; | |
5286 | } | |
5287 | ||
5288 | /** | |
5289 | * Return the number of fraction digits to display, or the total | |
5290 | * number of digits for significant digit formats and exponential | |
5291 | * formats. | |
5292 | */ | |
5293 | int32_t | |
729e4ab9 | 5294 | DecimalFormat::precision() const { |
374ca955 A |
5295 | if (areSignificantDigitsUsed()) { |
5296 | return getMaximumSignificantDigits(); | |
5297 | } else if (fUseExponentialNotation) { | |
5298 | return getMinimumIntegerDigits() + getMaximumFractionDigits(); | |
5299 | } else { | |
729e4ab9 A |
5300 | return getMaximumFractionDigits(); |
5301 | } | |
5302 | } | |
5303 | ||
5304 | ||
5305 | // TODO: template algorithm | |
5306 | Hashtable* | |
5307 | DecimalFormat::initHashForAffix(UErrorCode& status) { | |
5308 | if ( U_FAILURE(status) ) { | |
5309 | return NULL; | |
5310 | } | |
5311 | Hashtable* hTable; | |
5312 | if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { | |
5313 | status = U_MEMORY_ALLOCATION_ERROR; | |
5314 | return NULL; | |
5315 | } | |
5316 | if ( U_FAILURE(status) ) { | |
5317 | delete hTable; | |
5318 | return NULL; | |
5319 | } | |
5320 | hTable->setValueComparator(decimfmtAffixValueComparator); | |
5321 | return hTable; | |
5322 | } | |
5323 | ||
5324 | Hashtable* | |
5325 | DecimalFormat::initHashForAffixPattern(UErrorCode& status) { | |
5326 | if ( U_FAILURE(status) ) { | |
5327 | return NULL; | |
5328 | } | |
5329 | Hashtable* hTable; | |
5330 | if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { | |
5331 | status = U_MEMORY_ALLOCATION_ERROR; | |
5332 | return NULL; | |
5333 | } | |
5334 | if ( U_FAILURE(status) ) { | |
5335 | delete hTable; | |
5336 | return NULL; | |
5337 | } | |
5338 | hTable->setValueComparator(decimfmtAffixPatternValueComparator); | |
5339 | return hTable; | |
5340 | } | |
5341 | ||
5342 | void | |
5343 | DecimalFormat::deleteHashForAffix(Hashtable*& table) | |
5344 | { | |
5345 | if ( table == NULL ) { | |
5346 | return; | |
5347 | } | |
b331163b | 5348 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
5349 | const UHashElement* element = NULL; |
5350 | while ( (element = table->nextElement(pos)) != NULL ) { | |
729e4ab9 A |
5351 | const UHashTok valueTok = element->value; |
5352 | const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer; | |
5353 | delete value; | |
5354 | } | |
5355 | delete table; | |
5356 | table = NULL; | |
5357 | } | |
5358 | ||
5359 | ||
5360 | ||
5361 | void | |
5362 | DecimalFormat::deleteHashForAffixPattern() | |
5363 | { | |
5364 | if ( fAffixPatternsForCurrency == NULL ) { | |
5365 | return; | |
5366 | } | |
b331163b | 5367 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
5368 | const UHashElement* element = NULL; |
5369 | while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { | |
729e4ab9 A |
5370 | const UHashTok valueTok = element->value; |
5371 | const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; | |
5372 | delete value; | |
5373 | } | |
5374 | delete fAffixPatternsForCurrency; | |
5375 | fAffixPatternsForCurrency = NULL; | |
5376 | } | |
5377 | ||
5378 | ||
5379 | void | |
5380 | DecimalFormat::copyHashForAffixPattern(const Hashtable* source, | |
5381 | Hashtable* target, | |
5382 | UErrorCode& status) { | |
5383 | if ( U_FAILURE(status) ) { | |
5384 | return; | |
5385 | } | |
b331163b | 5386 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
5387 | const UHashElement* element = NULL; |
5388 | if ( source ) { | |
5389 | while ( (element = source->nextElement(pos)) != NULL ) { | |
5390 | const UHashTok keyTok = element->key; | |
5391 | const UnicodeString* key = (UnicodeString*)keyTok.pointer; | |
5392 | const UHashTok valueTok = element->value; | |
5393 | const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; | |
5394 | AffixPatternsForCurrency* copy = new AffixPatternsForCurrency( | |
5395 | value->negPrefixPatternForCurrency, | |
5396 | value->negSuffixPatternForCurrency, | |
5397 | value->posPrefixPatternForCurrency, | |
5398 | value->posSuffixPatternForCurrency, | |
5399 | value->patternType); | |
5400 | target->put(UnicodeString(*key), copy, status); | |
5401 | if ( U_FAILURE(status) ) { | |
5402 | return; | |
5403 | } | |
5404 | } | |
5405 | } | |
5406 | } | |
5407 | ||
57a6839d A |
5408 | // this is only overridden to call handleChanged() for fastpath purposes. |
5409 | void | |
5410 | DecimalFormat::setGroupingUsed(UBool newValue) { | |
5411 | NumberFormat::setGroupingUsed(newValue); | |
5412 | handleChanged(); | |
5413 | } | |
5414 | ||
5415 | // this is only overridden to call handleChanged() for fastpath purposes. | |
5416 | void | |
5417 | DecimalFormat::setParseIntegerOnly(UBool newValue) { | |
5418 | NumberFormat::setParseIntegerOnly(newValue); | |
5419 | handleChanged(); | |
5420 | } | |
5421 | ||
5422 | // this is only overridden to call handleChanged() for fastpath purposes. | |
5423 | // setContext doesn't affect the fastPath right now, but this is called for completeness | |
5424 | void | |
5425 | DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) { | |
5426 | NumberFormat::setContext(value, status); | |
5427 | handleChanged(); | |
5428 | } | |
5429 | ||
5430 | ||
51004dcb A |
5431 | DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr, |
5432 | int32_t newValue, | |
5433 | UErrorCode &status) { | |
5434 | if(U_FAILURE(status)) return *this; | |
5435 | ||
5436 | switch(attr) { | |
5437 | case UNUM_LENIENT_PARSE: | |
5438 | setLenient(newValue!=0); | |
5439 | break; | |
5440 | ||
5441 | case UNUM_PARSE_INT_ONLY: | |
5442 | setParseIntegerOnly(newValue!=0); | |
5443 | break; | |
5444 | ||
5445 | case UNUM_GROUPING_USED: | |
5446 | setGroupingUsed(newValue!=0); | |
5447 | break; | |
5448 | ||
5449 | case UNUM_DECIMAL_ALWAYS_SHOWN: | |
5450 | setDecimalSeparatorAlwaysShown(newValue!=0); | |
5451 | break; | |
5452 | ||
5453 | case UNUM_MAX_INTEGER_DIGITS: | |
5454 | setMaximumIntegerDigits(newValue); | |
5455 | break; | |
5456 | ||
5457 | case UNUM_MIN_INTEGER_DIGITS: | |
5458 | setMinimumIntegerDigits(newValue); | |
5459 | break; | |
5460 | ||
5461 | case UNUM_INTEGER_DIGITS: | |
5462 | setMinimumIntegerDigits(newValue); | |
5463 | setMaximumIntegerDigits(newValue); | |
5464 | break; | |
5465 | ||
5466 | case UNUM_MAX_FRACTION_DIGITS: | |
5467 | setMaximumFractionDigits(newValue); | |
5468 | break; | |
5469 | ||
5470 | case UNUM_MIN_FRACTION_DIGITS: | |
5471 | setMinimumFractionDigits(newValue); | |
5472 | break; | |
5473 | ||
5474 | case UNUM_FRACTION_DIGITS: | |
5475 | setMinimumFractionDigits(newValue); | |
5476 | setMaximumFractionDigits(newValue); | |
5477 | break; | |
5478 | ||
5479 | case UNUM_SIGNIFICANT_DIGITS_USED: | |
5480 | setSignificantDigitsUsed(newValue!=0); | |
5481 | break; | |
5482 | ||
5483 | case UNUM_MAX_SIGNIFICANT_DIGITS: | |
5484 | setMaximumSignificantDigits(newValue); | |
5485 | break; | |
5486 | ||
5487 | case UNUM_MIN_SIGNIFICANT_DIGITS: | |
5488 | setMinimumSignificantDigits(newValue); | |
5489 | break; | |
5490 | ||
5491 | case UNUM_MULTIPLIER: | |
5492 | setMultiplier(newValue); | |
5493 | break; | |
5494 | ||
5495 | case UNUM_GROUPING_SIZE: | |
5496 | setGroupingSize(newValue); | |
5497 | break; | |
5498 | ||
5499 | case UNUM_ROUNDING_MODE: | |
5500 | setRoundingMode((DecimalFormat::ERoundingMode)newValue); | |
5501 | break; | |
5502 | ||
5503 | case UNUM_FORMAT_WIDTH: | |
5504 | setFormatWidth(newValue); | |
5505 | break; | |
5506 | ||
5507 | case UNUM_PADDING_POSITION: | |
5508 | /** The position at which padding will take place. */ | |
5509 | setPadPosition((DecimalFormat::EPadPosition)newValue); | |
5510 | break; | |
5511 | ||
5512 | case UNUM_SECONDARY_GROUPING_SIZE: | |
5513 | setSecondaryGroupingSize(newValue); | |
5514 | break; | |
5515 | ||
5516 | #if UCONFIG_HAVE_PARSEALLINPUT | |
5517 | case UNUM_PARSE_ALL_INPUT: | |
5518 | setParseAllInput((UNumberFormatAttributeValue)newValue); | |
5519 | break; | |
5520 | #endif | |
5521 | ||
5522 | /* These are stored in fBoolFlags */ | |
5523 | case UNUM_PARSE_NO_EXPONENT: | |
5524 | case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: | |
b331163b | 5525 | case UNUM_PARSE_DECIMAL_MARK_REQUIRED: |
51004dcb A |
5526 | if(!fBoolFlags.isValidValue(newValue)) { |
5527 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
5528 | } else { | |
5529 | fBoolFlags.set(attr, newValue); | |
5530 | } | |
5531 | break; | |
5532 | ||
5533 | case UNUM_SCALE: | |
5534 | fScale = newValue; | |
5535 | break; | |
5536 | ||
b331163b A |
5537 | case UNUM_CURRENCY_USAGE: |
5538 | setCurrencyUsage((UCurrencyUsage)newValue, &status); | |
5539 | ||
51004dcb A |
5540 | default: |
5541 | status = U_UNSUPPORTED_ERROR; | |
5542 | break; | |
5543 | } | |
5544 | return *this; | |
5545 | } | |
5546 | ||
5547 | int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr, | |
5548 | UErrorCode &status ) const { | |
5549 | if(U_FAILURE(status)) return -1; | |
5550 | switch(attr) { | |
5551 | case UNUM_LENIENT_PARSE: | |
5552 | return isLenient(); | |
5553 | ||
5554 | case UNUM_PARSE_INT_ONLY: | |
5555 | return isParseIntegerOnly(); | |
5556 | ||
5557 | case UNUM_GROUPING_USED: | |
5558 | return isGroupingUsed(); | |
5559 | ||
5560 | case UNUM_DECIMAL_ALWAYS_SHOWN: | |
5561 | return isDecimalSeparatorAlwaysShown(); | |
5562 | ||
5563 | case UNUM_MAX_INTEGER_DIGITS: | |
5564 | return getMaximumIntegerDigits(); | |
5565 | ||
5566 | case UNUM_MIN_INTEGER_DIGITS: | |
5567 | return getMinimumIntegerDigits(); | |
5568 | ||
5569 | case UNUM_INTEGER_DIGITS: | |
5570 | // TBD: what should this return? | |
5571 | return getMinimumIntegerDigits(); | |
5572 | ||
5573 | case UNUM_MAX_FRACTION_DIGITS: | |
5574 | return getMaximumFractionDigits(); | |
5575 | ||
5576 | case UNUM_MIN_FRACTION_DIGITS: | |
5577 | return getMinimumFractionDigits(); | |
5578 | ||
5579 | case UNUM_FRACTION_DIGITS: | |
5580 | // TBD: what should this return? | |
5581 | return getMinimumFractionDigits(); | |
5582 | ||
5583 | case UNUM_SIGNIFICANT_DIGITS_USED: | |
5584 | return areSignificantDigitsUsed(); | |
5585 | ||
5586 | case UNUM_MAX_SIGNIFICANT_DIGITS: | |
5587 | return getMaximumSignificantDigits(); | |
5588 | ||
5589 | case UNUM_MIN_SIGNIFICANT_DIGITS: | |
5590 | return getMinimumSignificantDigits(); | |
5591 | ||
5592 | case UNUM_MULTIPLIER: | |
5593 | return getMultiplier(); | |
5594 | ||
5595 | case UNUM_GROUPING_SIZE: | |
5596 | return getGroupingSize(); | |
5597 | ||
5598 | case UNUM_ROUNDING_MODE: | |
5599 | return getRoundingMode(); | |
5600 | ||
5601 | case UNUM_FORMAT_WIDTH: | |
5602 | return getFormatWidth(); | |
5603 | ||
5604 | case UNUM_PADDING_POSITION: | |
5605 | return getPadPosition(); | |
5606 | ||
5607 | case UNUM_SECONDARY_GROUPING_SIZE: | |
5608 | return getSecondaryGroupingSize(); | |
5609 | ||
5610 | /* These are stored in fBoolFlags */ | |
5611 | case UNUM_PARSE_NO_EXPONENT: | |
5612 | case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: | |
b331163b | 5613 | case UNUM_PARSE_DECIMAL_MARK_REQUIRED: |
51004dcb A |
5614 | return fBoolFlags.get(attr); |
5615 | ||
5616 | case UNUM_SCALE: | |
5617 | return fScale; | |
5618 | ||
b331163b A |
5619 | case UNUM_CURRENCY_USAGE: |
5620 | return fCurrencyUsage; | |
5621 | ||
51004dcb A |
5622 | default: |
5623 | status = U_UNSUPPORTED_ERROR; | |
5624 | break; | |
5625 | } | |
729e4ab9 | 5626 | |
51004dcb A |
5627 | return -1; /* undefined */ |
5628 | } | |
5629 | ||
5630 | #if UCONFIG_HAVE_PARSEALLINPUT | |
5631 | void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) { | |
5632 | fParseAllInput = value; | |
5633 | #if UCONFIG_FORMAT_FASTPATHS_49 | |
5634 | handleChanged(); | |
5635 | #endif | |
5636 | } | |
5637 | #endif | |
729e4ab9 A |
5638 | |
5639 | void | |
5640 | DecimalFormat::copyHashForAffix(const Hashtable* source, | |
5641 | Hashtable* target, | |
5642 | UErrorCode& status) { | |
5643 | if ( U_FAILURE(status) ) { | |
5644 | return; | |
5645 | } | |
b331163b | 5646 | int32_t pos = UHASH_FIRST; |
729e4ab9 A |
5647 | const UHashElement* element = NULL; |
5648 | if ( source ) { | |
5649 | while ( (element = source->nextElement(pos)) != NULL ) { | |
5650 | const UHashTok keyTok = element->key; | |
5651 | const UnicodeString* key = (UnicodeString*)keyTok.pointer; | |
5652 | ||
5653 | const UHashTok valueTok = element->value; | |
5654 | const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer; | |
5655 | AffixesForCurrency* copy = new AffixesForCurrency( | |
5656 | value->negPrefixForCurrency, | |
5657 | value->negSuffixForCurrency, | |
5658 | value->posPrefixForCurrency, | |
5659 | value->posSuffixForCurrency); | |
5660 | target->put(UnicodeString(*key), copy, status); | |
5661 | if ( U_FAILURE(status) ) { | |
5662 | return; | |
5663 | } | |
5664 | } | |
374ca955 A |
5665 | } |
5666 | } | |
5667 | ||
b75a7d8f A |
5668 | U_NAMESPACE_END |
5669 | ||
5670 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
5671 | ||
5672 | //eof |