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
syntaxError(const UnicodeString & pattern,int32_t pos,UParseError & parseError)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
DecimalFormatPattern()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
DecimalFormatPatternParser()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
useSymbols(const DecimalFormatSymbols & symbols)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
applyPatternWithoutExpandAffix(const UnicodeString & pattern,DecimalFormatPattern & out,UParseError & parseError,UErrorCode & status)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