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