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 43U_NAMESPACE_BEGIN 44 45UOBJECT_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 62static const UChar gPositiveInfinity[] = {INFINITY, 0}; 63static 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 70ChoiceFormat::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 84ChoiceFormat::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 97ChoiceFormat::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 112ChoiceFormat::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 126ChoiceFormat::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 138UBool 139ChoiceFormat::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 159const ChoiceFormat& 160ChoiceFormat::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 201ChoiceFormat::~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 */ 215double 216ChoiceFormat::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 */ 230UnicodeString& 231ChoiceFormat::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 certain 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 285void 286ChoiceFormat::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 296void 297ChoiceFormat::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 449error: 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 461UnicodeString& 462ChoiceFormat::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. 516void 517ChoiceFormat::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. 526void 527ChoiceFormat::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 585const double* 586ChoiceFormat::getLimits(int32_t& cnt) const 587{ 588 cnt = fCount; 589 return fChoiceLimits; 590} 591 592// ------------------------------------- 593// Gets the closures array. 594 595const UBool* 596ChoiceFormat::getClosures(int32_t& cnt) const 597{ 598 cnt = fCount; 599 return fClosures; 600} 601 602// ------------------------------------- 603// Gets the format array. 604 605const UnicodeString* 606ChoiceFormat::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 617UnicodeString& 618ChoiceFormat::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 630UnicodeString& 631ChoiceFormat::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 641UnicodeString& 642ChoiceFormat::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 672UnicodeString& 673ChoiceFormat::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 700UnicodeString& 701ChoiceFormat::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 710void 711ChoiceFormat::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 743void 744ChoiceFormat::parse(const UnicodeString& text, 745 Formattable& result, 746 UErrorCode& status) const 747{ 748 NumberFormat::parse(text, result, status); 749} 750 751// ------------------------------------- 752 753Format* 754ChoiceFormat::clone() const 755{ 756 ChoiceFormat *aCopy = new ChoiceFormat(*this); 757 return aCopy; 758} 759 760U_NAMESPACE_END 761 762#endif /* #if !UCONFIG_NO_FORMATTING */ 763 764//eof 765