1 /* 2 * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de. 4 * Copyright 2012, John Scipione, jscipione@gmail.com 5 * All rights reserved. Distributed under the terms of the OpenBeOS License. 6 */ 7 8 9 #include <AutoDeleter.h> 10 #include <Autolock.h> 11 #include <CalendarView.h> 12 #include <Catalog.h> 13 #include <FormattingConventionsPrivate.h> 14 #include <LanguagePrivate.h> 15 #include <Locale.h> 16 #include <LocaleRoster.h> 17 #include <MutableLocaleRoster.h> 18 #include <TimeZone.h> 19 20 #include <ICUWrapper.h> 21 22 #include <unicode/datefmt.h> 23 #include <unicode/dcfmtsym.h> 24 #include <unicode/decimfmt.h> 25 #include <unicode/dtfmtsym.h> 26 #include <unicode/numfmt.h> 27 #include <unicode/smpdtfmt.h> 28 #include <unicode/ustring.h> 29 30 #include <vector> 31 32 33 using BPrivate::ObjectDeleter; 34 35 36 BLocale::BLocale(const BLanguage* language, 37 const BFormattingConventions* conventions) 38 { 39 if (conventions != NULL) 40 fConventions = *conventions; 41 else 42 BLocale::Default()->GetFormattingConventions(&fConventions); 43 44 if (language != NULL) 45 fLanguage = *language; 46 else 47 BLocale::Default()->GetLanguage(&fLanguage); 48 } 49 50 51 BLocale::BLocale(const BLocale& other) 52 : 53 fConventions(other.fConventions), 54 fLanguage(other.fLanguage) 55 { 56 } 57 58 59 /*static*/ const BLocale* 60 BLocale::Default() 61 { 62 return &BPrivate::RosterData::Default()->fDefaultLocale; 63 } 64 65 66 BLocale& 67 BLocale::operator=(const BLocale& other) 68 { 69 if (this == &other) 70 return *this; 71 72 BAutolock lock(fLock); 73 BAutolock otherLock(other.fLock); 74 if (!lock.IsLocked() || !otherLock.IsLocked()) 75 return *this; 76 77 fConventions = other.fConventions; 78 fLanguage = other.fLanguage; 79 80 return *this; 81 } 82 83 84 BLocale::~BLocale() 85 { 86 } 87 88 89 status_t 90 BLocale::GetCollator(BCollator* collator) const 91 { 92 if (!collator) 93 return B_BAD_VALUE; 94 95 BAutolock lock(fLock); 96 if (!lock.IsLocked()) 97 return B_ERROR; 98 99 *collator = fCollator; 100 101 return B_OK; 102 } 103 104 105 status_t 106 BLocale::GetLanguage(BLanguage* language) const 107 { 108 if (!language) 109 return B_BAD_VALUE; 110 111 BAutolock lock(fLock); 112 if (!lock.IsLocked()) 113 return B_ERROR; 114 115 *language = fLanguage; 116 117 return B_OK; 118 } 119 120 121 status_t 122 BLocale::GetFormattingConventions(BFormattingConventions* conventions) const 123 { 124 if (!conventions) 125 return B_BAD_VALUE; 126 127 BAutolock lock(fLock); 128 if (!lock.IsLocked()) 129 return B_ERROR; 130 131 *conventions = fConventions; 132 133 return B_OK; 134 } 135 136 137 const char * 138 BLocale::GetString(uint32 id) const 139 { 140 // Note: this code assumes a certain order of the string bases 141 142 BAutolock lock(fLock); 143 if (!lock.IsLocked()) 144 return ""; 145 146 if (id >= B_OTHER_STRINGS_BASE) { 147 if (id == B_CODESET) 148 return "UTF-8"; 149 150 return ""; 151 } 152 return fLanguage.GetString(id); 153 } 154 155 156 void 157 BLocale::SetFormattingConventions(const BFormattingConventions& conventions) 158 { 159 BAutolock lock(fLock); 160 if (!lock.IsLocked()) 161 return; 162 163 fConventions = conventions; 164 } 165 166 167 void 168 BLocale::SetCollator(const BCollator& newCollator) 169 { 170 BAutolock lock(fLock); 171 if (!lock.IsLocked()) 172 return; 173 174 fCollator = newCollator; 175 } 176 177 178 void 179 BLocale::SetLanguage(const BLanguage& newLanguage) 180 { 181 BAutolock lock(fLock); 182 if (!lock.IsLocked()) 183 return; 184 185 fLanguage = newLanguage; 186 } 187 188 189 // #pragma mark - Date 190 191 192 ssize_t 193 BLocale::FormatDate(char* string, size_t maxSize, time_t time, 194 BDateFormatStyle style) const 195 { 196 BAutolock lock(fLock); 197 if (!lock.IsLocked()) 198 return B_ERROR; 199 200 BString format; 201 fConventions.GetDateFormat(style, format); 202 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 203 if (dateFormatter.Get() == NULL) 204 return B_NO_MEMORY; 205 206 UnicodeString icuString; 207 dateFormatter->format((UDate)time * 1000, icuString); 208 209 CheckedArrayByteSink stringConverter(string, maxSize); 210 icuString.toUTF8(stringConverter); 211 212 if (stringConverter.Overflowed()) 213 return B_BAD_VALUE; 214 215 return stringConverter.NumberOfBytesWritten(); 216 } 217 218 219 status_t 220 BLocale::FormatDate(BString *string, time_t time, BDateFormatStyle style, 221 const BTimeZone* timeZone) const 222 { 223 BAutolock lock(fLock); 224 if (!lock.IsLocked()) 225 return B_ERROR; 226 227 BString format; 228 fConventions.GetDateFormat(style, format); 229 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 230 if (dateFormatter.Get() == NULL) 231 return B_NO_MEMORY; 232 233 if (timeZone != NULL) { 234 ObjectDeleter<TimeZone> icuTimeZone( 235 TimeZone::createTimeZone(timeZone->ID().String())); 236 if (icuTimeZone.Get() == NULL) 237 return B_NO_MEMORY; 238 dateFormatter->setTimeZone(*icuTimeZone.Get()); 239 } 240 241 UnicodeString icuString; 242 dateFormatter->format((UDate)time * 1000, icuString); 243 244 string->Truncate(0); 245 BStringByteSink stringConverter(string); 246 icuString.toUTF8(stringConverter); 247 248 return B_OK; 249 } 250 251 252 status_t 253 BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount, 254 time_t time, BDateFormatStyle style) const 255 { 256 BAutolock lock(fLock); 257 if (!lock.IsLocked()) 258 return B_ERROR; 259 260 BString format; 261 fConventions.GetDateFormat(style, format); 262 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 263 if (dateFormatter.Get() == NULL) 264 return B_NO_MEMORY; 265 266 fieldPositions = NULL; 267 UErrorCode error = U_ZERO_ERROR; 268 icu::FieldPositionIterator positionIterator; 269 UnicodeString icuString; 270 dateFormatter->format((UDate)time * 1000, icuString, &positionIterator, 271 error); 272 273 if (error != U_ZERO_ERROR) 274 return B_BAD_VALUE; 275 276 icu::FieldPosition field; 277 std::vector<int> fieldPosStorage; 278 fieldCount = 0; 279 while (positionIterator.next(field)) { 280 fieldPosStorage.push_back(field.getBeginIndex()); 281 fieldPosStorage.push_back(field.getEndIndex()); 282 fieldCount += 2; 283 } 284 285 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 286 287 for (int i = 0 ; i < fieldCount ; i++ ) 288 fieldPositions[i] = fieldPosStorage[i]; 289 290 string->Truncate(0); 291 BStringByteSink stringConverter(string); 292 293 icuString.toUTF8(stringConverter); 294 295 return B_OK; 296 } 297 298 299 status_t 300 BLocale::GetDateFields(BDateElement*& fields, int& fieldCount, 301 BDateFormatStyle style) const 302 { 303 BAutolock lock(fLock); 304 if (!lock.IsLocked()) 305 return B_ERROR; 306 307 BString format; 308 fConventions.GetDateFormat(style, format); 309 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 310 if (dateFormatter.Get() == NULL) 311 return B_NO_MEMORY; 312 313 fields = NULL; 314 UErrorCode error = U_ZERO_ERROR; 315 icu::FieldPositionIterator positionIterator; 316 UnicodeString icuString; 317 time_t now; 318 dateFormatter->format((UDate)time(&now) * 1000, icuString, 319 &positionIterator, error); 320 321 if (U_FAILURE(error)) 322 return B_BAD_VALUE; 323 324 icu::FieldPosition field; 325 std::vector<int> fieldPosStorage; 326 fieldCount = 0; 327 while (positionIterator.next(field)) { 328 fieldPosStorage.push_back(field.getField()); 329 fieldCount ++; 330 } 331 332 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 333 334 for (int i = 0 ; i < fieldCount ; i++ ) { 335 switch (fieldPosStorage[i]) { 336 case UDAT_YEAR_FIELD: 337 fields[i] = B_DATE_ELEMENT_YEAR; 338 break; 339 case UDAT_MONTH_FIELD: 340 fields[i] = B_DATE_ELEMENT_MONTH; 341 break; 342 case UDAT_DATE_FIELD: 343 fields[i] = B_DATE_ELEMENT_DAY; 344 break; 345 default: 346 fields[i] = B_DATE_ELEMENT_INVALID; 347 break; 348 } 349 } 350 351 return B_OK; 352 } 353 354 355 status_t 356 BLocale::GetStartOfWeek(BWeekday* startOfWeek) const 357 { 358 if (startOfWeek == NULL) 359 return B_BAD_VALUE; 360 361 BAutolock lock(fLock); 362 if (!lock.IsLocked()) 363 return B_ERROR; 364 365 UErrorCode err = U_ZERO_ERROR; 366 ObjectDeleter<Calendar> calendar = Calendar::createInstance( 367 *BFormattingConventions::Private(&fConventions).ICULocale(), err); 368 369 if (U_FAILURE(err)) 370 return B_ERROR; 371 372 UCalendarDaysOfWeek icuWeekStart = calendar->getFirstDayOfWeek(err); 373 if (U_FAILURE(err)) 374 return B_ERROR; 375 376 switch (icuWeekStart) { 377 case UCAL_SUNDAY: 378 *startOfWeek = B_WEEKDAY_SUNDAY; 379 break; 380 case UCAL_MONDAY: 381 *startOfWeek = B_WEEKDAY_MONDAY; 382 break; 383 case UCAL_TUESDAY: 384 *startOfWeek = B_WEEKDAY_TUESDAY; 385 break; 386 case UCAL_WEDNESDAY: 387 *startOfWeek = B_WEEKDAY_WEDNESDAY; 388 break; 389 case UCAL_THURSDAY: 390 *startOfWeek = B_WEEKDAY_THURSDAY; 391 break; 392 case UCAL_FRIDAY: 393 *startOfWeek = B_WEEKDAY_FRIDAY; 394 break; 395 case UCAL_SATURDAY: 396 *startOfWeek = B_WEEKDAY_SATURDAY; 397 break; 398 default: 399 return B_ERROR; 400 } 401 402 return B_OK; 403 } 404 405 406 ssize_t 407 BLocale::FormatDateTime(char* target, size_t maxSize, time_t time, 408 BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle) const 409 { 410 BAutolock lock(fLock); 411 if (!lock.IsLocked()) 412 return B_ERROR; 413 414 BString format; 415 fConventions.GetDateFormat(dateStyle, format); 416 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 417 if (dateFormatter.Get() == NULL) 418 return B_NO_MEMORY; 419 420 fConventions.GetTimeFormat(timeStyle, format); 421 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 422 if (timeFormatter.Get() == NULL) 423 return B_NO_MEMORY; 424 425 UnicodeString icuString; 426 dateFormatter->format((UDate)time * 1000, icuString); 427 428 icuString.append(UnicodeString::fromUTF8(", ")); 429 430 timeFormatter->format((UDate)time * 1000, icuString); 431 432 CheckedArrayByteSink stringConverter(target, maxSize); 433 icuString.toUTF8(stringConverter); 434 435 if (stringConverter.Overflowed()) 436 return B_BAD_VALUE; 437 438 return stringConverter.NumberOfBytesWritten(); 439 } 440 441 442 status_t 443 BLocale::FormatDateTime(BString* target, time_t time, 444 BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle, 445 const BTimeZone* timeZone) const 446 { 447 BAutolock lock(fLock); 448 if (!lock.IsLocked()) 449 return B_ERROR; 450 451 BString format; 452 fConventions.GetDateFormat(dateStyle, format); 453 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 454 if (dateFormatter.Get() == NULL) 455 return B_NO_MEMORY; 456 457 fConventions.GetTimeFormat(timeStyle, format); 458 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 459 if (timeFormatter.Get() == NULL) 460 return B_NO_MEMORY; 461 462 if (timeZone != NULL) { 463 ObjectDeleter<TimeZone> icuTimeZone( 464 TimeZone::createTimeZone(timeZone->ID().String())); 465 if (icuTimeZone.Get() == NULL) 466 return B_NO_MEMORY; 467 timeFormatter->setTimeZone(*icuTimeZone.Get()); 468 } 469 470 UnicodeString icuString; 471 dateFormatter->format((UDate)time * 1000, icuString); 472 icuString.append(UnicodeString::fromUTF8(", ")); 473 timeFormatter->format((UDate)time * 1000, icuString); 474 475 target->Truncate(0); 476 BStringByteSink stringConverter(target); 477 icuString.toUTF8(stringConverter); 478 479 return B_OK; 480 } 481 482 483 // #pragma mark - Time 484 485 486 ssize_t 487 BLocale::FormatTime(char* string, size_t maxSize, time_t time, 488 BTimeFormatStyle style) const 489 { 490 BAutolock lock(fLock); 491 if (!lock.IsLocked()) 492 return B_ERROR; 493 494 BString format; 495 fConventions.GetTimeFormat(style, format); 496 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 497 if (timeFormatter.Get() == NULL) 498 return B_NO_MEMORY; 499 500 UnicodeString icuString; 501 timeFormatter->format((UDate)time * 1000, icuString); 502 503 CheckedArrayByteSink stringConverter(string, maxSize); 504 icuString.toUTF8(stringConverter); 505 506 if (stringConverter.Overflowed()) 507 return B_BAD_VALUE; 508 509 return stringConverter.NumberOfBytesWritten(); 510 } 511 512 513 ssize_t 514 BLocale::FormatTime(char* string, size_t maxSize, time_t time, 515 BString format) const 516 { 517 BAutolock lock(fLock); 518 if (!lock.IsLocked()) 519 return B_ERROR; 520 521 if (format == NULL || format.CountChars() <= 0) 522 return B_BAD_VALUE; 523 524 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 525 if (timeFormatter.Get() == NULL) 526 return B_NO_MEMORY; 527 528 UnicodeString icuString; 529 timeFormatter->format((UDate)time * 1000, icuString); 530 531 CheckedArrayByteSink stringConverter(string, maxSize); 532 icuString.toUTF8(stringConverter); 533 534 if (stringConverter.Overflowed()) 535 return B_BAD_VALUE; 536 537 return stringConverter.NumberOfBytesWritten(); 538 } 539 540 541 status_t 542 BLocale::FormatTime(BString* string, time_t time, BTimeFormatStyle style, 543 const BTimeZone* timeZone) const 544 { 545 BAutolock lock(fLock); 546 if (!lock.IsLocked()) 547 return B_ERROR; 548 549 BString format; 550 fConventions.GetTimeFormat(style, format); 551 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 552 if (timeFormatter.Get() == NULL) 553 return B_NO_MEMORY; 554 555 if (timeZone != NULL) { 556 ObjectDeleter<TimeZone> icuTimeZone( 557 TimeZone::createTimeZone(timeZone->ID().String())); 558 if (icuTimeZone.Get() == NULL) 559 return B_NO_MEMORY; 560 timeFormatter->setTimeZone(*icuTimeZone.Get()); 561 } 562 563 UnicodeString icuString; 564 timeFormatter->format((UDate)time * 1000, icuString); 565 566 string->Truncate(0); 567 BStringByteSink stringConverter(string); 568 icuString.toUTF8(stringConverter); 569 570 return B_OK; 571 } 572 573 574 status_t 575 BLocale::FormatTime(BString* string, time_t time, BString format, 576 const BTimeZone* timeZone) const 577 { 578 BAutolock lock(fLock); 579 if (!lock.IsLocked()) 580 return B_ERROR; 581 582 if (format == NULL || format.CountChars() <= 0) 583 return B_BAD_VALUE; 584 585 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 586 if (timeFormatter.Get() == NULL) 587 return B_NO_MEMORY; 588 589 if (timeZone != NULL) { 590 ObjectDeleter<TimeZone> icuTimeZone( 591 TimeZone::createTimeZone(timeZone->ID().String())); 592 if (icuTimeZone.Get() == NULL) 593 return B_NO_MEMORY; 594 timeFormatter->setTimeZone(*icuTimeZone.Get()); 595 } 596 597 UnicodeString icuString; 598 timeFormatter->format((UDate)time * 1000, icuString); 599 600 string->Truncate(0); 601 BStringByteSink stringConverter(string); 602 icuString.toUTF8(stringConverter); 603 604 return B_OK; 605 } 606 607 608 status_t 609 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount, 610 time_t time, BTimeFormatStyle style) const 611 { 612 BAutolock lock(fLock); 613 if (!lock.IsLocked()) 614 return B_ERROR; 615 616 BString format; 617 fConventions.GetTimeFormat(style, format); 618 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 619 if (timeFormatter.Get() == NULL) 620 return B_NO_MEMORY; 621 622 fieldPositions = NULL; 623 UErrorCode error = U_ZERO_ERROR; 624 icu::FieldPositionIterator positionIterator; 625 UnicodeString icuString; 626 timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 627 error); 628 629 if (error != U_ZERO_ERROR) 630 return B_BAD_VALUE; 631 632 icu::FieldPosition field; 633 std::vector<int> fieldPosStorage; 634 fieldCount = 0; 635 while (positionIterator.next(field)) { 636 fieldPosStorage.push_back(field.getBeginIndex()); 637 fieldPosStorage.push_back(field.getEndIndex()); 638 fieldCount += 2; 639 } 640 641 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 642 643 for (int i = 0 ; i < fieldCount ; i++ ) 644 fieldPositions[i] = fieldPosStorage[i]; 645 646 string->Truncate(0); 647 BStringByteSink stringConverter(string); 648 icuString.toUTF8(stringConverter); 649 650 return B_OK; 651 } 652 653 654 status_t 655 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount, 656 BTimeFormatStyle style) const 657 { 658 BAutolock lock(fLock); 659 if (!lock.IsLocked()) 660 return B_ERROR; 661 662 BString format; 663 fConventions.GetTimeFormat(style, format); 664 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 665 if (timeFormatter.Get() == NULL) 666 return B_NO_MEMORY; 667 668 fields = NULL; 669 UErrorCode error = U_ZERO_ERROR; 670 icu::FieldPositionIterator positionIterator; 671 UnicodeString icuString; 672 time_t now; 673 timeFormatter->format((UDate)time(&now) * 1000, icuString, 674 &positionIterator, error); 675 676 if (error != U_ZERO_ERROR) 677 return B_BAD_VALUE; 678 679 icu::FieldPosition field; 680 std::vector<int> fieldPosStorage; 681 fieldCount = 0; 682 while (positionIterator.next(field)) { 683 fieldPosStorage.push_back(field.getField()); 684 fieldCount ++; 685 } 686 687 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 688 689 for (int i = 0 ; i < fieldCount ; i++ ) { 690 switch (fieldPosStorage[i]) { 691 case UDAT_HOUR_OF_DAY1_FIELD: 692 case UDAT_HOUR_OF_DAY0_FIELD: 693 case UDAT_HOUR1_FIELD: 694 case UDAT_HOUR0_FIELD: 695 fields[i] = B_DATE_ELEMENT_HOUR; 696 break; 697 case UDAT_MINUTE_FIELD: 698 fields[i] = B_DATE_ELEMENT_MINUTE; 699 break; 700 case UDAT_SECOND_FIELD: 701 fields[i] = B_DATE_ELEMENT_SECOND; 702 break; 703 case UDAT_AM_PM_FIELD: 704 fields[i] = B_DATE_ELEMENT_AM_PM; 705 break; 706 default: 707 fields[i] = B_DATE_ELEMENT_INVALID; 708 break; 709 } 710 } 711 712 return B_OK; 713 } 714 715 716 // #pragma mark - Numbers 717 718 719 ssize_t 720 BLocale::FormatNumber(char* string, size_t maxSize, double value) const 721 { 722 BString fullString; 723 status_t status = FormatNumber(&fullString, value); 724 if (status != B_OK) 725 return status; 726 727 return strlcpy(string, fullString.String(), maxSize); 728 } 729 730 731 status_t 732 BLocale::FormatNumber(BString* string, double value) const 733 { 734 BAutolock lock(fLock); 735 if (!lock.IsLocked()) 736 return B_ERROR; 737 738 UErrorCode err = U_ZERO_ERROR; 739 ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance( 740 *BFormattingConventions::Private(&fConventions).ICULocale(), 741 UNUM_DECIMAL, err)); 742 743 if (numberFormatter.Get() == NULL) 744 return B_NO_MEMORY; 745 if (U_FAILURE(err)) 746 return B_BAD_VALUE; 747 748 UnicodeString icuString; 749 numberFormatter->format(value, icuString); 750 751 string->Truncate(0); 752 BStringByteSink stringConverter(string); 753 icuString.toUTF8(stringConverter); 754 755 return B_OK; 756 } 757 758 759 ssize_t 760 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const 761 { 762 BString fullString; 763 status_t status = FormatNumber(&fullString, value); 764 if (status != B_OK) 765 return status; 766 767 return strlcpy(string, fullString.String(), maxSize); 768 } 769 770 771 status_t 772 BLocale::FormatNumber(BString* string, int32 value) const 773 { 774 BAutolock lock(fLock); 775 if (!lock.IsLocked()) 776 return B_ERROR; 777 778 UErrorCode err = U_ZERO_ERROR; 779 ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance( 780 *BFormattingConventions::Private(&fConventions).ICULocale(), 781 UNUM_DECIMAL, err)); 782 783 if (numberFormatter.Get() == NULL) 784 return B_NO_MEMORY; 785 if (U_FAILURE(err)) 786 return B_BAD_VALUE; 787 788 UnicodeString icuString; 789 numberFormatter->format((int32_t)value, icuString); 790 791 string->Truncate(0); 792 BStringByteSink stringConverter(string); 793 icuString.toUTF8(stringConverter); 794 795 return B_OK; 796 } 797 798 799 ssize_t 800 BLocale::FormatMonetary(char* string, size_t maxSize, double value) const 801 { 802 BString fullString; 803 status_t status = FormatMonetary(&fullString, value); 804 if (status != B_OK) 805 return status; 806 807 return strlcpy(string, fullString.String(), maxSize); 808 } 809 810 811 status_t 812 BLocale::FormatMonetary(BString* string, double value) const 813 { 814 if (string == NULL) 815 return B_BAD_VALUE; 816 817 BAutolock lock(fLock); 818 if (!lock.IsLocked()) 819 return B_ERROR; 820 821 UErrorCode err = U_ZERO_ERROR; 822 ObjectDeleter<NumberFormat> numberFormatter( 823 NumberFormat::createCurrencyInstance( 824 *BFormattingConventions::Private(&fConventions).ICULocale(), 825 err)); 826 827 if (numberFormatter.Get() == NULL) 828 return B_NO_MEMORY; 829 if (U_FAILURE(err)) 830 return B_BAD_VALUE; 831 832 UnicodeString icuString; 833 numberFormatter->format(value, icuString); 834 835 string->Truncate(0); 836 BStringByteSink stringConverter(string); 837 icuString.toUTF8(stringConverter); 838 839 return B_OK; 840 } 841 842 843 DateFormat* 844 BLocale::_CreateDateFormatter(const BString& format) const 845 { 846 Locale* icuLocale 847 = fConventions.UseStringsFromPreferredLanguage() 848 ? BLanguage::Private(&fLanguage).ICULocale() 849 : BFormattingConventions::Private(&fConventions).ICULocale(); 850 851 DateFormat* dateFormatter 852 = DateFormat::createDateInstance(DateFormat::kShort, *icuLocale); 853 if (dateFormatter == NULL) 854 return NULL; 855 856 SimpleDateFormat* dateFormatterImpl 857 = static_cast<SimpleDateFormat*>(dateFormatter); 858 859 UnicodeString pattern(format.String()); 860 dateFormatterImpl->applyPattern(pattern); 861 862 return dateFormatter; 863 } 864 865 866 DateFormat* 867 BLocale::_CreateTimeFormatter(const BString& format) const 868 { 869 Locale* icuLocale 870 = fConventions.UseStringsFromPreferredLanguage() 871 ? BLanguage::Private(&fLanguage).ICULocale() 872 : BFormattingConventions::Private(&fConventions).ICULocale(); 873 874 DateFormat* timeFormatter 875 = DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 876 if (timeFormatter == NULL) 877 return NULL; 878 879 SimpleDateFormat* timeFormatterImpl 880 = static_cast<SimpleDateFormat*>(timeFormatter); 881 882 UnicodeString pattern(format.String()); 883 timeFormatterImpl->applyPattern(pattern); 884 885 return timeFormatter; 886 } 887