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