1 /* 2 ******************************************************************************* 3 * Copyright (C) 1997-2011, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 * 7 * File FMTABLE.CPP 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 03/25/97 clhuang Initial Implementation. 13 ******************************************************************************** 14 */ 15 16 #include "unicode/utypes.h" 17 18 #if !UCONFIG_NO_FORMATTING 19 20 #include <math.h> 21 #include "unicode/fmtable.h" 22 #include "unicode/ustring.h" 23 #include "unicode/measure.h" 24 #include "unicode/curramt.h" 25 #include "charstr.h" 26 #include "cmemory.h" 27 #include "cstring.h" 28 #include "decNumber.h" 29 #include "digitlst.h" 30 31 // ***************************************************************************** 32 // class Formattable 33 // ***************************************************************************** 34 35 U_NAMESPACE_BEGIN 36 37 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable) 38 39 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 40 41 // NOTE: As of 3.0, there are limitations to the UObject API. It does 42 // not (yet) support cloning, operator=, nor operator==. To 43 // work around this, I implement some simple inlines here. Later 44 // these can be modified or removed. [alan] 45 46 // NOTE: These inlines assume that all fObjects are in fact instances 47 // of the Measure class, which is true as of 3.0. [alan] 48 49 // Return TRUE if *a == *b. 50 static inline UBool objectEquals(const UObject* a, const UObject* b) { 51 // LATER: return *a == *b; 52 return *((const Measure*) a) == *((const Measure*) b); 53 } 54 55 // Return a clone of *a. 56 static inline UObject* objectClone(const UObject* a) { 57 // LATER: return a->clone(); 58 return ((const Measure*) a)->clone(); 59 } 60 61 // Return TRUE if *a is an instance of Measure. 62 static inline UBool instanceOfMeasure(const UObject* a) { 63 return dynamic_cast<const Measure*>(a) != NULL; 64 } 65 66 /** 67 * Creates a new Formattable array and copies the values from the specified 68 * original. 69 * @param array the original array 70 * @param count the original array count 71 * @return the new Formattable array. 72 */ 73 static Formattable* createArrayCopy(const Formattable* array, int32_t count) { 74 Formattable *result = new Formattable[count]; 75 if (result != NULL) { 76 for (int32_t i=0; i<count; ++i) 77 result[i] = array[i]; // Don't memcpy! 78 } 79 return result; 80 } 81 82 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. 83 84 /** 85 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode. 86 */ 87 static void setError(UErrorCode& ec, UErrorCode err) { 88 if (U_SUCCESS(ec)) { 89 ec = err; 90 } 91 } 92 93 // 94 // Common initialization code, shared by constructors. 95 // Put everything into a known state. 96 // 97 void Formattable::init() { 98 fValue.fInt64 = 0; 99 fType = kLong; 100 fDecimalStr = NULL; 101 fDecimalNum = NULL; 102 fBogus.setToBogus(); 103 } 104 105 // ------------------------------------- 106 // default constructor. 107 // Creates a formattable object with a long value 0. 108 109 Formattable::Formattable() { 110 init(); 111 } 112 113 // ------------------------------------- 114 // Creates a formattable object with a Date instance. 115 116 Formattable::Formattable(UDate date, ISDATE /*isDate*/) 117 { 118 init(); 119 fType = kDate; 120 fValue.fDate = date; 121 } 122 123 // ------------------------------------- 124 // Creates a formattable object with a double value. 125 126 Formattable::Formattable(double value) 127 { 128 init(); 129 fType = kDouble; 130 fValue.fDouble = value; 131 } 132 133 // ------------------------------------- 134 // Creates a formattable object with an int32_t value. 135 136 Formattable::Formattable(int32_t value) 137 { 138 init(); 139 fValue.fInt64 = value; 140 } 141 142 // ------------------------------------- 143 // Creates a formattable object with an int64_t value. 144 145 Formattable::Formattable(int64_t value) 146 { 147 init(); 148 fType = kInt64; 149 fValue.fInt64 = value; 150 } 151 152 // ------------------------------------- 153 // Creates a formattable object with a decimal number value from a string. 154 155 Formattable::Formattable(const StringPiece &number, UErrorCode &status) { 156 init(); 157 setDecimalNumber(number, status); 158 } 159 160 161 // ------------------------------------- 162 // Creates a formattable object with a UnicodeString instance. 163 164 Formattable::Formattable(const UnicodeString& stringToCopy) 165 { 166 init(); 167 fType = kString; 168 fValue.fString = new UnicodeString(stringToCopy); 169 } 170 171 // ------------------------------------- 172 // Creates a formattable object with a UnicodeString* value. 173 // (adopting symantics) 174 175 Formattable::Formattable(UnicodeString* stringToAdopt) 176 { 177 init(); 178 fType = kString; 179 fValue.fString = stringToAdopt; 180 } 181 182 Formattable::Formattable(UObject* objectToAdopt) 183 { 184 init(); 185 fType = kObject; 186 fValue.fObject = objectToAdopt; 187 } 188 189 // ------------------------------------- 190 191 Formattable::Formattable(const Formattable* arrayToCopy, int32_t count) 192 : UObject(), fType(kArray) 193 { 194 init(); 195 fType = kArray; 196 fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count); 197 fValue.fArrayAndCount.fCount = count; 198 } 199 200 // ------------------------------------- 201 // copy constructor 202 203 204 Formattable::Formattable(const Formattable &source) 205 : UObject(*this) 206 { 207 init(); 208 *this = source; 209 } 210 211 // ------------------------------------- 212 // assignment operator 213 214 Formattable& 215 Formattable::operator=(const Formattable& source) 216 { 217 if (this != &source) 218 { 219 // Disposes the current formattable value/setting. 220 dispose(); 221 222 // Sets the correct data type for this value. 223 fType = source.fType; 224 switch (fType) 225 { 226 case kArray: 227 // Sets each element in the array one by one and records the array count. 228 fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount; 229 fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray, 230 source.fValue.fArrayAndCount.fCount); 231 break; 232 case kString: 233 // Sets the string value. 234 fValue.fString = new UnicodeString(*source.fValue.fString); 235 break; 236 case kDouble: 237 // Sets the double value. 238 fValue.fDouble = source.fValue.fDouble; 239 break; 240 case kLong: 241 case kInt64: 242 // Sets the long value. 243 fValue.fInt64 = source.fValue.fInt64; 244 break; 245 case kDate: 246 // Sets the Date value. 247 fValue.fDate = source.fValue.fDate; 248 break; 249 case kObject: 250 fValue.fObject = objectClone(source.fValue.fObject); 251 break; 252 } 253 254 UErrorCode status = U_ZERO_ERROR; 255 if (source.fDecimalNum != NULL) { 256 fDecimalNum = new DigitList(*source.fDecimalNum); 257 } 258 if (source.fDecimalStr != NULL) { 259 fDecimalStr = new CharString(*source.fDecimalStr, status); 260 if (U_FAILURE(status)) { 261 delete fDecimalStr; 262 fDecimalStr = NULL; 263 } 264 } 265 } 266 return *this; 267 } 268 269 // ------------------------------------- 270 271 UBool 272 Formattable::operator==(const Formattable& that) const 273 { 274 int32_t i; 275 276 if (this == &that) return TRUE; 277 278 // Returns FALSE if the data types are different. 279 if (fType != that.fType) return FALSE; 280 281 // Compares the actual data values. 282 UBool equal = TRUE; 283 switch (fType) { 284 case kDate: 285 equal = (fValue.fDate == that.fValue.fDate); 286 break; 287 case kDouble: 288 equal = (fValue.fDouble == that.fValue.fDouble); 289 break; 290 case kLong: 291 case kInt64: 292 equal = (fValue.fInt64 == that.fValue.fInt64); 293 break; 294 case kString: 295 equal = (*(fValue.fString) == *(that.fValue.fString)); 296 break; 297 case kArray: 298 if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) { 299 equal = FALSE; 300 break; 301 } 302 // Checks each element for equality. 303 for (i=0; i<fValue.fArrayAndCount.fCount; ++i) { 304 if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) { 305 equal = FALSE; 306 break; 307 } 308 } 309 break; 310 case kObject: 311 if (fValue.fObject == NULL || that.fValue.fObject == NULL) { 312 equal = FALSE; 313 } else { 314 equal = objectEquals(fValue.fObject, that.fValue.fObject); 315 } 316 break; 317 } 318 319 // TODO: compare digit lists if numeric. 320 return equal; 321 } 322 323 // ------------------------------------- 324 325 Formattable::~Formattable() 326 { 327 dispose(); 328 } 329 330 // ------------------------------------- 331 332 void Formattable::dispose() 333 { 334 // Deletes the data value if necessary. 335 switch (fType) { 336 case kString: 337 delete fValue.fString; 338 break; 339 case kArray: 340 delete[] fValue.fArrayAndCount.fArray; 341 break; 342 case kObject: 343 delete fValue.fObject; 344 break; 345 default: 346 break; 347 } 348 349 fType = kLong; 350 fValue.fInt64 = 0; 351 delete fDecimalStr; 352 fDecimalStr = NULL; 353 delete fDecimalNum; 354 fDecimalNum = NULL; 355 } 356 357 Formattable * 358 Formattable::clone() const { 359 return new Formattable(*this); 360 } 361 362 // ------------------------------------- 363 // Gets the data type of this Formattable object. 364 Formattable::Type 365 Formattable::getType() const 366 { 367 return fType; 368 } 369 370 UBool 371 Formattable::isNumeric() const { 372 switch (fType) { 373 case kDouble: 374 case kLong: 375 case kInt64: 376 return TRUE; 377 default: 378 return FALSE; 379 } 380 } 381 382 // ------------------------------------- 383 int32_t 384 //Formattable::getLong(UErrorCode* status) const 385 Formattable::getLong(UErrorCode& status) const 386 { 387 if (U_FAILURE(status)) { 388 return 0; 389 } 390 391 switch (fType) { 392 case Formattable::kLong: 393 return (int32_t)fValue.fInt64; 394 case Formattable::kInt64: 395 if (fValue.fInt64 > INT32_MAX) { 396 status = U_INVALID_FORMAT_ERROR; 397 return INT32_MAX; 398 } else if (fValue.fInt64 < INT32_MIN) { 399 status = U_INVALID_FORMAT_ERROR; 400 return INT32_MIN; 401 } else { 402 return (int32_t)fValue.fInt64; 403 } 404 case Formattable::kDouble: 405 if (fValue.fDouble > INT32_MAX) { 406 status = U_INVALID_FORMAT_ERROR; 407 return INT32_MAX; 408 } else if (fValue.fDouble < INT32_MIN) { 409 status = U_INVALID_FORMAT_ERROR; 410 return INT32_MIN; 411 } else { 412 return (int32_t)fValue.fDouble; // loses fraction 413 } 414 case Formattable::kObject: 415 if (fValue.fObject == NULL) { 416 status = U_MEMORY_ALLOCATION_ERROR; 417 return 0; 418 } 419 // TODO Later replace this with instanceof call 420 if (instanceOfMeasure(fValue.fObject)) { 421 return ((const Measure*) fValue.fObject)-> 422 getNumber().getLong(status); 423 } 424 default: 425 status = U_INVALID_FORMAT_ERROR; 426 return 0; 427 } 428 } 429 430 // ------------------------------------- 431 // Maximum int that can be represented exactly in a double. (53 bits) 432 // Larger ints may be rounded to a near-by value as not all are representable. 433 // TODO: move this constant elsewhere, possibly configure it for different 434 // floating point formats, if any non-standard ones are still in use. 435 static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL; 436 437 int64_t 438 Formattable::getInt64(UErrorCode& status) const 439 { 440 if (U_FAILURE(status)) { 441 return 0; 442 } 443 444 switch (fType) { 445 case Formattable::kLong: 446 case Formattable::kInt64: 447 return fValue.fInt64; 448 case Formattable::kDouble: 449 if (fValue.fDouble > (double)U_INT64_MAX) { 450 status = U_INVALID_FORMAT_ERROR; 451 return U_INT64_MAX; 452 } else if (fValue.fDouble < (double)U_INT64_MIN) { 453 status = U_INVALID_FORMAT_ERROR; 454 return U_INT64_MIN; 455 } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) { 456 int64_t val = fDecimalNum->getInt64(); 457 if (val != 0) { 458 return val; 459 } else { 460 status = U_INVALID_FORMAT_ERROR; 461 return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN; 462 } 463 } else { 464 return (int64_t)fValue.fDouble; 465 } 466 case Formattable::kObject: 467 if (fValue.fObject == NULL) { 468 status = U_MEMORY_ALLOCATION_ERROR; 469 return 0; 470 } 471 if (instanceOfMeasure(fValue.fObject)) { 472 return ((const Measure*) fValue.fObject)-> 473 getNumber().getInt64(status); 474 } 475 default: 476 status = U_INVALID_FORMAT_ERROR; 477 return 0; 478 } 479 } 480 481 // ------------------------------------- 482 double 483 Formattable::getDouble(UErrorCode& status) const 484 { 485 if (U_FAILURE(status)) { 486 return 0; 487 } 488 489 switch (fType) { 490 case Formattable::kLong: 491 case Formattable::kInt64: // loses precision 492 return (double)fValue.fInt64; 493 case Formattable::kDouble: 494 return fValue.fDouble; 495 case Formattable::kObject: 496 if (fValue.fObject == NULL) { 497 status = U_MEMORY_ALLOCATION_ERROR; 498 return 0; 499 } 500 // TODO Later replace this with instanceof call 501 if (instanceOfMeasure(fValue.fObject)) { 502 return ((const Measure*) fValue.fObject)-> 503 getNumber().getDouble(status); 504 } 505 default: 506 status = U_INVALID_FORMAT_ERROR; 507 return 0; 508 } 509 } 510 511 const UObject* 512 Formattable::getObject() const { 513 return (fType == kObject) ? fValue.fObject : NULL; 514 } 515 516 // ------------------------------------- 517 // Sets the value to a double value d. 518 519 void 520 Formattable::setDouble(double d) 521 { 522 dispose(); 523 fType = kDouble; 524 fValue.fDouble = d; 525 } 526 527 // ------------------------------------- 528 // Sets the value to a long value l. 529 530 void 531 Formattable::setLong(int32_t l) 532 { 533 dispose(); 534 fType = kLong; 535 fValue.fInt64 = l; 536 } 537 538 // ------------------------------------- 539 // Sets the value to an int64 value ll. 540 541 void 542 Formattable::setInt64(int64_t ll) 543 { 544 dispose(); 545 fType = kInt64; 546 fValue.fInt64 = ll; 547 } 548 549 // ------------------------------------- 550 // Sets the value to a Date instance d. 551 552 void 553 Formattable::setDate(UDate d) 554 { 555 dispose(); 556 fType = kDate; 557 fValue.fDate = d; 558 } 559 560 // ------------------------------------- 561 // Sets the value to a string value stringToCopy. 562 563 void 564 Formattable::setString(const UnicodeString& stringToCopy) 565 { 566 dispose(); 567 fType = kString; 568 fValue.fString = new UnicodeString(stringToCopy); 569 } 570 571 // ------------------------------------- 572 // Sets the value to an array of Formattable objects. 573 574 void 575 Formattable::setArray(const Formattable* array, int32_t count) 576 { 577 dispose(); 578 fType = kArray; 579 fValue.fArrayAndCount.fArray = createArrayCopy(array, count); 580 fValue.fArrayAndCount.fCount = count; 581 } 582 583 // ------------------------------------- 584 // Adopts the stringToAdopt value. 585 586 void 587 Formattable::adoptString(UnicodeString* stringToAdopt) 588 { 589 dispose(); 590 fType = kString; 591 fValue.fString = stringToAdopt; 592 } 593 594 // ------------------------------------- 595 // Adopts the array value and its count. 596 597 void 598 Formattable::adoptArray(Formattable* array, int32_t count) 599 { 600 dispose(); 601 fType = kArray; 602 fValue.fArrayAndCount.fArray = array; 603 fValue.fArrayAndCount.fCount = count; 604 } 605 606 void 607 Formattable::adoptObject(UObject* objectToAdopt) { 608 dispose(); 609 fType = kObject; 610 fValue.fObject = objectToAdopt; 611 } 612 613 // ------------------------------------- 614 UnicodeString& 615 Formattable::getString(UnicodeString& result, UErrorCode& status) const 616 { 617 if (fType != kString) { 618 setError(status, U_INVALID_FORMAT_ERROR); 619 result.setToBogus(); 620 } else { 621 if (fValue.fString == NULL) { 622 setError(status, U_MEMORY_ALLOCATION_ERROR); 623 } else { 624 result = *fValue.fString; 625 } 626 } 627 return result; 628 } 629 630 // ------------------------------------- 631 const UnicodeString& 632 Formattable::getString(UErrorCode& status) const 633 { 634 if (fType != kString) { 635 setError(status, U_INVALID_FORMAT_ERROR); 636 return *getBogus(); 637 } 638 if (fValue.fString == NULL) { 639 setError(status, U_MEMORY_ALLOCATION_ERROR); 640 return *getBogus(); 641 } 642 return *fValue.fString; 643 } 644 645 // ------------------------------------- 646 UnicodeString& 647 Formattable::getString(UErrorCode& status) 648 { 649 if (fType != kString) { 650 setError(status, U_INVALID_FORMAT_ERROR); 651 return *getBogus(); 652 } 653 if (fValue.fString == NULL) { 654 setError(status, U_MEMORY_ALLOCATION_ERROR); 655 return *getBogus(); 656 } 657 return *fValue.fString; 658 } 659 660 // ------------------------------------- 661 const Formattable* 662 Formattable::getArray(int32_t& count, UErrorCode& status) const 663 { 664 if (fType != kArray) { 665 setError(status, U_INVALID_FORMAT_ERROR); 666 count = 0; 667 return NULL; 668 } 669 count = fValue.fArrayAndCount.fCount; 670 return fValue.fArrayAndCount.fArray; 671 } 672 673 // ------------------------------------- 674 // Gets the bogus string, ensures mondo bogosity. 675 676 UnicodeString* 677 Formattable::getBogus() const 678 { 679 return (UnicodeString*)&fBogus; /* cast away const :-( */ 680 } 681 682 683 // -------------------------------------- 684 StringPiece Formattable::getDecimalNumber(UErrorCode &status) { 685 if (U_FAILURE(status)) { 686 return ""; 687 } 688 if (fDecimalStr != NULL) { 689 return fDecimalStr->toStringPiece(); 690 } 691 692 if (fDecimalNum == NULL) { 693 // No decimal number for the formattable yet. Which means the value was 694 // set directly by the user as an int, int64 or double. If the value came 695 // from parsing, or from the user setting a decimal number, fDecimalNum 696 // would already be set. 697 // 698 fDecimalNum = new DigitList; 699 if (fDecimalNum == NULL) { 700 status = U_MEMORY_ALLOCATION_ERROR; 701 return ""; 702 } 703 704 switch (fType) { 705 case kDouble: 706 fDecimalNum->set(this->getDouble()); 707 break; 708 case kLong: 709 fDecimalNum->set(this->getLong()); 710 break; 711 case kInt64: 712 fDecimalNum->set(this->getInt64()); 713 break; 714 default: 715 // The formattable's value is not a numeric type. 716 status = U_INVALID_STATE_ERROR; 717 return ""; 718 } 719 } 720 721 fDecimalStr = new CharString; 722 if (fDecimalStr == NULL) { 723 status = U_MEMORY_ALLOCATION_ERROR; 724 return ""; 725 } 726 fDecimalNum->getDecimal(*fDecimalStr, status); 727 728 return fDecimalStr->toStringPiece(); 729 } 730 731 732 733 // --------------------------------------- 734 void 735 Formattable::adoptDigitList(DigitList *dl) { 736 dispose(); 737 738 fDecimalNum = dl; 739 740 // Set the value into the Union of simple type values. 741 // Cannot use the set() functions because they would delete the fDecimalNum value, 742 743 if (fDecimalNum->fitsIntoLong(FALSE)) { 744 fType = kLong; 745 fValue.fInt64 = fDecimalNum->getLong(); 746 } else if (fDecimalNum->fitsIntoInt64(FALSE)) { 747 fType = kInt64; 748 fValue.fInt64 = fDecimalNum->getInt64(); 749 } else { 750 fType = kDouble; 751 fValue.fDouble = fDecimalNum->getDouble(); 752 } 753 } 754 755 756 // --------------------------------------- 757 void 758 Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) { 759 if (U_FAILURE(status)) { 760 return; 761 } 762 dispose(); 763 764 // Copy the input string and nul-terminate it. 765 // The decNumber library requires nul-terminated input. StringPiece input 766 // is not guaranteed nul-terminated. Too bad. 767 // CharString automatically adds the nul. 768 DigitList *dnum = new DigitList(); 769 if (dnum == NULL) { 770 status = U_MEMORY_ALLOCATION_ERROR; 771 return; 772 } 773 dnum->set(CharString(numberString, status).toStringPiece(), status); 774 if (U_FAILURE(status)) { 775 delete dnum; 776 return; // String didn't contain a decimal number. 777 } 778 adoptDigitList(dnum); 779 780 // Note that we do not hang on to the caller's input string. 781 // If we are asked for the string, we will regenerate one from fDecimalNum. 782 } 783 784 #if 0 785 //---------------------------------------------------- 786 // console I/O 787 //---------------------------------------------------- 788 #ifdef _DEBUG 789 790 #if U_IOSTREAM_SOURCE >= 199711 791 #include <iostream> 792 using namespace std; 793 #elif U_IOSTREAM_SOURCE >= 198506 794 #include <iostream.h> 795 #endif 796 797 #include "unicode/datefmt.h" 798 #include "unistrm.h" 799 800 class FormattableStreamer /* not : public UObject because all methods are static */ { 801 public: 802 static void streamOut(ostream& stream, const Formattable& obj); 803 804 private: 805 FormattableStreamer() {} // private - forbid instantiation 806 }; 807 808 // This is for debugging purposes only. This will send a displayable 809 // form of the Formattable object to the output stream. 810 811 void 812 FormattableStreamer::streamOut(ostream& stream, const Formattable& obj) 813 { 814 static DateFormat *defDateFormat = 0; 815 816 UnicodeString buffer; 817 switch(obj.getType()) { 818 case Formattable::kDate : 819 // Creates a DateFormat instance for formatting the 820 // Date instance. 821 if (defDateFormat == 0) { 822 defDateFormat = DateFormat::createInstance(); 823 } 824 defDateFormat->format(obj.getDate(), buffer); 825 stream << buffer; 826 break; 827 case Formattable::kDouble : 828 // Output the double as is. 829 stream << obj.getDouble() << 'D'; 830 break; 831 case Formattable::kLong : 832 // Output the double as is. 833 stream << obj.getLong() << 'L'; 834 break; 835 case Formattable::kString: 836 // Output the double as is. Please see UnicodeString console 837 // I/O routine for more details. 838 stream << '"' << obj.getString(buffer) << '"'; 839 break; 840 case Formattable::kArray: 841 int32_t i, count; 842 const Formattable* array; 843 array = obj.getArray(count); 844 stream << '['; 845 // Recursively calling the console I/O routine for each element in the array. 846 for (i=0; i<count; ++i) { 847 FormattableStreamer::streamOut(stream, array[i]); 848 stream << ( (i==(count-1)) ? "" : ", " ); 849 } 850 stream << ']'; 851 break; 852 default: 853 // Not a recognizable Formattable object. 854 stream << "INVALID_Formattable"; 855 } 856 stream.flush(); 857 } 858 #endif 859 860 #endif 861 862 U_NAMESPACE_END 863 864 #endif /* #if !UCONFIG_NO_FORMATTING */ 865 866 //eof 867