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