Index: source/i18n/reldatefmt.cpp |
diff --git a/source/i18n/reldatefmt.cpp b/source/i18n/reldatefmt.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b4bfe429dd6aca723392dc746e3f8bc50c6604a4 |
--- /dev/null |
+++ b/source/i18n/reldatefmt.cpp |
@@ -0,0 +1,901 @@ |
+/* |
+****************************************************************************** |
+* Copyright (C) 2014, International Business Machines Corporation and |
+* others. All Rights Reserved. |
+****************************************************************************** |
+* |
+* File RELDATEFMT.CPP |
+****************************************************************************** |
+*/ |
+ |
+#include "unicode/reldatefmt.h" |
+ |
+#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION |
+ |
+#include "unicode/localpointer.h" |
+#include "quantityformatter.h" |
+#include "unicode/plurrule.h" |
+#include "unicode/msgfmt.h" |
+#include "unicode/decimfmt.h" |
+#include "unicode/numfmt.h" |
+#include "unicode/brkiter.h" |
+#include "uresimp.h" |
+#include "unicode/ures.h" |
+#include "cstring.h" |
+#include "ucln_in.h" |
+#include "mutex.h" |
+#include "charstr.h" |
+#include "uassert.h" |
+ |
+#include "sharedbreakiterator.h" |
+#include "sharedpluralrules.h" |
+#include "sharednumberformat.h" |
+#include "unifiedcache.h" |
+ |
+// Copied from uscript_props.cpp |
+ |
+static UMutex gBrkIterMutex = U_MUTEX_INITIALIZER; |
+ |
+U_NAMESPACE_BEGIN |
+ |
+// RelativeDateTimeFormatter specific data for a single locale |
+class RelativeDateTimeCacheData: public SharedObject { |
+public: |
+ RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { } |
+ virtual ~RelativeDateTimeCacheData(); |
+ |
+ // no numbers: e.g Next Tuesday; Yesterday; etc. |
+ UnicodeString absoluteUnits[UDAT_STYLE_COUNT][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT]; |
+ |
+ // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0 |
+ // means past e.g 5 days ago; 1 means future e.g in 5 days. |
+ QuantityFormatter relativeUnits[UDAT_STYLE_COUNT][UDAT_RELATIVE_UNIT_COUNT][2]; |
+ |
+ void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) { |
+ delete combinedDateAndTime; |
+ combinedDateAndTime = mfToAdopt; |
+ } |
+ const MessageFormat *getCombinedDateAndTime() const { |
+ return combinedDateAndTime; |
+ } |
+private: |
+ MessageFormat *combinedDateAndTime; |
+ RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other); |
+ RelativeDateTimeCacheData& operator=( |
+ const RelativeDateTimeCacheData &other); |
+}; |
+ |
+RelativeDateTimeCacheData::~RelativeDateTimeCacheData() { |
+ delete combinedDateAndTime; |
+} |
+ |
+static UBool getStringWithFallback( |
+ const UResourceBundle *resource, |
+ const char *key, |
+ UnicodeString &result, |
+ UErrorCode &status) { |
+ int32_t len = 0; |
+ const UChar *resStr = ures_getStringByKeyWithFallback( |
+ resource, key, &len, &status); |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ result.setTo(TRUE, resStr, len); |
+ return TRUE; |
+} |
+ |
+static UBool getOptionalStringWithFallback( |
+ const UResourceBundle *resource, |
+ const char *key, |
+ UnicodeString &result, |
+ UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ int32_t len = 0; |
+ const UChar *resStr = ures_getStringByKey( |
+ resource, key, &len, &status); |
+ if (status == U_MISSING_RESOURCE_ERROR) { |
+ result.remove(); |
+ status = U_ZERO_ERROR; |
+ return TRUE; |
+ } |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ result.setTo(TRUE, resStr, len); |
+ return TRUE; |
+} |
+ |
+static UBool getString( |
+ const UResourceBundle *resource, |
+ UnicodeString &result, |
+ UErrorCode &status) { |
+ int32_t len = 0; |
+ const UChar *resStr = ures_getString(resource, &len, &status); |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ result.setTo(TRUE, resStr, len); |
+ return TRUE; |
+} |
+ |
+static UBool getStringByIndex( |
+ const UResourceBundle *resource, |
+ int32_t idx, |
+ UnicodeString &result, |
+ UErrorCode &status) { |
+ int32_t len = 0; |
+ const UChar *resStr = ures_getStringByIndex( |
+ resource, idx, &len, &status); |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ result.setTo(TRUE, resStr, len); |
+ return TRUE; |
+} |
+ |
+static void initAbsoluteUnit( |
+ const UResourceBundle *resource, |
+ const UnicodeString &unitName, |
+ UnicodeString *absoluteUnit, |
+ UErrorCode &status) { |
+ getStringWithFallback( |
+ resource, |
+ "-1", |
+ absoluteUnit[UDAT_DIRECTION_LAST], |
+ status); |
+ getStringWithFallback( |
+ resource, |
+ "0", |
+ absoluteUnit[UDAT_DIRECTION_THIS], |
+ status); |
+ getStringWithFallback( |
+ resource, |
+ "1", |
+ absoluteUnit[UDAT_DIRECTION_NEXT], |
+ status); |
+ getOptionalStringWithFallback( |
+ resource, |
+ "-2", |
+ absoluteUnit[UDAT_DIRECTION_LAST_2], |
+ status); |
+ getOptionalStringWithFallback( |
+ resource, |
+ "2", |
+ absoluteUnit[UDAT_DIRECTION_NEXT_2], |
+ status); |
+ absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName; |
+} |
+ |
+static void initQuantityFormatter( |
+ const UResourceBundle *resource, |
+ QuantityFormatter &formatter, |
+ UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ int32_t size = ures_getSize(resource); |
+ for (int32_t i = 0; i < size; ++i) { |
+ LocalUResourceBundlePointer pluralBundle( |
+ ures_getByIndex(resource, i, NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ UnicodeString rawPattern; |
+ if (!getString(pluralBundle.getAlias(), rawPattern, status)) { |
+ return; |
+ } |
+ if (!formatter.add( |
+ ures_getKey(pluralBundle.getAlias()), |
+ rawPattern, |
+ status)) { |
+ return; |
+ } |
+ } |
+} |
+ |
+static void initRelativeUnit( |
+ const UResourceBundle *resource, |
+ QuantityFormatter *relativeUnit, |
+ UErrorCode &status) { |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback( |
+ resource, "relativeTime", NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback( |
+ topLevel.getAlias(), "future", NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initQuantityFormatter( |
+ futureBundle.getAlias(), |
+ relativeUnit[1], |
+ status); |
+ LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback( |
+ topLevel.getAlias(), "past", NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initQuantityFormatter( |
+ pastBundle.getAlias(), |
+ relativeUnit[0], |
+ status); |
+} |
+ |
+static void initRelativeUnit( |
+ const UResourceBundle *resource, |
+ const char *path, |
+ QuantityFormatter *relativeUnit, |
+ UErrorCode &status) { |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback(resource, path, NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
+} |
+ |
+static void addTimeUnit( |
+ const UResourceBundle *resource, |
+ const char *path, |
+ QuantityFormatter *relativeUnit, |
+ UnicodeString *absoluteUnit, |
+ UErrorCode &status) { |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback(resource, path, NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
+ UnicodeString unitName; |
+ if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) { |
+ return; |
+ } |
+ // TODO(Travis Keep): This is a hack to get around CLDR bug 6818. |
+ const char *localeId = ures_getLocaleByType( |
+ topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ Locale locale(localeId); |
+ if (uprv_strcmp("en", locale.getLanguage()) == 0) { |
+ unitName.toLower(); |
+ } |
+ // end hack |
+ ures_getByKeyWithFallback( |
+ topLevel.getAlias(), "relative", topLevel.getAlias(), &status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initAbsoluteUnit( |
+ topLevel.getAlias(), |
+ unitName, |
+ absoluteUnit, |
+ status); |
+} |
+ |
+static void readDaysOfWeek( |
+ const UResourceBundle *resource, |
+ const char *path, |
+ UnicodeString *daysOfWeek, |
+ UErrorCode &status) { |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback(resource, path, NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ int32_t size = ures_getSize(topLevel.getAlias()); |
+ if (size != 7) { |
+ status = U_INTERNAL_PROGRAM_ERROR; |
+ return; |
+ } |
+ for (int32_t i = 0; i < size; ++i) { |
+ if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) { |
+ return; |
+ } |
+ } |
+} |
+ |
+static void addWeekDay( |
+ const UResourceBundle *resource, |
+ const char *path, |
+ const UnicodeString *daysOfWeek, |
+ UDateAbsoluteUnit absoluteUnit, |
+ UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT], |
+ UErrorCode &status) { |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback(resource, path, NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initAbsoluteUnit( |
+ topLevel.getAlias(), |
+ daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY], |
+ absoluteUnits[absoluteUnit], |
+ status); |
+} |
+ |
+static void addTimeUnits( |
+ const UResourceBundle *resource, |
+ const char *path, const char *pathShort, const char *pathNarrow, |
+ UDateRelativeUnit relativeUnit, |
+ UDateAbsoluteUnit absoluteUnit, |
+ RelativeDateTimeCacheData &cacheData, |
+ UErrorCode &status) { |
+ addTimeUnit( |
+ resource, |
+ path, |
+ cacheData.relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
+ cacheData.absoluteUnits[UDAT_STYLE_LONG][absoluteUnit], |
+ status); |
+ addTimeUnit( |
+ resource, |
+ pathShort, |
+ cacheData.relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
+ cacheData.absoluteUnits[UDAT_STYLE_SHORT][absoluteUnit], |
+ status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ addTimeUnit( |
+ resource, |
+ pathNarrow, |
+ cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
+ cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
+ status); |
+ if (status == U_MISSING_RESOURCE_ERROR) { |
+ // retry addTimeUnit for UDAT_STYLE_NARROW using pathShort |
+ status = U_ZERO_ERROR; |
+ addTimeUnit( |
+ resource, |
+ pathShort, |
+ cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
+ cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
+ status); |
+ } |
+} |
+ |
+static void initRelativeUnits( |
+ const UResourceBundle *resource, |
+ const char *path, const char *pathShort, const char *pathNarrow, |
+ UDateRelativeUnit relativeUnit, |
+ QuantityFormatter relativeUnits[][UDAT_RELATIVE_UNIT_COUNT][2], |
+ UErrorCode &status) { |
+ initRelativeUnit( |
+ resource, |
+ path, |
+ relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
+ status); |
+ initRelativeUnit( |
+ resource, |
+ pathShort, |
+ relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
+ status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ initRelativeUnit( |
+ resource, |
+ pathNarrow, |
+ relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
+ status); |
+ if (status == U_MISSING_RESOURCE_ERROR) { |
+ // retry initRelativeUnit for UDAT_STYLE_NARROW using pathShort |
+ status = U_ZERO_ERROR; |
+ initRelativeUnit( |
+ resource, |
+ pathShort, |
+ relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
+ status); |
+ } |
+} |
+ |
+static void addWeekDays( |
+ const UResourceBundle *resource, |
+ const char *path, const char *pathShort, const char *pathNarrow, |
+ const UnicodeString daysOfWeek[][7], |
+ UDateAbsoluteUnit absoluteUnit, |
+ UnicodeString absoluteUnits[][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT], |
+ UErrorCode &status) { |
+ addWeekDay( |
+ resource, |
+ path, |
+ daysOfWeek[UDAT_STYLE_LONG], |
+ absoluteUnit, |
+ absoluteUnits[UDAT_STYLE_LONG], |
+ status); |
+ addWeekDay( |
+ resource, |
+ pathShort, |
+ daysOfWeek[UDAT_STYLE_SHORT], |
+ absoluteUnit, |
+ absoluteUnits[UDAT_STYLE_SHORT], |
+ status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ addWeekDay( |
+ resource, |
+ pathNarrow, |
+ daysOfWeek[UDAT_STYLE_NARROW], |
+ absoluteUnit, |
+ absoluteUnits[UDAT_STYLE_NARROW], |
+ status); |
+ if (status == U_MISSING_RESOURCE_ERROR) { |
+ // retry addWeekDay for UDAT_STYLE_NARROW using pathShort |
+ status = U_ZERO_ERROR; |
+ addWeekDay( |
+ resource, |
+ pathShort, |
+ daysOfWeek[UDAT_STYLE_NARROW], |
+ absoluteUnit, |
+ absoluteUnits[UDAT_STYLE_NARROW], |
+ status); |
+ } |
+} |
+ |
+static UBool loadUnitData( |
+ const UResourceBundle *resource, |
+ RelativeDateTimeCacheData &cacheData, |
+ UErrorCode &status) { |
+ addTimeUnits( |
+ resource, |
+ "fields/day", "fields/day-short", "fields/day-narrow", |
+ UDAT_RELATIVE_DAYS, |
+ UDAT_ABSOLUTE_DAY, |
+ cacheData, |
+ status); |
+ addTimeUnits( |
+ resource, |
+ "fields/week", "fields/week-short", "fields/week-narrow", |
+ UDAT_RELATIVE_WEEKS, |
+ UDAT_ABSOLUTE_WEEK, |
+ cacheData, |
+ status); |
+ addTimeUnits( |
+ resource, |
+ "fields/month", "fields/month-short", "fields/month-narrow", |
+ UDAT_RELATIVE_MONTHS, |
+ UDAT_ABSOLUTE_MONTH, |
+ cacheData, |
+ status); |
+ addTimeUnits( |
+ resource, |
+ "fields/year", "fields/year-short", "fields/year-narrow", |
+ UDAT_RELATIVE_YEARS, |
+ UDAT_ABSOLUTE_YEAR, |
+ cacheData, |
+ status); |
+ initRelativeUnits( |
+ resource, |
+ "fields/second", "fields/second-short", "fields/second-narrow", |
+ UDAT_RELATIVE_SECONDS, |
+ cacheData.relativeUnits, |
+ status); |
+ initRelativeUnits( |
+ resource, |
+ "fields/minute", "fields/minute-short", "fields/minute-narrow", |
+ UDAT_RELATIVE_MINUTES, |
+ cacheData.relativeUnits, |
+ status); |
+ initRelativeUnits( |
+ resource, |
+ "fields/hour", "fields/hour-short", "fields/hour-narrow", |
+ UDAT_RELATIVE_HOURS, |
+ cacheData.relativeUnits, |
+ status); |
+ getStringWithFallback( |
+ resource, |
+ "fields/second/relative/0", |
+ cacheData.absoluteUnits[UDAT_STYLE_LONG][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
+ status); |
+ getStringWithFallback( |
+ resource, |
+ "fields/second-short/relative/0", |
+ cacheData.absoluteUnits[UDAT_STYLE_SHORT][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
+ status); |
+ getStringWithFallback( |
+ resource, |
+ "fields/second-narrow/relative/0", |
+ cacheData.absoluteUnits[UDAT_STYLE_NARROW][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
+ status); |
+ UnicodeString daysOfWeek[UDAT_STYLE_COUNT][7]; |
+ readDaysOfWeek( |
+ resource, |
+ "calendar/gregorian/dayNames/stand-alone/wide", |
+ daysOfWeek[UDAT_STYLE_LONG], |
+ status); |
+ readDaysOfWeek( |
+ resource, |
+ "calendar/gregorian/dayNames/stand-alone/short", |
+ daysOfWeek[UDAT_STYLE_SHORT], |
+ status); |
+ readDaysOfWeek( |
+ resource, |
+ "calendar/gregorian/dayNames/stand-alone/narrow", |
+ daysOfWeek[UDAT_STYLE_NARROW], |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/mon/relative", |
+ "fields/mon-short/relative", |
+ "fields/mon-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_MONDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/tue/relative", |
+ "fields/tue-short/relative", |
+ "fields/tue-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_TUESDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/wed/relative", |
+ "fields/wed-short/relative", |
+ "fields/wed-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_WEDNESDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/thu/relative", |
+ "fields/thu-short/relative", |
+ "fields/thu-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_THURSDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/fri/relative", |
+ "fields/fri-short/relative", |
+ "fields/fri-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_FRIDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/sat/relative", |
+ "fields/sat-short/relative", |
+ "fields/sat-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_SATURDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ addWeekDays( |
+ resource, |
+ "fields/sun/relative", |
+ "fields/sun-short/relative", |
+ "fields/sun-narrow/relative", |
+ daysOfWeek, |
+ UDAT_ABSOLUTE_SUNDAY, |
+ cacheData.absoluteUnits, |
+ status); |
+ return U_SUCCESS(status); |
+} |
+ |
+static UBool getDateTimePattern( |
+ const UResourceBundle *resource, |
+ UnicodeString &result, |
+ UErrorCode &status) { |
+ UnicodeString defaultCalendarName; |
+ if (!getStringWithFallback( |
+ resource, |
+ "calendar/default", |
+ defaultCalendarName, |
+ status)) { |
+ return FALSE; |
+ } |
+ CharString pathBuffer; |
+ pathBuffer.append("calendar/", status) |
+ .appendInvariantChars(defaultCalendarName, status) |
+ .append("/DateTimePatterns", status); |
+ LocalUResourceBundlePointer topLevel( |
+ ures_getByKeyWithFallback( |
+ resource, pathBuffer.data(), NULL, &status)); |
+ if (U_FAILURE(status)) { |
+ return FALSE; |
+ } |
+ int32_t size = ures_getSize(topLevel.getAlias()); |
+ if (size <= 8) { |
+ // Oops, size is to small to access the index that we want, fallback |
+ // to a hard-coded value. |
+ result = UNICODE_STRING_SIMPLE("{1} {0}"); |
+ return TRUE; |
+ } |
+ return getStringByIndex(topLevel.getAlias(), 8, result, status); |
+} |
+ |
+template<> U_I18N_API |
+const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::createObject(const void * /*unused*/, UErrorCode &status) const { |
+ const char *localeId = fLoc.getName(); |
+ LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status)); |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ LocalPointer<RelativeDateTimeCacheData> result( |
+ new RelativeDateTimeCacheData()); |
+ if (result.isNull()) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return NULL; |
+ } |
+ if (!loadUnitData( |
+ topLevel.getAlias(), |
+ *result, |
+ status)) { |
+ return NULL; |
+ } |
+ UnicodeString dateTimePattern; |
+ if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) { |
+ return NULL; |
+ } |
+ result->adoptCombinedDateAndTime( |
+ new MessageFormat(dateTimePattern, localeId, status)); |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ result->addRef(); |
+ return result.orphan(); |
+} |
+ |
+RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) : |
+ fCache(NULL), |
+ fNumberFormat(NULL), |
+ fPluralRules(NULL), |
+ fStyle(UDAT_STYLE_LONG), |
+ fContext(UDISPCTX_CAPITALIZATION_NONE), |
+ fOptBreakIterator(NULL) { |
+ init(NULL, NULL, status); |
+} |
+ |
+RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
+ const Locale& locale, UErrorCode& status) : |
+ fCache(NULL), |
+ fNumberFormat(NULL), |
+ fPluralRules(NULL), |
+ fStyle(UDAT_STYLE_LONG), |
+ fContext(UDISPCTX_CAPITALIZATION_NONE), |
+ fOptBreakIterator(NULL), |
+ fLocale(locale) { |
+ init(NULL, NULL, status); |
+} |
+ |
+RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
+ const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) : |
+ fCache(NULL), |
+ fNumberFormat(NULL), |
+ fPluralRules(NULL), |
+ fStyle(UDAT_STYLE_LONG), |
+ fContext(UDISPCTX_CAPITALIZATION_NONE), |
+ fOptBreakIterator(NULL), |
+ fLocale(locale) { |
+ init(nfToAdopt, NULL, status); |
+} |
+ |
+RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
+ const Locale& locale, |
+ NumberFormat *nfToAdopt, |
+ UDateRelativeDateTimeFormatterStyle styl, |
+ UDisplayContext capitalizationContext, |
+ UErrorCode& status) : |
+ fCache(NULL), |
+ fNumberFormat(NULL), |
+ fPluralRules(NULL), |
+ fStyle(styl), |
+ fContext(capitalizationContext), |
+ fOptBreakIterator(NULL), |
+ fLocale(locale) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ if ((capitalizationContext >> 8) != UDISPCTX_TYPE_CAPITALIZATION) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return; |
+ } |
+ if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) { |
+ BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ init(nfToAdopt, bi, status); |
+ } else { |
+ init(nfToAdopt, NULL, status); |
+ } |
+} |
+ |
+RelativeDateTimeFormatter::RelativeDateTimeFormatter( |
+ const RelativeDateTimeFormatter& other) |
+ : UObject(other), |
+ fCache(other.fCache), |
+ fNumberFormat(other.fNumberFormat), |
+ fPluralRules(other.fPluralRules), |
+ fStyle(other.fStyle), |
+ fContext(other.fContext), |
+ fOptBreakIterator(other.fOptBreakIterator), |
+ fLocale(other.fLocale) { |
+ fCache->addRef(); |
+ fNumberFormat->addRef(); |
+ fPluralRules->addRef(); |
+ if (fOptBreakIterator != NULL) { |
+ fOptBreakIterator->addRef(); |
+ } |
+} |
+ |
+RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=( |
+ const RelativeDateTimeFormatter& other) { |
+ if (this != &other) { |
+ SharedObject::copyPtr(other.fCache, fCache); |
+ SharedObject::copyPtr(other.fNumberFormat, fNumberFormat); |
+ SharedObject::copyPtr(other.fPluralRules, fPluralRules); |
+ SharedObject::copyPtr(other.fOptBreakIterator, fOptBreakIterator); |
+ fStyle = other.fStyle; |
+ fContext = other.fContext; |
+ fLocale = other.fLocale; |
+ } |
+ return *this; |
+} |
+ |
+RelativeDateTimeFormatter::~RelativeDateTimeFormatter() { |
+ if (fCache != NULL) { |
+ fCache->removeRef(); |
+ } |
+ if (fNumberFormat != NULL) { |
+ fNumberFormat->removeRef(); |
+ } |
+ if (fPluralRules != NULL) { |
+ fPluralRules->removeRef(); |
+ } |
+ if (fOptBreakIterator != NULL) { |
+ fOptBreakIterator->removeRef(); |
+ } |
+} |
+ |
+const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const { |
+ return **fNumberFormat; |
+} |
+ |
+UDisplayContext RelativeDateTimeFormatter::getCapitalizationContext() const { |
+ return fContext; |
+} |
+ |
+UDateRelativeDateTimeFormatterStyle RelativeDateTimeFormatter::getFormatStyle() const { |
+ return fStyle; |
+} |
+ |
+UnicodeString& RelativeDateTimeFormatter::format( |
+ double quantity, UDateDirection direction, UDateRelativeUnit unit, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
+ if (U_FAILURE(status)) { |
+ return appendTo; |
+ } |
+ if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return appendTo; |
+ } |
+ int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0; |
+ FieldPosition pos(FieldPosition::DONT_CARE); |
+ if (fOptBreakIterator == NULL) { |
+ return fCache->relativeUnits[fStyle][unit][bFuture].format( |
+ quantity, |
+ **fNumberFormat, |
+ **fPluralRules, |
+ appendTo, |
+ pos, |
+ status); |
+ } |
+ UnicodeString result; |
+ fCache->relativeUnits[fStyle][unit][bFuture].format( |
+ quantity, |
+ **fNumberFormat, |
+ **fPluralRules, |
+ result, |
+ pos, |
+ status); |
+ adjustForContext(result); |
+ return appendTo.append(result); |
+} |
+ |
+UnicodeString& RelativeDateTimeFormatter::format( |
+ UDateDirection direction, UDateAbsoluteUnit unit, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
+ if (U_FAILURE(status)) { |
+ return appendTo; |
+ } |
+ if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return appendTo; |
+ } |
+ if (fOptBreakIterator == NULL) { |
+ return appendTo.append(fCache->absoluteUnits[fStyle][unit][direction]); |
+ } |
+ UnicodeString result(fCache->absoluteUnits[fStyle][unit][direction]); |
+ adjustForContext(result); |
+ return appendTo.append(result); |
+} |
+ |
+UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( |
+ const UnicodeString& relativeDateString, const UnicodeString& timeString, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
+ Formattable args[2] = {timeString, relativeDateString}; |
+ FieldPosition fpos(0); |
+ return fCache->getCombinedDateAndTime()->format( |
+ args, 2, appendTo, fpos, status); |
+} |
+ |
+void RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const { |
+ if (fOptBreakIterator == NULL |
+ || str.length() == 0 || !u_islower(str.char32At(0))) { |
+ return; |
+ } |
+ |
+ // Must guarantee that one thread at a time accesses the shared break |
+ // iterator. |
+ Mutex lock(&gBrkIterMutex); |
+ str.toTitle( |
+ fOptBreakIterator->get(), |
+ fLocale, |
+ U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); |
+} |
+ |
+void RelativeDateTimeFormatter::init( |
+ NumberFormat *nfToAdopt, |
+ BreakIterator *biToAdopt, |
+ UErrorCode &status) { |
+ LocalPointer<NumberFormat> nf(nfToAdopt); |
+ LocalPointer<BreakIterator> bi(biToAdopt); |
+ UnifiedCache::getByLocale(fLocale, fCache, status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ const SharedPluralRules *pr = PluralRules::createSharedInstance( |
+ fLocale, UPLURAL_TYPE_CARDINAL, status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ SharedObject::copyPtr(pr, fPluralRules); |
+ pr->removeRef(); |
+ if (nf.isNull()) { |
+ const SharedNumberFormat *shared = NumberFormat::createSharedInstance( |
+ fLocale, UNUM_DECIMAL, status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ SharedObject::copyPtr(shared, fNumberFormat); |
+ shared->removeRef(); |
+ } else { |
+ SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); |
+ if (shared == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ nf.orphan(); |
+ SharedObject::copyPtr(shared, fNumberFormat); |
+ } |
+ if (bi.isNull()) { |
+ SharedObject::clearPtr(fOptBreakIterator); |
+ } else { |
+ SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias()); |
+ if (shared == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ bi.orphan(); |
+ SharedObject::copyPtr(shared, fOptBreakIterator); |
+ } |
+} |
+ |
+ |
+U_NAMESPACE_END |
+ |
+#endif /* !UCONFIG_NO_FORMATTING */ |
+ |