• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ******************************************************************************
6 *
7 * File RELDATEFMT.CPP
8 ******************************************************************************
9 */
10 
11 #include "unicode/reldatefmt.h"
12 
13 #if !UCONFIG_NO_FORMATTING
14 
15 #include "unicode/localpointer.h"
16 #include "quantityformatter.h"
17 #include "unicode/plurrule.h"
18 #include "unicode/msgfmt.h"
19 #include "unicode/decimfmt.h"
20 #include "unicode/numfmt.h"
21 #include "lrucache.h"
22 #include "uresimp.h"
23 #include "unicode/ures.h"
24 #include "cstring.h"
25 #include "ucln_in.h"
26 #include "mutex.h"
27 #include "charstr.h"
28 
29 #include "sharedptr.h"
30 #include "sharedpluralrules.h"
31 #include "sharednumberformat.h"
32 
33 // Copied from uscript_props.cpp
34 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
35 
36 static icu::LRUCache *gCache = NULL;
37 static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
38 static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
39 
40 U_CDECL_BEGIN
reldatefmt_cleanup()41 static UBool U_CALLCONV reldatefmt_cleanup() {
42     gCacheInitOnce.reset();
43     if (gCache) {
44         delete gCache;
45         gCache = NULL;
46     }
47     return TRUE;
48 }
49 U_CDECL_END
50 
51 U_NAMESPACE_BEGIN
52 
53 // RelativeDateTimeFormatter specific data for a single locale
54 class RelativeDateTimeCacheData: public SharedObject {
55 public:
RelativeDateTimeCacheData()56     RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { }
57     virtual ~RelativeDateTimeCacheData();
58 
59     // no numbers: e.g Next Tuesday; Yesterday; etc.
60     UnicodeString absoluteUnits[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
61 
62     // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0
63     // means past e.g 5 days ago; 1 means future e.g in 5 days.
64     QuantityFormatter relativeUnits[UDAT_RELATIVE_UNIT_COUNT][2];
65 
adoptCombinedDateAndTime(MessageFormat * mfToAdopt)66     void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) {
67         delete combinedDateAndTime;
68         combinedDateAndTime = mfToAdopt;
69     }
getCombinedDateAndTime() const70     const MessageFormat *getCombinedDateAndTime() const {
71         return combinedDateAndTime;
72     }
73 private:
74     MessageFormat *combinedDateAndTime;
75     RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other);
76     RelativeDateTimeCacheData& operator=(
77             const RelativeDateTimeCacheData &other);
78 };
79 
~RelativeDateTimeCacheData()80 RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
81     delete combinedDateAndTime;
82 }
83 
getStringWithFallback(const UResourceBundle * resource,const char * key,UnicodeString & result,UErrorCode & status)84 static UBool getStringWithFallback(
85         const UResourceBundle *resource,
86         const char *key,
87         UnicodeString &result,
88         UErrorCode &status) {
89     int32_t len = 0;
90     const UChar *resStr = ures_getStringByKeyWithFallback(
91         resource, key, &len, &status);
92     if (U_FAILURE(status)) {
93         return FALSE;
94     }
95     result.setTo(TRUE, resStr, len);
96     return TRUE;
97 }
98 
getOptionalStringWithFallback(const UResourceBundle * resource,const char * key,UnicodeString & result,UErrorCode & status)99 static UBool getOptionalStringWithFallback(
100         const UResourceBundle *resource,
101         const char *key,
102         UnicodeString &result,
103         UErrorCode &status) {
104     if (U_FAILURE(status)) {
105         return FALSE;
106     }
107     int32_t len = 0;
108     const UChar *resStr = ures_getStringByKey(
109         resource, key, &len, &status);
110     if (status == U_MISSING_RESOURCE_ERROR) {
111         result.remove();
112         status = U_ZERO_ERROR;
113         return TRUE;
114     }
115     if (U_FAILURE(status)) {
116         return FALSE;
117     }
118     result.setTo(TRUE, resStr, len);
119     return TRUE;
120 }
121 
getString(const UResourceBundle * resource,UnicodeString & result,UErrorCode & status)122 static UBool getString(
123         const UResourceBundle *resource,
124         UnicodeString &result,
125         UErrorCode &status) {
126     int32_t len = 0;
127     const UChar *resStr = ures_getString(resource, &len, &status);
128     if (U_FAILURE(status)) {
129         return FALSE;
130     }
131     result.setTo(TRUE, resStr, len);
132     return TRUE;
133 }
134 
getStringByIndex(const UResourceBundle * resource,int32_t idx,UnicodeString & result,UErrorCode & status)135 static UBool getStringByIndex(
136         const UResourceBundle *resource,
137         int32_t idx,
138         UnicodeString &result,
139         UErrorCode &status) {
140     int32_t len = 0;
141     const UChar *resStr = ures_getStringByIndex(
142             resource, idx, &len, &status);
143     if (U_FAILURE(status)) {
144         return FALSE;
145     }
146     result.setTo(TRUE, resStr, len);
147     return TRUE;
148 }
149 
initAbsoluteUnit(const UResourceBundle * resource,const UnicodeString & unitName,UnicodeString * absoluteUnit,UErrorCode & status)150 static void initAbsoluteUnit(
151             const UResourceBundle *resource,
152             const UnicodeString &unitName,
153             UnicodeString *absoluteUnit,
154             UErrorCode &status) {
155     getStringWithFallback(
156             resource,
157             "-1",
158             absoluteUnit[UDAT_DIRECTION_LAST],
159             status);
160     getStringWithFallback(
161             resource,
162             "0",
163             absoluteUnit[UDAT_DIRECTION_THIS],
164             status);
165     getStringWithFallback(
166             resource,
167             "1",
168             absoluteUnit[UDAT_DIRECTION_NEXT],
169             status);
170     getOptionalStringWithFallback(
171             resource,
172             "-2",
173             absoluteUnit[UDAT_DIRECTION_LAST_2],
174             status);
175     getOptionalStringWithFallback(
176             resource,
177             "2",
178             absoluteUnit[UDAT_DIRECTION_NEXT_2],
179             status);
180     absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName;
181 }
182 
initQuantityFormatter(const UResourceBundle * resource,QuantityFormatter & formatter,UErrorCode & status)183 static void initQuantityFormatter(
184         const UResourceBundle *resource,
185         QuantityFormatter &formatter,
186         UErrorCode &status) {
187     if (U_FAILURE(status)) {
188         return;
189     }
190     int32_t size = ures_getSize(resource);
191     for (int32_t i = 0; i < size; ++i) {
192         LocalUResourceBundlePointer pluralBundle(
193                 ures_getByIndex(resource, i, NULL, &status));
194         if (U_FAILURE(status)) {
195             return;
196         }
197         UnicodeString rawPattern;
198         if (!getString(pluralBundle.getAlias(), rawPattern, status)) {
199             return;
200         }
201         if (!formatter.add(
202                 ures_getKey(pluralBundle.getAlias()),
203                 rawPattern,
204                 status)) {
205             return;
206         }
207     }
208 }
209 
initRelativeUnit(const UResourceBundle * resource,QuantityFormatter * relativeUnit,UErrorCode & status)210 static void initRelativeUnit(
211         const UResourceBundle *resource,
212         QuantityFormatter *relativeUnit,
213         UErrorCode &status) {
214     LocalUResourceBundlePointer topLevel(
215             ures_getByKeyWithFallback(
216                     resource, "relativeTime", NULL, &status));
217     if (U_FAILURE(status)) {
218         return;
219     }
220     LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback(
221             topLevel.getAlias(), "future", NULL, &status));
222     if (U_FAILURE(status)) {
223         return;
224     }
225     initQuantityFormatter(
226             futureBundle.getAlias(),
227             relativeUnit[1],
228             status);
229     LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback(
230             topLevel.getAlias(), "past", NULL, &status));
231     if (U_FAILURE(status)) {
232         return;
233     }
234     initQuantityFormatter(
235             pastBundle.getAlias(),
236             relativeUnit[0],
237             status);
238 }
239 
initRelativeUnit(const UResourceBundle * resource,const char * path,QuantityFormatter * relativeUnit,UErrorCode & status)240 static void initRelativeUnit(
241         const UResourceBundle *resource,
242         const char *path,
243         QuantityFormatter *relativeUnit,
244         UErrorCode &status) {
245     LocalUResourceBundlePointer topLevel(
246             ures_getByKeyWithFallback(resource, path, NULL, &status));
247     if (U_FAILURE(status)) {
248         return;
249     }
250     initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
251 }
252 
addTimeUnit(const UResourceBundle * resource,const char * path,QuantityFormatter * relativeUnit,UnicodeString * absoluteUnit,UErrorCode & status)253 static void addTimeUnit(
254         const UResourceBundle *resource,
255         const char *path,
256         QuantityFormatter *relativeUnit,
257         UnicodeString *absoluteUnit,
258         UErrorCode &status) {
259     LocalUResourceBundlePointer topLevel(
260             ures_getByKeyWithFallback(resource, path, NULL, &status));
261     if (U_FAILURE(status)) {
262         return;
263     }
264     initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
265     UnicodeString unitName;
266     if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) {
267         return;
268     }
269     // TODO(Travis Keep): This is a hack to get around CLDR bug 6818.
270     const char *localeId = ures_getLocaleByType(
271             topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status);
272     if (U_FAILURE(status)) {
273         return;
274     }
275     Locale locale(localeId);
276     if (uprv_strcmp("en", locale.getLanguage()) == 0) {
277          unitName.toLower();
278     }
279     // end hack
280     ures_getByKeyWithFallback(
281             topLevel.getAlias(), "relative", topLevel.getAlias(), &status);
282     if (U_FAILURE(status)) {
283         return;
284     }
285     initAbsoluteUnit(
286             topLevel.getAlias(),
287             unitName,
288             absoluteUnit,
289             status);
290 }
291 
readDaysOfWeek(const UResourceBundle * resource,const char * path,UnicodeString * daysOfWeek,UErrorCode & status)292 static void readDaysOfWeek(
293         const UResourceBundle *resource,
294         const char *path,
295         UnicodeString *daysOfWeek,
296         UErrorCode &status) {
297     LocalUResourceBundlePointer topLevel(
298             ures_getByKeyWithFallback(resource, path, NULL, &status));
299     if (U_FAILURE(status)) {
300         return;
301     }
302     int32_t size = ures_getSize(topLevel.getAlias());
303     if (size != 7) {
304         status = U_INTERNAL_PROGRAM_ERROR;
305         return;
306     }
307     for (int32_t i = 0; i < size; ++i) {
308         if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) {
309             return;
310         }
311     }
312 }
313 
addWeekDay(const UResourceBundle * resource,const char * path,const UnicodeString * daysOfWeek,UDateAbsoluteUnit absoluteUnit,UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT],UErrorCode & status)314 static void addWeekDay(
315         const UResourceBundle *resource,
316         const char *path,
317         const UnicodeString *daysOfWeek,
318         UDateAbsoluteUnit absoluteUnit,
319         UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT],
320         UErrorCode &status) {
321     LocalUResourceBundlePointer topLevel(
322             ures_getByKeyWithFallback(resource, path, NULL, &status));
323     if (U_FAILURE(status)) {
324         return;
325     }
326     initAbsoluteUnit(
327             topLevel.getAlias(),
328             daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY],
329             absoluteUnits[absoluteUnit],
330             status);
331 }
332 
loadUnitData(const UResourceBundle * resource,RelativeDateTimeCacheData & cacheData,UErrorCode & status)333 static UBool loadUnitData(
334         const UResourceBundle *resource,
335         RelativeDateTimeCacheData &cacheData,
336         UErrorCode &status) {
337     addTimeUnit(
338             resource,
339             "fields/day",
340             cacheData.relativeUnits[UDAT_RELATIVE_DAYS],
341             cacheData.absoluteUnits[UDAT_ABSOLUTE_DAY],
342             status);
343     addTimeUnit(
344             resource,
345             "fields/week",
346             cacheData.relativeUnits[UDAT_RELATIVE_WEEKS],
347             cacheData.absoluteUnits[UDAT_ABSOLUTE_WEEK],
348             status);
349     addTimeUnit(
350             resource,
351             "fields/month",
352             cacheData.relativeUnits[UDAT_RELATIVE_MONTHS],
353             cacheData.absoluteUnits[UDAT_ABSOLUTE_MONTH],
354             status);
355     addTimeUnit(
356             resource,
357             "fields/year",
358             cacheData.relativeUnits[UDAT_RELATIVE_YEARS],
359             cacheData.absoluteUnits[UDAT_ABSOLUTE_YEAR],
360             status);
361     initRelativeUnit(
362             resource,
363             "fields/second",
364             cacheData.relativeUnits[UDAT_RELATIVE_SECONDS],
365             status);
366     initRelativeUnit(
367             resource,
368             "fields/minute",
369             cacheData.relativeUnits[UDAT_RELATIVE_MINUTES],
370             status);
371     initRelativeUnit(
372             resource,
373             "fields/hour",
374             cacheData.relativeUnits[UDAT_RELATIVE_HOURS],
375             status);
376     getStringWithFallback(
377             resource,
378             "fields/second/relative/0",
379             cacheData.absoluteUnits[UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN],
380             status);
381     UnicodeString daysOfWeek[7];
382     readDaysOfWeek(
383             resource,
384             "calendar/gregorian/dayNames/stand-alone/wide",
385             daysOfWeek,
386             status);
387     addWeekDay(
388             resource,
389             "fields/mon/relative",
390             daysOfWeek,
391             UDAT_ABSOLUTE_MONDAY,
392             cacheData.absoluteUnits,
393             status);
394     addWeekDay(
395             resource,
396             "fields/tue/relative",
397             daysOfWeek,
398             UDAT_ABSOLUTE_TUESDAY,
399             cacheData.absoluteUnits,
400             status);
401     addWeekDay(
402             resource,
403             "fields/wed/relative",
404             daysOfWeek,
405             UDAT_ABSOLUTE_WEDNESDAY,
406             cacheData.absoluteUnits,
407             status);
408     addWeekDay(
409             resource,
410             "fields/thu/relative",
411             daysOfWeek,
412             UDAT_ABSOLUTE_THURSDAY,
413             cacheData.absoluteUnits,
414             status);
415     addWeekDay(
416             resource,
417             "fields/fri/relative",
418             daysOfWeek,
419             UDAT_ABSOLUTE_FRIDAY,
420             cacheData.absoluteUnits,
421             status);
422     addWeekDay(
423             resource,
424             "fields/sat/relative",
425             daysOfWeek,
426             UDAT_ABSOLUTE_SATURDAY,
427             cacheData.absoluteUnits,
428             status);
429     addWeekDay(
430             resource,
431             "fields/sun/relative",
432             daysOfWeek,
433             UDAT_ABSOLUTE_SUNDAY,
434             cacheData.absoluteUnits,
435             status);
436     return U_SUCCESS(status);
437 }
438 
getDateTimePattern(const UResourceBundle * resource,UnicodeString & result,UErrorCode & status)439 static UBool getDateTimePattern(
440         const UResourceBundle *resource,
441         UnicodeString &result,
442         UErrorCode &status) {
443     UnicodeString defaultCalendarName;
444     if (!getStringWithFallback(
445             resource,
446             "calendar/default",
447             defaultCalendarName,
448             status)) {
449         return FALSE;
450     }
451     CharString pathBuffer;
452     pathBuffer.append("calendar/", status)
453             .appendInvariantChars(defaultCalendarName, status)
454             .append("/DateTimePatterns", status);
455     LocalUResourceBundlePointer topLevel(
456             ures_getByKeyWithFallback(
457                     resource, pathBuffer.data(), NULL, &status));
458     if (U_FAILURE(status)) {
459         return FALSE;
460     }
461     int32_t size = ures_getSize(topLevel.getAlias());
462     if (size <= 8) {
463         // Oops, size is to small to access the index that we want, fallback
464         // to a hard-coded value.
465         result = UNICODE_STRING_SIMPLE("{1} {0}");
466         return TRUE;
467     }
468     return getStringByIndex(topLevel.getAlias(), 8, result, status);
469 }
470 
471 // Creates RelativeDateTimeFormatter specific data for a given locale
createData(const char * localeId,UErrorCode & status)472 static SharedObject *U_CALLCONV createData(
473         const char *localeId, UErrorCode &status) {
474     LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
475     if (U_FAILURE(status)) {
476         return NULL;
477     }
478     LocalPointer<RelativeDateTimeCacheData> result(
479             new RelativeDateTimeCacheData());
480     if (result.isNull()) {
481         status = U_MEMORY_ALLOCATION_ERROR;
482         return NULL;
483     }
484     if (!loadUnitData(
485             topLevel.getAlias(),
486             *result,
487             status)) {
488         return NULL;
489     }
490     UnicodeString dateTimePattern;
491     if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
492         return NULL;
493     }
494     result->adoptCombinedDateAndTime(
495             new MessageFormat(dateTimePattern, localeId, status));
496     if (U_FAILURE(status)) {
497         return NULL;
498     }
499     return result.orphan();
500 }
501 
cacheInit(UErrorCode & status)502 static void U_CALLCONV cacheInit(UErrorCode &status) {
503     U_ASSERT(gCache == NULL);
504     ucln_i18n_registerCleanup(UCLN_I18N_RELDATEFMT, reldatefmt_cleanup);
505     gCache = new SimpleLRUCache(100, &createData, status);
506     if (U_FAILURE(status)) {
507         delete gCache;
508         gCache = NULL;
509     }
510 }
511 
getFromCache(const char * locale,const RelativeDateTimeCacheData * & ptr,UErrorCode & status)512 static UBool getFromCache(
513         const char *locale,
514         const RelativeDateTimeCacheData *&ptr,
515         UErrorCode &status) {
516     umtx_initOnce(gCacheInitOnce, &cacheInit, status);
517     if (U_FAILURE(status)) {
518         return FALSE;
519     }
520     Mutex lock(&gCacheMutex);
521     gCache->get(locale, ptr, status);
522     return U_SUCCESS(status);
523 }
524 
RelativeDateTimeFormatter(UErrorCode & status)525 RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status)
526         : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
527     init(Locale::getDefault(), NULL, status);
528 }
529 
RelativeDateTimeFormatter(const Locale & locale,UErrorCode & status)530 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
531         const Locale& locale, UErrorCode& status)
532         : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
533     init(locale, NULL, status);
534 }
535 
RelativeDateTimeFormatter(const Locale & locale,NumberFormat * nfToAdopt,UErrorCode & status)536 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
537         const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status)
538         : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
539     init(locale, nfToAdopt, status);
540 }
541 
RelativeDateTimeFormatter(const RelativeDateTimeFormatter & other)542 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
543         const RelativeDateTimeFormatter& other)
544         : cache(other.cache),
545           numberFormat(other.numberFormat),
546           pluralRules(other.pluralRules) {
547     cache->addRef();
548     numberFormat->addRef();
549     pluralRules->addRef();
550 }
551 
operator =(const RelativeDateTimeFormatter & other)552 RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
553         const RelativeDateTimeFormatter& other) {
554     if (this != &other) {
555         SharedObject::copyPtr(other.cache, cache);
556         SharedObject::copyPtr(other.numberFormat, numberFormat);
557         SharedObject::copyPtr(other.pluralRules, pluralRules);
558     }
559     return *this;
560 }
561 
~RelativeDateTimeFormatter()562 RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
563     if (cache != NULL) {
564         cache->removeRef();
565     }
566     if (numberFormat != NULL) {
567         numberFormat->removeRef();
568     }
569     if (pluralRules != NULL) {
570         pluralRules->removeRef();
571     }
572 }
573 
getNumberFormat() const574 const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
575     return **numberFormat;
576 }
577 
format(double quantity,UDateDirection direction,UDateRelativeUnit unit,UnicodeString & appendTo,UErrorCode & status) const578 UnicodeString& RelativeDateTimeFormatter::format(
579         double quantity, UDateDirection direction, UDateRelativeUnit unit,
580         UnicodeString& appendTo, UErrorCode& status) const {
581     if (U_FAILURE(status)) {
582         return appendTo;
583     }
584     if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
585         status = U_ILLEGAL_ARGUMENT_ERROR;
586         return appendTo;
587     }
588     int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
589     FieldPosition pos(FieldPosition::DONT_CARE);
590     return cache->relativeUnits[unit][bFuture].format(
591             quantity,
592             **numberFormat,
593             **pluralRules,
594             appendTo,
595             pos,
596             status);
597 }
598 
format(UDateDirection direction,UDateAbsoluteUnit unit,UnicodeString & appendTo,UErrorCode & status) const599 UnicodeString& RelativeDateTimeFormatter::format(
600         UDateDirection direction, UDateAbsoluteUnit unit,
601         UnicodeString& appendTo, UErrorCode& status) const {
602     if (U_FAILURE(status)) {
603         return appendTo;
604     }
605     if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) {
606         status = U_ILLEGAL_ARGUMENT_ERROR;
607         return appendTo;
608     }
609     return appendTo.append(cache->absoluteUnits[unit][direction]);
610 }
611 
combineDateAndTime(const UnicodeString & relativeDateString,const UnicodeString & timeString,UnicodeString & appendTo,UErrorCode & status) const612 UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
613     const UnicodeString& relativeDateString, const UnicodeString& timeString,
614     UnicodeString& appendTo, UErrorCode& status) const {
615     Formattable args[2] = {timeString, relativeDateString};
616     FieldPosition fpos(0);
617     return cache->getCombinedDateAndTime()->format(
618             args, 2, appendTo, fpos, status);
619 }
620 
init(const Locale & locale,NumberFormat * nfToAdopt,UErrorCode & status)621 void RelativeDateTimeFormatter::init(
622         const Locale &locale, NumberFormat *nfToAdopt, UErrorCode &status) {
623     LocalPointer<NumberFormat> nf(nfToAdopt);
624     if (!getFromCache(locale.getName(), cache, status)) {
625         return;
626     }
627     SharedObject::copyPtr(
628             PluralRules::createSharedInstance(
629                     locale, UPLURAL_TYPE_CARDINAL, status),
630             pluralRules);
631     if (U_FAILURE(status)) {
632         return;
633     }
634     pluralRules->removeRef();
635     if (nf.isNull()) {
636        SharedObject::copyPtr(
637                NumberFormat::createSharedInstance(
638                        locale, UNUM_DECIMAL, status),
639                numberFormat);
640         if (U_FAILURE(status)) {
641             return;
642         }
643         numberFormat->removeRef();
644     } else {
645         SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
646         if (shared == NULL) {
647             status = U_MEMORY_ALLOCATION_ERROR;
648             return;
649         }
650         nf.orphan();
651         SharedObject::copyPtr(shared, numberFormat);
652     }
653 }
654 
655 
656 U_NAMESPACE_END
657 
658 #endif /* !UCONFIG_NO_FORMATTING */
659 
660