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