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