X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/729e4ab9bc6618bc3d8a898e575df7f4019e29ca..f59164e3d128c7675a4d3934206346a3384e53a5:/icuSources/i18n/tmutfmt.cpp diff --git a/icuSources/i18n/tmutfmt.cpp b/icuSources/i18n/tmutfmt.cpp index f8ad9a39..fa31d7b3 100644 --- a/icuSources/i18n/tmutfmt.cpp +++ b/icuSources/i18n/tmutfmt.cpp @@ -1,21 +1,26 @@ /* ******************************************************************************* - * Copyright (C) 2008-2011, Google, International Business Machines Corporation - * and others. All Rights Reserved. + * Copyright (C) 2008-2015, Google, International Business Machines Corporation + * and others. All Rights Reserved. ******************************************************************************* */ -#include // for 'typeid' to work - #include "unicode/tmutfmt.h" #if !UCONFIG_NO_FORMATTING +#include "unicode/decimfmt.h" +#include "unicode/localpointer.h" +#include "plurrule_impl.h" +#include "uvector.h" +#include "charstr.h" #include "cmemory.h" #include "cstring.h" #include "hash.h" #include "uresimp.h" +#include "ureslocs.h" #include "unicode/msgfmt.h" +#include "uassert.h" #define LEFT_CURLY_BRACKET ((UChar)0x007B) #define RIGHT_CURLY_BRACKET ((UChar)0x007D) @@ -73,82 +78,80 @@ static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0}; static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0}; static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0}; - -TimeUnitFormat::TimeUnitFormat(UErrorCode& status) -: fNumberFormat(NULL), - fPluralRules(NULL) { - create(Locale::getDefault(), kFull, status); +TimeUnitFormat::TimeUnitFormat(UErrorCode& status) { + initMeasureFormat(Locale::getDefault(), UMEASFMT_WIDTH_WIDE, NULL, status); + create(UTMUTFMT_FULL_STYLE, status); } -TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status) -: fNumberFormat(NULL), - fPluralRules(NULL) { - create(locale, kFull, status); +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status) { + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status); + create(UTMUTFMT_FULL_STYLE, status); } -TimeUnitFormat::TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status) -: fNumberFormat(NULL), - fPluralRules(NULL) { - create(locale, style, status); +TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) { + switch (style) { + case UTMUTFMT_FULL_STYLE: + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status); + break; + case UTMUTFMT_ABBREVIATED_STYLE: + initMeasureFormat(locale, UMEASFMT_WIDTH_SHORT, NULL, status); + break; + default: + initMeasureFormat(locale, UMEASFMT_WIDTH_WIDE, NULL, status); + break; + } + create(style, status); } - TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other) : MeasureFormat(other), - fNumberFormat(NULL), - fPluralRules(NULL), - fStyle(kFull) + fStyle(other.fStyle) { for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { - fTimeUnitToCountToPatterns[i] = NULL; + UErrorCode status = U_ZERO_ERROR; + fTimeUnitToCountToPatterns[i] = initHash(status); + if (U_SUCCESS(status)) { + copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status); + } else { + delete fTimeUnitToCountToPatterns[i]; + fTimeUnitToCountToPatterns[i] = NULL; + } } - *this = other; } TimeUnitFormat::~TimeUnitFormat() { - delete fNumberFormat; - fNumberFormat = NULL; for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { deleteHash(fTimeUnitToCountToPatterns[i]); fTimeUnitToCountToPatterns[i] = NULL; } - delete fPluralRules; - fPluralRules = NULL; } -Format* +Format* TimeUnitFormat::clone(void) const { return new TimeUnitFormat(*this); } -TimeUnitFormat& +TimeUnitFormat& TimeUnitFormat::operator=(const TimeUnitFormat& other) { if (this == &other) { return *this; } - delete fNumberFormat; + MeasureFormat::operator=(other); for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { deleteHash(fTimeUnitToCountToPatterns[i]); fTimeUnitToCountToPatterns[i] = NULL; } - delete fPluralRules; - if (other.fNumberFormat) { - fNumberFormat = (NumberFormat*)other.fNumberFormat->clone(); - } else { - fNumberFormat = NULL; - } - fLocale = other.fLocale; for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { @@ -160,83 +163,16 @@ TimeUnitFormat::operator=(const TimeUnitFormat& other) { delete fTimeUnitToCountToPatterns[i]; fTimeUnitToCountToPatterns[i] = NULL; } - } - if (other.fPluralRules) { - fPluralRules = (PluralRules*)other.fPluralRules->clone(); - } else { - fPluralRules = NULL; } fStyle = other.fStyle; return *this; } - -UBool -TimeUnitFormat::operator==(const Format& other) const { - if (typeid(*this) == typeid(other)) { - TimeUnitFormat* fmt = (TimeUnitFormat*)&other; - UBool ret = ( ((fNumberFormat && fmt->fNumberFormat && *fNumberFormat == *fmt->fNumberFormat) - || fNumberFormat == fmt->fNumberFormat ) - && fLocale == fmt->fLocale - && ((fPluralRules && fmt->fPluralRules && *fPluralRules == *fmt->fPluralRules) - || fPluralRules == fmt->fPluralRules) - && fStyle == fmt->fStyle); - if (ret) { - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; - i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret; - i = (TimeUnit::UTimeUnitFields)(i+1)) { - ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i])); - } - } - return ret; - } - return false; -} - - -UnicodeString& -TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo, - FieldPosition& pos, UErrorCode& status) const { - if (U_FAILURE(status)) { - return toAppendTo; - } - if (obj.getType() == Formattable::kObject) { - const UObject* formatObj = obj.getObject(); - const TimeUnitAmount* amount = dynamic_cast(formatObj); - if (amount != NULL){ - Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()]; - double number; - const Formattable& amtNumber = amount->getNumber(); - if (amtNumber.getType() == Formattable::kDouble) { - number = amtNumber.getDouble(); - } else if (amtNumber.getType() == Formattable::kLong) { - number = amtNumber.getLong(); - } else { - status = U_ILLEGAL_ARGUMENT_ERROR; - return toAppendTo; - } - UnicodeString count = fPluralRules->select(number); -#ifdef TMUTFMT_DEBUG - char result[1000]; - count.extract(0, count.length(), result, "UTF-8"); - std::cout << "number: " << number << "; format plural count: " << result << "\n"; -#endif - MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle]; - Formattable formattable[1]; - formattable[0].setDouble(number); - return pattern->format(formattable, 1, toAppendTo, pos, status); - } - } - status = U_ILLEGAL_ARGUMENT_ERROR; - return toAppendTo; -} - - -void -TimeUnitFormat::parseObject(const UnicodeString& source, +void +TimeUnitFormat::parseObject(const UnicodeString& source, Formattable& result, ParsePosition& pos) const { - double resultNumber = -1; + Formattable resultNumber(0.0); UBool withNumberFormat = false; TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT; int32_t oldPos = pos.getIndex(); @@ -246,7 +182,7 @@ TimeUnitFormat::parseObject(const UnicodeString& source, #ifdef TMUTFMT_DEBUG char res[1000]; source.extract(0, source.length(), res, "UTF-8"); - std::cout << "parse source: " << res << "\n"; + std::cout << "parse source: " << res << "\n"; #endif // parse by iterating through all available patterns // and looking for the longest match. @@ -254,19 +190,20 @@ TimeUnitFormat::parseObject(const UnicodeString& source, i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; - int32_t elemPos = -1; + int32_t elemPos = UHASH_FIRST; const UHashElement* elem = NULL; while ((elem = countToPatterns->nextElement(elemPos)) != NULL){ const UHashTok keyTok = elem->key; UnicodeString* count = (UnicodeString*)keyTok.pointer; #ifdef TMUTFMT_DEBUG count->extract(0, count->length(), res, "UTF-8"); - std::cout << "parse plural count: " << res << "\n"; + std::cout << "parse plural count: " << res << "\n"; #endif const UHashTok valueTok = elem->value; // the value is a pair of MessageFormat* MessageFormat** patterns = (MessageFormat**)valueTok.pointer; - for (EStyle style = kFull; style < kTotal; style = (EStyle)(style + 1)) { + for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT; + style = (UTimeUnitFormatStyle)(style + 1)) { MessageFormat* pattern = patterns[style]; pos.setErrorIndex(-1); pos.setIndex(oldPos); @@ -279,26 +216,21 @@ TimeUnitFormat::parseObject(const UnicodeString& source, #ifdef TMUTFMT_DEBUG std::cout << "parsed.getType: " << parsed.getType() << "\n"; #endif - double tmpNumber = 0; + Formattable tmpNumber(0.0); if (pattern->getArgTypeCount() != 0) { - // pattern with Number as beginning, such as "{0} d". - // check to make sure that the timeUnit is consistent Formattable& temp = parsed[0]; - if (temp.getType() == Formattable::kDouble) { - tmpNumber = temp.getDouble(); - } else if (temp.getType() == Formattable::kLong) { - tmpNumber = temp.getLong(); + if (temp.getType() == Formattable::kString) { + UnicodeString tmpString; + UErrorCode pStatus = U_ZERO_ERROR; + getNumberFormat().parse(temp.getString(tmpString), tmpNumber, pStatus); + if (U_FAILURE(pStatus)) { + continue; + } + } else if (temp.isNumeric()) { + tmpNumber = temp; } else { continue; } - UnicodeString select = fPluralRules->select(tmpNumber); - #ifdef TMUTFMT_DEBUG - select.extract(0, select.length(), res, "UTF-8"); - std::cout << "parse plural select count: " << res << "\n"; - #endif - if (*count != select) { - continue; - } } int32_t parseDistance = pos.getIndex() - oldPos; if (parseDistance > longestParseDistance) { @@ -323,16 +255,16 @@ TimeUnitFormat::parseObject(const UnicodeString& source, */ if (withNumberFormat == false && longestParseDistance != 0) { // set the number using plurrual count - if ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) { - resultNumber = 0; - } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) { - resultNumber = 1; - } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) { - resultNumber = 2; + if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) { + resultNumber = Formattable(0.0); + } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) { + resultNumber = Formattable(1.0); + } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) { + resultNumber = Formattable(2.0); } else { // should not happen. // TODO: how to handle? - resultNumber = 3; + resultNumber = Formattable(3.0); } } if (longestParseDistance == 0) { @@ -340,9 +272,9 @@ TimeUnitFormat::parseObject(const UnicodeString& source, pos.setErrorIndex(0); } else { UErrorCode status = U_ZERO_ERROR; - TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status); + LocalPointer tmutamt(new TimeUnitAmount(resultNumber, resultTimeUnit, status), status); if (U_SUCCESS(status)) { - result.adoptObject(tmutamt); + result.adoptObject(tmutamt.orphan()); pos.setIndex(newPos); pos.setErrorIndex(-1); } else { @@ -352,23 +284,25 @@ TimeUnitFormat::parseObject(const UnicodeString& source, } } - void -TimeUnitFormat::create(const Locale& locale, EStyle style, UErrorCode& status) { +TimeUnitFormat::create(UTimeUnitFormatStyle style, UErrorCode& status) { + // fTimeUnitToCountToPatterns[] must have its elements initialized to NULL first + // before checking for failure status. + for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; + i < TimeUnit::UTIMEUNIT_FIELD_COUNT; + i = (TimeUnit::UTimeUnitFields)(i+1)) { + fTimeUnitToCountToPatterns[i] = NULL; + } + if (U_FAILURE(status)) { return; } - if (style < kFull || style > kAbbreviate) { + if (style < UTMUTFMT_FULL_STYLE || style >= UTMUTFMT_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return; } fStyle = style; - fLocale = locale; - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; - i < TimeUnit::UTIMEUNIT_FIELD_COUNT; - i = (TimeUnit::UTimeUnitFields)(i+1)) { - fTimeUnitToCountToPatterns[i] = NULL; - } + //TODO: format() and parseObj() are const member functions, //so, can not do lazy initialization in C++. //setup has to be done in constructors. @@ -376,17 +310,27 @@ TimeUnitFormat::create(const Locale& locale, EStyle style, UErrorCode& status) { //In Java, create an empty instance does not setup locale as //default locale. If it followed by setNumberFormat(), //in format(), the locale will set up as the locale in fNumberFormat. - //But in C++, this sets the locale as the default locale. + //But in C++, this sets the locale as the default locale. setup(status); } -void +void TimeUnitFormat::setup(UErrorCode& err) { initDataMembers(err); - readFromCurrentLocale(kFull, gUnitsTag, err); - checkConsistency(kFull, gUnitsTag, err); - readFromCurrentLocale(kAbbreviate, gShortUnitsTag, err); - checkConsistency(kAbbreviate, gShortUnitsTag, err); + + UVector pluralCounts(0, uhash_compareUnicodeString, 6, err); + LocalPointer keywords(getPluralRules().getKeywords(err), err); + if (U_FAILURE(err)) { + return; + } + UnicodeString* pluralCount; + while ((pluralCount = const_cast(keywords->snext(err))) != NULL) { + pluralCounts.addElement(pluralCount, err); + } + readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, pluralCounts, err); + checkConsistency(UTMUTFMT_FULL_STYLE, gUnitsTag, err); + readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, pluralCounts, err); + checkConsistency(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err); } @@ -395,11 +339,6 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){ if (U_FAILURE(err)) { return; } - if (fNumberFormat == NULL) { - fNumberFormat = NumberFormat::createInstance(fLocale, err); - } - delete fPluralRules; - fPluralRules = PluralRules::forLocale(fLocale, err); for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { @@ -408,11 +347,9 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){ } } - - - void -TimeUnitFormat::readFromCurrentLocale(EStyle style, const char* key, UErrorCode& err) { +TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, + const UVector& pluralCounts, UErrorCode& err) { if (U_FAILURE(err)) { return; } @@ -421,123 +358,109 @@ TimeUnitFormat::readFromCurrentLocale(EStyle style, const char* key, UErrorCode& // status is an error code used in resource lookup. // status does not affect "err". UErrorCode status = U_ZERO_ERROR; - UResourceBundle *rb, *unitsRes; - rb = ures_open(NULL, fLocale.getName(), &status); - unitsRes = ures_getByKey(rb, key, NULL, &status); + LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_UNIT, getLocaleID(status), &status)); + + LocalUResourceBundlePointer unitsRes(ures_getByKey(rb.getAlias(), key, NULL, &status)); + ures_getByKey(unitsRes.getAlias(), "duration", unitsRes.getAlias(), &status); if (U_FAILURE(status)) { - ures_close(unitsRes); - ures_close(rb); return; } - int32_t size = ures_getSize(unitsRes); + int32_t size = ures_getSize(unitsRes.getAlias()); for ( int32_t index = 0; index < size; ++index) { + status = U_ZERO_ERROR; // resource of one time unit - UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index, - NULL, &status); - if (U_SUCCESS(status)) { - const char* timeUnitName = ures_getKey(oneTimeUnit); - if (timeUnitName == NULL) { - ures_close(oneTimeUnit); - continue; + LocalUResourceBundlePointer oneTimeUnit( + ures_getByIndex(unitsRes.getAlias(), index, NULL, &status)); + if (U_FAILURE(status)) { + continue; + } + const char* timeUnitName = ures_getKey(oneTimeUnit.getAlias()); + if (timeUnitName == NULL) { + continue; + } + LocalUResourceBundlePointer countsToPatternRB( + ures_getByKey(unitsRes.getAlias(), timeUnitName, NULL, &status)); + if (countsToPatternRB.isNull() || U_FAILURE(status)) { + continue; + } + TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT; + if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_YEAR; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_MONTH; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_DAY; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_HOUR; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_MINUTE; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_SECOND; + } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) { + timeUnitField = TimeUnit::UTIMEUNIT_WEEK; + } else { + continue; + } + LocalPointer localCountToPatterns; + Hashtable *countToPatterns = fTimeUnitToCountToPatterns[timeUnitField]; + if (countToPatterns == NULL) { + localCountToPatterns.adoptInsteadAndCheckErrorCode(initHash(err), err); + countToPatterns = localCountToPatterns.getAlias(); + if (U_FAILURE(err)) { + return; } - UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes, - timeUnitName, - NULL, &status); - if (countsToPatternRB == NULL || U_FAILURE(status)) { - ures_close(countsToPatternRB); - ures_close(oneTimeUnit); + } + int32_t count = ures_getSize(countsToPatternRB.getAlias()); + const char* pluralCount; + for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) { + // resource of count to pattern + status = U_ZERO_ERROR; + UnicodeString pattern = + ures_getNextUnicodeString(countsToPatternRB.getAlias(), &pluralCount, &status); + if (U_FAILURE(status)) { continue; } - TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT; - if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_YEAR; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_MONTH; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_DAY; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_HOUR; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_MINUTE; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_SECOND; - } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) { - timeUnitField = TimeUnit::UTIMEUNIT_WEEK; - } else { - ures_close(countsToPatternRB); - ures_close(oneTimeUnit); + UnicodeString pluralCountUniStr(pluralCount, -1, US_INV); + if (!pluralCounts.contains(&pluralCountUniStr)) { continue; } - Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField]; - if (countToPatterns == NULL) { - countToPatterns = initHash(err); - if (U_FAILURE(err)) { - ures_close(countsToPatternRB); - ures_close(oneTimeUnit); - delete countToPatterns; - break; - } + LocalPointer messageFormat(new MessageFormat(pattern, getLocale(err), err), err); + if (U_FAILURE(err)) { + return; } - int32_t count = ures_getSize(countsToPatternRB); - const UChar* pattern; - const char* pluralCount; - int32_t ptLength; - for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) { - // resource of count to pattern - pattern = ures_getNextString(countsToPatternRB, &ptLength, - &pluralCount, &status); - if (U_FAILURE(status)) { - continue; + MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr); + if (formatters == NULL) { + LocalMemory localFormatters( + (MessageFormat **)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*))); + if (localFormatters.isNull()) { + err = U_MEMORY_ALLOCATION_ERROR; + return; } - MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err); - if ( U_SUCCESS(err) ) { - if (fNumberFormat != NULL) { - messageFormat->setFormat(0, *fNumberFormat); - } - MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount); - if (formatters == NULL) { - formatters = (MessageFormat**)uprv_malloc(kTotal*sizeof(MessageFormat*)); - formatters[kFull] = NULL; - formatters[kAbbreviate] = NULL; - countToPatterns->put(pluralCount, formatters, err); - if (U_FAILURE(err)) { - uprv_free(formatters); - } - } - if (U_SUCCESS(err)) { - //delete formatters[style]; - formatters[style] = messageFormat; - } - } + localFormatters[UTMUTFMT_FULL_STYLE] = NULL; + localFormatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL; + countToPatterns->put(pluralCountUniStr, localFormatters.getAlias(), err); if (U_FAILURE(err)) { - ures_close(countsToPatternRB); - ures_close(oneTimeUnit); - ures_close(unitsRes); - ures_close(rb); - delete messageFormat; - delete countToPatterns; return; } + formatters = localFormatters.orphan(); } - if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) { - fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns; - } - ures_close(countsToPatternRB); + //delete formatters[style]; + formatters[style] = messageFormat.orphan(); + } + if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) { + fTimeUnitToCountToPatterns[timeUnitField] = localCountToPatterns.orphan(); } - ures_close(oneTimeUnit); } - ures_close(unitsRes); - ures_close(rb); } -void -TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) { +void +TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) { if (U_FAILURE(err)) { return; } // there should be patterns for each plural rule in each time unit. - // For each time unit, + // For each time unit, // for each plural rule, following is unit pattern fall-back rule: // ( for example: "one" hour ) // look for its unit pattern in its locale tree. @@ -548,43 +471,41 @@ TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) // fallback to plural count "other", // look for the pattern of "other" in the locale tree: // "de_DE" to "de" to "root". - // If not found, fall back to value of - // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". + // If not found, fall back to value of + // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". // // Following is consistency check to create pattern for each // plural rule in each time unit using above fall-back rule. // - StringEnumeration* keywords = fPluralRules->getKeywords(err); - if (U_SUCCESS(err)) { - const char* pluralCount; - while ((pluralCount = keywords->next(NULL, err)) != NULL) { - if ( U_SUCCESS(err) ) { - for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { - // for each time unit, - // get all the patterns for each plural rule in this locale. - Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; - if ( countToPatterns == NULL ) { - countToPatterns = initHash(err); - if (U_FAILURE(err)) { - delete countToPatterns; - return; - } - fTimeUnitToCountToPatterns[i] = countToPatterns; - } - MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount); - if( formatters == NULL || formatters[style] == NULL ) { - // look through parents - const char* localeName = fLocale.getName(); - searchInLocaleChain(style, key, localeName, - (TimeUnit::UTimeUnitFields)i, - pluralCount, pluralCount, - countToPatterns, err); - } + LocalPointer keywords( + getPluralRules().getKeywords(err), err); + const UnicodeString* pluralCount; + while (U_SUCCESS(err) && (pluralCount = keywords->snext(err)) != NULL) { + for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { + // for each time unit, + // get all the patterns for each plural rule in this locale. + Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; + if ( countToPatterns == NULL ) { + fTimeUnitToCountToPatterns[i] = countToPatterns = initHash(err); + if (U_FAILURE(err)) { + return; } } + MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount); + if( formatters == NULL || formatters[style] == NULL ) { + // look through parents + const char* localeName = getLocaleID(err); + CharString pluralCountChars; + pluralCountChars.appendInvariantChars(*pluralCount, err); + searchInLocaleChain(style, key, localeName, + (TimeUnit::UTimeUnitFields)i, + *pluralCount, pluralCountChars.data(), + countToPatterns, err); + } + // TODO: what to do with U_FAILURE(err) at this point. + // As is, the outer loop continues to run, but does nothing. } } - delete keywords; } @@ -594,14 +515,14 @@ TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) // searchPluralCount is the fallback plural count. // For example, to search for pattern for ""one" hour", // "one" is the srcPluralCount, -// if the pattern is not found even in root, fallback to -// using patterns of plural count "other", +// if the pattern is not found even in root, fallback to +// using patterns of plural count "other", // then, "other" is the searchPluralCount. -void -TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key, const char* localeName, +void +TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, const char* key, const char* localeName, TimeUnit::UTimeUnitFields srcTimeUnitField, - const char* srcPluralCount, - const char* searchPluralCount, + const UnicodeString& srcPluralCount, + const char* searchPluralCount, Hashtable* countToPatterns, UErrorCode& err) { if (U_FAILURE(err)) { @@ -611,52 +532,42 @@ TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key, const char* l char parentLocale[ULOC_FULLNAME_CAPACITY]; uprv_strcpy(parentLocale, localeName); int32_t locNameLen; + U_ASSERT(countToPatterns != NULL); while ((locNameLen = uloc_getParent(parentLocale, parentLocale, ULOC_FULLNAME_CAPACITY, &status)) >= 0){ // look for pattern for srcPluralCount in locale tree - UResourceBundle *rb, *unitsRes, *countsToPatternRB; - rb = ures_open(NULL, parentLocale, &status); - unitsRes = ures_getByKey(rb, key, NULL, &status); + LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_UNIT, parentLocale, &status)); + LocalUResourceBundlePointer unitsRes(ures_getByKey(rb.getAlias(), key, NULL, &status)); const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status); - countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status); + LocalUResourceBundlePointer countsToPatternRB(ures_getByKey(unitsRes.getAlias(), timeUnitName, NULL, &status)); const UChar* pattern; int32_t ptLength; - pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status); + pattern = ures_getStringByKeyWithFallback(countsToPatternRB.getAlias(), searchPluralCount, &ptLength, &status); if (U_SUCCESS(status)) { //found - MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err); - if (U_SUCCESS(err)) { - if (fNumberFormat != NULL) { - messageFormat->setFormat(0, *fNumberFormat); - } - MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); - if (formatters == NULL) { - formatters = (MessageFormat**)uprv_malloc(kTotal*sizeof(MessageFormat*)); - formatters[kFull] = NULL; - formatters[kAbbreviate] = NULL; - countToPatterns->put(srcPluralCount, formatters, err); - if (U_FAILURE(err)) { - uprv_free(formatters); - delete messageFormat; - } - } - if (U_SUCCESS(err)) { - //delete formatters[style]; - formatters[style] = messageFormat; + LocalPointer messageFormat( + new MessageFormat(UnicodeString(TRUE, pattern, ptLength), getLocale(err), err), err); + if (U_FAILURE(err)) { + return; + } + MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); + if (formatters == NULL) { + LocalMemory localFormatters( + (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*))); + formatters = localFormatters.getAlias(); + localFormatters[UTMUTFMT_FULL_STYLE] = NULL; + localFormatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL; + countToPatterns->put(srcPluralCount, localFormatters.orphan(), err); + if (U_FAILURE(err)) { + return; } - } else { - delete messageFormat; } - ures_close(countsToPatternRB); - ures_close(unitsRes); - ures_close(rb); + //delete formatters[style]; + formatters[style] = messageFormat.orphan(); return; } - ures_close(countsToPatternRB); - ures_close(unitsRes); - ures_close(rb); status = U_ZERO_ERROR; - if ( locNameLen ==0 ) { + if (locNameLen == 0) { break; } } @@ -667,16 +578,18 @@ TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key, const char* l #ifdef TMUTFMT_DEBUG std::cout << "loop into searchInLocaleChain since Short-Long-Alternative \n"; #endif - char pLocale[ULOC_FULLNAME_CAPACITY]; - uprv_strcpy(pLocale, localeName); + CharString pLocale(localeName, -1, err); // Add an underscore at the tail of locale name, // so that searchInLocaleChain will check the current locale before falling back - uprv_strcat(pLocale, "_"); - searchInLocaleChain(style, gUnitsTag, pLocale, srcTimeUnitField, srcPluralCount, + pLocale.append('_', err); + searchInLocaleChain(style, gUnitsTag, pLocale.data(), srcTimeUnitField, srcPluralCount, searchPluralCount, countToPatterns, err); - if (countToPatterns != NULL) { - MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); - if (formatters != NULL && formatters[style] != NULL) return; + if (U_FAILURE(err)) { + return; + } + MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); + if (formatters != NULL && formatters[style] != NULL) { + return; } } @@ -684,93 +597,81 @@ TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key, const char* l // fall-back to plural count "other" if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) { // set default fall back the same as the resource in root - MessageFormat* messageFormat = NULL; + LocalPointer messageFormat; + const UChar *pattern = NULL; if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_SECOND; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_MINUTE; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_HOUR; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_WEEK; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_DAY; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_MONTH; } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) { - messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, fLocale, err); + pattern = DEFAULT_PATTERN_FOR_YEAR; } - if (U_SUCCESS(err)) { - if (fNumberFormat != NULL && messageFormat != NULL) { - messageFormat->setFormat(0, *fNumberFormat); - } - MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); - if (formatters == NULL) { - formatters = (MessageFormat**)uprv_malloc(kTotal*sizeof(MessageFormat*)); - formatters[kFull] = NULL; - formatters[kAbbreviate] = NULL; - countToPatterns->put(srcPluralCount, formatters, err); - if (U_FAILURE(err)) { - uprv_free(formatters); - delete messageFormat; - } - } - if (U_SUCCESS(err)) { - //delete formatters[style]; - formatters[style] = messageFormat; + if (pattern != NULL) { + messageFormat.adoptInsteadAndCheckErrorCode( + new MessageFormat(UnicodeString(TRUE, pattern, -1), getLocale(err), err), err); + } + if (U_FAILURE(err)) { + return; + } + MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount); + if (formatters == NULL) { + LocalMemory localFormatters ( + (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*))); + if (localFormatters.isNull()) { + err = U_MEMORY_ALLOCATION_ERROR; + return; } - } else { - delete messageFormat; + formatters = localFormatters.getAlias(); + formatters[UTMUTFMT_FULL_STYLE] = NULL; + formatters[UTMUTFMT_ABBREVIATED_STYLE] = NULL; + countToPatterns->put(srcPluralCount, localFormatters.orphan(), err); + } + if (U_SUCCESS(err)) { + //delete formatters[style]; + formatters[style] = messageFormat.orphan(); } } else { // fall back to rule "other", and search in parents - searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount, + searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount, gPluralCountOther, countToPatterns, err); } } -void +void TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) { - if (U_SUCCESS(status) && fLocale != locale) { - fLocale = locale; + if (setMeasureFormatLocale(locale, status)) { setup(status); } } -void +void TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){ - if (U_FAILURE(status) || (fNumberFormat && format == *fNumberFormat)) { + if (U_FAILURE(status)) { return; } - delete fNumberFormat; - fNumberFormat = (NumberFormat*)format.clone(); - // reset the number formatter in the fTimeUnitToCountToPatterns map - for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; - i < TimeUnit::UTIMEUNIT_FIELD_COUNT; - i = (TimeUnit::UTimeUnitFields)(i+1)) { - int32_t pos = -1; - const UHashElement* elem = NULL; - while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){ - const UHashTok keyTok = elem->value; - MessageFormat** pattern = (MessageFormat**)keyTok.pointer; - pattern[kFull]->setFormat(0, format); - pattern[kAbbreviate]->setFormat(0, format); - } - } + adoptNumberFormat((NumberFormat *)format.clone(), status); } void TimeUnitFormat::deleteHash(Hashtable* htable) { - int32_t pos = -1; + int32_t pos = UHASH_FIRST; const UHashElement* element = NULL; if ( htable ) { while ( (element = htable->nextElement(pos)) != NULL ) { const UHashTok valueTok = element->value; const MessageFormat** value = (const MessageFormat**)valueTok.pointer; - delete value[kFull]; - delete value[kAbbreviate]; + delete value[UTMUTFMT_FULL_STYLE]; + delete value[UTMUTFMT_ABBREVIATED_STYLE]; //delete[] value; uprv_free(value); } @@ -784,7 +685,7 @@ TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& if ( U_FAILURE(status) ) { return; } - int32_t pos = -1; + int32_t pos = UHASH_FIRST; const UHashElement* element = NULL; if ( source ) { while ( (element = source->nextElement(pos)) != NULL ) { @@ -792,7 +693,7 @@ TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& const UnicodeString* key = (UnicodeString*)keyTok.pointer; const UHashTok valueTok = element->value; const MessageFormat** value = (const MessageFormat**)valueTok.pointer; - MessageFormat** newVal = (MessageFormat**)uprv_malloc(kTotal*sizeof(MessageFormat*)); + MessageFormat** newVal = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*)); newVal[0] = (MessageFormat*)value[0]->clone(); newVal[1] = (MessageFormat*)value[1]->clone(); target->put(UnicodeString(*key), newVal, status); @@ -807,7 +708,7 @@ TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& } -U_CDECL_BEGIN +U_CDECL_BEGIN /** * set hash table value comparator @@ -838,7 +739,7 @@ TimeUnitFormat::initHash(UErrorCode& status) { return NULL; } if ( U_FAILURE(status) ) { - delete hTable; + delete hTable; return NULL; } hTable->setValueComparator(tmutfmtHashTableValueComparator); @@ -847,7 +748,7 @@ TimeUnitFormat::initHash(UErrorCode& status) { const char* -TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField, +TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField, UErrorCode& status) { if (U_FAILURE(status)) { return NULL;