2 *******************************************************************************
3 * Copyright (C) 2008-2014, Google, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 *******************************************************************************
8 #include "unicode/tmutfmt.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/decimfmt.h"
13 #include "plurrule_impl.h"
21 #include "unicode/msgfmt.h"
24 #define LEFT_CURLY_BRACKET ((UChar)0x007B)
25 #define RIGHT_CURLY_BRACKET ((UChar)0x007D)
26 #define SPACE ((UChar)0x0020)
27 #define DIGIT_ZERO ((UChar)0x0030)
28 #define LOW_S ((UChar)0x0073)
29 #define LOW_M ((UChar)0x006D)
30 #define LOW_I ((UChar)0x0069)
31 #define LOW_N ((UChar)0x006E)
32 #define LOW_H ((UChar)0x0068)
33 #define LOW_W ((UChar)0x0077)
34 #define LOW_D ((UChar)0x0064)
35 #define LOW_Y ((UChar)0x0079)
36 #define LOW_Z ((UChar)0x007A)
37 #define LOW_E ((UChar)0x0065)
38 #define LOW_R ((UChar)0x0072)
39 #define LOW_O ((UChar)0x006F)
40 #define LOW_N ((UChar)0x006E)
41 #define LOW_T ((UChar)0x0074)
44 //TODO: define in compile time
45 //#define TMUTFMT_DEBUG 1
55 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat
)
57 static const char gUnitsTag
[] = "units";
58 static const char gShortUnitsTag
[] = "unitsShort";
59 static const char gTimeUnitYear
[] = "year";
60 static const char gTimeUnitMonth
[] = "month";
61 static const char gTimeUnitDay
[] = "day";
62 static const char gTimeUnitWeek
[] = "week";
63 static const char gTimeUnitHour
[] = "hour";
64 static const char gTimeUnitMinute
[] = "minute";
65 static const char gTimeUnitSecond
[] = "second";
66 static const char gPluralCountOther
[] = "other";
68 static const UChar DEFAULT_PATTERN_FOR_SECOND
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_S
, 0};
69 static const UChar DEFAULT_PATTERN_FOR_MINUTE
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_M
, LOW_I
, LOW_N
, 0};
70 static const UChar DEFAULT_PATTERN_FOR_HOUR
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_H
, 0};
71 static const UChar DEFAULT_PATTERN_FOR_WEEK
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_W
, 0};
72 static const UChar DEFAULT_PATTERN_FOR_DAY
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_D
, 0};
73 static const UChar DEFAULT_PATTERN_FOR_MONTH
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_M
, 0};
74 static const UChar DEFAULT_PATTERN_FOR_YEAR
[] = {LEFT_CURLY_BRACKET
, DIGIT_ZERO
, RIGHT_CURLY_BRACKET
, SPACE
, LOW_Y
, 0};
76 static const UChar PLURAL_COUNT_ZERO
[] = {LOW_Z
, LOW_E
, LOW_R
, LOW_O
, 0};
77 static const UChar PLURAL_COUNT_ONE
[] = {LOW_O
, LOW_N
, LOW_E
, 0};
78 static const UChar PLURAL_COUNT_TWO
[] = {LOW_T
, LOW_W
, LOW_O
, 0};
80 TimeUnitFormat::TimeUnitFormat(UErrorCode
& status
) {
81 initMeasureFormat(Locale::getDefault(), UMEASFMT_WIDTH_WIDE
, NULL
, status
);
82 create(UTMUTFMT_FULL_STYLE
, status
);
86 TimeUnitFormat::TimeUnitFormat(const Locale
& locale
, UErrorCode
& status
) {
87 initMeasureFormat(locale
, UMEASFMT_WIDTH_WIDE
, NULL
, status
);
88 create(UTMUTFMT_FULL_STYLE
, status
);
92 TimeUnitFormat::TimeUnitFormat(const Locale
& locale
, UTimeUnitFormatStyle style
, UErrorCode
& status
) {
94 case UTMUTFMT_FULL_STYLE
:
95 initMeasureFormat(locale
, UMEASFMT_WIDTH_WIDE
, NULL
, status
);
97 case UTMUTFMT_ABBREVIATED_STYLE
:
98 initMeasureFormat(locale
, UMEASFMT_WIDTH_SHORT
, NULL
, status
);
101 initMeasureFormat(locale
, UMEASFMT_WIDTH_WIDE
, NULL
, status
);
104 create(style
, status
);
107 TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat
& other
)
108 : MeasureFormat(other
),
111 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
112 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
113 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
114 UErrorCode status
= U_ZERO_ERROR
;
115 fTimeUnitToCountToPatterns
[i
] = initHash(status
);
116 if (U_SUCCESS(status
)) {
117 copyHash(other
.fTimeUnitToCountToPatterns
[i
], fTimeUnitToCountToPatterns
[i
], status
);
119 delete fTimeUnitToCountToPatterns
[i
];
120 fTimeUnitToCountToPatterns
[i
] = NULL
;
126 TimeUnitFormat::~TimeUnitFormat() {
127 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
128 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
129 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
130 deleteHash(fTimeUnitToCountToPatterns
[i
]);
131 fTimeUnitToCountToPatterns
[i
] = NULL
;
137 TimeUnitFormat::clone(void) const {
138 return new TimeUnitFormat(*this);
143 TimeUnitFormat::operator=(const TimeUnitFormat
& other
) {
144 if (this == &other
) {
147 MeasureFormat::operator=(other
);
148 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
149 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
150 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
151 deleteHash(fTimeUnitToCountToPatterns
[i
]);
152 fTimeUnitToCountToPatterns
[i
] = NULL
;
154 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
155 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
156 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
157 UErrorCode status
= U_ZERO_ERROR
;
158 fTimeUnitToCountToPatterns
[i
] = initHash(status
);
159 if (U_SUCCESS(status
)) {
160 copyHash(other
.fTimeUnitToCountToPatterns
[i
], fTimeUnitToCountToPatterns
[i
], status
);
162 delete fTimeUnitToCountToPatterns
[i
];
163 fTimeUnitToCountToPatterns
[i
] = NULL
;
166 fStyle
= other
.fStyle
;
171 TimeUnitFormat::parseObject(const UnicodeString
& source
,
173 ParsePosition
& pos
) const {
174 Formattable
resultNumber(0.0);
175 UBool withNumberFormat
= false;
176 TimeUnit::UTimeUnitFields resultTimeUnit
= TimeUnit::UTIMEUNIT_FIELD_COUNT
;
177 int32_t oldPos
= pos
.getIndex();
179 int32_t longestParseDistance
= 0;
180 UnicodeString
* countOfLongestMatch
= NULL
;
183 source
.extract(0, source
.length(), res
, "UTF-8");
184 std::cout
<< "parse source: " << res
<< "\n";
186 // parse by iterating through all available patterns
187 // and looking for the longest match.
188 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
189 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
190 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
191 Hashtable
* countToPatterns
= fTimeUnitToCountToPatterns
[i
];
192 int32_t elemPos
= UHASH_FIRST
;
193 const UHashElement
* elem
= NULL
;
194 while ((elem
= countToPatterns
->nextElement(elemPos
)) != NULL
){
195 const UHashTok keyTok
= elem
->key
;
196 UnicodeString
* count
= (UnicodeString
*)keyTok
.pointer
;
198 count
->extract(0, count
->length(), res
, "UTF-8");
199 std::cout
<< "parse plural count: " << res
<< "\n";
201 const UHashTok valueTok
= elem
->value
;
202 // the value is a pair of MessageFormat*
203 MessageFormat
** patterns
= (MessageFormat
**)valueTok
.pointer
;
204 for (UTimeUnitFormatStyle style
= UTMUTFMT_FULL_STYLE
; style
< UTMUTFMT_FORMAT_STYLE_COUNT
;
205 style
= (UTimeUnitFormatStyle
)(style
+ 1)) {
206 MessageFormat
* pattern
= patterns
[style
];
207 pos
.setErrorIndex(-1);
208 pos
.setIndex(oldPos
);
209 // see if we can parse
211 pattern
->parseObject(source
, parsed
, pos
);
212 if (pos
.getErrorIndex() != -1 || pos
.getIndex() == oldPos
) {
216 std::cout
<< "parsed.getType: " << parsed
.getType() << "\n";
218 Formattable
tmpNumber(0.0);
219 if (pattern
->getArgTypeCount() != 0) {
220 Formattable
& temp
= parsed
[0];
221 if (temp
.getType() == Formattable::kString
) {
222 UnicodeString tmpString
;
223 UErrorCode pStatus
= U_ZERO_ERROR
;
224 getNumberFormat().parse(temp
.getString(tmpString
), tmpNumber
, pStatus
);
225 if (U_FAILURE(pStatus
)) {
228 } else if (temp
.isNumeric()) {
234 int32_t parseDistance
= pos
.getIndex() - oldPos
;
235 if (parseDistance
> longestParseDistance
) {
236 if (pattern
->getArgTypeCount() != 0) {
237 resultNumber
= tmpNumber
;
238 withNumberFormat
= true;
240 withNumberFormat
= false;
243 newPos
= pos
.getIndex();
244 longestParseDistance
= parseDistance
;
245 countOfLongestMatch
= count
;
250 /* After find the longest match, parse the number.
251 * Result number could be null for the pattern without number pattern.
252 * such as unit pattern in Arabic.
253 * When result number is null, use plural rule to set the number.
255 if (withNumberFormat
== false && longestParseDistance
!= 0) {
256 // set the number using plurrual count
257 if (0 == countOfLongestMatch
->compare(PLURAL_COUNT_ZERO
, 4)) {
258 resultNumber
= Formattable(0.0);
259 } else if (0 == countOfLongestMatch
->compare(PLURAL_COUNT_ONE
, 3)) {
260 resultNumber
= Formattable(1.0);
261 } else if (0 == countOfLongestMatch
->compare(PLURAL_COUNT_TWO
, 3)) {
262 resultNumber
= Formattable(2.0);
264 // should not happen.
265 // TODO: how to handle?
266 resultNumber
= Formattable(3.0);
269 if (longestParseDistance
== 0) {
270 pos
.setIndex(oldPos
);
271 pos
.setErrorIndex(0);
273 UErrorCode status
= U_ZERO_ERROR
;
274 TimeUnitAmount
* tmutamt
= new TimeUnitAmount(resultNumber
, resultTimeUnit
, status
);
275 if (U_SUCCESS(status
)) {
276 result
.adoptObject(tmutamt
);
277 pos
.setIndex(newPos
);
278 pos
.setErrorIndex(-1);
280 pos
.setIndex(oldPos
);
281 pos
.setErrorIndex(0);
287 TimeUnitFormat::create(UTimeUnitFormatStyle style
, UErrorCode
& status
) {
288 // fTimeUnitToCountToPatterns[] must have its elements initialized to NULL first
289 // before checking for failure status.
290 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
291 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
292 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
293 fTimeUnitToCountToPatterns
[i
] = NULL
;
296 if (U_FAILURE(status
)) {
299 if (style
< UTMUTFMT_FULL_STYLE
|| style
>= UTMUTFMT_FORMAT_STYLE_COUNT
) {
300 status
= U_ILLEGAL_ARGUMENT_ERROR
;
305 //TODO: format() and parseObj() are const member functions,
306 //so, can not do lazy initialization in C++.
307 //setup has to be done in constructors.
308 //and here, the behavior is not consistent with Java.
309 //In Java, create an empty instance does not setup locale as
310 //default locale. If it followed by setNumberFormat(),
311 //in format(), the locale will set up as the locale in fNumberFormat.
312 //But in C++, this sets the locale as the default locale.
317 TimeUnitFormat::setup(UErrorCode
& err
) {
318 initDataMembers(err
);
320 UVector
pluralCounts(0, uhash_compareUnicodeString
, 6, err
);
321 StringEnumeration
* keywords
= getPluralRules().getKeywords(err
);
322 if (U_FAILURE(err
)) {
325 UnicodeString
* pluralCount
;
326 while ((pluralCount
= const_cast<UnicodeString
*>(keywords
->snext(err
))) != NULL
) {
327 pluralCounts
.addElement(pluralCount
, err
);
329 readFromCurrentLocale(UTMUTFMT_FULL_STYLE
, gUnitsTag
, pluralCounts
, err
);
330 checkConsistency(UTMUTFMT_FULL_STYLE
, gUnitsTag
, err
);
331 readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE
, gShortUnitsTag
, pluralCounts
, err
);
332 checkConsistency(UTMUTFMT_ABBREVIATED_STYLE
, gShortUnitsTag
, err
);
338 TimeUnitFormat::initDataMembers(UErrorCode
& err
){
339 if (U_FAILURE(err
)) {
342 for (TimeUnit::UTimeUnitFields i
= TimeUnit::UTIMEUNIT_YEAR
;
343 i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
;
344 i
= (TimeUnit::UTimeUnitFields
)(i
+1)) {
345 deleteHash(fTimeUnitToCountToPatterns
[i
]);
346 fTimeUnitToCountToPatterns
[i
] = NULL
;
351 TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style
, const char* key
,
352 const UVector
& pluralCounts
, UErrorCode
& err
) {
353 if (U_FAILURE(err
)) {
356 // fill timeUnitToCountToPatterns from resource file
357 // err is used to indicate wrong status except missing resource.
358 // status is an error code used in resource lookup.
359 // status does not affect "err".
360 UErrorCode status
= U_ZERO_ERROR
;
361 UResourceBundle
*rb
, *unitsRes
;
362 rb
= ures_open(U_ICUDATA_UNIT
, getLocaleID(status
), &status
);
363 unitsRes
= ures_getByKey(rb
, key
, NULL
, &status
);
364 unitsRes
= ures_getByKey(unitsRes
, "duration", unitsRes
, &status
);
365 if (U_FAILURE(status
)) {
366 ures_close(unitsRes
);
370 int32_t size
= ures_getSize(unitsRes
);
371 for ( int32_t index
= 0; index
< size
; ++index
) {
372 // resource of one time unit
373 UResourceBundle
* oneTimeUnit
= ures_getByIndex(unitsRes
, index
,
375 if (U_SUCCESS(status
)) {
376 const char* timeUnitName
= ures_getKey(oneTimeUnit
);
377 if (timeUnitName
== NULL
) {
378 ures_close(oneTimeUnit
);
381 UResourceBundle
* countsToPatternRB
= ures_getByKey(unitsRes
,
384 if (countsToPatternRB
== NULL
|| U_FAILURE(status
)) {
385 ures_close(countsToPatternRB
);
386 ures_close(oneTimeUnit
);
389 TimeUnit::UTimeUnitFields timeUnitField
= TimeUnit::UTIMEUNIT_FIELD_COUNT
;
390 if ( uprv_strcmp(timeUnitName
, gTimeUnitYear
) == 0 ) {
391 timeUnitField
= TimeUnit::UTIMEUNIT_YEAR
;
392 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitMonth
) == 0 ) {
393 timeUnitField
= TimeUnit::UTIMEUNIT_MONTH
;
394 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitDay
) == 0 ) {
395 timeUnitField
= TimeUnit::UTIMEUNIT_DAY
;
396 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitHour
) == 0 ) {
397 timeUnitField
= TimeUnit::UTIMEUNIT_HOUR
;
398 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitMinute
) == 0 ) {
399 timeUnitField
= TimeUnit::UTIMEUNIT_MINUTE
;
400 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitSecond
) == 0 ) {
401 timeUnitField
= TimeUnit::UTIMEUNIT_SECOND
;
402 } else if ( uprv_strcmp(timeUnitName
, gTimeUnitWeek
) == 0 ) {
403 timeUnitField
= TimeUnit::UTIMEUNIT_WEEK
;
405 ures_close(countsToPatternRB
);
406 ures_close(oneTimeUnit
);
409 Hashtable
* countToPatterns
= fTimeUnitToCountToPatterns
[timeUnitField
];
410 if (countToPatterns
== NULL
) {
411 countToPatterns
= initHash(err
);
412 if (U_FAILURE(err
)) {
413 ures_close(countsToPatternRB
);
414 ures_close(oneTimeUnit
);
415 delete countToPatterns
;
419 int32_t count
= ures_getSize(countsToPatternRB
);
420 const char* pluralCount
;
421 for ( int32_t pluralIndex
= 0; pluralIndex
< count
; ++pluralIndex
) {
422 // resource of count to pattern
423 UnicodeString pattern
=
424 ures_getNextUnicodeString(countsToPatternRB
, &pluralCount
, &status
);
425 if (U_FAILURE(status
)) {
428 UnicodeString
pluralCountUniStr(pluralCount
, -1, US_INV
);
429 if (!pluralCounts
.contains(&pluralCountUniStr
)) {
432 MessageFormat
* messageFormat
= new MessageFormat(pattern
, getLocale(err
), err
);
433 if ( U_SUCCESS(err
) ) {
434 MessageFormat
** formatters
= (MessageFormat
**)countToPatterns
->get(pluralCountUniStr
);
435 if (formatters
== NULL
) {
436 formatters
= (MessageFormat
**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT
*sizeof(MessageFormat
*));
437 formatters
[UTMUTFMT_FULL_STYLE
] = NULL
;
438 formatters
[UTMUTFMT_ABBREVIATED_STYLE
] = NULL
;
439 countToPatterns
->put(pluralCountUniStr
, formatters
, err
);
440 if (U_FAILURE(err
)) {
441 uprv_free(formatters
);
444 if (U_SUCCESS(err
)) {
445 //delete formatters[style];
446 formatters
[style
] = messageFormat
;
449 if (U_FAILURE(err
)) {
450 ures_close(countsToPatternRB
);
451 ures_close(oneTimeUnit
);
452 ures_close(unitsRes
);
454 delete messageFormat
;
455 delete countToPatterns
;
459 if (fTimeUnitToCountToPatterns
[timeUnitField
] == NULL
) {
460 fTimeUnitToCountToPatterns
[timeUnitField
] = countToPatterns
;
462 ures_close(countsToPatternRB
);
464 ures_close(oneTimeUnit
);
466 ures_close(unitsRes
);
472 TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style
, const char* key
, UErrorCode
& err
) {
473 if (U_FAILURE(err
)) {
476 // there should be patterns for each plural rule in each time unit.
477 // For each time unit,
478 // for each plural rule, following is unit pattern fall-back rule:
479 // ( for example: "one" hour )
480 // look for its unit pattern in its locale tree.
481 // if pattern is not found in its own locale, such as de_DE,
482 // look for the pattern in its parent, such as de,
483 // keep looking till found or till root.
484 // if the pattern is not found in root either,
485 // fallback to plural count "other",
486 // look for the pattern of "other" in the locale tree:
487 // "de_DE" to "de" to "root".
488 // If not found, fall back to value of
489 // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
491 // Following is consistency check to create pattern for each
492 // plural rule in each time unit using above fall-back rule.
494 StringEnumeration
* keywords
= getPluralRules().getKeywords(err
);
495 if (U_SUCCESS(err
)) {
496 const UnicodeString
* pluralCount
;
497 while ((pluralCount
= keywords
->snext(err
)) != NULL
) {
498 if ( U_SUCCESS(err
) ) {
499 for (int32_t i
= 0; i
< TimeUnit::UTIMEUNIT_FIELD_COUNT
; ++i
) {
500 // for each time unit,
501 // get all the patterns for each plural rule in this locale.
502 Hashtable
* countToPatterns
= fTimeUnitToCountToPatterns
[i
];
503 if ( countToPatterns
== NULL
) {
504 countToPatterns
= initHash(err
);
505 if (U_FAILURE(err
)) {
506 delete countToPatterns
;
509 fTimeUnitToCountToPatterns
[i
] = countToPatterns
;
511 MessageFormat
** formatters
= (MessageFormat
**)countToPatterns
->get(*pluralCount
);
512 if( formatters
== NULL
|| formatters
[style
] == NULL
) {
513 // look through parents
514 const char* localeName
= getLocaleID(err
);
515 CharString pluralCountChars
;
516 pluralCountChars
.appendInvariantChars(*pluralCount
, err
);
517 searchInLocaleChain(style
, key
, localeName
,
518 (TimeUnit::UTimeUnitFields
)i
,
519 *pluralCount
, pluralCountChars
.data(),
520 countToPatterns
, err
);
531 // srcPluralCount is the original plural count on which the pattern is
533 // searchPluralCount is the fallback plural count.
534 // For example, to search for pattern for ""one" hour",
535 // "one" is the srcPluralCount,
536 // if the pattern is not found even in root, fallback to
537 // using patterns of plural count "other",
538 // then, "other" is the searchPluralCount.
540 TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style
, const char* key
, const char* localeName
,
541 TimeUnit::UTimeUnitFields srcTimeUnitField
,
542 const UnicodeString
& srcPluralCount
,
543 const char* searchPluralCount
,
544 Hashtable
* countToPatterns
,
546 if (U_FAILURE(err
)) {
549 UErrorCode status
= U_ZERO_ERROR
;
550 char parentLocale
[ULOC_FULLNAME_CAPACITY
];
551 uprv_strcpy(parentLocale
, localeName
);
553 U_ASSERT(countToPatterns
!= NULL
);
554 while ((locNameLen
= uloc_getParent(parentLocale
, parentLocale
,
555 ULOC_FULLNAME_CAPACITY
, &status
)) >= 0){
556 // look for pattern for srcPluralCount in locale tree
557 UResourceBundle
*rb
, *unitsRes
, *countsToPatternRB
;
558 rb
= ures_open(U_ICUDATA_UNIT
, parentLocale
, &status
);
559 unitsRes
= ures_getByKey(rb
, key
, NULL
, &status
);
560 const char* timeUnitName
= getTimeUnitName(srcTimeUnitField
, status
);
561 countsToPatternRB
= ures_getByKey(unitsRes
, timeUnitName
, NULL
, &status
);
562 const UChar
* pattern
;
564 pattern
= ures_getStringByKeyWithFallback(countsToPatternRB
, searchPluralCount
, &ptLength
, &status
);
565 if (U_SUCCESS(status
)) {
567 MessageFormat
* messageFormat
= new MessageFormat(UnicodeString(TRUE
, pattern
, ptLength
), getLocale(err
), err
);
568 if (U_SUCCESS(err
)) {
569 MessageFormat
** formatters
= (MessageFormat
**)countToPatterns
->get(srcPluralCount
);
570 if (formatters
== NULL
) {
571 formatters
= (MessageFormat
**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT
*sizeof(MessageFormat
*));
572 formatters
[UTMUTFMT_FULL_STYLE
] = NULL
;
573 formatters
[UTMUTFMT_ABBREVIATED_STYLE
] = NULL
;
574 countToPatterns
->put(srcPluralCount
, formatters
, err
);
575 if (U_FAILURE(err
)) {
576 uprv_free(formatters
);
577 delete messageFormat
;
580 if (U_SUCCESS(err
)) {
581 //delete formatters[style];
582 formatters
[style
] = messageFormat
;
585 delete messageFormat
;
587 ures_close(countsToPatternRB
);
588 ures_close(unitsRes
);
592 ures_close(countsToPatternRB
);
593 ures_close(unitsRes
);
595 status
= U_ZERO_ERROR
;
596 if ( locNameLen
==0 ) {
601 // if no unitsShort resource was found even after fallback to root locale
602 // then search the units resource fallback from the current level to root
603 if ( locNameLen
== 0 && uprv_strcmp(key
, gShortUnitsTag
) == 0) {
605 std::cout
<< "loop into searchInLocaleChain since Short-Long-Alternative \n";
607 char pLocale
[ULOC_FULLNAME_CAPACITY
];
608 uprv_strcpy(pLocale
, localeName
);
609 // Add an underscore at the tail of locale name,
610 // so that searchInLocaleChain will check the current locale before falling back
611 uprv_strcat(pLocale
, "_");
612 searchInLocaleChain(style
, gUnitsTag
, pLocale
, srcTimeUnitField
, srcPluralCount
,
613 searchPluralCount
, countToPatterns
, err
);
614 MessageFormat
** formatters
= (MessageFormat
**)countToPatterns
->get(srcPluralCount
);
615 if (formatters
!= NULL
&& formatters
[style
] != NULL
) {
620 // if not found the pattern for this plural count at all,
621 // fall-back to plural count "other"
622 if ( uprv_strcmp(searchPluralCount
, gPluralCountOther
) == 0 ) {
623 // set default fall back the same as the resource in root
624 MessageFormat
* messageFormat
= NULL
;
625 const UChar
*pattern
= NULL
;
626 if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_SECOND
) {
627 pattern
= DEFAULT_PATTERN_FOR_SECOND
;
628 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_MINUTE
) {
629 pattern
= DEFAULT_PATTERN_FOR_MINUTE
;
630 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_HOUR
) {
631 pattern
= DEFAULT_PATTERN_FOR_HOUR
;
632 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_WEEK
) {
633 pattern
= DEFAULT_PATTERN_FOR_WEEK
;
634 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_DAY
) {
635 pattern
= DEFAULT_PATTERN_FOR_DAY
;
636 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_MONTH
) {
637 pattern
= DEFAULT_PATTERN_FOR_MONTH
;
638 } else if ( srcTimeUnitField
== TimeUnit::UTIMEUNIT_YEAR
) {
639 pattern
= DEFAULT_PATTERN_FOR_YEAR
;
641 if (pattern
!= NULL
) {
642 messageFormat
= new MessageFormat(UnicodeString(TRUE
, pattern
, -1), getLocale(err
), err
);
644 if (U_SUCCESS(err
)) {
645 MessageFormat
** formatters
= (MessageFormat
**)countToPatterns
->get(srcPluralCount
);
646 if (formatters
== NULL
) {
647 formatters
= (MessageFormat
**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT
*sizeof(MessageFormat
*));
648 formatters
[UTMUTFMT_FULL_STYLE
] = NULL
;
649 formatters
[UTMUTFMT_ABBREVIATED_STYLE
] = NULL
;
650 countToPatterns
->put(srcPluralCount
, formatters
, err
);
651 if (U_FAILURE(err
)) {
652 uprv_free(formatters
);
653 delete messageFormat
;
656 if (U_SUCCESS(err
)) {
657 //delete formatters[style];
658 formatters
[style
] = messageFormat
;
661 delete messageFormat
;
664 // fall back to rule "other", and search in parents
665 searchInLocaleChain(style
, key
, localeName
, srcTimeUnitField
, srcPluralCount
,
666 gPluralCountOther
, countToPatterns
, err
);
671 TimeUnitFormat::setLocale(const Locale
& locale
, UErrorCode
& status
) {
672 if (setMeasureFormatLocale(locale
, status
)) {
679 TimeUnitFormat::setNumberFormat(const NumberFormat
& format
, UErrorCode
& status
){
680 if (U_FAILURE(status
)) {
683 adoptNumberFormat((NumberFormat
*)format
.clone(), status
);
688 TimeUnitFormat::deleteHash(Hashtable
* htable
) {
689 int32_t pos
= UHASH_FIRST
;
690 const UHashElement
* element
= NULL
;
692 while ( (element
= htable
->nextElement(pos
)) != NULL
) {
693 const UHashTok valueTok
= element
->value
;
694 const MessageFormat
** value
= (const MessageFormat
**)valueTok
.pointer
;
695 delete value
[UTMUTFMT_FULL_STYLE
];
696 delete value
[UTMUTFMT_ABBREVIATED_STYLE
];
706 TimeUnitFormat::copyHash(const Hashtable
* source
, Hashtable
* target
, UErrorCode
& status
) {
707 if ( U_FAILURE(status
) ) {
710 int32_t pos
= UHASH_FIRST
;
711 const UHashElement
* element
= NULL
;
713 while ( (element
= source
->nextElement(pos
)) != NULL
) {
714 const UHashTok keyTok
= element
->key
;
715 const UnicodeString
* key
= (UnicodeString
*)keyTok
.pointer
;
716 const UHashTok valueTok
= element
->value
;
717 const MessageFormat
** value
= (const MessageFormat
**)valueTok
.pointer
;
718 MessageFormat
** newVal
= (MessageFormat
**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT
*sizeof(MessageFormat
*));
719 newVal
[0] = (MessageFormat
*)value
[0]->clone();
720 newVal
[1] = (MessageFormat
*)value
[1]->clone();
721 target
->put(UnicodeString(*key
), newVal
, status
);
722 if ( U_FAILURE(status
) ) {
736 * set hash table value comparator
738 * @param val1 one value in comparison
739 * @param val2 the other value in comparison
740 * @return TRUE if 2 values are the same, FALSE otherwise
742 static UBool U_CALLCONV
tmutfmtHashTableValueComparator(UHashTok val1
, UHashTok val2
);
745 U_CALLCONV
tmutfmtHashTableValueComparator(UHashTok val1
, UHashTok val2
) {
746 const MessageFormat
** pattern1
= (const MessageFormat
**)val1
.pointer
;
747 const MessageFormat
** pattern2
= (const MessageFormat
**)val2
.pointer
;
748 return *pattern1
[0] == *pattern2
[0] && *pattern1
[1] == *pattern2
[1];
754 TimeUnitFormat::initHash(UErrorCode
& status
) {
755 if ( U_FAILURE(status
) ) {
759 if ( (hTable
= new Hashtable(TRUE
, status
)) == NULL
) {
760 status
= U_MEMORY_ALLOCATION_ERROR
;
763 if ( U_FAILURE(status
) ) {
767 hTable
->setValueComparator(tmutfmtHashTableValueComparator
);
773 TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField
,
774 UErrorCode
& status
) {
775 if (U_FAILURE(status
)) {
779 case TimeUnit::UTIMEUNIT_YEAR
:
780 return gTimeUnitYear
;
781 case TimeUnit::UTIMEUNIT_MONTH
:
782 return gTimeUnitMonth
;
783 case TimeUnit::UTIMEUNIT_DAY
:
785 case TimeUnit::UTIMEUNIT_WEEK
:
786 return gTimeUnitWeek
;
787 case TimeUnit::UTIMEUNIT_HOUR
:
788 return gTimeUnitHour
;
789 case TimeUnit::UTIMEUNIT_MINUTE
:
790 return gTimeUnitMinute
;
791 case TimeUnit::UTIMEUNIT_SECOND
:
792 return gTimeUnitSecond
;
794 status
= U_ILLEGAL_ARGUMENT_ERROR
;