Line data Source code
1 : // © 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 :
27 : U_NAMESPACE_BEGIN
28 :
29 : // TODO: Travis Keep: Copied from numfmt.cpp
30 : static int32_t kDoubleIntegerDigits = 309;
31 : static int32_t kDoubleFractionDigits = 340;
32 :
33 :
34 : // TODO: Travis Keep: Copied from numfmt.cpp
35 : static int32_t gDefaultMaxIntegerDigits = 2000000000;
36 :
37 : // TODO: Travis Keep: This function was copied from format.cpp
38 0 : static void syntaxError(const UnicodeString& pattern,
39 : int32_t pos,
40 : UParseError& parseError) {
41 0 : parseError.offset = pos;
42 0 : parseError.line=0; // we are not using line number
43 :
44 : // for pre-context
45 0 : int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1
46 0 : /* subtract 1 so that we have room for null*/));
47 0 : int32_t stop = pos;
48 0 : pattern.extract(start,stop-start,parseError.preContext,0);
49 : //null terminate the buffer
50 0 : parseError.preContext[stop-start] = 0;
51 :
52 : //for post-context
53 0 : start = pos+1;
54 0 : stop = ((pos+U_PARSE_CONTEXT_LEN)<=pattern.length()) ? (pos+(U_PARSE_CONTEXT_LEN-1)) :
55 : pattern.length();
56 0 : pattern.extract(start,stop-start,parseError.postContext,0);
57 : //null terminate the buffer
58 0 : parseError.postContext[stop-start]= 0;
59 0 : }
60 :
61 0 : 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),
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 0 : fPadPosition(DecimalFormatPattern::kPadBeforePrefix) {
89 0 : }
90 :
91 :
92 0 : 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 0 : fPadEscape((UChar)kPatternPadEscape) {
105 0 : }
106 :
107 0 : void DecimalFormatPatternParser::useSymbols(
108 : const DecimalFormatSymbols& symbols) {
109 0 : fZeroDigit = symbols.getConstSymbol(
110 0 : DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
111 0 : fSigDigit = symbols.getConstSymbol(
112 0 : DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
113 : fGroupingSeparator = symbols.getConstSymbol(
114 0 : DecimalFormatSymbols::kGroupingSeparatorSymbol);
115 : fDecimalSeparator = symbols.getConstSymbol(
116 0 : DecimalFormatSymbols::kDecimalSeparatorSymbol);
117 : fPercent = symbols.getConstSymbol(
118 0 : DecimalFormatSymbols::kPercentSymbol);
119 : fPerMill = symbols.getConstSymbol(
120 0 : DecimalFormatSymbols::kPerMillSymbol);
121 : fDigit = symbols.getConstSymbol(
122 0 : DecimalFormatSymbols::kDigitSymbol);
123 : fSeparator = symbols.getConstSymbol(
124 0 : DecimalFormatSymbols::kPatternSeparatorSymbol);
125 : fExponent = symbols.getConstSymbol(
126 0 : DecimalFormatSymbols::kExponentialSymbol);
127 : fPlus = symbols.getConstSymbol(
128 0 : DecimalFormatSymbols::kPlusSignSymbol);
129 : fMinus = symbols.getConstSymbol(
130 0 : DecimalFormatSymbols::kMinusSignSymbol);
131 : fPadEscape = symbols.getConstSymbol(
132 0 : DecimalFormatSymbols::kPadEscapeSymbol);
133 0 : }
134 :
135 : void
136 0 : DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
137 : const UnicodeString& pattern,
138 : DecimalFormatPattern& out,
139 : UParseError& parseError,
140 : UErrorCode& status) {
141 0 : if (U_FAILURE(status))
142 : {
143 0 : return;
144 : }
145 0 : out = DecimalFormatPattern();
146 :
147 : // Clear error struct
148 0 : parseError.offset = -1;
149 0 : parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
150 :
151 : // TODO: Travis Keep: This won't always work.
152 0 : UChar nineDigit = (UChar)(fZeroDigit + 9);
153 0 : int32_t digitLen = fDigit.length();
154 0 : int32_t groupSepLen = fGroupingSeparator.length();
155 0 : int32_t decimalSepLen = fDecimalSeparator.length();
156 :
157 0 : int32_t pos = 0;
158 0 : int32_t patLen = pattern.length();
159 : // Part 0 is the positive pattern. Part 1, if present, is the negative
160 : // pattern.
161 0 : 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 0 : 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 0 : UnicodeString prefix;
176 0 : UnicodeString suffix;
177 0 : int32_t decimalPos = -1;
178 0 : int32_t multiplier = 1;
179 0 : int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
180 0 : int8_t groupingCount = -1;
181 0 : int8_t groupingCount2 = -1;
182 0 : int32_t padPos = -1;
183 0 : UChar32 padChar = 0;
184 0 : int32_t roundingPos = -1;
185 0 : DigitList roundingInc;
186 0 : int8_t expDigits = -1;
187 0 : UBool expSignAlways = FALSE;
188 :
189 : // The affix is either the prefix or the suffix.
190 0 : UnicodeString* affix = &prefix;
191 :
192 0 : int32_t start = pos;
193 0 : UBool isPartDone = FALSE;
194 : UChar32 ch;
195 :
196 0 : for (; !isPartDone && pos < patLen; ) {
197 : // Todo: account for surrogate pairs
198 0 : ch = pattern.char32At(pos);
199 0 : 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 0 : if (pattern.compare(pos, digitLen, fDigit) == 0) {
211 0 : if (zeroDigitCount > 0 || sigDigitCount > 0) {
212 0 : ++digitRightCount;
213 : } else {
214 0 : ++digitLeftCount;
215 : }
216 0 : if (groupingCount >= 0 && decimalPos < 0) {
217 0 : ++groupingCount;
218 : }
219 0 : pos += digitLen;
220 0 : } else if ((ch >= fZeroDigit && ch <= nineDigit) ||
221 0 : ch == fSigDigit) {
222 0 : if (digitRightCount > 0) {
223 : // Unexpected '0'
224 : debug("Unexpected '0'")
225 0 : status = U_UNEXPECTED_TOKEN;
226 0 : syntaxError(pattern,pos,parseError);
227 0 : return;
228 : }
229 0 : if (ch == fSigDigit) {
230 0 : ++sigDigitCount;
231 : } else {
232 0 : if (ch != fZeroDigit && roundingPos < 0) {
233 0 : roundingPos = digitLeftCount + zeroDigitCount;
234 : }
235 0 : if (roundingPos >= 0) {
236 0 : roundingInc.append((char)(ch - fZeroDigit + '0'));
237 : }
238 0 : ++zeroDigitCount;
239 : }
240 0 : if (groupingCount >= 0 && decimalPos < 0) {
241 0 : ++groupingCount;
242 : }
243 0 : pos += U16_LENGTH(ch);
244 0 : } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) {
245 0 : if (decimalPos >= 0) {
246 : // Grouping separator after decimal
247 : debug("Grouping separator after decimal")
248 0 : status = U_UNEXPECTED_TOKEN;
249 0 : syntaxError(pattern,pos,parseError);
250 0 : return;
251 : }
252 0 : groupingCount2 = groupingCount;
253 0 : groupingCount = 0;
254 0 : pos += groupSepLen;
255 0 : } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) {
256 0 : if (decimalPos >= 0) {
257 : // Multiple decimal separators
258 : debug("Multiple decimal separators")
259 0 : status = U_MULTIPLE_DECIMAL_SEPARATORS;
260 0 : syntaxError(pattern,pos,parseError);
261 0 : 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 0 : decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
267 0 : pos += decimalSepLen;
268 : } else {
269 0 : if (pattern.compare(pos, fExponent.length(), fExponent) == 0) {
270 0 : if (expDigits >= 0) {
271 : // Multiple exponential symbols
272 : debug("Multiple exponential symbols")
273 0 : status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
274 0 : syntaxError(pattern,pos,parseError);
275 0 : return;
276 : }
277 0 : if (groupingCount >= 0) {
278 : // Grouping separator in exponential pattern
279 : debug("Grouping separator in exponential pattern")
280 0 : status = U_MALFORMED_EXPONENTIAL_PATTERN;
281 0 : syntaxError(pattern,pos,parseError);
282 0 : return;
283 : }
284 0 : pos += fExponent.length();
285 : // Check for positive prefix
286 0 : if (pos < patLen
287 0 : && pattern.compare(pos, fPlus.length(), fPlus) == 0) {
288 0 : expSignAlways = TRUE;
289 0 : pos += fPlus.length();
290 : }
291 : // Use lookahead to parse out the exponential part of the
292 : // pattern, then jump into suffix subpart.
293 0 : expDigits = 0;
294 0 : while (pos < patLen &&
295 0 : pattern.char32At(pos) == fZeroDigit) {
296 0 : ++expDigits;
297 0 : 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 0 : if (((digitLeftCount + zeroDigitCount) < 1 &&
304 0 : (sigDigitCount + digitRightCount) < 1) ||
305 0 : (sigDigitCount > 0 && digitLeftCount > 0) ||
306 : expDigits < 1) {
307 : // Malformed exponential pattern
308 : debug("Malformed exponential pattern")
309 0 : status = U_MALFORMED_EXPONENTIAL_PATTERN;
310 0 : syntaxError(pattern,pos,parseError);
311 0 : return;
312 : }
313 : }
314 : // Transition to suffix subpart
315 0 : subpart = 2; // suffix subpart
316 0 : affix = &suffix;
317 0 : sub0Limit = pos;
318 0 : continue;
319 : }
320 0 : 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 0 : if (!pattern.compare(pos, digitLen, fDigit) ||
331 0 : !pattern.compare(pos, groupSepLen, fGroupingSeparator) ||
332 0 : !pattern.compare(pos, decimalSepLen, fDecimalSeparator) ||
333 0 : (ch >= fZeroDigit && ch <= nineDigit) ||
334 0 : ch == fSigDigit) {
335 0 : if (subpart == 1) { // prefix subpart
336 0 : subpart = 0; // pattern proper subpart
337 0 : sub0Start = pos; // Reprocess this character
338 0 : continue;
339 : } else {
340 0 : status = U_UNQUOTED_SPECIAL;
341 0 : syntaxError(pattern,pos,parseError);
342 0 : return;
343 : }
344 0 : } else if (ch == kCurrencySign) {
345 0 : 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 0 : if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
350 0 : affix->append(kCurrencySign);
351 0 : ++pos; // Skip over the doubled character
352 0 : if ((pos+1) < pattern.length() &&
353 0 : pattern[pos+1] == kCurrencySign) {
354 0 : affix->append(kCurrencySign);
355 0 : ++pos; // Skip over the doubled character
356 0 : out.fCurrencySignCount = fgCurrencySignCountInPluralFormat;
357 : } else {
358 0 : out.fCurrencySignCount = fgCurrencySignCountInISOFormat;
359 : }
360 : } else {
361 0 : out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
362 : }
363 : // Fall through to append(ch)
364 0 : } 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 0 : ++pos;
370 0 : if (pos < pattern.length() && pattern[pos] == kQuote) {
371 0 : affix->append(kQuote); // Encode quote
372 : // Fall through to append(ch)
373 : } else {
374 0 : subpart += 2; // open quote
375 0 : continue;
376 : }
377 0 : } 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 0 : if (subpart == 1 || part == 1) {
381 : // Unexpected separator
382 : debug("Unexpected separator")
383 0 : status = U_UNEXPECTED_TOKEN;
384 0 : syntaxError(pattern,pos,parseError);
385 0 : return;
386 : }
387 0 : sub2Limit = pos;
388 0 : isPartDone = TRUE; // Go to next part
389 0 : pos += fSeparator.length();
390 0 : break;
391 0 : } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) {
392 : // Next handle characters which are appended directly.
393 0 : if (multiplier != 1) {
394 : // Too many percent/perMill characters
395 : debug("Too many percent characters")
396 0 : status = U_MULTIPLE_PERCENT_SYMBOLS;
397 0 : syntaxError(pattern,pos,parseError);
398 0 : return;
399 : }
400 0 : affix->append(kQuote); // Encode percent/perMill
401 0 : affix->append(kPatternPercent); // Use unlocalized pattern char
402 0 : multiplier = 100;
403 0 : pos += fPercent.length();
404 0 : break;
405 0 : } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) {
406 : // Next handle characters which are appended directly.
407 0 : if (multiplier != 1) {
408 : // Too many percent/perMill characters
409 : debug("Too many perMill characters")
410 0 : status = U_MULTIPLE_PERMILL_SYMBOLS;
411 0 : syntaxError(pattern,pos,parseError);
412 0 : return;
413 : }
414 0 : affix->append(kQuote); // Encode percent/perMill
415 0 : affix->append(kPatternPerMill); // Use unlocalized pattern char
416 0 : multiplier = 1000;
417 0 : pos += fPerMill.length();
418 0 : break;
419 0 : } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) {
420 0 : if (padPos >= 0 || // Multiple pad specifiers
421 0 : (pos+1) == pattern.length()) { // Nothing after padEscape
422 : debug("Multiple pad specifiers")
423 0 : status = U_MULTIPLE_PAD_SPECIFIERS;
424 0 : syntaxError(pattern,pos,parseError);
425 0 : return;
426 : }
427 0 : padPos = pos;
428 0 : pos += fPadEscape.length();
429 0 : padChar = pattern.char32At(pos);
430 0 : pos += U16_LENGTH(padChar);
431 0 : break;
432 0 : } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) {
433 0 : affix->append(kQuote); // Encode minus
434 0 : affix->append(kPatternMinus);
435 0 : pos += fMinus.length();
436 0 : break;
437 0 : } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) {
438 0 : affix->append(kQuote); // Encode plus
439 0 : affix->append(kPatternPlus);
440 0 : pos += fPlus.length();
441 0 : 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 0 : affix->append(ch);
447 0 : pos += U16_LENGTH(ch);
448 0 : 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 0 : if (ch == kQuote) {
455 0 : ++pos;
456 0 : if (pos < pattern.length() && pattern[pos] == kQuote) {
457 0 : affix->append(kQuote); // Encode quote
458 : // Fall through to append(ch)
459 : } else {
460 0 : subpart -= 2; // close quote
461 0 : continue;
462 : }
463 : }
464 0 : affix->append(ch);
465 0 : pos += U16_LENGTH(ch);
466 0 : break;
467 : }
468 : }
469 :
470 0 : if (sub0Limit == 0) {
471 0 : sub0Limit = pattern.length();
472 : }
473 :
474 0 : if (sub2Limit == 0) {
475 0 : 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 0 : if (zeroDigitCount == 0 && sigDigitCount == 0 &&
492 0 : digitLeftCount > 0 && decimalPos >= 0) {
493 : // Handle "###.###" and "###." and ".###"
494 0 : int n = decimalPos;
495 0 : if (n == 0)
496 0 : ++n; // Handle ".###"
497 0 : digitRightCount = digitLeftCount - n;
498 0 : digitLeftCount = n - 1;
499 0 : zeroDigitCount = 1;
500 : }
501 :
502 : // Do syntax checking on the digits, decimal points, and quotes.
503 0 : if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
504 0 : (decimalPos >= 0 &&
505 0 : (sigDigitCount > 0 ||
506 0 : decimalPos < digitLeftCount ||
507 0 : decimalPos > (digitLeftCount + zeroDigitCount))) ||
508 0 : groupingCount == 0 || groupingCount2 == 0 ||
509 0 : (sigDigitCount > 0 && zeroDigitCount > 0) ||
510 : subpart > 2)
511 : { // subpart > 2 == unmatched quote
512 : debug("Syntax error")
513 0 : status = U_PATTERN_SYNTAX_ERROR;
514 0 : syntaxError(pattern,pos,parseError);
515 0 : return;
516 : }
517 :
518 : // Make sure pad is at legal position before or after affix.
519 0 : if (padPos >= 0) {
520 0 : if (padPos == start) {
521 0 : padPos = DecimalFormatPattern::kPadBeforePrefix;
522 0 : } else if (padPos+2 == sub0Start) {
523 0 : padPos = DecimalFormatPattern::kPadAfterPrefix;
524 0 : } else if (padPos == sub0Limit) {
525 0 : padPos = DecimalFormatPattern::kPadBeforeSuffix;
526 0 : } else if (padPos+2 == sub2Limit) {
527 0 : padPos = DecimalFormatPattern::kPadAfterSuffix;
528 : } else {
529 : // Illegal pad position
530 : debug("Illegal pad position")
531 0 : status = U_ILLEGAL_PAD_POSITION;
532 0 : syntaxError(pattern,pos,parseError);
533 0 : return;
534 : }
535 : }
536 :
537 0 : if (part == 0) {
538 0 : out.fPosPatternsBogus = FALSE;
539 0 : out.fPosPrefixPattern = prefix;
540 0 : out.fPosSuffixPattern = suffix;
541 0 : out.fNegPatternsBogus = TRUE;
542 0 : out.fNegPrefixPattern.remove();
543 0 : out.fNegSuffixPattern.remove();
544 :
545 0 : out.fUseExponentialNotation = (expDigits >= 0);
546 0 : if (out.fUseExponentialNotation) {
547 0 : out.fMinExponentDigits = expDigits;
548 : }
549 0 : out.fExponentSignAlwaysShown = expSignAlways;
550 0 : 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 0 : int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
556 0 : UBool isSigDig = (sigDigitCount > 0);
557 0 : out.fUseSignificantDigits = isSigDig;
558 0 : if (isSigDig) {
559 0 : out.fMinimumSignificantDigits = sigDigitCount;
560 0 : out.fMaximumSignificantDigits = sigDigitCount + digitRightCount;
561 : } else {
562 0 : int32_t minInt = effectiveDecimalPos - digitLeftCount;
563 0 : out.fMinimumIntegerDigits = minInt;
564 0 : out.fMaximumIntegerDigits = out.fUseExponentialNotation
565 0 : ? digitLeftCount + out.fMinimumIntegerDigits
566 : : gDefaultMaxIntegerDigits;
567 0 : out.fMaximumFractionDigits = decimalPos >= 0
568 0 : ? (digitTotalCount - decimalPos) : 0;
569 0 : out.fMinimumFractionDigits = decimalPos >= 0
570 0 : ? (digitLeftCount + zeroDigitCount - decimalPos) : 0;
571 : }
572 0 : out.fGroupingUsed = groupingCount > 0;
573 0 : out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
574 0 : out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
575 0 : ? groupingCount2 : 0;
576 0 : out.fMultiplier = multiplier;
577 0 : out.fDecimalSeparatorAlwaysShown = decimalPos == 0
578 0 : || decimalPos == digitTotalCount;
579 0 : if (padPos >= 0) {
580 0 : 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 0 : out.fFormatWidth = sub0Limit - sub0Start;
587 0 : out.fPad = padChar;
588 : } else {
589 0 : out.fFormatWidth = 0;
590 : }
591 0 : if (roundingPos >= 0) {
592 0 : out.fRoundingIncrementUsed = TRUE;
593 0 : roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
594 0 : out.fRoundingIncrement = roundingInc;
595 : } else {
596 0 : out.fRoundingIncrementUsed = FALSE;
597 : }
598 : } else {
599 0 : out.fNegPatternsBogus = FALSE;
600 0 : out.fNegPrefixPattern = prefix;
601 0 : out.fNegSuffixPattern = suffix;
602 : }
603 : }
604 :
605 0 : if (pattern.length() == 0) {
606 0 : out.fNegPatternsBogus = TRUE;
607 0 : out.fNegPrefixPattern.remove();
608 0 : out.fNegSuffixPattern.remove();
609 0 : out.fPosPatternsBogus = FALSE;
610 0 : out.fPosPrefixPattern.remove();
611 0 : out.fPosSuffixPattern.remove();
612 :
613 0 : out.fMinimumIntegerDigits = 0;
614 0 : out.fMaximumIntegerDigits = kDoubleIntegerDigits;
615 0 : out.fMinimumFractionDigits = 0;
616 0 : out.fMaximumFractionDigits = kDoubleFractionDigits;
617 :
618 0 : out.fUseExponentialNotation = FALSE;
619 0 : out.fCurrencySignCount = fgCurrencySignCountZero;
620 0 : out.fGroupingUsed = FALSE;
621 0 : out.fGroupingSize = 0;
622 0 : out.fGroupingSize2 = 0;
623 0 : out.fMultiplier = 1;
624 0 : out.fDecimalSeparatorAlwaysShown = FALSE;
625 0 : out.fFormatWidth = 0;
626 0 : 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 0 : if (out.fNegPatternsBogus ||
633 0 : (out.fNegPrefixPattern == out.fPosPrefixPattern
634 0 : && out.fNegSuffixPattern == out.fPosSuffixPattern)) {
635 0 : out.fNegPatternsBogus = FALSE;
636 0 : out.fNegSuffixPattern = out.fPosSuffixPattern;
637 0 : out.fNegPrefixPattern.remove();
638 0 : out.fNegPrefixPattern.append(kQuote).append(kPatternMinus)
639 0 : .append(out.fPosPrefixPattern);
640 : }
641 : // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields.
642 : AffixPattern::parseAffixString(
643 0 : out.fNegSuffixPattern, out.fNegSuffixAffix, status);
644 : AffixPattern::parseAffixString(
645 0 : out.fPosSuffixPattern, out.fPosSuffixAffix, status);
646 : AffixPattern::parseAffixString(
647 0 : out.fNegPrefixPattern, out.fNegPrefixAffix, status);
648 : AffixPattern::parseAffixString(
649 0 : out.fPosPrefixPattern, out.fPosPrefixAffix, status);
650 : }
651 :
652 : U_NAMESPACE_END
653 :
654 : #endif /* !UCONFIG_NO_FORMATTING */
|