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