intl/icu/source/i18n/tmutfmt.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * Copyright (C) 2008-2013, Google, International Business Machines Corporation
michael@0 4 * and others. All Rights Reserved.
michael@0 5 *******************************************************************************
michael@0 6 */
michael@0 7
michael@0 8 #include "utypeinfo.h" // for 'typeid' to work
michael@0 9
michael@0 10 #include "unicode/tmutfmt.h"
michael@0 11
michael@0 12 #if !UCONFIG_NO_FORMATTING
michael@0 13
michael@0 14 #include "uvector.h"
michael@0 15 #include "charstr.h"
michael@0 16 #include "cmemory.h"
michael@0 17 #include "cstring.h"
michael@0 18 #include "hash.h"
michael@0 19 #include "uresimp.h"
michael@0 20 #include "unicode/msgfmt.h"
michael@0 21 #include "uassert.h"
michael@0 22
michael@0 23 #define LEFT_CURLY_BRACKET ((UChar)0x007B)
michael@0 24 #define RIGHT_CURLY_BRACKET ((UChar)0x007D)
michael@0 25 #define SPACE ((UChar)0x0020)
michael@0 26 #define DIGIT_ZERO ((UChar)0x0030)
michael@0 27 #define LOW_S ((UChar)0x0073)
michael@0 28 #define LOW_M ((UChar)0x006D)
michael@0 29 #define LOW_I ((UChar)0x0069)
michael@0 30 #define LOW_N ((UChar)0x006E)
michael@0 31 #define LOW_H ((UChar)0x0068)
michael@0 32 #define LOW_W ((UChar)0x0077)
michael@0 33 #define LOW_D ((UChar)0x0064)
michael@0 34 #define LOW_Y ((UChar)0x0079)
michael@0 35 #define LOW_Z ((UChar)0x007A)
michael@0 36 #define LOW_E ((UChar)0x0065)
michael@0 37 #define LOW_R ((UChar)0x0072)
michael@0 38 #define LOW_O ((UChar)0x006F)
michael@0 39 #define LOW_N ((UChar)0x006E)
michael@0 40 #define LOW_T ((UChar)0x0074)
michael@0 41
michael@0 42
michael@0 43 //TODO: define in compile time
michael@0 44 //#define TMUTFMT_DEBUG 1
michael@0 45
michael@0 46 #ifdef TMUTFMT_DEBUG
michael@0 47 #include <iostream>
michael@0 48 #endif
michael@0 49
michael@0 50 U_NAMESPACE_BEGIN
michael@0 51
michael@0 52
michael@0 53
michael@0 54 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
michael@0 55
michael@0 56 static const char gUnitsTag[] = "units";
michael@0 57 static const char gShortUnitsTag[] = "unitsShort";
michael@0 58 static const char gTimeUnitYear[] = "year";
michael@0 59 static const char gTimeUnitMonth[] = "month";
michael@0 60 static const char gTimeUnitDay[] = "day";
michael@0 61 static const char gTimeUnitWeek[] = "week";
michael@0 62 static const char gTimeUnitHour[] = "hour";
michael@0 63 static const char gTimeUnitMinute[] = "minute";
michael@0 64 static const char gTimeUnitSecond[] = "second";
michael@0 65 static const char gPluralCountOther[] = "other";
michael@0 66
michael@0 67 static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
michael@0 68 static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
michael@0 69 static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
michael@0 70 static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
michael@0 71 static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
michael@0 72 static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
michael@0 73 static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
michael@0 74
michael@0 75 static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
michael@0 76 static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
michael@0 77 static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
michael@0 78
michael@0 79 TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
michael@0 80 : fNumberFormat(NULL),
michael@0 81 fPluralRules(NULL) {
michael@0 82 create(Locale::getDefault(), UTMUTFMT_FULL_STYLE, status);
michael@0 83 }
michael@0 84
michael@0 85
michael@0 86 TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
michael@0 87 : fNumberFormat(NULL),
michael@0 88 fPluralRules(NULL) {
michael@0 89 create(locale, UTMUTFMT_FULL_STYLE, status);
michael@0 90 }
michael@0 91
michael@0 92
michael@0 93 TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status)
michael@0 94 : fNumberFormat(NULL),
michael@0 95 fPluralRules(NULL) {
michael@0 96 create(locale, style, status);
michael@0 97 }
michael@0 98
michael@0 99
michael@0 100 TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
michael@0 101 : MeasureFormat(other),
michael@0 102 fNumberFormat(NULL),
michael@0 103 fPluralRules(NULL),
michael@0 104 fStyle(UTMUTFMT_FULL_STYLE)
michael@0 105 {
michael@0 106 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 107 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 108 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 109 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 110 }
michael@0 111 *this = other;
michael@0 112 }
michael@0 113
michael@0 114
michael@0 115 TimeUnitFormat::~TimeUnitFormat() {
michael@0 116 delete fNumberFormat;
michael@0 117 fNumberFormat = NULL;
michael@0 118 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 119 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 120 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 121 deleteHash(fTimeUnitToCountToPatterns[i]);
michael@0 122 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 123 }
michael@0 124 delete fPluralRules;
michael@0 125 fPluralRules = NULL;
michael@0 126 }
michael@0 127
michael@0 128
michael@0 129 Format*
michael@0 130 TimeUnitFormat::clone(void) const {
michael@0 131 return new TimeUnitFormat(*this);
michael@0 132 }
michael@0 133
michael@0 134
michael@0 135 TimeUnitFormat&
michael@0 136 TimeUnitFormat::operator=(const TimeUnitFormat& other) {
michael@0 137 if (this == &other) {
michael@0 138 return *this;
michael@0 139 }
michael@0 140 delete fNumberFormat;
michael@0 141 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 142 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 143 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 144 deleteHash(fTimeUnitToCountToPatterns[i]);
michael@0 145 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 146 }
michael@0 147 delete fPluralRules;
michael@0 148 if (other.fNumberFormat) {
michael@0 149 fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
michael@0 150 } else {
michael@0 151 fNumberFormat = NULL;
michael@0 152 }
michael@0 153 fLocale = other.fLocale;
michael@0 154 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 155 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 156 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 157 UErrorCode status = U_ZERO_ERROR;
michael@0 158 fTimeUnitToCountToPatterns[i] = initHash(status);
michael@0 159 if (U_SUCCESS(status)) {
michael@0 160 copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
michael@0 161 } else {
michael@0 162 delete fTimeUnitToCountToPatterns[i];
michael@0 163 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 164 }
michael@0 165 }
michael@0 166 if (other.fPluralRules) {
michael@0 167 fPluralRules = (PluralRules*)other.fPluralRules->clone();
michael@0 168 } else {
michael@0 169 fPluralRules = NULL;
michael@0 170 }
michael@0 171 fStyle = other.fStyle;
michael@0 172 return *this;
michael@0 173 }
michael@0 174
michael@0 175
michael@0 176 UBool
michael@0 177 TimeUnitFormat::operator==(const Format& other) const {
michael@0 178 if (typeid(*this) == typeid(other)) {
michael@0 179 TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
michael@0 180 UBool ret = ( ((fNumberFormat && fmt->fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)
michael@0 181 || fNumberFormat == fmt->fNumberFormat )
michael@0 182 && fLocale == fmt->fLocale
michael@0 183 && ((fPluralRules && fmt->fPluralRules && *fPluralRules == *fmt->fPluralRules)
michael@0 184 || fPluralRules == fmt->fPluralRules)
michael@0 185 && fStyle == fmt->fStyle);
michael@0 186 if (ret) {
michael@0 187 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 188 i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
michael@0 189 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 190 ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
michael@0 191 }
michael@0 192 }
michael@0 193 return ret;
michael@0 194 }
michael@0 195 return false;
michael@0 196 }
michael@0 197
michael@0 198
michael@0 199 UnicodeString&
michael@0 200 TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
michael@0 201 FieldPosition& pos, UErrorCode& status) const {
michael@0 202 if (U_FAILURE(status)) {
michael@0 203 return toAppendTo;
michael@0 204 }
michael@0 205 if (obj.getType() == Formattable::kObject) {
michael@0 206 const UObject* formatObj = obj.getObject();
michael@0 207 const TimeUnitAmount* amount = dynamic_cast<const TimeUnitAmount*>(formatObj);
michael@0 208 if (amount != NULL){
michael@0 209 Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
michael@0 210 double number;
michael@0 211 const Formattable& amtNumber = amount->getNumber();
michael@0 212 if (amtNumber.getType() == Formattable::kDouble) {
michael@0 213 number = amtNumber.getDouble();
michael@0 214 } else if (amtNumber.getType() == Formattable::kLong) {
michael@0 215 number = amtNumber.getLong();
michael@0 216 } else {
michael@0 217 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 218 return toAppendTo;
michael@0 219 }
michael@0 220 UnicodeString count = fPluralRules->select(number);
michael@0 221 #ifdef TMUTFMT_DEBUG
michael@0 222 char result[1000];
michael@0 223 count.extract(0, count.length(), result, "UTF-8");
michael@0 224 std::cout << "number: " << number << "; format plural count: " << result << "\n";
michael@0 225 #endif
michael@0 226 MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
michael@0 227 Formattable formattable[1];
michael@0 228 formattable[0].setDouble(number);
michael@0 229 return pattern->format(formattable, 1, toAppendTo, pos, status);
michael@0 230 }
michael@0 231 }
michael@0 232 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 233 return toAppendTo;
michael@0 234 }
michael@0 235
michael@0 236
michael@0 237 void
michael@0 238 TimeUnitFormat::parseObject(const UnicodeString& source,
michael@0 239 Formattable& result,
michael@0 240 ParsePosition& pos) const {
michael@0 241 double resultNumber = -1;
michael@0 242 UBool withNumberFormat = false;
michael@0 243 TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 244 int32_t oldPos = pos.getIndex();
michael@0 245 int32_t newPos = -1;
michael@0 246 int32_t longestParseDistance = 0;
michael@0 247 UnicodeString* countOfLongestMatch = NULL;
michael@0 248 #ifdef TMUTFMT_DEBUG
michael@0 249 char res[1000];
michael@0 250 source.extract(0, source.length(), res, "UTF-8");
michael@0 251 std::cout << "parse source: " << res << "\n";
michael@0 252 #endif
michael@0 253 // parse by iterating through all available patterns
michael@0 254 // and looking for the longest match.
michael@0 255 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 256 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 257 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 258 Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
michael@0 259 int32_t elemPos = -1;
michael@0 260 const UHashElement* elem = NULL;
michael@0 261 while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
michael@0 262 const UHashTok keyTok = elem->key;
michael@0 263 UnicodeString* count = (UnicodeString*)keyTok.pointer;
michael@0 264 #ifdef TMUTFMT_DEBUG
michael@0 265 count->extract(0, count->length(), res, "UTF-8");
michael@0 266 std::cout << "parse plural count: " << res << "\n";
michael@0 267 #endif
michael@0 268 const UHashTok valueTok = elem->value;
michael@0 269 // the value is a pair of MessageFormat*
michael@0 270 MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
michael@0 271 for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT;
michael@0 272 style = (UTimeUnitFormatStyle)(style + 1)) {
michael@0 273 MessageFormat* pattern = patterns[style];
michael@0 274 pos.setErrorIndex(-1);
michael@0 275 pos.setIndex(oldPos);
michael@0 276 // see if we can parse
michael@0 277 Formattable parsed;
michael@0 278 pattern->parseObject(source, parsed, pos);
michael@0 279 if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
michael@0 280 continue;
michael@0 281 }
michael@0 282 #ifdef TMUTFMT_DEBUG
michael@0 283 std::cout << "parsed.getType: " << parsed.getType() << "\n";
michael@0 284 #endif
michael@0 285 double tmpNumber = 0;
michael@0 286 if (pattern->getArgTypeCount() != 0) {
michael@0 287 // pattern with Number as beginning, such as "{0} d".
michael@0 288 // check to make sure that the timeUnit is consistent
michael@0 289 Formattable& temp = parsed[0];
michael@0 290 if (temp.getType() == Formattable::kDouble) {
michael@0 291 tmpNumber = temp.getDouble();
michael@0 292 } else if (temp.getType() == Formattable::kLong) {
michael@0 293 tmpNumber = temp.getLong();
michael@0 294 } else {
michael@0 295 continue;
michael@0 296 }
michael@0 297 UnicodeString select = fPluralRules->select(tmpNumber);
michael@0 298 #ifdef TMUTFMT_DEBUG
michael@0 299 select.extract(0, select.length(), res, "UTF-8");
michael@0 300 std::cout << "parse plural select count: " << res << "\n";
michael@0 301 #endif
michael@0 302 if (*count != select) {
michael@0 303 continue;
michael@0 304 }
michael@0 305 }
michael@0 306 int32_t parseDistance = pos.getIndex() - oldPos;
michael@0 307 if (parseDistance > longestParseDistance) {
michael@0 308 if (pattern->getArgTypeCount() != 0) {
michael@0 309 resultNumber = tmpNumber;
michael@0 310 withNumberFormat = true;
michael@0 311 } else {
michael@0 312 withNumberFormat = false;
michael@0 313 }
michael@0 314 resultTimeUnit = i;
michael@0 315 newPos = pos.getIndex();
michael@0 316 longestParseDistance = parseDistance;
michael@0 317 countOfLongestMatch = count;
michael@0 318 }
michael@0 319 }
michael@0 320 }
michael@0 321 }
michael@0 322 /* After find the longest match, parse the number.
michael@0 323 * Result number could be null for the pattern without number pattern.
michael@0 324 * such as unit pattern in Arabic.
michael@0 325 * When result number is null, use plural rule to set the number.
michael@0 326 */
michael@0 327 if (withNumberFormat == false && longestParseDistance != 0) {
michael@0 328 // set the number using plurrual count
michael@0 329 if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) {
michael@0 330 resultNumber = 0;
michael@0 331 } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) {
michael@0 332 resultNumber = 1;
michael@0 333 } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) {
michael@0 334 resultNumber = 2;
michael@0 335 } else {
michael@0 336 // should not happen.
michael@0 337 // TODO: how to handle?
michael@0 338 resultNumber = 3;
michael@0 339 }
michael@0 340 }
michael@0 341 if (longestParseDistance == 0) {
michael@0 342 pos.setIndex(oldPos);
michael@0 343 pos.setErrorIndex(0);
michael@0 344 } else {
michael@0 345 UErrorCode status = U_ZERO_ERROR;
michael@0 346 TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
michael@0 347 if (U_SUCCESS(status)) {
michael@0 348 result.adoptObject(tmutamt);
michael@0 349 pos.setIndex(newPos);
michael@0 350 pos.setErrorIndex(-1);
michael@0 351 } else {
michael@0 352 pos.setIndex(oldPos);
michael@0 353 pos.setErrorIndex(0);
michael@0 354 }
michael@0 355 }
michael@0 356 }
michael@0 357
michael@0 358 void
michael@0 359 TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
michael@0 360 if (U_FAILURE(status)) {
michael@0 361 return;
michael@0 362 }
michael@0 363 if (style < UTMUTFMT_FULL_STYLE || style >= UTMUTFMT_FORMAT_STYLE_COUNT) {
michael@0 364 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 365 return;
michael@0 366 }
michael@0 367 fStyle = style;
michael@0 368 fLocale = locale;
michael@0 369 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 370 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 371 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 372 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 373 }
michael@0 374 //TODO: format() and parseObj() are const member functions,
michael@0 375 //so, can not do lazy initialization in C++.
michael@0 376 //setup has to be done in constructors.
michael@0 377 //and here, the behavior is not consistent with Java.
michael@0 378 //In Java, create an empty instance does not setup locale as
michael@0 379 //default locale. If it followed by setNumberFormat(),
michael@0 380 //in format(), the locale will set up as the locale in fNumberFormat.
michael@0 381 //But in C++, this sets the locale as the default locale.
michael@0 382 setup(status);
michael@0 383 }
michael@0 384
michael@0 385 void
michael@0 386 TimeUnitFormat::setup(UErrorCode& err) {
michael@0 387 initDataMembers(err);
michael@0 388
michael@0 389 UVector pluralCounts(0, uhash_compareUnicodeString, 6, err);
michael@0 390 StringEnumeration* keywords = fPluralRules->getKeywords(err);
michael@0 391 if (U_FAILURE(err)) {
michael@0 392 return;
michael@0 393 }
michael@0 394 UnicodeString* pluralCount;
michael@0 395 while ((pluralCount = const_cast<UnicodeString*>(keywords->snext(err))) != NULL) {
michael@0 396 pluralCounts.addElement(pluralCount, err);
michael@0 397 }
michael@0 398 readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, pluralCounts, err);
michael@0 399 checkConsistency(UTMUTFMT_FULL_STYLE, gUnitsTag, err);
michael@0 400 readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, pluralCounts, err);
michael@0 401 checkConsistency(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err);
michael@0 402 delete keywords;
michael@0 403 }
michael@0 404
michael@0 405
michael@0 406 void
michael@0 407 TimeUnitFormat::initDataMembers(UErrorCode& err){
michael@0 408 if (U_FAILURE(err)) {
michael@0 409 return;
michael@0 410 }
michael@0 411 if (fNumberFormat == NULL) {
michael@0 412 fNumberFormat = NumberFormat::createInstance(fLocale, err);
michael@0 413 }
michael@0 414 delete fPluralRules;
michael@0 415 fPluralRules = PluralRules::forLocale(fLocale, err);
michael@0 416 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 417 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 418 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 419 deleteHash(fTimeUnitToCountToPatterns[i]);
michael@0 420 fTimeUnitToCountToPatterns[i] = NULL;
michael@0 421 }
michael@0 422 }
michael@0 423
michael@0 424 void
michael@0 425 TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key,
michael@0 426 const UVector& pluralCounts, UErrorCode& err) {
michael@0 427 if (U_FAILURE(err)) {
michael@0 428 return;
michael@0 429 }
michael@0 430 // fill timeUnitToCountToPatterns from resource file
michael@0 431 // err is used to indicate wrong status except missing resource.
michael@0 432 // status is an error code used in resource lookup.
michael@0 433 // status does not affect "err".
michael@0 434 UErrorCode status = U_ZERO_ERROR;
michael@0 435 UResourceBundle *rb, *unitsRes;
michael@0 436 rb = ures_open(NULL, fLocale.getName(), &status);
michael@0 437 unitsRes = ures_getByKey(rb, key, NULL, &status);
michael@0 438 unitsRes = ures_getByKey(unitsRes, "duration", unitsRes, &status);
michael@0 439 if (U_FAILURE(status)) {
michael@0 440 ures_close(unitsRes);
michael@0 441 ures_close(rb);
michael@0 442 return;
michael@0 443 }
michael@0 444 int32_t size = ures_getSize(unitsRes);
michael@0 445 for ( int32_t index = 0; index < size; ++index) {
michael@0 446 // resource of one time unit
michael@0 447 UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
michael@0 448 NULL, &status);
michael@0 449 if (U_SUCCESS(status)) {
michael@0 450 const char* timeUnitName = ures_getKey(oneTimeUnit);
michael@0 451 if (timeUnitName == NULL) {
michael@0 452 ures_close(oneTimeUnit);
michael@0 453 continue;
michael@0 454 }
michael@0 455 UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes,
michael@0 456 timeUnitName,
michael@0 457 NULL, &status);
michael@0 458 if (countsToPatternRB == NULL || U_FAILURE(status)) {
michael@0 459 ures_close(countsToPatternRB);
michael@0 460 ures_close(oneTimeUnit);
michael@0 461 continue;
michael@0 462 }
michael@0 463 TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 464 if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
michael@0 465 timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
michael@0 466 } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
michael@0 467 timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
michael@0 468 } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
michael@0 469 timeUnitField = TimeUnit::UTIMEUNIT_DAY;
michael@0 470 } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
michael@0 471 timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
michael@0 472 } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
michael@0 473 timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
michael@0 474 } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
michael@0 475 timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
michael@0 476 } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
michael@0 477 timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
michael@0 478 } else {
michael@0 479 ures_close(countsToPatternRB);
michael@0 480 ures_close(oneTimeUnit);
michael@0 481 continue;
michael@0 482 }
michael@0 483 Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
michael@0 484 if (countToPatterns == NULL) {
michael@0 485 countToPatterns = initHash(err);
michael@0 486 if (U_FAILURE(err)) {
michael@0 487 ures_close(countsToPatternRB);
michael@0 488 ures_close(oneTimeUnit);
michael@0 489 delete countToPatterns;
michael@0 490 break;
michael@0 491 }
michael@0 492 }
michael@0 493 int32_t count = ures_getSize(countsToPatternRB);
michael@0 494 const char* pluralCount;
michael@0 495 for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
michael@0 496 // resource of count to pattern
michael@0 497 UnicodeString pattern =
michael@0 498 ures_getNextUnicodeString(countsToPatternRB, &pluralCount, &status);
michael@0 499 if (U_FAILURE(status)) {
michael@0 500 continue;
michael@0 501 }
michael@0 502 UnicodeString pluralCountUniStr(pluralCount, -1, US_INV);
michael@0 503 if (!pluralCounts.contains(&pluralCountUniStr)) {
michael@0 504 continue;
michael@0 505 }
michael@0 506 MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
michael@0 507 if ( U_SUCCESS(err) ) {
michael@0 508 if (fNumberFormat != NULL) {
michael@0 509 messageFormat->setFormat(0, *fNumberFormat);
michael@0 510 }
michael@0 511 MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr);
michael@0 512 if (formatters == NULL) {
michael@0 513 formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
michael@0 514 formatters[UTMUTFMT_FULL_STYLE] = NULL;
michael@0 515 formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
michael@0 516 countToPatterns->put(pluralCountUniStr, formatters, err);
michael@0 517 if (U_FAILURE(err)) {
michael@0 518 uprv_free(formatters);
michael@0 519 }
michael@0 520 }
michael@0 521 if (U_SUCCESS(err)) {
michael@0 522 //delete formatters[style];
michael@0 523 formatters[style] = messageFormat;
michael@0 524 }
michael@0 525 }
michael@0 526 if (U_FAILURE(err)) {
michael@0 527 ures_close(countsToPatternRB);
michael@0 528 ures_close(oneTimeUnit);
michael@0 529 ures_close(unitsRes);
michael@0 530 ures_close(rb);
michael@0 531 delete messageFormat;
michael@0 532 delete countToPatterns;
michael@0 533 return;
michael@0 534 }
michael@0 535 }
michael@0 536 if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
michael@0 537 fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
michael@0 538 }
michael@0 539 ures_close(countsToPatternRB);
michael@0 540 }
michael@0 541 ures_close(oneTimeUnit);
michael@0 542 }
michael@0 543 ures_close(unitsRes);
michael@0 544 ures_close(rb);
michael@0 545 }
michael@0 546
michael@0 547
michael@0 548 void
michael@0 549 TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) {
michael@0 550 if (U_FAILURE(err)) {
michael@0 551 return;
michael@0 552 }
michael@0 553 // there should be patterns for each plural rule in each time unit.
michael@0 554 // For each time unit,
michael@0 555 // for each plural rule, following is unit pattern fall-back rule:
michael@0 556 // ( for example: "one" hour )
michael@0 557 // look for its unit pattern in its locale tree.
michael@0 558 // if pattern is not found in its own locale, such as de_DE,
michael@0 559 // look for the pattern in its parent, such as de,
michael@0 560 // keep looking till found or till root.
michael@0 561 // if the pattern is not found in root either,
michael@0 562 // fallback to plural count "other",
michael@0 563 // look for the pattern of "other" in the locale tree:
michael@0 564 // "de_DE" to "de" to "root".
michael@0 565 // If not found, fall back to value of
michael@0 566 // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
michael@0 567 //
michael@0 568 // Following is consistency check to create pattern for each
michael@0 569 // plural rule in each time unit using above fall-back rule.
michael@0 570 //
michael@0 571 StringEnumeration* keywords = fPluralRules->getKeywords(err);
michael@0 572 if (U_SUCCESS(err)) {
michael@0 573 const UnicodeString* pluralCount;
michael@0 574 while ((pluralCount = keywords->snext(err)) != NULL) {
michael@0 575 if ( U_SUCCESS(err) ) {
michael@0 576 for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
michael@0 577 // for each time unit,
michael@0 578 // get all the patterns for each plural rule in this locale.
michael@0 579 Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
michael@0 580 if ( countToPatterns == NULL ) {
michael@0 581 countToPatterns = initHash(err);
michael@0 582 if (U_FAILURE(err)) {
michael@0 583 delete countToPatterns;
michael@0 584 return;
michael@0 585 }
michael@0 586 fTimeUnitToCountToPatterns[i] = countToPatterns;
michael@0 587 }
michael@0 588 MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount);
michael@0 589 if( formatters == NULL || formatters[style] == NULL ) {
michael@0 590 // look through parents
michael@0 591 const char* localeName = fLocale.getName();
michael@0 592 CharString pluralCountChars;
michael@0 593 pluralCountChars.appendInvariantChars(*pluralCount, err);
michael@0 594 searchInLocaleChain(style, key, localeName,
michael@0 595 (TimeUnit::UTimeUnitFields)i,
michael@0 596 *pluralCount, pluralCountChars.data(),
michael@0 597 countToPatterns, err);
michael@0 598 }
michael@0 599 }
michael@0 600 }
michael@0 601 }
michael@0 602 }
michael@0 603 delete keywords;
michael@0 604 }
michael@0 605
michael@0 606
michael@0 607
michael@0 608 // srcPluralCount is the original plural count on which the pattern is
michael@0 609 // searched for.
michael@0 610 // searchPluralCount is the fallback plural count.
michael@0 611 // For example, to search for pattern for ""one" hour",
michael@0 612 // "one" is the srcPluralCount,
michael@0 613 // if the pattern is not found even in root, fallback to
michael@0 614 // using patterns of plural count "other",
michael@0 615 // then, "other" is the searchPluralCount.
michael@0 616 void
michael@0 617 TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key, const char* localeName,
michael@0 618 TimeUnit::UTimeUnitFields srcTimeUnitField,
michael@0 619 const UnicodeString& srcPluralCount,
michael@0 620 const char* searchPluralCount,
michael@0 621 Hashtable* countToPatterns,
michael@0 622 UErrorCode& err) {
michael@0 623 if (U_FAILURE(err)) {
michael@0 624 return;
michael@0 625 }
michael@0 626 UErrorCode status = U_ZERO_ERROR;
michael@0 627 char parentLocale[ULOC_FULLNAME_CAPACITY];
michael@0 628 uprv_strcpy(parentLocale, localeName);
michael@0 629 int32_t locNameLen;
michael@0 630 U_ASSERT(countToPatterns != NULL);
michael@0 631 while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
michael@0 632 ULOC_FULLNAME_CAPACITY, &status)) >= 0){
michael@0 633 // look for pattern for srcPluralCount in locale tree
michael@0 634 UResourceBundle *rb, *unitsRes, *countsToPatternRB;
michael@0 635 rb = ures_open(NULL, parentLocale, &status);
michael@0 636 unitsRes = ures_getByKey(rb, key, NULL, &status);
michael@0 637 const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
michael@0 638 countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
michael@0 639 const UChar* pattern;
michael@0 640 int32_t ptLength;
michael@0 641 pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
michael@0 642 if (U_SUCCESS(status)) {
michael@0 643 //found
michael@0 644 MessageFormat* messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, ptLength), fLocale, err);
michael@0 645 if (U_SUCCESS(err)) {
michael@0 646 if (fNumberFormat != NULL) {
michael@0 647 messageFormat->setFormat(0, *fNumberFormat);
michael@0 648 }
michael@0 649 MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
michael@0 650 if (formatters == NULL) {
michael@0 651 formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
michael@0 652 formatters[UTMUTFMT_FULL_STYLE] = NULL;
michael@0 653 formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
michael@0 654 countToPatterns->put(srcPluralCount, formatters, err);
michael@0 655 if (U_FAILURE(err)) {
michael@0 656 uprv_free(formatters);
michael@0 657 delete messageFormat;
michael@0 658 }
michael@0 659 }
michael@0 660 if (U_SUCCESS(err)) {
michael@0 661 //delete formatters[style];
michael@0 662 formatters[style] = messageFormat;
michael@0 663 }
michael@0 664 } else {
michael@0 665 delete messageFormat;
michael@0 666 }
michael@0 667 ures_close(countsToPatternRB);
michael@0 668 ures_close(unitsRes);
michael@0 669 ures_close(rb);
michael@0 670 return;
michael@0 671 }
michael@0 672 ures_close(countsToPatternRB);
michael@0 673 ures_close(unitsRes);
michael@0 674 ures_close(rb);
michael@0 675 status = U_ZERO_ERROR;
michael@0 676 if ( locNameLen ==0 ) {
michael@0 677 break;
michael@0 678 }
michael@0 679 }
michael@0 680
michael@0 681 // if no unitsShort resource was found even after fallback to root locale
michael@0 682 // then search the units resource fallback from the current level to root
michael@0 683 if ( locNameLen == 0 && uprv_strcmp(key, gShortUnitsTag) == 0) {
michael@0 684 #ifdef TMUTFMT_DEBUG
michael@0 685 std::cout << "loop into searchInLocaleChain since Short-Long-Alternative \n";
michael@0 686 #endif
michael@0 687 char pLocale[ULOC_FULLNAME_CAPACITY];
michael@0 688 uprv_strcpy(pLocale, localeName);
michael@0 689 // Add an underscore at the tail of locale name,
michael@0 690 // so that searchInLocaleChain will check the current locale before falling back
michael@0 691 uprv_strcat(pLocale, "_");
michael@0 692 searchInLocaleChain(style, gUnitsTag, pLocale, srcTimeUnitField, srcPluralCount,
michael@0 693 searchPluralCount, countToPatterns, err);
michael@0 694 MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
michael@0 695 if (formatters != NULL && formatters[style] != NULL) {
michael@0 696 return;
michael@0 697 }
michael@0 698 }
michael@0 699
michael@0 700 // if not found the pattern for this plural count at all,
michael@0 701 // fall-back to plural count "other"
michael@0 702 if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
michael@0 703 // set default fall back the same as the resource in root
michael@0 704 MessageFormat* messageFormat = NULL;
michael@0 705 const UChar *pattern = NULL;
michael@0 706 if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
michael@0 707 pattern = DEFAULT_PATTERN_FOR_SECOND;
michael@0 708 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
michael@0 709 pattern = DEFAULT_PATTERN_FOR_MINUTE;
michael@0 710 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
michael@0 711 pattern = DEFAULT_PATTERN_FOR_HOUR;
michael@0 712 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
michael@0 713 pattern = DEFAULT_PATTERN_FOR_WEEK;
michael@0 714 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
michael@0 715 pattern = DEFAULT_PATTERN_FOR_DAY;
michael@0 716 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
michael@0 717 pattern = DEFAULT_PATTERN_FOR_MONTH;
michael@0 718 } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
michael@0 719 pattern = DEFAULT_PATTERN_FOR_YEAR;
michael@0 720 }
michael@0 721 if (pattern != NULL) {
michael@0 722 messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, -1), fLocale, err);
michael@0 723 }
michael@0 724 if (U_SUCCESS(err)) {
michael@0 725 if (fNumberFormat != NULL && messageFormat != NULL) {
michael@0 726 messageFormat->setFormat(0, *fNumberFormat);
michael@0 727 }
michael@0 728 MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
michael@0 729 if (formatters == NULL) {
michael@0 730 formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
michael@0 731 formatters[UTMUTFMT_FULL_STYLE] = NULL;
michael@0 732 formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
michael@0 733 countToPatterns->put(srcPluralCount, formatters, err);
michael@0 734 if (U_FAILURE(err)) {
michael@0 735 uprv_free(formatters);
michael@0 736 delete messageFormat;
michael@0 737 }
michael@0 738 }
michael@0 739 if (U_SUCCESS(err)) {
michael@0 740 //delete formatters[style];
michael@0 741 formatters[style] = messageFormat;
michael@0 742 }
michael@0 743 } else {
michael@0 744 delete messageFormat;
michael@0 745 }
michael@0 746 } else {
michael@0 747 // fall back to rule "other", and search in parents
michael@0 748 searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount,
michael@0 749 gPluralCountOther, countToPatterns, err);
michael@0 750 }
michael@0 751 }
michael@0 752
michael@0 753 void
michael@0 754 TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
michael@0 755 if (U_SUCCESS(status) && fLocale != locale) {
michael@0 756 fLocale = locale;
michael@0 757 setup(status);
michael@0 758 }
michael@0 759 }
michael@0 760
michael@0 761
michael@0 762 void
michael@0 763 TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
michael@0 764 if (U_FAILURE(status) || (fNumberFormat && format == *fNumberFormat)) {
michael@0 765 return;
michael@0 766 }
michael@0 767 delete fNumberFormat;
michael@0 768 fNumberFormat = (NumberFormat*)format.clone();
michael@0 769 // reset the number formatter in the fTimeUnitToCountToPatterns map
michael@0 770 for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
michael@0 771 i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
michael@0 772 i = (TimeUnit::UTimeUnitFields)(i+1)) {
michael@0 773 int32_t pos = -1;
michael@0 774 const UHashElement* elem = NULL;
michael@0 775 while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
michael@0 776 const UHashTok keyTok = elem->value;
michael@0 777 MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
michael@0 778
michael@0 779 pattern[UTMUTFMT_FULL_STYLE]->setFormat(0, format);
michael@0 780 pattern[UTMUTFMT_ABBREVIATED_STYLE]->setFormat(0, format);
michael@0 781 }
michael@0 782 }
michael@0 783 }
michael@0 784
michael@0 785
michael@0 786 void
michael@0 787 TimeUnitFormat::deleteHash(Hashtable* htable) {
michael@0 788 int32_t pos = -1;
michael@0 789 const UHashElement* element = NULL;
michael@0 790 if ( htable ) {
michael@0 791 while ( (element = htable->nextElement(pos)) != NULL ) {
michael@0 792 const UHashTok valueTok = element->value;
michael@0 793 const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
michael@0 794 delete value[UTMUTFMT_FULL_STYLE];
michael@0 795 delete value[UTMUTFMT_ABBREVIATED_STYLE];
michael@0 796 //delete[] value;
michael@0 797 uprv_free(value);
michael@0 798 }
michael@0 799 }
michael@0 800 delete htable;
michael@0 801 }
michael@0 802
michael@0 803
michael@0 804 void
michael@0 805 TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
michael@0 806 if ( U_FAILURE(status) ) {
michael@0 807 return;
michael@0 808 }
michael@0 809 int32_t pos = -1;
michael@0 810 const UHashElement* element = NULL;
michael@0 811 if ( source ) {
michael@0 812 while ( (element = source->nextElement(pos)) != NULL ) {
michael@0 813 const UHashTok keyTok = element->key;
michael@0 814 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 815 const UHashTok valueTok = element->value;
michael@0 816 const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
michael@0 817 MessageFormat** newVal = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
michael@0 818 newVal[0] = (MessageFormat*)value[0]->clone();
michael@0 819 newVal[1] = (MessageFormat*)value[1]->clone();
michael@0 820 target->put(UnicodeString(*key), newVal, status);
michael@0 821 if ( U_FAILURE(status) ) {
michael@0 822 delete newVal[0];
michael@0 823 delete newVal[1];
michael@0 824 uprv_free(newVal);
michael@0 825 return;
michael@0 826 }
michael@0 827 }
michael@0 828 }
michael@0 829 }
michael@0 830
michael@0 831
michael@0 832 U_CDECL_BEGIN
michael@0 833
michael@0 834 /**
michael@0 835 * set hash table value comparator
michael@0 836 *
michael@0 837 * @param val1 one value in comparison
michael@0 838 * @param val2 the other value in comparison
michael@0 839 * @return TRUE if 2 values are the same, FALSE otherwise
michael@0 840 */
michael@0 841 static UBool U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2);
michael@0 842
michael@0 843 static UBool
michael@0 844 U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2) {
michael@0 845 const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
michael@0 846 const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
michael@0 847 return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
michael@0 848 }
michael@0 849
michael@0 850 U_CDECL_END
michael@0 851
michael@0 852 Hashtable*
michael@0 853 TimeUnitFormat::initHash(UErrorCode& status) {
michael@0 854 if ( U_FAILURE(status) ) {
michael@0 855 return NULL;
michael@0 856 }
michael@0 857 Hashtable* hTable;
michael@0 858 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
michael@0 859 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 860 return NULL;
michael@0 861 }
michael@0 862 if ( U_FAILURE(status) ) {
michael@0 863 delete hTable;
michael@0 864 return NULL;
michael@0 865 }
michael@0 866 hTable->setValueComparator(tmutfmtHashTableValueComparator);
michael@0 867 return hTable;
michael@0 868 }
michael@0 869
michael@0 870
michael@0 871 const char*
michael@0 872 TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
michael@0 873 UErrorCode& status) {
michael@0 874 if (U_FAILURE(status)) {
michael@0 875 return NULL;
michael@0 876 }
michael@0 877 switch (unitField) {
michael@0 878 case TimeUnit::UTIMEUNIT_YEAR:
michael@0 879 return gTimeUnitYear;
michael@0 880 case TimeUnit::UTIMEUNIT_MONTH:
michael@0 881 return gTimeUnitMonth;
michael@0 882 case TimeUnit::UTIMEUNIT_DAY:
michael@0 883 return gTimeUnitDay;
michael@0 884 case TimeUnit::UTIMEUNIT_WEEK:
michael@0 885 return gTimeUnitWeek;
michael@0 886 case TimeUnit::UTIMEUNIT_HOUR:
michael@0 887 return gTimeUnitHour;
michael@0 888 case TimeUnit::UTIMEUNIT_MINUTE:
michael@0 889 return gTimeUnitMinute;
michael@0 890 case TimeUnit::UTIMEUNIT_SECOND:
michael@0 891 return gTimeUnitSecond;
michael@0 892 default:
michael@0 893 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 894 return NULL;
michael@0 895 }
michael@0 896 }
michael@0 897
michael@0 898 U_NAMESPACE_END
michael@0 899
michael@0 900 #endif

mercurial