/*
*******************************************************************************
- * 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 <typeinfo> // 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)
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)) {
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<const TimeUnitAmount*>(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();
#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.
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);
#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) {
*/
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) {
pos.setErrorIndex(0);
} else {
UErrorCode status = U_ZERO_ERROR;
- TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
+ LocalPointer<TimeUnitAmount> 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 {
}
}
-
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.
//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<StringEnumeration> keywords(getPluralRules().getKeywords(err), err);
+ if (U_FAILURE(err)) {
+ return;
+ }
+ UnicodeString* pluralCount;
+ while ((pluralCount = const_cast<UnicodeString*>(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);
}
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)) {
}
}
-
-
-
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;
}
// 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<Hashtable> 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> 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<MessageFormat *> 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.
// 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<StringEnumeration> 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;
}
// 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)) {
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> 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<MessageFormat *> 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;
}
}
#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;
}
}
// 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> 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<MessageFormat *> 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);
}
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 ) {
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);
}
-U_CDECL_BEGIN
+U_CDECL_BEGIN
/**
* set hash table value comparator
return NULL;
}
if ( U_FAILURE(status) ) {
- delete hTable;
+ delete hTable;
return NULL;
}
hTable->setValueComparator(tmutfmtHashTableValueComparator);
const char*
-TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
+TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
UErrorCode& status) {
if (U_FAILURE(status)) {
return NULL;