1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 1997-2015, International Business Machines Corporation and *
6 * others. All Rights Reserved. *
7 *******************************************************************************
11 #include "decimalformatpattern.h"
13 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/dcfmtsym.h"
16 #include "unicode/format.h"
17 #include "unicode/utf16.h"
18 #include "decimalformatpatternimpl.h"
22 #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
29 // TODO: Travis Keep: Copied from numfmt.cpp
30 static int32_t kDoubleIntegerDigits
= 309;
31 static int32_t kDoubleFractionDigits
= 340;
34 // TODO: Travis Keep: Copied from numfmt.cpp
35 static int32_t gDefaultMaxIntegerDigits
= 2000000000;
37 // TODO: Travis Keep: This function was copied from format.cpp
38 static void syntaxError(const UnicodeString
& pattern
,
40 UParseError
& parseError
) {
41 parseError
.offset
= pos
;
42 parseError
.line
=0; // we are not using line number
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*/));
48 pattern
.extract(start
,stop
-start
,parseError
.preContext
,0);
49 //null terminate the buffer
50 parseError
.preContext
[stop
-start
] = 0;
54 stop
= ((pos
+U_PARSE_CONTEXT_LEN
)<=pattern
.length()) ? (pos
+(U_PARSE_CONTEXT_LEN
-1)) :
56 pattern
.extract(start
,stop
-start
,parseError
.postContext
,0);
57 //null terminate the buffer
58 parseError
.postContext
[stop
-start
]= 0;
61 DecimalFormatPattern::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
),
77 fDecimalSeparatorAlwaysShown(FALSE
),
79 fRoundingIncrementUsed(FALSE
),
82 fNegPatternsBogus(TRUE
),
83 fPosPatternsBogus(TRUE
),
88 fPadPosition(DecimalFormatPattern::kPadBeforePrefix
) {
92 DecimalFormatPatternParser::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
) {
107 void 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
);
136 DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
137 const UnicodeString
& pattern
,
138 DecimalFormatPattern
& out
,
139 UParseError
& parseError
,
140 UErrorCode
& status
) {
141 if (U_FAILURE(status
))
145 out
= DecimalFormatPattern();
147 // Clear error struct
148 parseError
.offset
= -1;
149 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
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();
158 int32_t patLen
= pattern
.length();
159 // Part 0 is the positive pattern. Part 1, if present, is the negative
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;
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;
184 int32_t roundingPos
= -1;
185 DigitList roundingInc
;
186 int8_t expDigits
= -1;
187 UBool expSignAlways
= FALSE
;
189 // The affix is either the prefix or the suffix.
190 UnicodeString
* affix
= &prefix
;
193 UBool isPartDone
= FALSE
;
196 for (; !isPartDone
&& pos
< patLen
; ) {
197 // Todo: account for surrogate pairs
198 ch
= pattern
.char32At(pos
);
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) {
216 if (groupingCount
>= 0 && decimalPos
< 0) {
220 } else if ((ch
>= fZeroDigit
&& ch
<= nineDigit
) ||
222 if (digitRightCount
> 0) {
224 debug("Unexpected '0'")
225 status
= U_UNEXPECTED_TOKEN
;
226 syntaxError(pattern
,pos
,parseError
);
229 if (ch
== fSigDigit
) {
232 if (ch
!= fZeroDigit
&& roundingPos
< 0) {
233 roundingPos
= digitLeftCount
+ zeroDigitCount
;
235 if (roundingPos
>= 0) {
236 roundingInc
.append((char)(ch
- fZeroDigit
+ '0'));
240 if (groupingCount
>= 0 && decimalPos
< 0) {
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
);
252 groupingCount2
= groupingCount
;
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
);
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
;
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
);
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
);
284 pos
+= fExponent
.length();
285 // Check for positive prefix
287 && pattern
.compare(pos
, fPlus
.length(), fPlus
) == 0) {
288 expSignAlways
= TRUE
;
289 pos
+= fPlus
.length();
291 // Use lookahead to parse out the exponential part of the
292 // pattern, then jump into suffix subpart.
294 while (pos
< patLen
&&
295 pattern
.char32At(pos
) == fZeroDigit
) {
297 pos
+= U16_LENGTH(fZeroDigit
);
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) ||
307 // Malformed exponential pattern
308 debug("Malformed exponential pattern")
309 status
= U_MALFORMED_EXPONENTIAL_PATTERN
;
310 syntaxError(pattern
,pos
,parseError
);
314 // Transition to suffix subpart
315 subpart
= 2; // suffix subpart
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
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
) ||
335 if (subpart
== 1) { // prefix subpart
336 subpart
= 0; // pattern proper subpart
337 sub0Start
= pos
; // Reprocess this character
340 status
= U_UNQUOTED_SPECIAL
;
341 syntaxError(pattern
,pos
,parseError
);
344 } else if (ch
== kCurrencySign
) {
345 affix
->append(kQuote
); // Encode currency
346 // Use lookahead to determine if the currency sign is
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
;
358 out
.fCurrencySignCount
= fgCurrencySignCountInISOFormat
;
361 out
.fCurrencySignCount
= fgCurrencySignCountInSymbolFormat
;
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);
370 if (pos
< pattern
.length() && pattern
[pos
] == kQuote
) {
371 affix
->append(kQuote
); // Encode quote
372 // Fall through to append(ch)
374 subpart
+= 2; // open quote
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
);
388 isPartDone
= TRUE
; // Go to next part
389 pos
+= fSeparator
.length();
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
);
400 affix
->append(kQuote
); // Encode percent/perMill
401 affix
->append(kPatternPercent
); // Use unlocalized pattern char
403 pos
+= fPercent
.length();
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
);
414 affix
->append(kQuote
); // Encode percent/perMill
415 affix
->append(kPatternPerMill
); // Use unlocalized pattern char
417 pos
+= fPerMill
.length();
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
);
428 pos
+= fPadEscape
.length();
429 padChar
= pattern
.char32At(pos
);
430 pos
+= U16_LENGTH(padChar
);
432 } else if (pattern
.compare(pos
, fMinus
.length(), fMinus
) == 0) {
433 affix
->append(kQuote
); // Encode minus
434 affix
->append(kPatternMinus
);
435 pos
+= fMinus
.length();
437 } else if (pattern
.compare(pos
, fPlus
.length(), fPlus
) == 0) {
438 affix
->append(kQuote
); // Encode plus
439 affix
->append(kPatternPlus
);
440 pos
+= fPlus
.length();
443 // Unquoted, non-special characters fall through to here, as
444 // well as other code which needs to append something to the
447 pos
+= U16_LENGTH(ch
);
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'.
456 if (pos
< pattern
.length() && pattern
[pos
] == kQuote
) {
457 affix
->append(kQuote
); // Encode quote
458 // Fall through to append(ch)
460 subpart
-= 2; // close quote
465 pos
+= U16_LENGTH(ch
);
470 if (sub0Limit
== 0) {
471 sub0Limit
= pattern
.length();
474 if (sub2Limit
== 0) {
475 sub2Limit
= pattern
.length();
478 /* Handle patterns with no '0' pattern character. These patterns
479 * are legal, but must be recodified to make sense. "##.###" ->
480 * "#0.###". ".###" -> ".0##".
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).
491 if (zeroDigitCount
== 0 && sigDigitCount
== 0 &&
492 digitLeftCount
> 0 && decimalPos
>= 0) {
493 // Handle "###.###" and "###." and ".###"
496 ++n
; // Handle ".###"
497 digitRightCount
= digitLeftCount
- n
;
498 digitLeftCount
= n
- 1;
502 // Do syntax checking on the digits, decimal points, and quotes.
503 if ((decimalPos
< 0 && digitRightCount
> 0 && sigDigitCount
== 0) ||
505 (sigDigitCount
> 0 ||
506 decimalPos
< digitLeftCount
||
507 decimalPos
> (digitLeftCount
+ zeroDigitCount
))) ||
508 groupingCount
== 0 || groupingCount2
== 0 ||
509 (sigDigitCount
> 0 && zeroDigitCount
> 0) ||
511 { // subpart > 2 == unmatched quote
512 debug("Syntax error")
513 status
= U_PATTERN_SYNTAX_ERROR
;
514 syntaxError(pattern
,pos
,parseError
);
518 // Make sure pad is at legal position before or after affix.
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
;
529 // Illegal pad position
530 debug("Illegal pad position")
531 status
= U_ILLEGAL_PAD_POSITION
;
532 syntaxError(pattern
,pos
,parseError
);
538 out
.fPosPatternsBogus
= FALSE
;
539 out
.fPosPrefixPattern
= prefix
;
540 out
.fPosSuffixPattern
= suffix
;
541 out
.fNegPatternsBogus
= TRUE
;
542 out
.fNegPrefixPattern
.remove();
543 out
.fNegSuffixPattern
.remove();
545 out
.fUseExponentialNotation
= (expDigits
>= 0);
546 if (out
.fUseExponentialNotation
) {
547 out
.fMinExponentDigits
= expDigits
;
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 +
555 int32_t effectiveDecimalPos
= decimalPos
>= 0 ? decimalPos
: digitTotalCount
;
556 UBool isSigDig
= (sigDigitCount
> 0);
557 out
.fUseSignificantDigits
= isSigDig
;
559 out
.fMinimumSignificantDigits
= sigDigitCount
;
560 out
.fMaximumSignificantDigits
= sigDigitCount
+ digitRightCount
;
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;
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
;
580 out
.fPadPosition
= (DecimalFormatPattern::EPadPosition
) padPos
;
581 // To compute the format width, first set up sub0Limit -
582 // sub0Start. Add in prefix/suffix length later.
584 // fFormatWidth = prefix.length() + suffix.length() +
585 // sub0Limit - sub0Start;
586 out
.fFormatWidth
= sub0Limit
- sub0Start
;
589 out
.fFormatWidth
= 0;
591 if (roundingPos
>= 0) {
592 out
.fRoundingIncrementUsed
= TRUE
;
593 roundingInc
.setDecimalAt(effectiveDecimalPos
- roundingPos
);
594 out
.fRoundingIncrement
= roundingInc
;
596 out
.fRoundingIncrementUsed
= FALSE
;
599 out
.fNegPatternsBogus
= FALSE
;
600 out
.fNegPrefixPattern
= prefix
;
601 out
.fNegSuffixPattern
= suffix
;
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();
613 out
.fMinimumIntegerDigits
= 0;
614 out
.fMaximumIntegerDigits
= kDoubleIntegerDigits
;
615 out
.fMinimumFractionDigits
= 0;
616 out
.fMaximumFractionDigits
= kDoubleFractionDigits
;
618 out
.fUseExponentialNotation
= FALSE
;
619 out
.fCurrencySignCount
= fgCurrencySignCountZero
;
620 out
.fGroupingUsed
= FALSE
;
621 out
.fGroupingSize
= 0;
622 out
.fGroupingSize2
= 0;
624 out
.fDecimalSeparatorAlwaysShown
= FALSE
;
625 out
.fFormatWidth
= 0;
626 out
.fRoundingIncrementUsed
= FALSE
;
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
);
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
);
654 #endif /* !UCONFIG_NO_FORMATTING */