2 *******************************************************************************
3 * Copyright (C) 1997-2014, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 #include "decimalformatpattern.h"
11 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/dcfmtsym.h"
14 #include "unicode/format.h"
15 #include "unicode/utf16.h"
18 #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
23 #define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
24 #define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
25 #define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
26 #define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
27 #define kPatternPerMill ((UChar)0x2030)
28 #define kPatternPercent ((UChar)0x0025) /*'%'*/
29 #define kPatternDigit ((UChar)0x0023) /*'#'*/
30 #define kPatternSeparator ((UChar)0x003B) /*';'*/
31 #define kPatternExponent ((UChar)0x0045) /*'E'*/
32 #define kPatternPlus ((UChar)0x002B) /*'+'*/
33 #define kPatternMinus ((UChar)0x002D) /*'-'*/
34 #define kPatternPadEscape ((UChar)0x002A) /*'*'*/
35 #define kQuote ((UChar)0x0027) /*'\''*/
37 #define kCurrencySign ((UChar)0x00A4)
38 #define kDefaultPad ((UChar)0x0020) /* */
42 // TODO: Travis Keep: Copied from numfmt.cpp
43 static int32_t kDoubleIntegerDigits
= 309;
44 static int32_t kDoubleFractionDigits
= 340;
47 // TODO: Travis Keep: Copied from numfmt.cpp
48 static int32_t gDefaultMaxIntegerDigits
= 2000000000;
50 // TODO: Travis Keep: This function was copied from format.cpp
51 static void syntaxError(const UnicodeString
& pattern
,
53 UParseError
& parseError
) {
54 parseError
.offset
= pos
;
55 parseError
.line
=0; // we are not using line number
58 int32_t start
= (pos
< U_PARSE_CONTEXT_LEN
)? 0 : (pos
- (U_PARSE_CONTEXT_LEN
-1
59 /* subtract 1 so that we have room for null*/));
61 pattern
.extract(start
,stop
-start
,parseError
.preContext
,0);
62 //null terminate the buffer
63 parseError
.preContext
[stop
-start
] = 0;
67 stop
= ((pos
+U_PARSE_CONTEXT_LEN
)<=pattern
.length()) ? (pos
+(U_PARSE_CONTEXT_LEN
-1)) :
69 pattern
.extract(start
,stop
-start
,parseError
.postContext
,0);
70 //null terminate the buffer
71 parseError
.postContext
[stop
-start
]= 0;
74 DecimalFormatPattern::DecimalFormatPattern()
75 : fMinimumIntegerDigits(1),
76 fMaximumIntegerDigits(gDefaultMaxIntegerDigits
),
77 fMinimumFractionDigits(0),
78 fMaximumFractionDigits(3),
79 fUseSignificantDigits(FALSE
),
80 fMinimumSignificantDigits(1),
81 fMaximumSignificantDigits(6),
82 fUseExponentialNotation(FALSE
),
83 fMinExponentDigits(0),
84 fExponentSignAlwaysShown(FALSE
),
85 fCurrencySignCount(fgCurrencySignCountZero
),
90 fDecimalSeparatorAlwaysShown(FALSE
),
92 fRoundingIncrementUsed(FALSE
),
94 fPad(kPatternPadEscape
),
95 fNegPatternsBogus(TRUE
),
96 fPosPatternsBogus(TRUE
),
101 fPadPosition(DecimalFormatPattern::kPadBeforePrefix
) {
105 DecimalFormatPatternParser::DecimalFormatPatternParser() :
106 fZeroDigit(kPatternZeroDigit
),
107 fSigDigit(kPatternSignificantDigit
),
108 fGroupingSeparator((UChar
)kPatternGroupingSeparator
),
109 fDecimalSeparator((UChar
)kPatternDecimalSeparator
),
110 fPercent((UChar
)kPatternPercent
),
111 fPerMill((UChar
)kPatternPerMill
),
112 fDigit((UChar
)kPatternDigit
),
113 fSeparator((UChar
)kPatternSeparator
),
114 fExponent((UChar
)kPatternExponent
),
115 fPlus((UChar
)kPatternPlus
),
116 fMinus((UChar
)kPatternMinus
),
117 fPadEscape((UChar
)kPatternPadEscape
) {
120 void DecimalFormatPatternParser::useSymbols(
121 const DecimalFormatSymbols
& symbols
) {
122 fZeroDigit
= symbols
.getConstSymbol(
123 DecimalFormatSymbols::kZeroDigitSymbol
).char32At(0);
124 fSigDigit
= symbols
.getConstSymbol(
125 DecimalFormatSymbols::kSignificantDigitSymbol
).char32At(0);
126 fGroupingSeparator
= symbols
.getConstSymbol(
127 DecimalFormatSymbols::kGroupingSeparatorSymbol
);
128 fDecimalSeparator
= symbols
.getConstSymbol(
129 DecimalFormatSymbols::kDecimalSeparatorSymbol
);
130 fPercent
= symbols
.getConstSymbol(
131 DecimalFormatSymbols::kPercentSymbol
);
132 fPerMill
= symbols
.getConstSymbol(
133 DecimalFormatSymbols::kPerMillSymbol
);
134 fDigit
= symbols
.getConstSymbol(
135 DecimalFormatSymbols::kDigitSymbol
);
136 fSeparator
= symbols
.getConstSymbol(
137 DecimalFormatSymbols::kPatternSeparatorSymbol
);
138 fExponent
= symbols
.getConstSymbol(
139 DecimalFormatSymbols::kExponentialSymbol
);
140 fPlus
= symbols
.getConstSymbol(
141 DecimalFormatSymbols::kPlusSignSymbol
);
142 fMinus
= symbols
.getConstSymbol(
143 DecimalFormatSymbols::kMinusSignSymbol
);
144 fPadEscape
= symbols
.getConstSymbol(
145 DecimalFormatSymbols::kPadEscapeSymbol
);
149 DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
150 const UnicodeString
& pattern
,
151 DecimalFormatPattern
& out
,
152 UParseError
& parseError
,
153 UErrorCode
& status
) {
154 if (U_FAILURE(status
))
158 out
= DecimalFormatPattern();
160 // Clear error struct
161 parseError
.offset
= -1;
162 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
164 // TODO: Travis Keep: This won't always work.
165 UChar nineDigit
= (UChar
)(fZeroDigit
+ 9);
166 int32_t digitLen
= fDigit
.length();
167 int32_t groupSepLen
= fGroupingSeparator
.length();
168 int32_t decimalSepLen
= fDecimalSeparator
.length();
171 int32_t patLen
= pattern
.length();
172 // Part 0 is the positive pattern. Part 1, if present, is the negative
174 for (int32_t part
=0; part
<2 && pos
<patLen
; ++part
) {
175 // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
176 // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
177 // between the prefix and suffix, and consists of pattern
178 // characters. In the prefix and suffix, percent, perMill, and
179 // currency symbols are recognized and translated.
180 int32_t subpart
= 1, sub0Start
= 0, sub0Limit
= 0, sub2Limit
= 0;
182 // It's important that we don't change any fields of this object
183 // prematurely. We set the following variables for the multiplier,
184 // grouping, etc., and then only change the actual object fields if
185 // everything parses correctly. This also lets us register
186 // the data from part 0 and ignore the part 1, except for the
187 // prefix and suffix.
188 UnicodeString prefix
;
189 UnicodeString suffix
;
190 int32_t decimalPos
= -1;
191 int32_t multiplier
= 1;
192 int32_t digitLeftCount
= 0, zeroDigitCount
= 0, digitRightCount
= 0, sigDigitCount
= 0;
193 int8_t groupingCount
= -1;
194 int8_t groupingCount2
= -1;
197 int32_t roundingPos
= -1;
198 DigitList roundingInc
;
199 int8_t expDigits
= -1;
200 UBool expSignAlways
= FALSE
;
202 // The affix is either the prefix or the suffix.
203 UnicodeString
* affix
= &prefix
;
206 UBool isPartDone
= FALSE
;
209 for (; !isPartDone
&& pos
< patLen
; ) {
210 // Todo: account for surrogate pairs
211 ch
= pattern
.char32At(pos
);
213 case 0: // Pattern proper subpart (between prefix & suffix)
214 // Process the digits, decimal, and grouping characters. We
215 // record five pieces of information. We expect the digits
216 // to occur in the pattern ####00.00####, and we record the
217 // number of left digits, zero (central) digits, and right
218 // digits. The position of the last grouping character is
219 // recorded (should be somewhere within the first two blocks
220 // of characters), as is the position of the decimal point,
221 // if any (should be in the zero digits). If there is no
222 // decimal point, then there should be no right digits.
223 if (pattern
.compare(pos
, digitLen
, fDigit
) == 0) {
224 if (zeroDigitCount
> 0 || sigDigitCount
> 0) {
229 if (groupingCount
>= 0 && decimalPos
< 0) {
233 } else if ((ch
>= fZeroDigit
&& ch
<= nineDigit
) ||
235 if (digitRightCount
> 0) {
237 debug("Unexpected '0'")
238 status
= U_UNEXPECTED_TOKEN
;
239 syntaxError(pattern
,pos
,parseError
);
242 if (ch
== fSigDigit
) {
245 if (ch
!= fZeroDigit
&& roundingPos
< 0) {
246 roundingPos
= digitLeftCount
+ zeroDigitCount
;
248 if (roundingPos
>= 0) {
249 roundingInc
.append((char)(ch
- fZeroDigit
+ '0'));
253 if (groupingCount
>= 0 && decimalPos
< 0) {
256 pos
+= U16_LENGTH(ch
);
257 } else if (pattern
.compare(pos
, groupSepLen
, fGroupingSeparator
) == 0) {
258 if (decimalPos
>= 0) {
259 // Grouping separator after decimal
260 debug("Grouping separator after decimal")
261 status
= U_UNEXPECTED_TOKEN
;
262 syntaxError(pattern
,pos
,parseError
);
265 groupingCount2
= groupingCount
;
268 } else if (pattern
.compare(pos
, decimalSepLen
, fDecimalSeparator
) == 0) {
269 if (decimalPos
>= 0) {
270 // Multiple decimal separators
271 debug("Multiple decimal separators")
272 status
= U_MULTIPLE_DECIMAL_SEPARATORS
;
273 syntaxError(pattern
,pos
,parseError
);
276 // Intentionally incorporate the digitRightCount,
277 // even though it is illegal for this to be > 0
278 // at this point. We check pattern syntax below.
279 decimalPos
= digitLeftCount
+ zeroDigitCount
+ digitRightCount
;
280 pos
+= decimalSepLen
;
282 if (pattern
.compare(pos
, fExponent
.length(), fExponent
) == 0) {
283 if (expDigits
>= 0) {
284 // Multiple exponential symbols
285 debug("Multiple exponential symbols")
286 status
= U_MULTIPLE_EXPONENTIAL_SYMBOLS
;
287 syntaxError(pattern
,pos
,parseError
);
290 if (groupingCount
>= 0) {
291 // Grouping separator in exponential pattern
292 debug("Grouping separator in exponential pattern")
293 status
= U_MALFORMED_EXPONENTIAL_PATTERN
;
294 syntaxError(pattern
,pos
,parseError
);
297 pos
+= fExponent
.length();
298 // Check for positive prefix
300 && pattern
.compare(pos
, fPlus
.length(), fPlus
) == 0) {
301 expSignAlways
= TRUE
;
302 pos
+= fPlus
.length();
304 // Use lookahead to parse out the exponential part of the
305 // pattern, then jump into suffix subpart.
307 while (pos
< patLen
&&
308 pattern
.char32At(pos
) == fZeroDigit
) {
310 pos
+= U16_LENGTH(fZeroDigit
);
313 // 1. Require at least one mantissa pattern digit
314 // 2. Disallow "#+ @" in mantissa
315 // 3. Require at least one exponent pattern digit
316 if (((digitLeftCount
+ zeroDigitCount
) < 1 &&
317 (sigDigitCount
+ digitRightCount
) < 1) ||
318 (sigDigitCount
> 0 && digitLeftCount
> 0) ||
320 // Malformed exponential pattern
321 debug("Malformed exponential pattern")
322 status
= U_MALFORMED_EXPONENTIAL_PATTERN
;
323 syntaxError(pattern
,pos
,parseError
);
327 // Transition to suffix subpart
328 subpart
= 2; // suffix subpart
334 case 1: // Prefix subpart
335 case 2: // Suffix subpart
336 // Process the prefix / suffix characters
337 // Process unquoted characters seen in prefix or suffix
340 // Several syntax characters implicitly begins the
341 // next subpart if we are in the prefix; otherwise
342 // they are illegal if unquoted.
343 if (!pattern
.compare(pos
, digitLen
, fDigit
) ||
344 !pattern
.compare(pos
, groupSepLen
, fGroupingSeparator
) ||
345 !pattern
.compare(pos
, decimalSepLen
, fDecimalSeparator
) ||
346 (ch
>= fZeroDigit
&& ch
<= nineDigit
) ||
348 if (subpart
== 1) { // prefix subpart
349 subpart
= 0; // pattern proper subpart
350 sub0Start
= pos
; // Reprocess this character
353 status
= U_UNQUOTED_SPECIAL
;
354 syntaxError(pattern
,pos
,parseError
);
357 } else if (ch
== kCurrencySign
) {
358 affix
->append(kQuote
); // Encode currency
359 // Use lookahead to determine if the currency sign is
361 U_ASSERT(U16_LENGTH(kCurrencySign
) == 1);
362 if ((pos
+1) < pattern
.length() && pattern
[pos
+1] == kCurrencySign
) {
363 affix
->append(kCurrencySign
);
364 ++pos
; // Skip over the doubled character
365 if ((pos
+1) < pattern
.length() &&
366 pattern
[pos
+1] == kCurrencySign
) {
367 affix
->append(kCurrencySign
);
368 ++pos
; // Skip over the doubled character
369 out
.fCurrencySignCount
= fgCurrencySignCountInPluralFormat
;
371 out
.fCurrencySignCount
= fgCurrencySignCountInISOFormat
;
374 out
.fCurrencySignCount
= fgCurrencySignCountInSymbolFormat
;
376 // Fall through to append(ch)
377 } else if (ch
== kQuote
) {
378 // A quote outside quotes indicates either the opening
379 // quote or two quotes, which is a quote literal. That is,
380 // we have the first quote in 'do' or o''clock.
381 U_ASSERT(U16_LENGTH(kQuote
) == 1);
383 if (pos
< pattern
.length() && pattern
[pos
] == kQuote
) {
384 affix
->append(kQuote
); // Encode quote
385 // Fall through to append(ch)
387 subpart
+= 2; // open quote
390 } else if (pattern
.compare(pos
, fSeparator
.length(), fSeparator
) == 0) {
391 // Don't allow separators in the prefix, and don't allow
392 // separators in the second pattern (part == 1).
393 if (subpart
== 1 || part
== 1) {
394 // Unexpected separator
395 debug("Unexpected separator")
396 status
= U_UNEXPECTED_TOKEN
;
397 syntaxError(pattern
,pos
,parseError
);
401 isPartDone
= TRUE
; // Go to next part
402 pos
+= fSeparator
.length();
404 } else if (pattern
.compare(pos
, fPercent
.length(), fPercent
) == 0) {
405 // Next handle characters which are appended directly.
406 if (multiplier
!= 1) {
407 // Too many percent/perMill characters
408 debug("Too many percent characters")
409 status
= U_MULTIPLE_PERCENT_SYMBOLS
;
410 syntaxError(pattern
,pos
,parseError
);
413 affix
->append(kQuote
); // Encode percent/perMill
414 affix
->append(kPatternPercent
); // Use unlocalized pattern char
416 pos
+= fPercent
.length();
418 } else if (pattern
.compare(pos
, fPerMill
.length(), fPerMill
) == 0) {
419 // Next handle characters which are appended directly.
420 if (multiplier
!= 1) {
421 // Too many percent/perMill characters
422 debug("Too many perMill characters")
423 status
= U_MULTIPLE_PERMILL_SYMBOLS
;
424 syntaxError(pattern
,pos
,parseError
);
427 affix
->append(kQuote
); // Encode percent/perMill
428 affix
->append(kPatternPerMill
); // Use unlocalized pattern char
430 pos
+= fPerMill
.length();
432 } else if (pattern
.compare(pos
, fPadEscape
.length(), fPadEscape
) == 0) {
433 if (padPos
>= 0 || // Multiple pad specifiers
434 (pos
+1) == pattern
.length()) { // Nothing after padEscape
435 debug("Multiple pad specifiers")
436 status
= U_MULTIPLE_PAD_SPECIFIERS
;
437 syntaxError(pattern
,pos
,parseError
);
441 pos
+= fPadEscape
.length();
442 padChar
= pattern
.char32At(pos
);
443 pos
+= U16_LENGTH(padChar
);
445 } else if (pattern
.compare(pos
, fMinus
.length(), fMinus
) == 0) {
446 affix
->append(kQuote
); // Encode minus
447 affix
->append(kPatternMinus
);
448 pos
+= fMinus
.length();
450 } else if (pattern
.compare(pos
, fPlus
.length(), fPlus
) == 0) {
451 affix
->append(kQuote
); // Encode plus
452 affix
->append(kPatternPlus
);
453 pos
+= fPlus
.length();
456 // Unquoted, non-special characters fall through to here, as
457 // well as other code which needs to append something to the
460 pos
+= U16_LENGTH(ch
);
462 case 3: // Prefix subpart, in quote
463 case 4: // Suffix subpart, in quote
464 // A quote within quotes indicates either the closing
465 // quote or two quotes, which is a quote literal. That is,
466 // we have the second quote in 'do' or 'don''t'.
469 if (pos
< pattern
.length() && pattern
[pos
] == kQuote
) {
470 affix
->append(kQuote
); // Encode quote
471 // Fall through to append(ch)
473 subpart
-= 2; // close quote
478 pos
+= U16_LENGTH(ch
);
483 if (sub0Limit
== 0) {
484 sub0Limit
= pattern
.length();
487 if (sub2Limit
== 0) {
488 sub2Limit
= pattern
.length();
491 /* Handle patterns with no '0' pattern character. These patterns
492 * are legal, but must be recodified to make sense. "##.###" ->
493 * "#0.###". ".###" -> ".0##".
495 * We allow patterns of the form "####" to produce a zeroDigitCount
496 * of zero (got that?); although this seems like it might make it
497 * possible for format() to produce empty strings, format() checks
498 * for this condition and outputs a zero digit in this situation.
499 * Having a zeroDigitCount of zero yields a minimum integer digits
500 * of zero, which allows proper round-trip patterns. We don't want
501 * "#" to become "#0" when toPattern() is called (even though that's
502 * what it really is, semantically).
504 if (zeroDigitCount
== 0 && sigDigitCount
== 0 &&
505 digitLeftCount
> 0 && decimalPos
>= 0) {
506 // Handle "###.###" and "###." and ".###"
509 ++n
; // Handle ".###"
510 digitRightCount
= digitLeftCount
- n
;
511 digitLeftCount
= n
- 1;
515 // Do syntax checking on the digits, decimal points, and quotes.
516 if ((decimalPos
< 0 && digitRightCount
> 0 && sigDigitCount
== 0) ||
518 (sigDigitCount
> 0 ||
519 decimalPos
< digitLeftCount
||
520 decimalPos
> (digitLeftCount
+ zeroDigitCount
))) ||
521 groupingCount
== 0 || groupingCount2
== 0 ||
522 (sigDigitCount
> 0 && zeroDigitCount
> 0) ||
524 { // subpart > 2 == unmatched quote
525 debug("Syntax error")
526 status
= U_PATTERN_SYNTAX_ERROR
;
527 syntaxError(pattern
,pos
,parseError
);
531 // Make sure pad is at legal position before or after affix.
533 if (padPos
== start
) {
534 padPos
= DecimalFormatPattern::kPadBeforePrefix
;
535 } else if (padPos
+2 == sub0Start
) {
536 padPos
= DecimalFormatPattern::kPadAfterPrefix
;
537 } else if (padPos
== sub0Limit
) {
538 padPos
= DecimalFormatPattern::kPadBeforeSuffix
;
539 } else if (padPos
+2 == sub2Limit
) {
540 padPos
= DecimalFormatPattern::kPadAfterSuffix
;
542 // Illegal pad position
543 debug("Illegal pad position")
544 status
= U_ILLEGAL_PAD_POSITION
;
545 syntaxError(pattern
,pos
,parseError
);
551 out
.fPosPatternsBogus
= FALSE
;
552 out
.fPosPrefixPattern
= prefix
;
553 out
.fPosSuffixPattern
= suffix
;
554 out
.fNegPatternsBogus
= TRUE
;
555 out
.fNegPrefixPattern
.remove();
556 out
.fNegSuffixPattern
.remove();
558 out
.fUseExponentialNotation
= (expDigits
>= 0);
559 if (out
.fUseExponentialNotation
) {
560 out
.fMinExponentDigits
= expDigits
;
562 out
.fExponentSignAlwaysShown
= expSignAlways
;
563 int32_t digitTotalCount
= digitLeftCount
+ zeroDigitCount
+ digitRightCount
;
564 // The effectiveDecimalPos is the position the decimal is at or
565 // would be at if there is no decimal. Note that if
566 // decimalPos<0, then digitTotalCount == digitLeftCount +
568 int32_t effectiveDecimalPos
= decimalPos
>= 0 ? decimalPos
: digitTotalCount
;
569 UBool isSigDig
= (sigDigitCount
> 0);
570 out
.fUseSignificantDigits
= isSigDig
;
572 out
.fMinimumSignificantDigits
= sigDigitCount
;
573 out
.fMaximumSignificantDigits
= sigDigitCount
+ digitRightCount
;
575 int32_t minInt
= effectiveDecimalPos
- digitLeftCount
;
576 out
.fMinimumIntegerDigits
= minInt
;
577 out
.fMaximumIntegerDigits
= out
.fUseExponentialNotation
578 ? digitLeftCount
+ out
.fMinimumIntegerDigits
579 : gDefaultMaxIntegerDigits
;
580 out
.fMaximumFractionDigits
= decimalPos
>= 0
581 ? (digitTotalCount
- decimalPos
) : 0;
582 out
.fMinimumFractionDigits
= decimalPos
>= 0
583 ? (digitLeftCount
+ zeroDigitCount
- decimalPos
) : 0;
585 out
.fGroupingUsed
= groupingCount
> 0;
586 out
.fGroupingSize
= (groupingCount
> 0) ? groupingCount
: 0;
587 out
.fGroupingSize2
= (groupingCount2
> 0 && groupingCount2
!= groupingCount
)
588 ? groupingCount2
: 0;
589 out
.fMultiplier
= multiplier
;
590 out
.fDecimalSeparatorAlwaysShown
= decimalPos
== 0
591 || decimalPos
== digitTotalCount
;
593 out
.fPadPosition
= (DecimalFormatPattern::EPadPosition
) padPos
;
594 // To compute the format width, first set up sub0Limit -
595 // sub0Start. Add in prefix/suffix length later.
597 // fFormatWidth = prefix.length() + suffix.length() +
598 // sub0Limit - sub0Start;
599 out
.fFormatWidth
= sub0Limit
- sub0Start
;
602 out
.fFormatWidth
= 0;
604 if (roundingPos
>= 0) {
605 out
.fRoundingIncrementUsed
= TRUE
;
606 roundingInc
.setDecimalAt(effectiveDecimalPos
- roundingPos
);
607 out
.fRoundingIncrement
= roundingInc
;
609 out
.fRoundingIncrementUsed
= FALSE
;
612 out
.fNegPatternsBogus
= FALSE
;
613 out
.fNegPrefixPattern
= prefix
;
614 out
.fNegSuffixPattern
= suffix
;
618 if (pattern
.length() == 0) {
619 out
.fNegPatternsBogus
= TRUE
;
620 out
.fNegPrefixPattern
.remove();
621 out
.fNegSuffixPattern
.remove();
622 out
.fPosPatternsBogus
= FALSE
;
623 out
.fPosPrefixPattern
.remove();
624 out
.fPosSuffixPattern
.remove();
626 out
.fMinimumIntegerDigits
= 0;
627 out
.fMaximumIntegerDigits
= kDoubleIntegerDigits
;
628 out
.fMinimumFractionDigits
= 0;
629 out
.fMaximumFractionDigits
= kDoubleFractionDigits
;
631 out
.fUseExponentialNotation
= FALSE
;
632 out
.fCurrencySignCount
= fgCurrencySignCountZero
;
633 out
.fGroupingUsed
= FALSE
;
634 out
.fGroupingSize
= 0;
635 out
.fGroupingSize2
= 0;
637 out
.fDecimalSeparatorAlwaysShown
= FALSE
;
638 out
.fFormatWidth
= 0;
639 out
.fRoundingIncrementUsed
= FALSE
;
642 // If there was no negative pattern, or if the negative pattern is
643 // identical to the positive pattern, then prepend the minus sign to the
644 // positive pattern to form the negative pattern.
645 if (out
.fNegPatternsBogus
||
646 (out
.fNegPrefixPattern
== out
.fPosPrefixPattern
647 && out
.fNegSuffixPattern
== out
.fPosSuffixPattern
)) {
648 out
.fNegPatternsBogus
= FALSE
;
649 out
.fNegSuffixPattern
= out
.fPosSuffixPattern
;
650 out
.fNegPrefixPattern
.remove();
651 out
.fNegPrefixPattern
.append(kQuote
).append(kPatternMinus
)
652 .append(out
.fPosPrefixPattern
);
658 #endif /* !UCONFIG_NO_FORMATTING */