intl/icu/source/i18n/tmutfmt.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/tmutfmt.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,900 @@
     1.4 +/*
     1.5 + *******************************************************************************
     1.6 + * Copyright (C) 2008-2013, Google, International Business Machines Corporation
     1.7 + * and others. All Rights Reserved.
     1.8 + *******************************************************************************
     1.9 + */
    1.10 +
    1.11 +#include "utypeinfo.h"  // for 'typeid' to work
    1.12 +
    1.13 +#include "unicode/tmutfmt.h"
    1.14 +
    1.15 +#if !UCONFIG_NO_FORMATTING
    1.16 +
    1.17 +#include "uvector.h"
    1.18 +#include "charstr.h"
    1.19 +#include "cmemory.h"
    1.20 +#include "cstring.h"
    1.21 +#include "hash.h"
    1.22 +#include "uresimp.h"
    1.23 +#include "unicode/msgfmt.h"
    1.24 +#include "uassert.h"
    1.25 +
    1.26 +#define LEFT_CURLY_BRACKET  ((UChar)0x007B)
    1.27 +#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
    1.28 +#define SPACE             ((UChar)0x0020)
    1.29 +#define DIGIT_ZERO        ((UChar)0x0030)
    1.30 +#define LOW_S             ((UChar)0x0073)
    1.31 +#define LOW_M             ((UChar)0x006D)
    1.32 +#define LOW_I             ((UChar)0x0069)
    1.33 +#define LOW_N             ((UChar)0x006E)
    1.34 +#define LOW_H             ((UChar)0x0068)
    1.35 +#define LOW_W             ((UChar)0x0077)
    1.36 +#define LOW_D             ((UChar)0x0064)
    1.37 +#define LOW_Y             ((UChar)0x0079)
    1.38 +#define LOW_Z             ((UChar)0x007A)
    1.39 +#define LOW_E             ((UChar)0x0065)
    1.40 +#define LOW_R             ((UChar)0x0072)
    1.41 +#define LOW_O             ((UChar)0x006F)
    1.42 +#define LOW_N             ((UChar)0x006E)
    1.43 +#define LOW_T             ((UChar)0x0074)
    1.44 +
    1.45 +
    1.46 +//TODO: define in compile time
    1.47 +//#define TMUTFMT_DEBUG 1
    1.48 +
    1.49 +#ifdef TMUTFMT_DEBUG
    1.50 +#include <iostream>
    1.51 +#endif
    1.52 +
    1.53 +U_NAMESPACE_BEGIN
    1.54 +
    1.55 +
    1.56 +
    1.57 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
    1.58 +
    1.59 +static const char gUnitsTag[] = "units";
    1.60 +static const char gShortUnitsTag[] = "unitsShort";
    1.61 +static const char gTimeUnitYear[] = "year";
    1.62 +static const char gTimeUnitMonth[] = "month";
    1.63 +static const char gTimeUnitDay[] = "day";
    1.64 +static const char gTimeUnitWeek[] = "week";
    1.65 +static const char gTimeUnitHour[] = "hour";
    1.66 +static const char gTimeUnitMinute[] = "minute";
    1.67 +static const char gTimeUnitSecond[] = "second";
    1.68 +static const char gPluralCountOther[] = "other";
    1.69 +
    1.70 +static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
    1.71 +static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
    1.72 +static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
    1.73 +static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
    1.74 +static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
    1.75 +static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
    1.76 +static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
    1.77 +
    1.78 +static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
    1.79 +static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
    1.80 +static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
    1.81 +
    1.82 +TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
    1.83 +:   fNumberFormat(NULL),
    1.84 +    fPluralRules(NULL) {
    1.85 +    create(Locale::getDefault(), UTMUTFMT_FULL_STYLE, status);
    1.86 +}
    1.87 +
    1.88 +
    1.89 +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
    1.90 +:   fNumberFormat(NULL),
    1.91 +    fPluralRules(NULL) {
    1.92 +    create(locale, UTMUTFMT_FULL_STYLE, status);
    1.93 +}
    1.94 +
    1.95 +
    1.96 +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status)
    1.97 +:   fNumberFormat(NULL),
    1.98 +    fPluralRules(NULL) {
    1.99 +    create(locale, style, status);
   1.100 +}
   1.101 +
   1.102 +
   1.103 +TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
   1.104 +:   MeasureFormat(other),
   1.105 +    fNumberFormat(NULL),
   1.106 +    fPluralRules(NULL),
   1.107 +    fStyle(UTMUTFMT_FULL_STYLE)
   1.108 +{
   1.109 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.110 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.111 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.112 +        fTimeUnitToCountToPatterns[i] = NULL;
   1.113 +    }
   1.114 +    *this = other;
   1.115 +}
   1.116 +
   1.117 +
   1.118 +TimeUnitFormat::~TimeUnitFormat() {
   1.119 +    delete fNumberFormat;
   1.120 +    fNumberFormat = NULL;
   1.121 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.122 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.123 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.124 +        deleteHash(fTimeUnitToCountToPatterns[i]);
   1.125 +        fTimeUnitToCountToPatterns[i] = NULL;
   1.126 +    }
   1.127 +    delete fPluralRules;
   1.128 +    fPluralRules = NULL;
   1.129 +}
   1.130 +
   1.131 +
   1.132 +Format* 
   1.133 +TimeUnitFormat::clone(void) const {
   1.134 +    return new TimeUnitFormat(*this);
   1.135 +}
   1.136 +
   1.137 +
   1.138 +TimeUnitFormat& 
   1.139 +TimeUnitFormat::operator=(const TimeUnitFormat& other) {
   1.140 +    if (this == &other) {
   1.141 +        return *this;
   1.142 +    }
   1.143 +    delete fNumberFormat;
   1.144 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.145 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.146 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.147 +        deleteHash(fTimeUnitToCountToPatterns[i]);
   1.148 +        fTimeUnitToCountToPatterns[i] = NULL;
   1.149 +    }
   1.150 +    delete fPluralRules;
   1.151 +    if (other.fNumberFormat) {
   1.152 +        fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
   1.153 +    } else {
   1.154 +        fNumberFormat = NULL;
   1.155 +    }
   1.156 +    fLocale = other.fLocale;
   1.157 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.158 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.159 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.160 +        UErrorCode status = U_ZERO_ERROR;
   1.161 +        fTimeUnitToCountToPatterns[i] = initHash(status);
   1.162 +        if (U_SUCCESS(status)) {
   1.163 +            copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
   1.164 +        } else {
   1.165 +            delete fTimeUnitToCountToPatterns[i];
   1.166 +            fTimeUnitToCountToPatterns[i] = NULL;
   1.167 +        }
   1.168 +    } 
   1.169 +    if (other.fPluralRules) {
   1.170 +        fPluralRules = (PluralRules*)other.fPluralRules->clone();
   1.171 +    } else {
   1.172 +        fPluralRules = NULL;
   1.173 +    }
   1.174 +    fStyle = other.fStyle;
   1.175 +    return *this;
   1.176 +}
   1.177 +
   1.178 +
   1.179 +UBool 
   1.180 +TimeUnitFormat::operator==(const Format& other) const {
   1.181 +    if (typeid(*this) == typeid(other)) {
   1.182 +        TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
   1.183 +        UBool ret =  ( ((fNumberFormat && fmt->fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)
   1.184 +                            || fNumberFormat == fmt->fNumberFormat ) 
   1.185 +                        && fLocale == fmt->fLocale 
   1.186 +                        && ((fPluralRules && fmt->fPluralRules && *fPluralRules == *fmt->fPluralRules) 
   1.187 +                            || fPluralRules == fmt->fPluralRules) 
   1.188 +                        && fStyle == fmt->fStyle); 
   1.189 +        if (ret) {
   1.190 +            for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.191 +                 i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
   1.192 +                 i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.193 +                ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
   1.194 +            }
   1.195 +        }
   1.196 +        return ret;
   1.197 +    }
   1.198 +    return false;
   1.199 +}
   1.200 +
   1.201 +
   1.202 +UnicodeString& 
   1.203 +TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
   1.204 +                       FieldPosition& pos, UErrorCode& status) const {
   1.205 +    if (U_FAILURE(status)) {
   1.206 +        return toAppendTo;
   1.207 +    }
   1.208 +    if (obj.getType() == Formattable::kObject) {
   1.209 +        const UObject* formatObj = obj.getObject();
   1.210 +        const TimeUnitAmount* amount = dynamic_cast<const TimeUnitAmount*>(formatObj);
   1.211 +        if (amount != NULL){
   1.212 +            Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
   1.213 +            double number;
   1.214 +            const Formattable& amtNumber = amount->getNumber();
   1.215 +            if (amtNumber.getType() == Formattable::kDouble) {
   1.216 +                number = amtNumber.getDouble();
   1.217 +            } else if (amtNumber.getType() == Formattable::kLong) {
   1.218 +                number = amtNumber.getLong();
   1.219 +            } else {
   1.220 +                status = U_ILLEGAL_ARGUMENT_ERROR;
   1.221 +                return toAppendTo;
   1.222 +            }
   1.223 +            UnicodeString count = fPluralRules->select(number);
   1.224 +#ifdef TMUTFMT_DEBUG
   1.225 +            char result[1000];
   1.226 +            count.extract(0, count.length(), result, "UTF-8");
   1.227 +            std::cout << "number: " << number << "; format plural count: " << result << "\n";           
   1.228 +#endif
   1.229 +            MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
   1.230 +            Formattable formattable[1];
   1.231 +            formattable[0].setDouble(number);
   1.232 +            return pattern->format(formattable, 1, toAppendTo, pos, status);
   1.233 +        }
   1.234 +    }
   1.235 +    status = U_ILLEGAL_ARGUMENT_ERROR;
   1.236 +    return toAppendTo;
   1.237 +}
   1.238 +
   1.239 +
   1.240 +void 
   1.241 +TimeUnitFormat::parseObject(const UnicodeString& source, 
   1.242 +                            Formattable& result,
   1.243 +                            ParsePosition& pos) const {
   1.244 +    double resultNumber = -1; 
   1.245 +    UBool withNumberFormat = false;
   1.246 +    TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.247 +    int32_t oldPos = pos.getIndex();
   1.248 +    int32_t newPos = -1;
   1.249 +    int32_t longestParseDistance = 0;
   1.250 +    UnicodeString* countOfLongestMatch = NULL;
   1.251 +#ifdef TMUTFMT_DEBUG
   1.252 +    char res[1000];
   1.253 +    source.extract(0, source.length(), res, "UTF-8");
   1.254 +    std::cout << "parse source: " << res << "\n";           
   1.255 +#endif
   1.256 +    // parse by iterating through all available patterns
   1.257 +    // and looking for the longest match.
   1.258 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.259 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.260 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.261 +        Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
   1.262 +        int32_t elemPos = -1;
   1.263 +        const UHashElement* elem = NULL;
   1.264 +        while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
   1.265 +            const UHashTok keyTok = elem->key;
   1.266 +            UnicodeString* count = (UnicodeString*)keyTok.pointer;
   1.267 +#ifdef TMUTFMT_DEBUG
   1.268 +            count->extract(0, count->length(), res, "UTF-8");
   1.269 +            std::cout << "parse plural count: " << res << "\n";           
   1.270 +#endif
   1.271 +            const UHashTok valueTok = elem->value;
   1.272 +            // the value is a pair of MessageFormat*
   1.273 +            MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
   1.274 +            for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT;
   1.275 +                 style = (UTimeUnitFormatStyle)(style + 1)) {
   1.276 +                MessageFormat* pattern = patterns[style];
   1.277 +                pos.setErrorIndex(-1);
   1.278 +                pos.setIndex(oldPos);
   1.279 +                // see if we can parse
   1.280 +                Formattable parsed;
   1.281 +                pattern->parseObject(source, parsed, pos);
   1.282 +                if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
   1.283 +                    continue;
   1.284 +                }
   1.285 +    #ifdef TMUTFMT_DEBUG
   1.286 +                std::cout << "parsed.getType: " << parsed.getType() << "\n";
   1.287 +    #endif
   1.288 +                double tmpNumber = 0;
   1.289 +                if (pattern->getArgTypeCount() != 0) {
   1.290 +                    // pattern with Number as beginning, such as "{0} d".
   1.291 +                    // check to make sure that the timeUnit is consistent
   1.292 +                    Formattable& temp = parsed[0];
   1.293 +                    if (temp.getType() == Formattable::kDouble) {
   1.294 +                        tmpNumber = temp.getDouble();
   1.295 +                    } else if (temp.getType() == Formattable::kLong) {
   1.296 +                        tmpNumber = temp.getLong();
   1.297 +                    } else {
   1.298 +                        continue;
   1.299 +                    }
   1.300 +                    UnicodeString select = fPluralRules->select(tmpNumber);
   1.301 +    #ifdef TMUTFMT_DEBUG
   1.302 +                    select.extract(0, select.length(), res, "UTF-8");
   1.303 +                    std::cout << "parse plural select count: " << res << "\n"; 
   1.304 +    #endif
   1.305 +                    if (*count != select) {
   1.306 +                        continue;
   1.307 +                    }
   1.308 +                }
   1.309 +                int32_t parseDistance = pos.getIndex() - oldPos;
   1.310 +                if (parseDistance > longestParseDistance) {
   1.311 +                    if (pattern->getArgTypeCount() != 0) {
   1.312 +                        resultNumber = tmpNumber;
   1.313 +                        withNumberFormat = true;
   1.314 +                    } else {
   1.315 +                        withNumberFormat = false;
   1.316 +                    }
   1.317 +                    resultTimeUnit = i;
   1.318 +                    newPos = pos.getIndex();
   1.319 +                    longestParseDistance = parseDistance;
   1.320 +                    countOfLongestMatch = count;
   1.321 +                }
   1.322 +            }
   1.323 +        }
   1.324 +    }
   1.325 +    /* After find the longest match, parse the number.
   1.326 +     * Result number could be null for the pattern without number pattern.
   1.327 +     * such as unit pattern in Arabic.
   1.328 +     * When result number is null, use plural rule to set the number.
   1.329 +     */
   1.330 +    if (withNumberFormat == false && longestParseDistance != 0) {
   1.331 +        // set the number using plurrual count
   1.332 +        if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) {
   1.333 +            resultNumber = 0;
   1.334 +        } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) {
   1.335 +            resultNumber = 1;
   1.336 +        } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) {
   1.337 +            resultNumber = 2;
   1.338 +        } else {
   1.339 +            // should not happen.
   1.340 +            // TODO: how to handle?
   1.341 +            resultNumber = 3;
   1.342 +        }
   1.343 +    }
   1.344 +    if (longestParseDistance == 0) {
   1.345 +        pos.setIndex(oldPos);
   1.346 +        pos.setErrorIndex(0);
   1.347 +    } else {
   1.348 +        UErrorCode status = U_ZERO_ERROR;
   1.349 +        TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
   1.350 +        if (U_SUCCESS(status)) {
   1.351 +            result.adoptObject(tmutamt);
   1.352 +            pos.setIndex(newPos);
   1.353 +            pos.setErrorIndex(-1);
   1.354 +        } else {
   1.355 +            pos.setIndex(oldPos);
   1.356 +            pos.setErrorIndex(0);
   1.357 +        }
   1.358 +    }
   1.359 +}
   1.360 +
   1.361 +void
   1.362 +TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
   1.363 +    if (U_FAILURE(status)) {
   1.364 +        return;
   1.365 +    }
   1.366 +    if (style < UTMUTFMT_FULL_STYLE || style >= UTMUTFMT_FORMAT_STYLE_COUNT) {
   1.367 +        status = U_ILLEGAL_ARGUMENT_ERROR;
   1.368 +        return;
   1.369 +    }
   1.370 +    fStyle = style;
   1.371 +    fLocale = locale;
   1.372 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.373 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.374 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.375 +        fTimeUnitToCountToPatterns[i] = NULL;
   1.376 +    }
   1.377 +    //TODO: format() and parseObj() are const member functions,
   1.378 +    //so, can not do lazy initialization in C++.
   1.379 +    //setup has to be done in constructors.
   1.380 +    //and here, the behavior is not consistent with Java.
   1.381 +    //In Java, create an empty instance does not setup locale as
   1.382 +    //default locale. If it followed by setNumberFormat(),
   1.383 +    //in format(), the locale will set up as the locale in fNumberFormat.
   1.384 +    //But in C++, this sets the locale as the default locale. 
   1.385 +    setup(status);
   1.386 +}
   1.387 +
   1.388 +void 
   1.389 +TimeUnitFormat::setup(UErrorCode& err) {
   1.390 +    initDataMembers(err);
   1.391 +
   1.392 +    UVector pluralCounts(0, uhash_compareUnicodeString, 6, err);
   1.393 +    StringEnumeration* keywords = fPluralRules->getKeywords(err);
   1.394 +    if (U_FAILURE(err)) {
   1.395 +        return;
   1.396 +    }
   1.397 +    UnicodeString* pluralCount;
   1.398 +    while ((pluralCount = const_cast<UnicodeString*>(keywords->snext(err))) != NULL) {
   1.399 +      pluralCounts.addElement(pluralCount, err);
   1.400 +    }
   1.401 +    readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, pluralCounts, err);
   1.402 +    checkConsistency(UTMUTFMT_FULL_STYLE, gUnitsTag, err);
   1.403 +    readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, pluralCounts, err);
   1.404 +    checkConsistency(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err);
   1.405 +    delete keywords;
   1.406 +}
   1.407 +
   1.408 +
   1.409 +void
   1.410 +TimeUnitFormat::initDataMembers(UErrorCode& err){
   1.411 +    if (U_FAILURE(err)) {
   1.412 +        return;
   1.413 +    }
   1.414 +    if (fNumberFormat == NULL) {
   1.415 +        fNumberFormat = NumberFormat::createInstance(fLocale, err);
   1.416 +    }
   1.417 +    delete fPluralRules;
   1.418 +    fPluralRules = PluralRules::forLocale(fLocale, err);
   1.419 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.420 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.421 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.422 +        deleteHash(fTimeUnitToCountToPatterns[i]);
   1.423 +        fTimeUnitToCountToPatterns[i] = NULL;
   1.424 +    }
   1.425 +}
   1.426 +
   1.427 +void
   1.428 +TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key,
   1.429 +                                      const UVector& pluralCounts, UErrorCode& err) {
   1.430 +    if (U_FAILURE(err)) {
   1.431 +        return;
   1.432 +    }
   1.433 +    // fill timeUnitToCountToPatterns from resource file
   1.434 +    // err is used to indicate wrong status except missing resource.
   1.435 +    // status is an error code used in resource lookup.
   1.436 +    // status does not affect "err".
   1.437 +    UErrorCode status = U_ZERO_ERROR;
   1.438 +    UResourceBundle *rb, *unitsRes;
   1.439 +    rb = ures_open(NULL, fLocale.getName(), &status);
   1.440 +    unitsRes = ures_getByKey(rb, key, NULL, &status);
   1.441 +    unitsRes = ures_getByKey(unitsRes, "duration", unitsRes, &status);
   1.442 +    if (U_FAILURE(status)) {
   1.443 +        ures_close(unitsRes);
   1.444 +        ures_close(rb);
   1.445 +        return;
   1.446 +    }
   1.447 +    int32_t size = ures_getSize(unitsRes);
   1.448 +    for ( int32_t index = 0; index < size; ++index) {
   1.449 +        // resource of one time unit
   1.450 +        UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
   1.451 +                                                       NULL, &status);
   1.452 +        if (U_SUCCESS(status)) {
   1.453 +            const char* timeUnitName = ures_getKey(oneTimeUnit);
   1.454 +            if (timeUnitName == NULL) {
   1.455 +                ures_close(oneTimeUnit);
   1.456 +                continue;
   1.457 +            }
   1.458 +            UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes, 
   1.459 +                                                             timeUnitName, 
   1.460 +                                                             NULL, &status);
   1.461 +            if (countsToPatternRB == NULL || U_FAILURE(status)) {
   1.462 +                ures_close(countsToPatternRB);
   1.463 +                ures_close(oneTimeUnit);
   1.464 +                continue;
   1.465 +            }
   1.466 +            TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.467 +            if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
   1.468 +                timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
   1.469 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
   1.470 +                timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
   1.471 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
   1.472 +                timeUnitField = TimeUnit::UTIMEUNIT_DAY;
   1.473 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
   1.474 +                timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
   1.475 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
   1.476 +                timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
   1.477 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
   1.478 +                timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
   1.479 +            } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
   1.480 +                timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
   1.481 +            } else {
   1.482 +                ures_close(countsToPatternRB);
   1.483 +                ures_close(oneTimeUnit);
   1.484 +                continue;
   1.485 +            }
   1.486 +            Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
   1.487 +            if (countToPatterns == NULL) {
   1.488 +                countToPatterns = initHash(err);
   1.489 +                if (U_FAILURE(err)) {
   1.490 +                    ures_close(countsToPatternRB);
   1.491 +                    ures_close(oneTimeUnit);
   1.492 +                    delete countToPatterns;
   1.493 +                    break;
   1.494 +                }
   1.495 +            }
   1.496 +            int32_t count = ures_getSize(countsToPatternRB);
   1.497 +            const char*  pluralCount;
   1.498 +            for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
   1.499 +                // resource of count to pattern
   1.500 +                UnicodeString pattern =
   1.501 +                    ures_getNextUnicodeString(countsToPatternRB, &pluralCount, &status);
   1.502 +                if (U_FAILURE(status)) {
   1.503 +                    continue;
   1.504 +                }
   1.505 +                UnicodeString pluralCountUniStr(pluralCount, -1, US_INV);
   1.506 +                if (!pluralCounts.contains(&pluralCountUniStr)) {
   1.507 +                  continue;
   1.508 +                }
   1.509 +                MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
   1.510 +                if ( U_SUCCESS(err) ) {
   1.511 +                  if (fNumberFormat != NULL) {
   1.512 +                    messageFormat->setFormat(0, *fNumberFormat);
   1.513 +                  }
   1.514 +                  MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr);
   1.515 +                  if (formatters == NULL) {
   1.516 +                    formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
   1.517 +                    formatters[UTMUTFMT_FULL_STYLE] = NULL;
   1.518 +                    formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
   1.519 +                    countToPatterns->put(pluralCountUniStr, formatters, err);
   1.520 +                    if (U_FAILURE(err)) {
   1.521 +                        uprv_free(formatters);
   1.522 +                    }
   1.523 +                  } 
   1.524 +                  if (U_SUCCESS(err)) {
   1.525 +                      //delete formatters[style];
   1.526 +                      formatters[style] = messageFormat;
   1.527 +                  }
   1.528 +                } 
   1.529 +                if (U_FAILURE(err)) {
   1.530 +                    ures_close(countsToPatternRB);
   1.531 +                    ures_close(oneTimeUnit);
   1.532 +                    ures_close(unitsRes);
   1.533 +                    ures_close(rb);
   1.534 +                    delete messageFormat;
   1.535 +                    delete countToPatterns;
   1.536 +                    return;
   1.537 +                }
   1.538 +            }
   1.539 +            if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
   1.540 +                fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
   1.541 +            }
   1.542 +            ures_close(countsToPatternRB);
   1.543 +        }
   1.544 +        ures_close(oneTimeUnit);
   1.545 +    }
   1.546 +    ures_close(unitsRes);
   1.547 +    ures_close(rb);
   1.548 +}
   1.549 +
   1.550 +
   1.551 +void 
   1.552 +TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) {
   1.553 +    if (U_FAILURE(err)) {
   1.554 +        return;
   1.555 +    }
   1.556 +    // there should be patterns for each plural rule in each time unit.
   1.557 +    // For each time unit, 
   1.558 +    //     for each plural rule, following is unit pattern fall-back rule:
   1.559 +    //         ( for example: "one" hour )
   1.560 +    //         look for its unit pattern in its locale tree.
   1.561 +    //         if pattern is not found in its own locale, such as de_DE,
   1.562 +    //         look for the pattern in its parent, such as de,
   1.563 +    //         keep looking till found or till root.
   1.564 +    //         if the pattern is not found in root either,
   1.565 +    //         fallback to plural count "other",
   1.566 +    //         look for the pattern of "other" in the locale tree:
   1.567 +    //         "de_DE" to "de" to "root".
   1.568 +    //         If not found, fall back to value of 
   1.569 +    //         static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". 
   1.570 +    //
   1.571 +    // Following is consistency check to create pattern for each
   1.572 +    // plural rule in each time unit using above fall-back rule.
   1.573 +    //
   1.574 +    StringEnumeration* keywords = fPluralRules->getKeywords(err);
   1.575 +    if (U_SUCCESS(err)) {
   1.576 +        const UnicodeString* pluralCount;
   1.577 +        while ((pluralCount = keywords->snext(err)) != NULL) {
   1.578 +            if ( U_SUCCESS(err) ) {
   1.579 +                for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
   1.580 +                    // for each time unit, 
   1.581 +                    // get all the patterns for each plural rule in this locale.
   1.582 +                    Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
   1.583 +                    if ( countToPatterns == NULL ) {
   1.584 +                        countToPatterns = initHash(err);
   1.585 +                        if (U_FAILURE(err)) {
   1.586 +                            delete countToPatterns;
   1.587 +                            return;
   1.588 +                        }
   1.589 +                        fTimeUnitToCountToPatterns[i] = countToPatterns;
   1.590 +                    }
   1.591 +                    MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount);
   1.592 +                    if( formatters == NULL || formatters[style] == NULL ) {
   1.593 +                        // look through parents
   1.594 +                        const char* localeName = fLocale.getName();
   1.595 +                        CharString pluralCountChars;
   1.596 +                        pluralCountChars.appendInvariantChars(*pluralCount, err);
   1.597 +                        searchInLocaleChain(style, key, localeName,
   1.598 +                                            (TimeUnit::UTimeUnitFields)i, 
   1.599 +                                            *pluralCount, pluralCountChars.data(), 
   1.600 +                                            countToPatterns, err);
   1.601 +                    }
   1.602 +                }
   1.603 +            }
   1.604 +        }
   1.605 +    }
   1.606 +    delete keywords;
   1.607 +}
   1.608 +
   1.609 +
   1.610 +
   1.611 +// srcPluralCount is the original plural count on which the pattern is
   1.612 +// searched for.
   1.613 +// searchPluralCount is the fallback plural count.
   1.614 +// For example, to search for pattern for ""one" hour",
   1.615 +// "one" is the srcPluralCount,
   1.616 +// if the pattern is not found even in root, fallback to 
   1.617 +// using patterns of plural count "other", 
   1.618 +// then, "other" is the searchPluralCount.
   1.619 +void 
   1.620 +TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key, const char* localeName,
   1.621 +                                TimeUnit::UTimeUnitFields srcTimeUnitField,
   1.622 +                                const UnicodeString& srcPluralCount,
   1.623 +                                const char* searchPluralCount, 
   1.624 +                                Hashtable* countToPatterns,
   1.625 +                                UErrorCode& err) {
   1.626 +    if (U_FAILURE(err)) {
   1.627 +        return;
   1.628 +    }
   1.629 +    UErrorCode status = U_ZERO_ERROR;
   1.630 +    char parentLocale[ULOC_FULLNAME_CAPACITY];
   1.631 +    uprv_strcpy(parentLocale, localeName);
   1.632 +    int32_t locNameLen;
   1.633 +    U_ASSERT(countToPatterns != NULL);
   1.634 +    while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
   1.635 +                                        ULOC_FULLNAME_CAPACITY, &status)) >= 0){
   1.636 +        // look for pattern for srcPluralCount in locale tree
   1.637 +        UResourceBundle *rb, *unitsRes, *countsToPatternRB;
   1.638 +        rb = ures_open(NULL, parentLocale, &status);
   1.639 +        unitsRes = ures_getByKey(rb, key, NULL, &status);
   1.640 +        const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
   1.641 +        countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
   1.642 +        const UChar* pattern;
   1.643 +        int32_t      ptLength;
   1.644 +        pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
   1.645 +        if (U_SUCCESS(status)) {
   1.646 +            //found
   1.647 +            MessageFormat* messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, ptLength), fLocale, err);
   1.648 +            if (U_SUCCESS(err)) {
   1.649 +                if (fNumberFormat != NULL) {
   1.650 +                    messageFormat->setFormat(0, *fNumberFormat);
   1.651 +                }
   1.652 +                MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
   1.653 +                if (formatters == NULL) {
   1.654 +                    formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
   1.655 +                    formatters[UTMUTFMT_FULL_STYLE] = NULL;
   1.656 +                    formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
   1.657 +                    countToPatterns->put(srcPluralCount, formatters, err);
   1.658 +                    if (U_FAILURE(err)) {
   1.659 +                        uprv_free(formatters);
   1.660 +                        delete messageFormat;
   1.661 +                    }
   1.662 +                } 
   1.663 +                if (U_SUCCESS(err)) {
   1.664 +                    //delete formatters[style];
   1.665 +                    formatters[style] = messageFormat;
   1.666 +                }
   1.667 +            } else {
   1.668 +                delete messageFormat;
   1.669 +            }
   1.670 +            ures_close(countsToPatternRB);
   1.671 +            ures_close(unitsRes);
   1.672 +            ures_close(rb);
   1.673 +            return;
   1.674 +        }
   1.675 +        ures_close(countsToPatternRB);
   1.676 +        ures_close(unitsRes);
   1.677 +        ures_close(rb);
   1.678 +        status = U_ZERO_ERROR;
   1.679 +        if ( locNameLen ==0 ) {
   1.680 +            break;
   1.681 +        }
   1.682 +    }
   1.683 +
   1.684 +    // if no unitsShort resource was found even after fallback to root locale
   1.685 +    // then search the units resource fallback from the current level to root
   1.686 +    if ( locNameLen == 0 && uprv_strcmp(key, gShortUnitsTag) == 0) {
   1.687 +#ifdef TMUTFMT_DEBUG
   1.688 +        std::cout << "loop into searchInLocaleChain since Short-Long-Alternative \n";
   1.689 +#endif
   1.690 +        char pLocale[ULOC_FULLNAME_CAPACITY];
   1.691 +        uprv_strcpy(pLocale, localeName);
   1.692 +        // Add an underscore at the tail of locale name,
   1.693 +        // so that searchInLocaleChain will check the current locale before falling back
   1.694 +        uprv_strcat(pLocale, "_");
   1.695 +        searchInLocaleChain(style, gUnitsTag, pLocale, srcTimeUnitField, srcPluralCount,
   1.696 +                             searchPluralCount, countToPatterns, err);
   1.697 +        MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
   1.698 +        if (formatters != NULL && formatters[style] != NULL) {
   1.699 +            return;
   1.700 +        }
   1.701 +    }
   1.702 +
   1.703 +    // if not found the pattern for this plural count at all,
   1.704 +    // fall-back to plural count "other"
   1.705 +    if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
   1.706 +        // set default fall back the same as the resource in root
   1.707 +        MessageFormat* messageFormat = NULL;
   1.708 +        const UChar *pattern = NULL;
   1.709 +        if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
   1.710 +            pattern = DEFAULT_PATTERN_FOR_SECOND;
   1.711 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
   1.712 +            pattern = DEFAULT_PATTERN_FOR_MINUTE;
   1.713 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
   1.714 +            pattern = DEFAULT_PATTERN_FOR_HOUR;
   1.715 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
   1.716 +            pattern = DEFAULT_PATTERN_FOR_WEEK;
   1.717 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
   1.718 +            pattern = DEFAULT_PATTERN_FOR_DAY;
   1.719 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
   1.720 +            pattern = DEFAULT_PATTERN_FOR_MONTH;
   1.721 +        } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
   1.722 +            pattern = DEFAULT_PATTERN_FOR_YEAR;
   1.723 +        }
   1.724 +        if (pattern != NULL) {
   1.725 +            messageFormat = new MessageFormat(UnicodeString(TRUE, pattern, -1), fLocale, err);
   1.726 +        }
   1.727 +        if (U_SUCCESS(err)) {
   1.728 +            if (fNumberFormat != NULL && messageFormat != NULL) {
   1.729 +                messageFormat->setFormat(0, *fNumberFormat);
   1.730 +            }
   1.731 +            MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
   1.732 +            if (formatters == NULL) {
   1.733 +                formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
   1.734 +                formatters[UTMUTFMT_FULL_STYLE] = NULL;
   1.735 +                formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL;
   1.736 +                countToPatterns->put(srcPluralCount, formatters, err);
   1.737 +                if (U_FAILURE(err)) {
   1.738 +                    uprv_free(formatters);
   1.739 +                    delete messageFormat;
   1.740 +                }
   1.741 +            }
   1.742 +            if (U_SUCCESS(err)) {
   1.743 +                //delete formatters[style];
   1.744 +                formatters[style] = messageFormat;
   1.745 +            }
   1.746 +        } else {
   1.747 +            delete messageFormat;
   1.748 +        }
   1.749 +    } else {
   1.750 +        // fall back to rule "other", and search in parents
   1.751 +        searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount, 
   1.752 +                            gPluralCountOther, countToPatterns, err);
   1.753 +    }
   1.754 +}
   1.755 +
   1.756 +void 
   1.757 +TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
   1.758 +    if (U_SUCCESS(status) && fLocale != locale) {
   1.759 +        fLocale = locale;
   1.760 +        setup(status);
   1.761 +    }
   1.762 +}
   1.763 +
   1.764 +
   1.765 +void 
   1.766 +TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
   1.767 +    if (U_FAILURE(status) || (fNumberFormat && format == *fNumberFormat)) {
   1.768 +        return;
   1.769 +    }
   1.770 +    delete fNumberFormat;
   1.771 +    fNumberFormat = (NumberFormat*)format.clone();
   1.772 +    // reset the number formatter in the fTimeUnitToCountToPatterns map
   1.773 +    for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
   1.774 +         i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
   1.775 +         i = (TimeUnit::UTimeUnitFields)(i+1)) {
   1.776 +        int32_t pos = -1;
   1.777 +        const UHashElement* elem = NULL;
   1.778 +        while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
   1.779 +            const UHashTok keyTok = elem->value;
   1.780 +            MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
   1.781 +
   1.782 +            pattern[UTMUTFMT_FULL_STYLE]->setFormat(0, format);
   1.783 +            pattern[UTMUTFMT_ABBREVIATED_STYLE]->setFormat(0, format);
   1.784 +        }
   1.785 +    }
   1.786 +}
   1.787 +
   1.788 +
   1.789 +void
   1.790 +TimeUnitFormat::deleteHash(Hashtable* htable) {
   1.791 +    int32_t pos = -1;
   1.792 +    const UHashElement* element = NULL;
   1.793 +    if ( htable ) {
   1.794 +        while ( (element = htable->nextElement(pos)) != NULL ) {
   1.795 +            const UHashTok valueTok = element->value;
   1.796 +            const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
   1.797 +            delete value[UTMUTFMT_FULL_STYLE];
   1.798 +            delete value[UTMUTFMT_ABBREVIATED_STYLE];
   1.799 +            //delete[] value;
   1.800 +            uprv_free(value);
   1.801 +        }
   1.802 +    }
   1.803 +    delete htable;
   1.804 +}
   1.805 +
   1.806 +
   1.807 +void
   1.808 +TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
   1.809 +    if ( U_FAILURE(status) ) {
   1.810 +        return;
   1.811 +    }
   1.812 +    int32_t pos = -1;
   1.813 +    const UHashElement* element = NULL;
   1.814 +    if ( source ) {
   1.815 +        while ( (element = source->nextElement(pos)) != NULL ) {
   1.816 +            const UHashTok keyTok = element->key;
   1.817 +            const UnicodeString* key = (UnicodeString*)keyTok.pointer;
   1.818 +            const UHashTok valueTok = element->value;
   1.819 +            const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
   1.820 +            MessageFormat** newVal = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
   1.821 +            newVal[0] = (MessageFormat*)value[0]->clone();
   1.822 +            newVal[1] = (MessageFormat*)value[1]->clone();
   1.823 +            target->put(UnicodeString(*key), newVal, status);
   1.824 +            if ( U_FAILURE(status) ) {
   1.825 +                delete newVal[0];
   1.826 +                delete newVal[1];
   1.827 +                uprv_free(newVal);
   1.828 +                return;
   1.829 +            }
   1.830 +        }
   1.831 +    }
   1.832 +}
   1.833 +
   1.834 +
   1.835 +U_CDECL_BEGIN 
   1.836 +
   1.837 +/**
   1.838 + * set hash table value comparator
   1.839 + *
   1.840 + * @param val1  one value in comparison
   1.841 + * @param val2  the other value in comparison
   1.842 + * @return      TRUE if 2 values are the same, FALSE otherwise
   1.843 + */
   1.844 +static UBool U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2);
   1.845 +
   1.846 +static UBool
   1.847 +U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2) {
   1.848 +    const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
   1.849 +    const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
   1.850 +    return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
   1.851 +}
   1.852 +
   1.853 +U_CDECL_END
   1.854 +
   1.855 +Hashtable*
   1.856 +TimeUnitFormat::initHash(UErrorCode& status) {
   1.857 +    if ( U_FAILURE(status) ) {
   1.858 +        return NULL;
   1.859 +    }
   1.860 +    Hashtable* hTable;
   1.861 +    if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
   1.862 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.863 +        return NULL;
   1.864 +    }
   1.865 +    if ( U_FAILURE(status) ) {
   1.866 +        delete hTable; 
   1.867 +        return NULL;
   1.868 +    }
   1.869 +    hTable->setValueComparator(tmutfmtHashTableValueComparator);
   1.870 +    return hTable;
   1.871 +}
   1.872 +
   1.873 +
   1.874 +const char*
   1.875 +TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField, 
   1.876 +                                UErrorCode& status) {
   1.877 +    if (U_FAILURE(status)) {
   1.878 +        return NULL;
   1.879 +    }
   1.880 +    switch (unitField) {
   1.881 +      case TimeUnit::UTIMEUNIT_YEAR:
   1.882 +        return gTimeUnitYear;
   1.883 +      case TimeUnit::UTIMEUNIT_MONTH:
   1.884 +        return gTimeUnitMonth;
   1.885 +      case TimeUnit::UTIMEUNIT_DAY:
   1.886 +        return gTimeUnitDay;
   1.887 +      case TimeUnit::UTIMEUNIT_WEEK:
   1.888 +        return gTimeUnitWeek;
   1.889 +      case TimeUnit::UTIMEUNIT_HOUR:
   1.890 +        return gTimeUnitHour;
   1.891 +      case TimeUnit::UTIMEUNIT_MINUTE:
   1.892 +        return gTimeUnitMinute;
   1.893 +      case TimeUnit::UTIMEUNIT_SECOND:
   1.894 +        return gTimeUnitSecond;
   1.895 +      default:
   1.896 +        status = U_ILLEGAL_ARGUMENT_ERROR;
   1.897 +        return NULL;
   1.898 +    }
   1.899 +}
   1.900 +
   1.901 +U_NAMESPACE_END
   1.902 +
   1.903 +#endif

mercurial