/* ****************************************************************************** * Copyright (C) 2014-2015, 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.addIfAbsent( 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 */