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