Home | History | Annotate | Download | only in i18n
      1 //  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
     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 
     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 
     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 
    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
    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