LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - decimalformatpattern.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 340 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : static void syntaxError(const UnicodeString& pattern,
      39             :                          int32_t pos,
      40             :                          UParseError& parseError) {
      41           0 :     parseError.offset = pos;
      42           0 :     parseError.line=0;  // we are not using line number
      43             : 
      44             :     // for pre-context
      45           0 :     int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1
      46           0 :                                                              /* subtract 1 so that we have room for null*/));
      47           0 :     int32_t stop  = pos;
      48           0 :     pattern.extract(start,stop-start,parseError.preContext,0);
      49             :     //null terminate the buffer
      50           0 :     parseError.preContext[stop-start] = 0;
      51             : 
      52             :     //for post-context
      53           0 :     start = pos+1;
      54           0 :     stop  = ((pos+U_PARSE_CONTEXT_LEN)<=pattern.length()) ? (pos+(U_PARSE_CONTEXT_LEN-1)) :
      55             :         pattern.length();
      56           0 :     pattern.extract(start,stop-start,parseError.postContext,0);
      57             :     //null terminate the buffer
      58           0 :     parseError.postContext[stop-start]= 0;
      59           0 : }
      60             : 
      61           0 : 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           0 :           fPadPosition(DecimalFormatPattern::kPadBeforePrefix) {
      89           0 : }
      90             : 
      91             : 
      92           0 : 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           0 :     fPadEscape((UChar)kPatternPadEscape) {
     105           0 : }
     106             : 
     107           0 : void DecimalFormatPatternParser::useSymbols(
     108             :         const DecimalFormatSymbols& symbols) {
     109           0 :     fZeroDigit = symbols.getConstSymbol(
     110           0 :             DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
     111           0 :     fSigDigit = symbols.getConstSymbol(
     112           0 :             DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
     113             :     fGroupingSeparator = symbols.getConstSymbol(
     114           0 :             DecimalFormatSymbols::kGroupingSeparatorSymbol);
     115             :     fDecimalSeparator = symbols.getConstSymbol(
     116           0 :             DecimalFormatSymbols::kDecimalSeparatorSymbol);
     117             :     fPercent = symbols.getConstSymbol(
     118           0 :             DecimalFormatSymbols::kPercentSymbol);
     119             :     fPerMill = symbols.getConstSymbol(
     120           0 :             DecimalFormatSymbols::kPerMillSymbol);
     121             :     fDigit = symbols.getConstSymbol(
     122           0 :             DecimalFormatSymbols::kDigitSymbol);
     123             :     fSeparator = symbols.getConstSymbol(
     124           0 :             DecimalFormatSymbols::kPatternSeparatorSymbol);
     125             :     fExponent = symbols.getConstSymbol(
     126           0 :             DecimalFormatSymbols::kExponentialSymbol);
     127             :     fPlus = symbols.getConstSymbol(
     128           0 :             DecimalFormatSymbols::kPlusSignSymbol);
     129             :     fMinus = symbols.getConstSymbol(
     130           0 :             DecimalFormatSymbols::kMinusSignSymbol);
     131             :     fPadEscape = symbols.getConstSymbol(
     132           0 :             DecimalFormatSymbols::kPadEscapeSymbol);
     133           0 : }
     134             : 
     135             : void
     136           0 : DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
     137             :         const UnicodeString& pattern,
     138             :         DecimalFormatPattern& out,
     139             :         UParseError& parseError,
     140             :         UErrorCode& status) {
     141           0 :     if (U_FAILURE(status))
     142             :     {
     143           0 :         return;
     144             :     }
     145           0 :     out = DecimalFormatPattern();
     146             : 
     147             :     // Clear error struct
     148           0 :     parseError.offset = -1;
     149           0 :     parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
     150             : 
     151             :     // TODO: Travis Keep: This won't always work.
     152           0 :     UChar nineDigit = (UChar)(fZeroDigit + 9);
     153           0 :     int32_t digitLen = fDigit.length();
     154           0 :     int32_t groupSepLen = fGroupingSeparator.length();
     155           0 :     int32_t decimalSepLen = fDecimalSeparator.length();
     156             : 
     157           0 :     int32_t pos = 0;
     158           0 :     int32_t patLen = pattern.length();
     159             :     // Part 0 is the positive pattern.  Part 1, if present, is the negative
     160             :     // pattern.
     161           0 :     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           0 :         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           0 :         UnicodeString prefix;
     176           0 :         UnicodeString suffix;
     177           0 :         int32_t decimalPos = -1;
     178           0 :         int32_t multiplier = 1;
     179           0 :         int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
     180           0 :         int8_t groupingCount = -1;
     181           0 :         int8_t groupingCount2 = -1;
     182           0 :         int32_t padPos = -1;
     183           0 :         UChar32 padChar = 0;
     184           0 :         int32_t roundingPos = -1;
     185           0 :         DigitList roundingInc;
     186           0 :         int8_t expDigits = -1;
     187           0 :         UBool expSignAlways = FALSE;
     188             : 
     189             :         // The affix is either the prefix or the suffix.
     190           0 :         UnicodeString* affix = &prefix;
     191             : 
     192           0 :         int32_t start = pos;
     193           0 :         UBool isPartDone = FALSE;
     194             :         UChar32 ch;
     195             : 
     196           0 :         for (; !isPartDone && pos < patLen; ) {
     197             :             // Todo: account for surrogate pairs
     198           0 :             ch = pattern.char32At(pos);
     199           0 :             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           0 :                 if (pattern.compare(pos, digitLen, fDigit) == 0) {
     211           0 :                     if (zeroDigitCount > 0 || sigDigitCount > 0) {
     212           0 :                         ++digitRightCount;
     213             :                     } else {
     214           0 :                         ++digitLeftCount;
     215             :                     }
     216           0 :                     if (groupingCount >= 0 && decimalPos < 0) {
     217           0 :                         ++groupingCount;
     218             :                     }
     219           0 :                     pos += digitLen;
     220           0 :                 } else if ((ch >= fZeroDigit && ch <= nineDigit) ||
     221           0 :                            ch == fSigDigit) {
     222           0 :                     if (digitRightCount > 0) {
     223             :                         // Unexpected '0'
     224             :                         debug("Unexpected '0'")
     225           0 :                         status = U_UNEXPECTED_TOKEN;
     226           0 :                         syntaxError(pattern,pos,parseError);
     227           0 :                         return;
     228             :                     }
     229           0 :                     if (ch == fSigDigit) {
     230           0 :                         ++sigDigitCount;
     231             :                     } else {
     232           0 :                         if (ch != fZeroDigit && roundingPos < 0) {
     233           0 :                             roundingPos = digitLeftCount + zeroDigitCount;
     234             :                         }
     235           0 :                         if (roundingPos >= 0) {
     236           0 :                             roundingInc.append((char)(ch - fZeroDigit + '0'));
     237             :                         }
     238           0 :                         ++zeroDigitCount;
     239             :                     }
     240           0 :                     if (groupingCount >= 0 && decimalPos < 0) {
     241           0 :                         ++groupingCount;
     242             :                     }
     243           0 :                     pos += U16_LENGTH(ch);
     244           0 :                 } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) {
     245           0 :                     if (decimalPos >= 0) {
     246             :                         // Grouping separator after decimal
     247             :                         debug("Grouping separator after decimal")
     248           0 :                         status = U_UNEXPECTED_TOKEN;
     249           0 :                         syntaxError(pattern,pos,parseError);
     250           0 :                         return;
     251             :                     }
     252           0 :                     groupingCount2 = groupingCount;
     253           0 :                     groupingCount = 0;
     254           0 :                     pos += groupSepLen;
     255           0 :                 } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) {
     256           0 :                     if (decimalPos >= 0) {
     257             :                         // Multiple decimal separators
     258             :                         debug("Multiple decimal separators")
     259           0 :                         status = U_MULTIPLE_DECIMAL_SEPARATORS;
     260           0 :                         syntaxError(pattern,pos,parseError);
     261           0 :                         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           0 :                     decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
     267           0 :                     pos += decimalSepLen;
     268             :                 } else {
     269           0 :                     if (pattern.compare(pos, fExponent.length(), fExponent) == 0) {
     270           0 :                         if (expDigits >= 0) {
     271             :                             // Multiple exponential symbols
     272             :                             debug("Multiple exponential symbols")
     273           0 :                             status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
     274           0 :                             syntaxError(pattern,pos,parseError);
     275           0 :                             return;
     276             :                         }
     277           0 :                         if (groupingCount >= 0) {
     278             :                             // Grouping separator in exponential pattern
     279             :                             debug("Grouping separator in exponential pattern")
     280           0 :                             status = U_MALFORMED_EXPONENTIAL_PATTERN;
     281           0 :                             syntaxError(pattern,pos,parseError);
     282           0 :                             return;
     283             :                         }
     284           0 :                         pos += fExponent.length();
     285             :                         // Check for positive prefix
     286           0 :                         if (pos < patLen
     287           0 :                             && pattern.compare(pos, fPlus.length(), fPlus) == 0) {
     288           0 :                             expSignAlways = TRUE;
     289           0 :                             pos += fPlus.length();
     290             :                         }
     291             :                         // Use lookahead to parse out the exponential part of the
     292             :                         // pattern, then jump into suffix subpart.
     293           0 :                         expDigits = 0;
     294           0 :                         while (pos < patLen &&
     295           0 :                                pattern.char32At(pos) == fZeroDigit) {
     296           0 :                             ++expDigits;
     297           0 :                             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           0 :                         if (((digitLeftCount + zeroDigitCount) < 1 &&
     304           0 :                              (sigDigitCount + digitRightCount) < 1) ||
     305           0 :                             (sigDigitCount > 0 && digitLeftCount > 0) ||
     306             :                             expDigits < 1) {
     307             :                             // Malformed exponential pattern
     308             :                             debug("Malformed exponential pattern")
     309           0 :                             status = U_MALFORMED_EXPONENTIAL_PATTERN;
     310           0 :                             syntaxError(pattern,pos,parseError);
     311           0 :                             return;
     312             :                         }
     313             :                     }
     314             :                     // Transition to suffix subpart
     315           0 :                     subpart = 2; // suffix subpart
     316           0 :                     affix = &suffix;
     317           0 :                     sub0Limit = pos;
     318           0 :                     continue;
     319             :                 }
     320           0 :                 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           0 :                 if (!pattern.compare(pos, digitLen, fDigit) ||
     331           0 :                     !pattern.compare(pos, groupSepLen, fGroupingSeparator) ||
     332           0 :                     !pattern.compare(pos, decimalSepLen, fDecimalSeparator) ||
     333           0 :                     (ch >= fZeroDigit && ch <= nineDigit) ||
     334           0 :                     ch == fSigDigit) {
     335           0 :                     if (subpart == 1) { // prefix subpart
     336           0 :                         subpart = 0; // pattern proper subpart
     337           0 :                         sub0Start = pos; // Reprocess this character
     338           0 :                         continue;
     339             :                     } else {
     340           0 :                         status = U_UNQUOTED_SPECIAL;
     341           0 :                         syntaxError(pattern,pos,parseError);
     342           0 :                         return;
     343             :                     }
     344           0 :                 } else if (ch == kCurrencySign) {
     345           0 :                     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           0 :                     if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
     350           0 :                         affix->append(kCurrencySign);
     351           0 :                         ++pos; // Skip over the doubled character
     352           0 :                         if ((pos+1) < pattern.length() &&
     353           0 :                             pattern[pos+1] == kCurrencySign) {
     354           0 :                             affix->append(kCurrencySign);
     355           0 :                             ++pos; // Skip over the doubled character
     356           0 :                             out.fCurrencySignCount = fgCurrencySignCountInPluralFormat;
     357             :                         } else {
     358           0 :                             out.fCurrencySignCount = fgCurrencySignCountInISOFormat;
     359             :                         }
     360             :                     } else {
     361           0 :                         out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
     362             :                     }
     363             :                     // Fall through to append(ch)
     364           0 :                 } 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           0 :                     ++pos;
     370           0 :                     if (pos < pattern.length() && pattern[pos] == kQuote) {
     371           0 :                         affix->append(kQuote); // Encode quote
     372             :                         // Fall through to append(ch)
     373             :                     } else {
     374           0 :                         subpart += 2; // open quote
     375           0 :                         continue;
     376             :                     }
     377           0 :                 } 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           0 :                     if (subpart == 1 || part == 1) {
     381             :                         // Unexpected separator
     382             :                         debug("Unexpected separator")
     383           0 :                         status = U_UNEXPECTED_TOKEN;
     384           0 :                         syntaxError(pattern,pos,parseError);
     385           0 :                         return;
     386             :                     }
     387           0 :                     sub2Limit = pos;
     388           0 :                     isPartDone = TRUE; // Go to next part
     389           0 :                     pos += fSeparator.length();
     390           0 :                     break;
     391           0 :                 } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) {
     392             :                     // Next handle characters which are appended directly.
     393           0 :                     if (multiplier != 1) {
     394             :                         // Too many percent/perMill characters
     395             :                         debug("Too many percent characters")
     396           0 :                         status = U_MULTIPLE_PERCENT_SYMBOLS;
     397           0 :                         syntaxError(pattern,pos,parseError);
     398           0 :                         return;
     399             :                     }
     400           0 :                     affix->append(kQuote); // Encode percent/perMill
     401           0 :                     affix->append(kPatternPercent); // Use unlocalized pattern char
     402           0 :                     multiplier = 100;
     403           0 :                     pos += fPercent.length();
     404           0 :                     break;
     405           0 :                 } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) {
     406             :                     // Next handle characters which are appended directly.
     407           0 :                     if (multiplier != 1) {
     408             :                         // Too many percent/perMill characters
     409             :                         debug("Too many perMill characters")
     410           0 :                         status = U_MULTIPLE_PERMILL_SYMBOLS;
     411           0 :                         syntaxError(pattern,pos,parseError);
     412           0 :                         return;
     413             :                     }
     414           0 :                     affix->append(kQuote); // Encode percent/perMill
     415           0 :                     affix->append(kPatternPerMill); // Use unlocalized pattern char
     416           0 :                     multiplier = 1000;
     417           0 :                     pos += fPerMill.length();
     418           0 :                     break;
     419           0 :                 } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) {
     420           0 :                     if (padPos >= 0 ||               // Multiple pad specifiers
     421           0 :                         (pos+1) == pattern.length()) { // Nothing after padEscape
     422             :                         debug("Multiple pad specifiers")
     423           0 :                         status = U_MULTIPLE_PAD_SPECIFIERS;
     424           0 :                         syntaxError(pattern,pos,parseError);
     425           0 :                         return;
     426             :                     }
     427           0 :                     padPos = pos;
     428           0 :                     pos += fPadEscape.length();
     429           0 :                     padChar = pattern.char32At(pos);
     430           0 :                     pos += U16_LENGTH(padChar);
     431           0 :                     break;
     432           0 :                 } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) {
     433           0 :                     affix->append(kQuote); // Encode minus
     434           0 :                     affix->append(kPatternMinus);
     435           0 :                     pos += fMinus.length();
     436           0 :                     break;
     437           0 :                 } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) {
     438           0 :                     affix->append(kQuote); // Encode plus
     439           0 :                     affix->append(kPatternPlus);
     440           0 :                     pos += fPlus.length();
     441           0 :                     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           0 :                 affix->append(ch);
     447           0 :                 pos += U16_LENGTH(ch);
     448           0 :                 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           0 :                 if (ch == kQuote) {
     455           0 :                     ++pos;
     456           0 :                     if (pos < pattern.length() && pattern[pos] == kQuote) {
     457           0 :                         affix->append(kQuote); // Encode quote
     458             :                         // Fall through to append(ch)
     459             :                     } else {
     460           0 :                         subpart -= 2; // close quote
     461           0 :                         continue;
     462             :                     }
     463             :                 }
     464           0 :                 affix->append(ch);
     465           0 :                 pos += U16_LENGTH(ch);
     466           0 :                 break;
     467             :             }
     468             :         }
     469             : 
     470           0 :         if (sub0Limit == 0) {
     471           0 :             sub0Limit = pattern.length();
     472             :         }
     473             : 
     474           0 :         if (sub2Limit == 0) {
     475           0 :             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           0 :         if (zeroDigitCount == 0 && sigDigitCount == 0 &&
     492           0 :             digitLeftCount > 0 && decimalPos >= 0) {
     493             :             // Handle "###.###" and "###." and ".###"
     494           0 :             int n = decimalPos;
     495           0 :             if (n == 0)
     496           0 :                 ++n; // Handle ".###"
     497           0 :             digitRightCount = digitLeftCount - n;
     498           0 :             digitLeftCount = n - 1;
     499           0 :             zeroDigitCount = 1;
     500             :         }
     501             : 
     502             :         // Do syntax checking on the digits, decimal points, and quotes.
     503           0 :         if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
     504           0 :             (decimalPos >= 0 &&
     505           0 :              (sigDigitCount > 0 ||
     506           0 :               decimalPos < digitLeftCount ||
     507           0 :               decimalPos > (digitLeftCount + zeroDigitCount))) ||
     508           0 :             groupingCount == 0 || groupingCount2 == 0 ||
     509           0 :             (sigDigitCount > 0 && zeroDigitCount > 0) ||
     510             :             subpart > 2)
     511             :         { // subpart > 2 == unmatched quote
     512             :             debug("Syntax error")
     513           0 :             status = U_PATTERN_SYNTAX_ERROR;
     514           0 :             syntaxError(pattern,pos,parseError);
     515           0 :             return;
     516             :         }
     517             : 
     518             :         // Make sure pad is at legal position before or after affix.
     519           0 :         if (padPos >= 0) {
     520           0 :             if (padPos == start) {
     521           0 :                 padPos = DecimalFormatPattern::kPadBeforePrefix;
     522           0 :             } else if (padPos+2 == sub0Start) {
     523           0 :                 padPos = DecimalFormatPattern::kPadAfterPrefix;
     524           0 :             } else if (padPos == sub0Limit) {
     525           0 :                 padPos = DecimalFormatPattern::kPadBeforeSuffix;
     526           0 :             } else if (padPos+2 == sub2Limit) {
     527           0 :                 padPos = DecimalFormatPattern::kPadAfterSuffix;
     528             :             } else {
     529             :                 // Illegal pad position
     530             :                 debug("Illegal pad position")
     531           0 :                 status = U_ILLEGAL_PAD_POSITION;
     532           0 :                 syntaxError(pattern,pos,parseError);
     533           0 :                 return;
     534             :             }
     535             :         }
     536             : 
     537           0 :         if (part == 0) {
     538           0 :             out.fPosPatternsBogus = FALSE;
     539           0 :             out.fPosPrefixPattern = prefix;
     540           0 :             out.fPosSuffixPattern = suffix;
     541           0 :             out.fNegPatternsBogus = TRUE;
     542           0 :             out.fNegPrefixPattern.remove();
     543           0 :             out.fNegSuffixPattern.remove();
     544             : 
     545           0 :             out.fUseExponentialNotation = (expDigits >= 0);
     546           0 :             if (out.fUseExponentialNotation) {
     547           0 :               out.fMinExponentDigits = expDigits;
     548             :             }
     549           0 :             out.fExponentSignAlwaysShown = expSignAlways;
     550           0 :             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           0 :             int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
     556           0 :             UBool isSigDig = (sigDigitCount > 0);
     557           0 :             out.fUseSignificantDigits = isSigDig;
     558           0 :             if (isSigDig) {
     559           0 :                 out.fMinimumSignificantDigits = sigDigitCount;
     560           0 :                 out.fMaximumSignificantDigits = sigDigitCount + digitRightCount;
     561             :             } else {
     562           0 :                 int32_t minInt = effectiveDecimalPos - digitLeftCount;
     563           0 :                 out.fMinimumIntegerDigits = minInt;
     564           0 :                 out.fMaximumIntegerDigits = out.fUseExponentialNotation
     565           0 :                     ? digitLeftCount + out.fMinimumIntegerDigits
     566             :                     : gDefaultMaxIntegerDigits;
     567           0 :                 out.fMaximumFractionDigits = decimalPos >= 0
     568           0 :                     ? (digitTotalCount - decimalPos) : 0;
     569           0 :                 out.fMinimumFractionDigits = decimalPos >= 0
     570           0 :                     ? (digitLeftCount + zeroDigitCount - decimalPos) : 0;
     571             :             }
     572           0 :             out.fGroupingUsed = groupingCount > 0;
     573           0 :             out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
     574           0 :             out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
     575           0 :                 ? groupingCount2 : 0;
     576           0 :             out.fMultiplier = multiplier;
     577           0 :             out.fDecimalSeparatorAlwaysShown = decimalPos == 0
     578           0 :                     || decimalPos == digitTotalCount;
     579           0 :             if (padPos >= 0) {
     580           0 :                 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           0 :                 out.fFormatWidth = sub0Limit - sub0Start;
     587           0 :                 out.fPad = padChar;
     588             :             } else {
     589           0 :                 out.fFormatWidth = 0;
     590             :             }
     591           0 :             if (roundingPos >= 0) {
     592           0 :                 out.fRoundingIncrementUsed = TRUE;
     593           0 :                 roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
     594           0 :                 out.fRoundingIncrement = roundingInc;
     595             :             } else {
     596           0 :                 out.fRoundingIncrementUsed = FALSE;
     597             :             }
     598             :         } else {
     599           0 :             out.fNegPatternsBogus = FALSE;
     600           0 :             out.fNegPrefixPattern = prefix;
     601           0 :             out.fNegSuffixPattern = suffix;
     602             :         }
     603             :     }
     604             : 
     605           0 :     if (pattern.length() == 0) {
     606           0 :         out.fNegPatternsBogus = TRUE;
     607           0 :         out.fNegPrefixPattern.remove();
     608           0 :         out.fNegSuffixPattern.remove();
     609           0 :         out.fPosPatternsBogus = FALSE;
     610           0 :         out.fPosPrefixPattern.remove();
     611           0 :         out.fPosSuffixPattern.remove();
     612             : 
     613           0 :         out.fMinimumIntegerDigits = 0;
     614           0 :         out.fMaximumIntegerDigits = kDoubleIntegerDigits;
     615           0 :         out.fMinimumFractionDigits = 0;
     616           0 :         out.fMaximumFractionDigits = kDoubleFractionDigits;
     617             : 
     618           0 :         out.fUseExponentialNotation = FALSE;
     619           0 :         out.fCurrencySignCount = fgCurrencySignCountZero;
     620           0 :         out.fGroupingUsed = FALSE;
     621           0 :         out.fGroupingSize = 0;
     622           0 :         out.fGroupingSize2 = 0;
     623           0 :         out.fMultiplier = 1;
     624           0 :         out.fDecimalSeparatorAlwaysShown = FALSE;
     625           0 :         out.fFormatWidth = 0;
     626           0 :         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           0 :     if (out.fNegPatternsBogus ||
     633           0 :         (out.fNegPrefixPattern == out.fPosPrefixPattern
     634           0 :          && out.fNegSuffixPattern == out.fPosSuffixPattern)) {
     635           0 :         out.fNegPatternsBogus = FALSE;
     636           0 :         out.fNegSuffixPattern = out.fPosSuffixPattern;
     637           0 :         out.fNegPrefixPattern.remove();
     638           0 :         out.fNegPrefixPattern.append(kQuote).append(kPatternMinus)
     639           0 :             .append(out.fPosPrefixPattern);
     640             :     }
     641             :     // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields.
     642             :     AffixPattern::parseAffixString( 
     643           0 :             out.fNegSuffixPattern, out.fNegSuffixAffix, status);
     644             :     AffixPattern::parseAffixString(
     645           0 :             out.fPosSuffixPattern, out.fPosSuffixAffix, status);
     646             :     AffixPattern::parseAffixString(
     647           0 :             out.fNegPrefixPattern, out.fNegPrefixAffix, status);
     648             :     AffixPattern::parseAffixString(
     649           0 :             out.fPosPrefixPattern, out.fPosPrefixAffix, status);
     650             : }
     651             : 
     652             : U_NAMESPACE_END
     653             : 
     654             : #endif /* !UCONFIG_NO_FORMATTING */

Generated by: LCOV version 1.13