• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 1997-2015, International Business Machines Corporation and    *
6 * others. All Rights Reserved.                                                *
7 *******************************************************************************
8 */
9 
10 #include "uassert.h"
11 #include "decimalformatpattern.h"
12 
13 #if !UCONFIG_NO_FORMATTING
14 
15 #include "unicode/dcfmtsym.h"
16 #include "unicode/format.h"
17 #include "unicode/utf16.h"
18 #include "decimalformatpatternimpl.h"
19 
20 
21 #ifdef FMT_DEBUG
22 #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
23 #else
24 #define debug(x)
25 #endif
26 
27 U_NAMESPACE_BEGIN
28 
29 // TODO: Travis Keep: Copied from numfmt.cpp
30 static int32_t kDoubleIntegerDigits  = 309;
31 static int32_t kDoubleFractionDigits = 340;
32 
33 
34 // TODO: Travis Keep: Copied from numfmt.cpp
35 static int32_t gDefaultMaxIntegerDigits = 2000000000;
36 
37 // TODO: Travis Keep: This function was copied from format.cpp
syntaxError(const UnicodeString & pattern,int32_t pos,UParseError & parseError)38 static void syntaxError(const UnicodeString& pattern,
39                          int32_t pos,
40                          UParseError& parseError) {
41     parseError.offset = pos;
42     parseError.line=0;  // we are not using line number
43 
44     // for pre-context
45     int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1
46                                                              /* subtract 1 so that we have room for null*/));
47     int32_t stop  = pos;
48     pattern.extract(start,stop-start,parseError.preContext,0);
49     //null terminate the buffer
50     parseError.preContext[stop-start] = 0;
51 
52     //for post-context
53     start = pos+1;
54     stop  = ((pos+U_PARSE_CONTEXT_LEN)<=pattern.length()) ? (pos+(U_PARSE_CONTEXT_LEN-1)) :
55         pattern.length();
56     pattern.extract(start,stop-start,parseError.postContext,0);
57     //null terminate the buffer
58     parseError.postContext[stop-start]= 0;
59 }
60 
DecimalFormatPattern()61 DecimalFormatPattern::DecimalFormatPattern()
62         : fMinimumIntegerDigits(1),
63           fMaximumIntegerDigits(gDefaultMaxIntegerDigits),
64           fMinimumFractionDigits(0),
65           fMaximumFractionDigits(3),
66           fUseSignificantDigits(FALSE),
67           fMinimumSignificantDigits(1),
68           fMaximumSignificantDigits(6),
69           fUseExponentialNotation(FALSE),
70           fMinExponentDigits(0),
71           fExponentSignAlwaysShown(FALSE),
72           fCurrencySignCount(fgCurrencySignCountZero),
73           fGroupingUsed(TRUE),
74           fGroupingSize(0),
75           fGroupingSize2(0),
76           fMultiplier(1),
77           fDecimalSeparatorAlwaysShown(FALSE),
78           fFormatWidth(0),
79           fRoundingIncrementUsed(FALSE),
80           fRoundingIncrement(),
81           fPad(kDefaultPad),
82           fNegPatternsBogus(TRUE),
83           fPosPatternsBogus(TRUE),
84           fNegPrefixPattern(),
85           fNegSuffixPattern(),
86           fPosPrefixPattern(),
87           fPosSuffixPattern(),
88           fPadPosition(DecimalFormatPattern::kPadBeforePrefix) {
89 }
90 
91 
DecimalFormatPatternParser()92 DecimalFormatPatternParser::DecimalFormatPatternParser() :
93     fZeroDigit(kPatternZeroDigit),
94     fSigDigit(kPatternSignificantDigit),
95     fGroupingSeparator((UChar)kPatternGroupingSeparator),
96     fDecimalSeparator((UChar)kPatternDecimalSeparator),
97     fPercent((UChar)kPatternPercent),
98     fPerMill((UChar)kPatternPerMill),
99     fDigit((UChar)kPatternDigit),
100     fSeparator((UChar)kPatternSeparator),
101     fExponent((UChar)kPatternExponent),
102     fPlus((UChar)kPatternPlus),
103     fMinus((UChar)kPatternMinus),
104     fPadEscape((UChar)kPatternPadEscape) {
105 }
106 
useSymbols(const DecimalFormatSymbols & symbols)107 void DecimalFormatPatternParser::useSymbols(
108         const DecimalFormatSymbols& symbols) {
109     fZeroDigit = symbols.getConstSymbol(
110             DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
111     fSigDigit = symbols.getConstSymbol(
112             DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
113     fGroupingSeparator = symbols.getConstSymbol(
114             DecimalFormatSymbols::kGroupingSeparatorSymbol);
115     fDecimalSeparator = symbols.getConstSymbol(
116             DecimalFormatSymbols::kDecimalSeparatorSymbol);
117     fPercent = symbols.getConstSymbol(
118             DecimalFormatSymbols::kPercentSymbol);
119     fPerMill = symbols.getConstSymbol(
120             DecimalFormatSymbols::kPerMillSymbol);
121     fDigit = symbols.getConstSymbol(
122             DecimalFormatSymbols::kDigitSymbol);
123     fSeparator = symbols.getConstSymbol(
124             DecimalFormatSymbols::kPatternSeparatorSymbol);
125     fExponent = symbols.getConstSymbol(
126             DecimalFormatSymbols::kExponentialSymbol);
127     fPlus = symbols.getConstSymbol(
128             DecimalFormatSymbols::kPlusSignSymbol);
129     fMinus = symbols.getConstSymbol(
130             DecimalFormatSymbols::kMinusSignSymbol);
131     fPadEscape = symbols.getConstSymbol(
132             DecimalFormatSymbols::kPadEscapeSymbol);
133 }
134 
135 void
applyPatternWithoutExpandAffix(const UnicodeString & pattern,DecimalFormatPattern & out,UParseError & parseError,UErrorCode & status)136 DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
137         const UnicodeString& pattern,
138         DecimalFormatPattern& out,
139         UParseError& parseError,
140         UErrorCode& status) {
141     if (U_FAILURE(status))
142     {
143         return;
144     }
145     out = DecimalFormatPattern();
146 
147     // Clear error struct
148     parseError.offset = -1;
149     parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
150 
151     // TODO: Travis Keep: This won't always work.
152     UChar nineDigit = (UChar)(fZeroDigit + 9);
153     int32_t digitLen = fDigit.length();
154     int32_t groupSepLen = fGroupingSeparator.length();
155     int32_t decimalSepLen = fDecimalSeparator.length();
156 
157     int32_t pos = 0;
158     int32_t patLen = pattern.length();
159     // Part 0 is the positive pattern.  Part 1, if present, is the negative
160     // pattern.
161     for (int32_t part=0; part<2 && pos<patLen; ++part) {
162         // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
163         // 2=suffix, 3=prefix in quote, 4=suffix in quote.  Subpart 0 is
164         // between the prefix and suffix, and consists of pattern
165         // characters.  In the prefix and suffix, percent, perMill, and
166         // currency symbols are recognized and translated.
167         int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
168 
169         // It's important that we don't change any fields of this object
170         // prematurely.  We set the following variables for the multiplier,
171         // grouping, etc., and then only change the actual object fields if
172         // everything parses correctly.  This also lets us register
173         // the data from part 0 and ignore the part 1, except for the
174         // prefix and suffix.
175         UnicodeString prefix;
176         UnicodeString suffix;
177         int32_t decimalPos = -1;
178         int32_t multiplier = 1;
179         int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
180         int8_t groupingCount = -1;
181         int8_t groupingCount2 = -1;
182         int32_t padPos = -1;
183         UChar32 padChar = 0;
184         int32_t roundingPos = -1;
185         DigitList roundingInc;
186         int8_t expDigits = -1;
187         UBool expSignAlways = FALSE;
188 
189         // The affix is either the prefix or the suffix.
190         UnicodeString* affix = &prefix;
191 
192         int32_t start = pos;
193         UBool isPartDone = FALSE;
194         UChar32 ch;
195 
196         for (; !isPartDone && pos < patLen; ) {
197             // Todo: account for surrogate pairs
198             ch = pattern.char32At(pos);
199             switch (subpart) {
200             case 0: // Pattern proper subpart (between prefix & suffix)
201                 // Process the digits, decimal, and grouping characters.  We
202                 // record five pieces of information.  We expect the digits
203                 // to occur in the pattern ####00.00####, and we record the
204                 // number of left digits, zero (central) digits, and right
205                 // digits.  The position of the last grouping character is
206                 // recorded (should be somewhere within the first two blocks
207                 // of characters), as is the position of the decimal point,
208                 // if any (should be in the zero digits).  If there is no
209                 // decimal point, then there should be no right digits.
210                 if (pattern.compare(pos, digitLen, fDigit) == 0) {
211                     if (zeroDigitCount > 0 || sigDigitCount > 0) {
212                         ++digitRightCount;
213                     } else {
214                         ++digitLeftCount;
215                     }
216                     if (groupingCount >= 0 && decimalPos < 0) {
217                         ++groupingCount;
218                     }
219                     pos += digitLen;
220                 } else if ((ch >= fZeroDigit && ch <= nineDigit) ||
221                            ch == fSigDigit) {
222                     if (digitRightCount > 0) {
223                         // Unexpected '0'
224                         debug("Unexpected '0'")
225                         status = U_UNEXPECTED_TOKEN;
226                         syntaxError(pattern,pos,parseError);
227                         return;
228                     }
229                     if (ch == fSigDigit) {
230                         ++sigDigitCount;
231                     } else {
232                         if (ch != fZeroDigit && roundingPos < 0) {
233                             roundingPos = digitLeftCount + zeroDigitCount;
234                         }
235                         if (roundingPos >= 0) {
236                             roundingInc.append((char)(ch - fZeroDigit + '0'));
237                         }
238                         ++zeroDigitCount;
239                     }
240                     if (groupingCount >= 0 && decimalPos < 0) {
241                         ++groupingCount;
242                     }
243                     pos += U16_LENGTH(ch);
244                 } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) {
245                     if (decimalPos >= 0) {
246                         // Grouping separator after decimal
247                         debug("Grouping separator after decimal")
248                         status = U_UNEXPECTED_TOKEN;
249                         syntaxError(pattern,pos,parseError);
250                         return;
251                     }
252                     groupingCount2 = groupingCount;
253                     groupingCount = 0;
254                     pos += groupSepLen;
255                 } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) {
256                     if (decimalPos >= 0) {
257                         // Multiple decimal separators
258                         debug("Multiple decimal separators")
259                         status = U_MULTIPLE_DECIMAL_SEPARATORS;
260                         syntaxError(pattern,pos,parseError);
261                         return;
262                     }
263                     // Intentionally incorporate the digitRightCount,
264                     // even though it is illegal for this to be > 0
265                     // at this point.  We check pattern syntax below.
266                     decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
267                     pos += decimalSepLen;
268                 } else {
269                     if (pattern.compare(pos, fExponent.length(), fExponent) == 0) {
270                         if (expDigits >= 0) {
271                             // Multiple exponential symbols
272                             debug("Multiple exponential symbols")
273                             status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
274                             syntaxError(pattern,pos,parseError);
275                             return;
276                         }
277                         if (groupingCount >= 0) {
278                             // Grouping separator in exponential pattern
279                             debug("Grouping separator in exponential pattern")
280                             status = U_MALFORMED_EXPONENTIAL_PATTERN;
281                             syntaxError(pattern,pos,parseError);
282                             return;
283                         }
284                         pos += fExponent.length();
285                         // Check for positive prefix
286                         if (pos < patLen
287                             && pattern.compare(pos, fPlus.length(), fPlus) == 0) {
288                             expSignAlways = TRUE;
289                             pos += fPlus.length();
290                         }
291                         // Use lookahead to parse out the exponential part of the
292                         // pattern, then jump into suffix subpart.
293                         expDigits = 0;
294                         while (pos < patLen &&
295                                pattern.char32At(pos) == fZeroDigit) {
296                             ++expDigits;
297                             pos += U16_LENGTH(fZeroDigit);
298                         }
299 
300                         // 1. Require at least one mantissa pattern digit
301                         // 2. Disallow "#+ @" in mantissa
302                         // 3. Require at least one exponent pattern digit
303                         if (((digitLeftCount + zeroDigitCount) < 1 &&
304                              (sigDigitCount + digitRightCount) < 1) ||
305                             (sigDigitCount > 0 && digitLeftCount > 0) ||
306                             expDigits < 1) {
307                             // Malformed exponential pattern
308                             debug("Malformed exponential pattern")
309                             status = U_MALFORMED_EXPONENTIAL_PATTERN;
310                             syntaxError(pattern,pos,parseError);
311                             return;
312                         }
313                     }
314                     // Transition to suffix subpart
315                     subpart = 2; // suffix subpart
316                     affix = &suffix;
317                     sub0Limit = pos;
318                     continue;
319                 }
320                 break;
321             case 1: // Prefix subpart
322             case 2: // Suffix subpart
323                 // Process the prefix / suffix characters
324                 // Process unquoted characters seen in prefix or suffix
325                 // subpart.
326 
327                 // Several syntax characters implicitly begins the
328                 // next subpart if we are in the prefix; otherwise
329                 // they are illegal if unquoted.
330                 if (!pattern.compare(pos, digitLen, fDigit) ||
331                     !pattern.compare(pos, groupSepLen, fGroupingSeparator) ||
332                     !pattern.compare(pos, decimalSepLen, fDecimalSeparator) ||
333                     (ch >= fZeroDigit && ch <= nineDigit) ||
334                     ch == fSigDigit) {
335                     if (subpart == 1) { // prefix subpart
336                         subpart = 0; // pattern proper subpart
337                         sub0Start = pos; // Reprocess this character
338                         continue;
339                     } else {
340                         status = U_UNQUOTED_SPECIAL;
341                         syntaxError(pattern,pos,parseError);
342                         return;
343                     }
344                 } else if (ch == kCurrencySign) {
345                     affix->append(kQuote); // Encode currency
346                     // Use lookahead to determine if the currency sign is
347                     // doubled or not.
348                     U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
349                     if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
350                         affix->append(kCurrencySign);
351                         ++pos; // Skip over the doubled character
352                         if ((pos+1) < pattern.length() &&
353                             pattern[pos+1] == kCurrencySign) {
354                             affix->append(kCurrencySign);
355                             ++pos; // Skip over the doubled character
356                             out.fCurrencySignCount = fgCurrencySignCountInPluralFormat;
357                         } else {
358                             out.fCurrencySignCount = fgCurrencySignCountInISOFormat;
359                         }
360                     } else {
361                         out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
362                     }
363                     // Fall through to append(ch)
364                 } else if (ch == kQuote) {
365                     // A quote outside quotes indicates either the opening
366                     // quote or two quotes, which is a quote literal.  That is,
367                     // we have the first quote in 'do' or o''clock.
368                     U_ASSERT(U16_LENGTH(kQuote) == 1);
369                     ++pos;
370                     if (pos < pattern.length() && pattern[pos] == kQuote) {
371                         affix->append(kQuote); // Encode quote
372                         // Fall through to append(ch)
373                     } else {
374                         subpart += 2; // open quote
375                         continue;
376                     }
377                 } else if (pattern.compare(pos, fSeparator.length(), fSeparator) == 0) {
378                     // Don't allow separators in the prefix, and don't allow
379                     // separators in the second pattern (part == 1).
380                     if (subpart == 1 || part == 1) {
381                         // Unexpected separator
382                         debug("Unexpected separator")
383                         status = U_UNEXPECTED_TOKEN;
384                         syntaxError(pattern,pos,parseError);
385                         return;
386                     }
387                     sub2Limit = pos;
388                     isPartDone = TRUE; // Go to next part
389                     pos += fSeparator.length();
390                     break;
391                 } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) {
392                     // Next handle characters which are appended directly.
393                     if (multiplier != 1) {
394                         // Too many percent/perMill characters
395                         debug("Too many percent characters")
396                         status = U_MULTIPLE_PERCENT_SYMBOLS;
397                         syntaxError(pattern,pos,parseError);
398                         return;
399                     }
400                     affix->append(kQuote); // Encode percent/perMill
401                     affix->append(kPatternPercent); // Use unlocalized pattern char
402                     multiplier = 100;
403                     pos += fPercent.length();
404                     break;
405                 } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) {
406                     // Next handle characters which are appended directly.
407                     if (multiplier != 1) {
408                         // Too many percent/perMill characters
409                         debug("Too many perMill characters")
410                         status = U_MULTIPLE_PERMILL_SYMBOLS;
411                         syntaxError(pattern,pos,parseError);
412                         return;
413                     }
414                     affix->append(kQuote); // Encode percent/perMill
415                     affix->append(kPatternPerMill); // Use unlocalized pattern char
416                     multiplier = 1000;
417                     pos += fPerMill.length();
418                     break;
419                 } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) {
420                     if (padPos >= 0 ||               // Multiple pad specifiers
421                         (pos+1) == pattern.length()) { // Nothing after padEscape
422                         debug("Multiple pad specifiers")
423                         status = U_MULTIPLE_PAD_SPECIFIERS;
424                         syntaxError(pattern,pos,parseError);
425                         return;
426                     }
427                     padPos = pos;
428                     pos += fPadEscape.length();
429                     padChar = pattern.char32At(pos);
430                     pos += U16_LENGTH(padChar);
431                     break;
432                 } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) {
433                     affix->append(kQuote); // Encode minus
434                     affix->append(kPatternMinus);
435                     pos += fMinus.length();
436                     break;
437                 } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) {
438                     affix->append(kQuote); // Encode plus
439                     affix->append(kPatternPlus);
440                     pos += fPlus.length();
441                     break;
442                 }
443                 // Unquoted, non-special characters fall through to here, as
444                 // well as other code which needs to append something to the
445                 // affix.
446                 affix->append(ch);
447                 pos += U16_LENGTH(ch);
448                 break;
449             case 3: // Prefix subpart, in quote
450             case 4: // Suffix subpart, in quote
451                 // A quote within quotes indicates either the closing
452                 // quote or two quotes, which is a quote literal.  That is,
453                 // we have the second quote in 'do' or 'don''t'.
454                 if (ch == kQuote) {
455                     ++pos;
456                     if (pos < pattern.length() && pattern[pos] == kQuote) {
457                         affix->append(kQuote); // Encode quote
458                         // Fall through to append(ch)
459                     } else {
460                         subpart -= 2; // close quote
461                         continue;
462                     }
463                 }
464                 affix->append(ch);
465                 pos += U16_LENGTH(ch);
466                 break;
467             }
468         }
469 
470         if (sub0Limit == 0) {
471             sub0Limit = pattern.length();
472         }
473 
474         if (sub2Limit == 0) {
475             sub2Limit = pattern.length();
476         }
477 
478         /* Handle patterns with no '0' pattern character.  These patterns
479          * are legal, but must be recodified to make sense.  "##.###" ->
480          * "#0.###".  ".###" -> ".0##".
481          *
482          * We allow patterns of the form "####" to produce a zeroDigitCount
483          * of zero (got that?); although this seems like it might make it
484          * possible for format() to produce empty strings, format() checks
485          * for this condition and outputs a zero digit in this situation.
486          * Having a zeroDigitCount of zero yields a minimum integer digits
487          * of zero, which allows proper round-trip patterns.  We don't want
488          * "#" to become "#0" when toPattern() is called (even though that's
489          * what it really is, semantically).
490          */
491         if (zeroDigitCount == 0 && sigDigitCount == 0 &&
492             digitLeftCount > 0 && decimalPos >= 0) {
493             // Handle "###.###" and "###." and ".###"
494             int n = decimalPos;
495             if (n == 0)
496                 ++n; // Handle ".###"
497             digitRightCount = digitLeftCount - n;
498             digitLeftCount = n - 1;
499             zeroDigitCount = 1;
500         }
501 
502         // Do syntax checking on the digits, decimal points, and quotes.
503         if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
504             (decimalPos >= 0 &&
505              (sigDigitCount > 0 ||
506               decimalPos < digitLeftCount ||
507               decimalPos > (digitLeftCount + zeroDigitCount))) ||
508             groupingCount == 0 || groupingCount2 == 0 ||
509             (sigDigitCount > 0 && zeroDigitCount > 0) ||
510             subpart > 2)
511         { // subpart > 2 == unmatched quote
512             debug("Syntax error")
513             status = U_PATTERN_SYNTAX_ERROR;
514             syntaxError(pattern,pos,parseError);
515             return;
516         }
517 
518         // Make sure pad is at legal position before or after affix.
519         if (padPos >= 0) {
520             if (padPos == start) {
521                 padPos = DecimalFormatPattern::kPadBeforePrefix;
522             } else if (padPos+2 == sub0Start) {
523                 padPos = DecimalFormatPattern::kPadAfterPrefix;
524             } else if (padPos == sub0Limit) {
525                 padPos = DecimalFormatPattern::kPadBeforeSuffix;
526             } else if (padPos+2 == sub2Limit) {
527                 padPos = DecimalFormatPattern::kPadAfterSuffix;
528             } else {
529                 // Illegal pad position
530                 debug("Illegal pad position")
531                 status = U_ILLEGAL_PAD_POSITION;
532                 syntaxError(pattern,pos,parseError);
533                 return;
534             }
535         }
536 
537         if (part == 0) {
538             out.fPosPatternsBogus = FALSE;
539             out.fPosPrefixPattern = prefix;
540             out.fPosSuffixPattern = suffix;
541             out.fNegPatternsBogus = TRUE;
542             out.fNegPrefixPattern.remove();
543             out.fNegSuffixPattern.remove();
544 
545             out.fUseExponentialNotation = (expDigits >= 0);
546             if (out.fUseExponentialNotation) {
547               out.fMinExponentDigits = expDigits;
548             }
549             out.fExponentSignAlwaysShown = expSignAlways;
550             int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
551             // The effectiveDecimalPos is the position the decimal is at or
552             // would be at if there is no decimal.  Note that if
553             // decimalPos<0, then digitTotalCount == digitLeftCount +
554             // zeroDigitCount.
555             int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
556             UBool isSigDig = (sigDigitCount > 0);
557             out.fUseSignificantDigits = isSigDig;
558             if (isSigDig) {
559                 out.fMinimumSignificantDigits = sigDigitCount;
560                 out.fMaximumSignificantDigits = sigDigitCount + digitRightCount;
561             } else {
562                 int32_t minInt = effectiveDecimalPos - digitLeftCount;
563                 out.fMinimumIntegerDigits = minInt;
564                 out.fMaximumIntegerDigits = out.fUseExponentialNotation
565                     ? digitLeftCount + out.fMinimumIntegerDigits
566                     : gDefaultMaxIntegerDigits;
567                 out.fMaximumFractionDigits = decimalPos >= 0
568                     ? (digitTotalCount - decimalPos) : 0;
569                 out.fMinimumFractionDigits = decimalPos >= 0
570                     ? (digitLeftCount + zeroDigitCount - decimalPos) : 0;
571             }
572             out.fGroupingUsed = groupingCount > 0;
573             out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
574             out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
575                 ? groupingCount2 : 0;
576             out.fMultiplier = multiplier;
577             out.fDecimalSeparatorAlwaysShown = decimalPos == 0
578                     || decimalPos == digitTotalCount;
579             if (padPos >= 0) {
580                 out.fPadPosition = (DecimalFormatPattern::EPadPosition) padPos;
581                 // To compute the format width, first set up sub0Limit -
582                 // sub0Start.  Add in prefix/suffix length later.
583 
584                 // fFormatWidth = prefix.length() + suffix.length() +
585                 //    sub0Limit - sub0Start;
586                 out.fFormatWidth = sub0Limit - sub0Start;
587                 out.fPad = padChar;
588             } else {
589                 out.fFormatWidth = 0;
590             }
591             if (roundingPos >= 0) {
592                 out.fRoundingIncrementUsed = TRUE;
593                 roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
594                 out.fRoundingIncrement = roundingInc;
595             } else {
596                 out.fRoundingIncrementUsed = FALSE;
597             }
598         } else {
599             out.fNegPatternsBogus = FALSE;
600             out.fNegPrefixPattern = prefix;
601             out.fNegSuffixPattern = suffix;
602         }
603     }
604 
605     if (pattern.length() == 0) {
606         out.fNegPatternsBogus = TRUE;
607         out.fNegPrefixPattern.remove();
608         out.fNegSuffixPattern.remove();
609         out.fPosPatternsBogus = FALSE;
610         out.fPosPrefixPattern.remove();
611         out.fPosSuffixPattern.remove();
612 
613         out.fMinimumIntegerDigits = 0;
614         out.fMaximumIntegerDigits = kDoubleIntegerDigits;
615         out.fMinimumFractionDigits = 0;
616         out.fMaximumFractionDigits = kDoubleFractionDigits;
617 
618         out.fUseExponentialNotation = FALSE;
619         out.fCurrencySignCount = fgCurrencySignCountZero;
620         out.fGroupingUsed = FALSE;
621         out.fGroupingSize = 0;
622         out.fGroupingSize2 = 0;
623         out.fMultiplier = 1;
624         out.fDecimalSeparatorAlwaysShown = FALSE;
625         out.fFormatWidth = 0;
626         out.fRoundingIncrementUsed = FALSE;
627     }
628 
629     // If there was no negative pattern, or if the negative pattern is
630     // identical to the positive pattern, then prepend the minus sign to the
631     // positive pattern to form the negative pattern.
632     if (out.fNegPatternsBogus ||
633         (out.fNegPrefixPattern == out.fPosPrefixPattern
634          && out.fNegSuffixPattern == out.fPosSuffixPattern)) {
635         out.fNegPatternsBogus = FALSE;
636         out.fNegSuffixPattern = out.fPosSuffixPattern;
637         out.fNegPrefixPattern.remove();
638         out.fNegPrefixPattern.append(kQuote).append(kPatternMinus)
639             .append(out.fPosPrefixPattern);
640     }
641     // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields.
642     AffixPattern::parseAffixString(
643             out.fNegSuffixPattern, out.fNegSuffixAffix, status);
644     AffixPattern::parseAffixString(
645             out.fPosSuffixPattern, out.fPosSuffixAffix, status);
646     AffixPattern::parseAffixString(
647             out.fNegPrefixPattern, out.fNegPrefixAffix, status);
648     AffixPattern::parseAffixString(
649             out.fPosPrefixPattern, out.fPosPrefixAffix, status);
650 }
651 
652 U_NAMESPACE_END
653 
654 #endif /* !UCONFIG_NO_FORMATTING */
655