OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * Copyright (C) 1997-2009, International Business Machines Corporation and * |
| 4 * others. All Rights Reserved. * |
| 5 ******************************************************************************* |
| 6 * |
| 7 * File CHOICFMT.CPP |
| 8 * |
| 9 * Modification History: |
| 10 * |
| 11 * Date Name Description |
| 12 * 02/19/97 aliu Converted from java. |
| 13 * 03/20/97 helena Finished first cut of implementation and got rid |
| 14 * of nextDouble/previousDouble and replaced with |
| 15 * boolean array. |
| 16 * 4/10/97 aliu Clean up. Modified to work on AIX. |
| 17 * 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
|
| 18 * wchar.h. |
| 19 * 07/09/97 helena Made ParsePosition into a class. |
| 20 * 08/06/97 nos removed overloaded constructor, fixed 'format(array)
' |
| 21 * 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags) |
| 22 * 02/22/99 stephen Removed character literals for EBCDIC safety |
| 23 ******************************************************************************** |
| 24 */ |
| 25 |
| 26 #include "unicode/utypes.h" |
| 27 |
| 28 #if !UCONFIG_NO_FORMATTING |
| 29 |
| 30 #include "unicode/choicfmt.h" |
| 31 #include "unicode/numfmt.h" |
| 32 #include "unicode/locid.h" |
| 33 #include "cpputils.h" |
| 34 #include "cstring.h" |
| 35 #include "putilimp.h" |
| 36 #include <stdio.h> |
| 37 #include <float.h> |
| 38 |
| 39 // ***************************************************************************** |
| 40 // class ChoiceFormat |
| 41 // ***************************************************************************** |
| 42 |
| 43 U_NAMESPACE_BEGIN |
| 44 |
| 45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat) |
| 46 |
| 47 // Special characters used by ChoiceFormat. There are two characters |
| 48 // used interchangeably to indicate <=. Either is parsed, but only |
| 49 // LESS_EQUAL is generated by toPattern(). |
| 50 #define SINGLE_QUOTE ((UChar)0x0027) /*'*/ |
| 51 #define LESS_THAN ((UChar)0x003C) /*<*/ |
| 52 #define LESS_EQUAL ((UChar)0x0023) /*#*/ |
| 53 #define LESS_EQUAL2 ((UChar)0x2264) |
| 54 #define VERTICAL_BAR ((UChar)0x007C) /*|*/ |
| 55 #define MINUS ((UChar)0x002D) /*-*/ |
| 56 |
| 57 #ifdef INFINITY |
| 58 #undef INFINITY |
| 59 #endif |
| 60 #define INFINITY ((UChar)0x221E) |
| 61 |
| 62 static const UChar gPositiveInfinity[] = {INFINITY, 0}; |
| 63 static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0}; |
| 64 #define POSITIVE_INF_STRLEN 1 |
| 65 #define NEGATIVE_INF_STRLEN 2 |
| 66 |
| 67 // ------------------------------------- |
| 68 // Creates a ChoiceFormat instance based on the pattern. |
| 69 |
| 70 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern, |
| 71 UErrorCode& status) |
| 72 : fChoiceLimits(0), |
| 73 fClosures(0), |
| 74 fChoiceFormats(0), |
| 75 fCount(0) |
| 76 { |
| 77 applyPattern(newPattern, status); |
| 78 } |
| 79 |
| 80 // ------------------------------------- |
| 81 // Creates a ChoiceFormat instance with the limit array and |
| 82 // format strings for each limit. |
| 83 |
| 84 ChoiceFormat::ChoiceFormat(const double* limits, |
| 85 const UnicodeString* formats, |
| 86 int32_t cnt ) |
| 87 : fChoiceLimits(0), |
| 88 fClosures(0), |
| 89 fChoiceFormats(0), |
| 90 fCount(0) |
| 91 { |
| 92 setChoices(limits, formats, cnt ); |
| 93 } |
| 94 |
| 95 // ------------------------------------- |
| 96 |
| 97 ChoiceFormat::ChoiceFormat(const double* limits, |
| 98 const UBool* closures, |
| 99 const UnicodeString* formats, |
| 100 int32_t cnt ) |
| 101 : fChoiceLimits(0), |
| 102 fClosures(0), |
| 103 fChoiceFormats(0), |
| 104 fCount(0) |
| 105 { |
| 106 setChoices(limits, closures, formats, cnt ); |
| 107 } |
| 108 |
| 109 // ------------------------------------- |
| 110 // copy constructor |
| 111 |
| 112 ChoiceFormat::ChoiceFormat(const ChoiceFormat& that) |
| 113 : NumberFormat(that), |
| 114 fChoiceLimits(0), |
| 115 fClosures(0), |
| 116 fChoiceFormats(0) |
| 117 { |
| 118 *this = that; |
| 119 } |
| 120 |
| 121 // ------------------------------------- |
| 122 // Private constructor that creates a |
| 123 // ChoiceFormat instance based on the |
| 124 // pattern and populates UParseError |
| 125 |
| 126 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern, |
| 127 UParseError& parseError, |
| 128 UErrorCode& status) |
| 129 : fChoiceLimits(0), |
| 130 fClosures(0), |
| 131 fChoiceFormats(0), |
| 132 fCount(0) |
| 133 { |
| 134 applyPattern(newPattern,parseError, status); |
| 135 } |
| 136 // ------------------------------------- |
| 137 |
| 138 UBool |
| 139 ChoiceFormat::operator==(const Format& that) const |
| 140 { |
| 141 if (this == &that) return TRUE; |
| 142 if (!NumberFormat::operator==(that)) return FALSE; |
| 143 ChoiceFormat& thatAlias = (ChoiceFormat&)that; |
| 144 if (fCount != thatAlias.fCount) return FALSE; |
| 145 // Checks the limits, the corresponding format string and LE or LT flags. |
| 146 // LE means less than and equal to, LT means less than. |
| 147 for (int32_t i = 0; i < fCount; i++) { |
| 148 if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) || |
| 149 (fClosures[i] != thatAlias.fClosures[i]) || |
| 150 (fChoiceFormats[i] != thatAlias.fChoiceFormats[i])) |
| 151 return FALSE; |
| 152 } |
| 153 return TRUE; |
| 154 } |
| 155 |
| 156 // ------------------------------------- |
| 157 // copy constructor |
| 158 |
| 159 const ChoiceFormat& |
| 160 ChoiceFormat::operator=(const ChoiceFormat& that) |
| 161 { |
| 162 if (this != &that) { |
| 163 NumberFormat::operator=(that); |
| 164 fCount = that.fCount; |
| 165 uprv_free(fChoiceLimits); |
| 166 fChoiceLimits = NULL; |
| 167 uprv_free(fClosures); |
| 168 fClosures = NULL; |
| 169 delete [] fChoiceFormats; |
| 170 fChoiceFormats = NULL; |
| 171 |
| 172 fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount); |
| 173 fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); |
| 174 fChoiceFormats = new UnicodeString[fCount]; |
| 175 |
| 176 // check for memory allocation error |
| 177 if (!fChoiceLimits || !fClosures || !fChoiceFormats) { |
| 178 if (fChoiceLimits) { |
| 179 uprv_free(fChoiceLimits); |
| 180 fChoiceLimits = NULL; |
| 181 } |
| 182 if (fClosures) { |
| 183 uprv_free(fClosures); |
| 184 fClosures = NULL; |
| 185 } |
| 186 if (fChoiceFormats) { |
| 187 delete[] fChoiceFormats; |
| 188 fChoiceFormats = NULL; |
| 189 } |
| 190 } else { |
| 191 uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount); |
| 192 uprv_arrayCopy(that.fClosures, fClosures, fCount); |
| 193 uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount); |
| 194 } |
| 195 } |
| 196 return *this; |
| 197 } |
| 198 |
| 199 // ------------------------------------- |
| 200 |
| 201 ChoiceFormat::~ChoiceFormat() |
| 202 { |
| 203 uprv_free(fChoiceLimits); |
| 204 fChoiceLimits = NULL; |
| 205 uprv_free(fClosures); |
| 206 fClosures = NULL; |
| 207 delete [] fChoiceFormats; |
| 208 fChoiceFormats = NULL; |
| 209 fCount = 0; |
| 210 } |
| 211 |
| 212 /** |
| 213 * Convert a string to a double value |
| 214 */ |
| 215 double |
| 216 ChoiceFormat::stod(const UnicodeString& string) |
| 217 { |
| 218 char source[256]; |
| 219 char* end; |
| 220 |
| 221 string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV);
/* invariant codepage */ |
| 222 return uprv_strtod(source,&end); |
| 223 } |
| 224 |
| 225 // ------------------------------------- |
| 226 |
| 227 /** |
| 228 * Convert a double value to a string without the overhead of ICU. |
| 229 */ |
| 230 UnicodeString& |
| 231 ChoiceFormat::dtos(double value, |
| 232 UnicodeString& string) |
| 233 { |
| 234 /* Buffer to contain the digits and any extra formatting stuff. */ |
| 235 char temp[DBL_DIG + 16]; |
| 236 char *itrPtr = temp; |
| 237 char *expPtr; |
| 238 |
| 239 sprintf(temp, "%.*g", DBL_DIG, value); |
| 240 |
| 241 /* Find and convert the decimal point. |
| 242 Using setlocale on some machines will cause sprintf to use a comma for ce
rtain locales. |
| 243 */ |
| 244 while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) { |
| 245 itrPtr++; |
| 246 } |
| 247 if (*itrPtr != 0 && *itrPtr != 'e') { |
| 248 /* We reached something that looks like a decimal point. |
| 249 In case someone used setlocale(), which changes the decimal point. */ |
| 250 *itrPtr = '.'; |
| 251 itrPtr++; |
| 252 } |
| 253 /* Search for the exponent */ |
| 254 while (*itrPtr && *itrPtr != 'e') { |
| 255 itrPtr++; |
| 256 } |
| 257 if (*itrPtr == 'e') { |
| 258 itrPtr++; |
| 259 /* Verify the exponent sign */ |
| 260 if (*itrPtr == '+' || *itrPtr == '-') { |
| 261 itrPtr++; |
| 262 } |
| 263 /* Remove leading zeros. You will see this on Windows machines. */ |
| 264 expPtr = itrPtr; |
| 265 while (*itrPtr == '0') { |
| 266 itrPtr++; |
| 267 } |
| 268 if (*itrPtr && expPtr != itrPtr) { |
| 269 /* Shift the exponent without zeros. */ |
| 270 while (*itrPtr) { |
| 271 *(expPtr++) = *(itrPtr++); |
| 272 } |
| 273 // NULL terminate |
| 274 *expPtr = 0; |
| 275 } |
| 276 } |
| 277 |
| 278 string = UnicodeString(temp, -1, US_INV); /* invariant codepage */ |
| 279 return string; |
| 280 } |
| 281 |
| 282 // ------------------------------------- |
| 283 // calls the overloaded applyPattern method. |
| 284 |
| 285 void |
| 286 ChoiceFormat::applyPattern(const UnicodeString& pattern, |
| 287 UErrorCode& status) |
| 288 { |
| 289 UParseError parseError; |
| 290 applyPattern(pattern, parseError, status); |
| 291 } |
| 292 |
| 293 // ------------------------------------- |
| 294 // Applies the pattern to this ChoiceFormat instance. |
| 295 |
| 296 void |
| 297 ChoiceFormat::applyPattern(const UnicodeString& pattern, |
| 298 UParseError& parseError, |
| 299 UErrorCode& status) |
| 300 { |
| 301 if (U_FAILURE(status)) |
| 302 { |
| 303 return; |
| 304 } |
| 305 |
| 306 // Clear error struct |
| 307 parseError.offset = -1; |
| 308 parseError.preContext[0] = parseError.postContext[0] = (UChar)0; |
| 309 |
| 310 // Perform 2 passes. The first computes the number of limits in |
| 311 // this pattern (fCount), which is 1 more than the number of |
| 312 // literal VERTICAL_BAR characters. |
| 313 int32_t count = 1; |
| 314 int32_t i; |
| 315 for (i=0; i<pattern.length(); ++i) { |
| 316 UChar c = pattern[i]; |
| 317 if (c == SINGLE_QUOTE) { |
| 318 // Skip over the entire quote, including embedded |
| 319 // contiguous pairs of SINGLE_QUOTE. |
| 320 for (;;) { |
| 321 do { |
| 322 ++i; |
| 323 } while (i<pattern.length() && |
| 324 pattern[i] != SINGLE_QUOTE); |
| 325 if ((i+1)<pattern.length() && |
| 326 pattern[i+1] == SINGLE_QUOTE) { |
| 327 // SINGLE_QUOTE pair; skip over it |
| 328 ++i; |
| 329 } else { |
| 330 break; |
| 331 } |
| 332 } |
| 333 } else if (c == VERTICAL_BAR) { |
| 334 ++count; |
| 335 } |
| 336 } |
| 337 |
| 338 // Allocate the required storage. |
| 339 double *newLimits = (double*) uprv_malloc( sizeof(double) * count); |
| 340 /* test for NULL */ |
| 341 if (newLimits == 0) { |
| 342 status = U_MEMORY_ALLOCATION_ERROR; |
| 343 return; |
| 344 } |
| 345 UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count); |
| 346 /* test for NULL */ |
| 347 if (newClosures == 0) { |
| 348 status = U_MEMORY_ALLOCATION_ERROR; |
| 349 uprv_free(newLimits); |
| 350 return; |
| 351 } |
| 352 UnicodeString *newFormats = new UnicodeString[count]; |
| 353 /* test for NULL */ |
| 354 if (newFormats == 0) { |
| 355 status = U_MEMORY_ALLOCATION_ERROR; |
| 356 uprv_free(newLimits); |
| 357 uprv_free(newClosures); |
| 358 return; |
| 359 } |
| 360 |
| 361 // Perform the second pass |
| 362 int32_t k = 0; // index into newXxx[] arrays |
| 363 UnicodeString buf; // scratch buffer |
| 364 UBool inQuote = FALSE; |
| 365 UBool inNumber = TRUE; // TRUE before < or #, FALSE after |
| 366 |
| 367 for (i=0; i<pattern.length(); ++i) { |
| 368 UChar c = pattern[i]; |
| 369 if (c == SINGLE_QUOTE) { |
| 370 // Check for SINGLE_QUOTE pair indicating a literal quote |
| 371 if ((i+1) < pattern.length() && |
| 372 pattern[i+1] == SINGLE_QUOTE) { |
| 373 buf += SINGLE_QUOTE; |
| 374 ++i; |
| 375 } else { |
| 376 inQuote = !inQuote; |
| 377 } |
| 378 } else if (inQuote) { |
| 379 buf += c; |
| 380 } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) { |
| 381 if (!inNumber || buf.length() == 0) { |
| 382 goto error; |
| 383 } |
| 384 inNumber = FALSE; |
| 385 |
| 386 double limit; |
| 387 buf.trim(); |
| 388 if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) { |
| 389 limit = uprv_getInfinity(); |
| 390 } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) { |
| 391 limit = -uprv_getInfinity(); |
| 392 } else { |
| 393 limit = stod(buf); |
| 394 } |
| 395 |
| 396 if (k == count) { |
| 397 // This shouldn't happen. If it does, it means that |
| 398 // the count determined in the first pass did not |
| 399 // match the number of elements found in the second |
| 400 // pass. |
| 401 goto error; |
| 402 } |
| 403 newLimits[k] = limit; |
| 404 newClosures[k] = (c == LESS_THAN); |
| 405 |
| 406 if (k > 0 && limit <= newLimits[k-1]) { |
| 407 // Each limit must be strictly > than the previous |
| 408 // limit. One exception: Two subsequent limits may be |
| 409 // == if the first closure is FALSE and the second |
| 410 // closure is TRUE. This places the limit value in |
| 411 // the second interval. |
| 412 if (!(limit == newLimits[k-1] && |
| 413 !newClosures[k-1] && |
| 414 newClosures[k])) { |
| 415 goto error; |
| 416 } |
| 417 } |
| 418 |
| 419 buf.truncate(0); |
| 420 } else if (c == VERTICAL_BAR) { |
| 421 if (inNumber) { |
| 422 goto error; |
| 423 } |
| 424 inNumber = TRUE; |
| 425 |
| 426 newFormats[k] = buf; |
| 427 ++k; |
| 428 buf.truncate(0); |
| 429 } else { |
| 430 buf += c; |
| 431 } |
| 432 } |
| 433 |
| 434 if (k != (count-1) || inNumber || inQuote) { |
| 435 goto error; |
| 436 } |
| 437 newFormats[k] = buf; |
| 438 |
| 439 // Don't modify this object until the parse succeeds |
| 440 uprv_free(fChoiceLimits); |
| 441 uprv_free(fClosures); |
| 442 delete[] fChoiceFormats; |
| 443 fCount = count; |
| 444 fChoiceLimits = newLimits; |
| 445 fClosures = newClosures; |
| 446 fChoiceFormats = newFormats; |
| 447 return; |
| 448 |
| 449 error: |
| 450 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 451 syntaxError(pattern,i,parseError); |
| 452 uprv_free(newLimits); |
| 453 uprv_free(newClosures); |
| 454 delete[] newFormats; |
| 455 return; |
| 456 |
| 457 } |
| 458 // ------------------------------------- |
| 459 // Reconstruct the original input pattern. |
| 460 |
| 461 UnicodeString& |
| 462 ChoiceFormat::toPattern(UnicodeString& result) const |
| 463 { |
| 464 result.remove(); |
| 465 for (int32_t i = 0; i < fCount; ++i) { |
| 466 if (i != 0) { |
| 467 result += VERTICAL_BAR; |
| 468 } |
| 469 UnicodeString buf; |
| 470 if (uprv_isPositiveInfinity(fChoiceLimits[i])) { |
| 471 result += INFINITY; |
| 472 } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) { |
| 473 result += MINUS; |
| 474 result += INFINITY; |
| 475 } else { |
| 476 result += dtos(fChoiceLimits[i], buf); |
| 477 } |
| 478 if (fClosures[i]) { |
| 479 result += LESS_THAN; |
| 480 } else { |
| 481 result += LESS_EQUAL; |
| 482 } |
| 483 // Append fChoiceFormats[i], using quotes if there are special |
| 484 // characters. Single quotes themselves must be escaped in |
| 485 // either case. |
| 486 const UnicodeString& text = fChoiceFormats[i]; |
| 487 UBool needQuote = text.indexOf(LESS_THAN) >= 0 |
| 488 || text.indexOf(LESS_EQUAL) >= 0 |
| 489 || text.indexOf(LESS_EQUAL2) >= 0 |
| 490 || text.indexOf(VERTICAL_BAR) >= 0; |
| 491 if (needQuote) { |
| 492 result += SINGLE_QUOTE; |
| 493 } |
| 494 if (text.indexOf(SINGLE_QUOTE) < 0) { |
| 495 result += text; |
| 496 } |
| 497 else { |
| 498 for (int32_t j = 0; j < text.length(); ++j) { |
| 499 UChar c = text[j]; |
| 500 result += c; |
| 501 if (c == SINGLE_QUOTE) { |
| 502 result += c; |
| 503 } |
| 504 } |
| 505 } |
| 506 if (needQuote) { |
| 507 result += SINGLE_QUOTE; |
| 508 } |
| 509 } |
| 510 |
| 511 return result; |
| 512 } |
| 513 |
| 514 // ------------------------------------- |
| 515 // Sets the limit and format arrays. |
| 516 void |
| 517 ChoiceFormat::setChoices( const double* limits, |
| 518 const UnicodeString* formats, |
| 519 int32_t cnt ) |
| 520 { |
| 521 setChoices(limits, 0, formats, cnt); |
| 522 } |
| 523 |
| 524 // ------------------------------------- |
| 525 // Sets the limit and format arrays. |
| 526 void |
| 527 ChoiceFormat::setChoices( const double* limits, |
| 528 const UBool* closures, |
| 529 const UnicodeString* formats, |
| 530 int32_t cnt ) |
| 531 { |
| 532 if(limits == 0 || formats == 0) |
| 533 return; |
| 534 |
| 535 if (fChoiceLimits) { |
| 536 uprv_free(fChoiceLimits); |
| 537 } |
| 538 if (fClosures) { |
| 539 uprv_free(fClosures); |
| 540 } |
| 541 if (fChoiceFormats) { |
| 542 delete [] fChoiceFormats; |
| 543 } |
| 544 |
| 545 // Note that the old arrays are deleted and this owns |
| 546 // the created array. |
| 547 fCount = cnt; |
| 548 fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount); |
| 549 fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); |
| 550 fChoiceFormats = new UnicodeString[fCount]; |
| 551 |
| 552 //check for memory allocation error |
| 553 if (!fChoiceLimits || !fClosures || !fChoiceFormats) { |
| 554 if (fChoiceLimits) { |
| 555 uprv_free(fChoiceLimits); |
| 556 fChoiceLimits = NULL; |
| 557 } |
| 558 if (fClosures) { |
| 559 uprv_free(fClosures); |
| 560 fClosures = NULL; |
| 561 } |
| 562 if (fChoiceFormats) { |
| 563 delete[] fChoiceFormats; |
| 564 fChoiceFormats = NULL; |
| 565 } |
| 566 return; |
| 567 } |
| 568 |
| 569 uprv_arrayCopy(limits, fChoiceLimits, fCount); |
| 570 uprv_arrayCopy(formats, fChoiceFormats, fCount); |
| 571 |
| 572 if (closures != 0) { |
| 573 uprv_arrayCopy(closures, fClosures, fCount); |
| 574 } else { |
| 575 int32_t i; |
| 576 for (i=0; i<fCount; ++i) { |
| 577 fClosures[i] = FALSE; |
| 578 } |
| 579 } |
| 580 } |
| 581 |
| 582 // ------------------------------------- |
| 583 // Gets the limit array. |
| 584 |
| 585 const double* |
| 586 ChoiceFormat::getLimits(int32_t& cnt) const |
| 587 { |
| 588 cnt = fCount; |
| 589 return fChoiceLimits; |
| 590 } |
| 591 |
| 592 // ------------------------------------- |
| 593 // Gets the closures array. |
| 594 |
| 595 const UBool* |
| 596 ChoiceFormat::getClosures(int32_t& cnt) const |
| 597 { |
| 598 cnt = fCount; |
| 599 return fClosures; |
| 600 } |
| 601 |
| 602 // ------------------------------------- |
| 603 // Gets the format array. |
| 604 |
| 605 const UnicodeString* |
| 606 ChoiceFormat::getFormats(int32_t& cnt) const |
| 607 { |
| 608 cnt = fCount; |
| 609 return fChoiceFormats; |
| 610 } |
| 611 |
| 612 // ------------------------------------- |
| 613 // Formats an int64 number, it's actually formatted as |
| 614 // a double. The returned format string may differ |
| 615 // from the input number because of this. |
| 616 |
| 617 UnicodeString& |
| 618 ChoiceFormat::format(int64_t number, |
| 619 UnicodeString& appendTo, |
| 620 FieldPosition& status) const |
| 621 { |
| 622 return format((double) number, appendTo, status); |
| 623 } |
| 624 |
| 625 // ------------------------------------- |
| 626 // Formats a long number, it's actually formatted as |
| 627 // a double. The returned format string may differ |
| 628 // from the input number because of this. |
| 629 |
| 630 UnicodeString& |
| 631 ChoiceFormat::format(int32_t number, |
| 632 UnicodeString& appendTo, |
| 633 FieldPosition& status) const |
| 634 { |
| 635 return format((double) number, appendTo, status); |
| 636 } |
| 637 |
| 638 // ------------------------------------- |
| 639 // Formats a double number. |
| 640 |
| 641 UnicodeString& |
| 642 ChoiceFormat::format(double number, |
| 643 UnicodeString& appendTo, |
| 644 FieldPosition& /*pos*/) const |
| 645 { |
| 646 // find the number |
| 647 int32_t i; |
| 648 for (i = 0; i < fCount; ++i) { |
| 649 if (fClosures[i]) { |
| 650 if (!(number > fChoiceLimits[i])) { |
| 651 // same as number <= fChoiceLimits, except catches NaN |
| 652 break; |
| 653 } |
| 654 } else if (!(number >= fChoiceLimits[i])) { |
| 655 // same as number < fChoiceLimits, except catches NaN |
| 656 break; |
| 657 } |
| 658 } |
| 659 --i; |
| 660 if (i < 0) { |
| 661 i = 0; |
| 662 } |
| 663 // return either a formatted number, or a string |
| 664 appendTo += fChoiceFormats[i]; |
| 665 return appendTo; |
| 666 } |
| 667 |
| 668 // ------------------------------------- |
| 669 // Formats an array of objects. Checks if the data type of the objects |
| 670 // to get the right value for formatting. |
| 671 |
| 672 UnicodeString& |
| 673 ChoiceFormat::format(const Formattable* objs, |
| 674 int32_t cnt, |
| 675 UnicodeString& appendTo, |
| 676 FieldPosition& pos, |
| 677 UErrorCode& status) const |
| 678 { |
| 679 if(cnt < 0) { |
| 680 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 681 return appendTo; |
| 682 } |
| 683 |
| 684 UnicodeString buffer; |
| 685 for (int32_t i = 0; i < cnt; i++) { |
| 686 double objDouble = objs[i].getDouble(status); |
| 687 if (U_SUCCESS(status)) { |
| 688 buffer.remove(); |
| 689 appendTo += format(objDouble, buffer, pos); |
| 690 } |
| 691 } |
| 692 |
| 693 return appendTo; |
| 694 } |
| 695 |
| 696 // ------------------------------------- |
| 697 // Formats an array of objects. Checks if the data type of the objects |
| 698 // to get the right value for formatting. |
| 699 |
| 700 UnicodeString& |
| 701 ChoiceFormat::format(const Formattable& obj, |
| 702 UnicodeString& appendTo, |
| 703 FieldPosition& pos, |
| 704 UErrorCode& status) const |
| 705 { |
| 706 return NumberFormat::format(obj, appendTo, pos, status); |
| 707 } |
| 708 // ------------------------------------- |
| 709 |
| 710 void |
| 711 ChoiceFormat::parse(const UnicodeString& text, |
| 712 Formattable& result, |
| 713 ParsePosition& status) const |
| 714 { |
| 715 // find the best number (defined as the one with the longest parse) |
| 716 int32_t start = status.getIndex(); |
| 717 int32_t furthest = start; |
| 718 double bestNumber = uprv_getNaN(); |
| 719 double tempNumber = 0.0; |
| 720 for (int i = 0; i < fCount; ++i) { |
| 721 int32_t len = fChoiceFormats[i].length(); |
| 722 if (text.compare(start, len, fChoiceFormats[i]) == 0) { |
| 723 status.setIndex(start + len); |
| 724 tempNumber = fChoiceLimits[i]; |
| 725 if (status.getIndex() > furthest) { |
| 726 furthest = status.getIndex(); |
| 727 bestNumber = tempNumber; |
| 728 if (furthest == text.length()) |
| 729 break; |
| 730 } |
| 731 } |
| 732 } |
| 733 status.setIndex(furthest); |
| 734 if (status.getIndex() == start) { |
| 735 status.setErrorIndex(furthest); |
| 736 } |
| 737 result.setDouble(bestNumber); |
| 738 } |
| 739 |
| 740 // ------------------------------------- |
| 741 // Parses the text and return the Formattable object. |
| 742 |
| 743 void |
| 744 ChoiceFormat::parse(const UnicodeString& text, |
| 745 Formattable& result, |
| 746 UErrorCode& status) const |
| 747 { |
| 748 NumberFormat::parse(text, result, status); |
| 749 } |
| 750 |
| 751 // ------------------------------------- |
| 752 |
| 753 Format* |
| 754 ChoiceFormat::clone() const |
| 755 { |
| 756 ChoiceFormat *aCopy = new ChoiceFormat(*this); |
| 757 return aCopy; |
| 758 } |
| 759 |
| 760 U_NAMESPACE_END |
| 761 |
| 762 #endif /* #if !UCONFIG_NO_FORMATTING */ |
| 763 |
| 764 //eof |
OLD | NEW |