• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
syntaxError(const UnicodeString & pattern,int32_t pos,UParseError & parseError)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 
DecimalFormatPattern()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 
DecimalFormatPatternParser()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 
useSymbols(const DecimalFormatSymbols & symbols)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
applyPatternWithoutExpandAffix(const UnicodeString & pattern,DecimalFormatPattern & out,UParseError & parseError,UErrorCode & status)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