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