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