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