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
40U_NAMESPACE_BEGIN
41
42// TODO: Travis Keep: Copied from numfmt.cpp
43static int32_t kDoubleIntegerDigits  = 309;
44static int32_t kDoubleFractionDigits = 340;
45
46
47// TODO: Travis Keep: Copied from numfmt.cpp
48static int32_t gDefaultMaxIntegerDigits = 2000000000;
49
50// TODO: Travis Keep: This function was copied from format.cpp
51static 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
74DecimalFormatPattern::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
105DecimalFormatPatternParser::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
120void 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
148void
149DecimalFormatPatternParser::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.append(kQuote).append(kPatternMinus)
651            .append(out.fPosPrefixPattern);
652    }
653}
654
655U_NAMESPACE_END
656
657#endif /* !UCONFIG_NO_FORMATTING */
658