1 /*
2 **********************************************************************
3 * Copyright (c) 2004-2016, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 * Author: Alan Liu
7 * Created: April 20, 2004
8 * Since: ICU 3.0
9 **********************************************************************
10 */
11 #include "utypeinfo.h"  // for 'typeid' to work
12 #include "unicode/utypes.h"
13 
14 #if !UCONFIG_NO_FORMATTING
15 
16 #include "unicode/measfmt.h"
17 #include "unicode/numfmt.h"
18 #include "currfmt.h"
19 #include "unicode/localpointer.h"
20 #include "resource.h"
21 #include "unicode/simpleformatter.h"
22 #include "quantityformatter.h"
23 #include "unicode/plurrule.h"
24 #include "unicode/decimfmt.h"
25 #include "uresimp.h"
26 #include "unicode/ures.h"
27 #include "ureslocs.h"
28 #include "cstring.h"
29 #include "mutex.h"
30 #include "ucln_in.h"
31 #include "unicode/listformatter.h"
32 #include "charstr.h"
33 #include "unicode/putil.h"
34 #include "unicode/smpdtfmt.h"
35 #include "uassert.h"
36 
37 #include "sharednumberformat.h"
38 #include "sharedpluralrules.h"
39 #include "standardplural.h"
40 #include "unifiedcache.h"
41 
42 #define MEAS_UNIT_COUNT 134
43 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
44 
45 U_NAMESPACE_BEGIN
46 
47 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
48 
49 // Used to format durations like 5:47 or 21:35:42.
50 class NumericDateFormatters : public UMemory {
51 public:
52     // Formats like H:mm
53     SimpleDateFormat hourMinute;
54 
55     // formats like M:ss
56     SimpleDateFormat minuteSecond;
57 
58     // formats like H:mm:ss
59     SimpleDateFormat hourMinuteSecond;
60 
61     // Constructor that takes the actual patterns for hour-minute,
62     // minute-second, and hour-minute-second respectively.
NumericDateFormatters(const UnicodeString & hm,const UnicodeString & ms,const UnicodeString & hms,UErrorCode & status)63     NumericDateFormatters(
64             const UnicodeString &hm,
65             const UnicodeString &ms,
66             const UnicodeString &hms,
67             UErrorCode &status) :
68             hourMinute(hm, status),
69             minuteSecond(ms, status),
70             hourMinuteSecond(hms, status) {
71         const TimeZone *gmt = TimeZone::getGMT();
72         hourMinute.setTimeZone(*gmt);
73         minuteSecond.setTimeZone(*gmt);
74         hourMinuteSecond.setTimeZone(*gmt);
75     }
76 private:
77     NumericDateFormatters(const NumericDateFormatters &other);
78     NumericDateFormatters &operator=(const NumericDateFormatters &other);
79 };
80 
getRegularWidth(UMeasureFormatWidth width)81 static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
82     if (width >= WIDTH_INDEX_COUNT) {
83         return UMEASFMT_WIDTH_NARROW;
84     }
85     return width;
86 }
87 
88 /**
89  * Instances contain all MeasureFormat specific data for a particular locale.
90  * This data is cached. It is never copied, but is shared via shared pointers.
91  *
92  * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
93  * complete sets of unit & per patterns,
94  * to correspond to the resource data and its aliases.
95  *
96  * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
97  */
98 class MeasureFormatCacheData : public SharedObject {
99 public:
100     static const int32_t PER_UNIT_INDEX = StandardPlural::COUNT;
101     static const int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1;
102 
103     /**
104      * Redirection data from root-bundle, top-level sideways aliases.
105      * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
106      * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
107      */
108     UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
109     /** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
110     SimpleFormatter *patterns[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT][PATTERN_COUNT];
111     SimpleFormatter perFormatters[WIDTH_INDEX_COUNT];
112 
113     MeasureFormatCacheData();
114     virtual ~MeasureFormatCacheData();
115 
hasPerFormatter(int32_t width) const116     UBool hasPerFormatter(int32_t width) const {
117         // TODO: Create a more obvious way to test if the per-formatter has been set?
118         // Use pointers, check for NULL? Or add an isValid() method?
119         return perFormatters[width].getArgumentLimit() == 2;
120     }
121 
adoptCurrencyFormat(int32_t widthIndex,NumberFormat * nfToAdopt)122     void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
123         delete currencyFormats[widthIndex];
124         currencyFormats[widthIndex] = nfToAdopt;
125     }
getCurrencyFormat(UMeasureFormatWidth width) const126     const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const {
127         return currencyFormats[getRegularWidth(width)];
128     }
adoptIntegerFormat(NumberFormat * nfToAdopt)129     void adoptIntegerFormat(NumberFormat *nfToAdopt) {
130         delete integerFormat;
131         integerFormat = nfToAdopt;
132     }
getIntegerFormat() const133     const NumberFormat *getIntegerFormat() const {
134         return integerFormat;
135     }
adoptNumericDateFormatters(NumericDateFormatters * formattersToAdopt)136     void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
137         delete numericDateFormatters;
138         numericDateFormatters = formattersToAdopt;
139     }
getNumericDateFormatters() const140     const NumericDateFormatters *getNumericDateFormatters() const {
141         return numericDateFormatters;
142     }
143 
144 private:
145     NumberFormat *currencyFormats[WIDTH_INDEX_COUNT];
146     NumberFormat *integerFormat;
147     NumericDateFormatters *numericDateFormatters;
148     MeasureFormatCacheData(const MeasureFormatCacheData &other);
149     MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
150 };
151 
MeasureFormatCacheData()152 MeasureFormatCacheData::MeasureFormatCacheData() {
153     for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
154         widthFallback[i] = UMEASFMT_WIDTH_COUNT;
155     }
156     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
157         currencyFormats[i] = NULL;
158     }
159     uprv_memset(patterns, 0, sizeof(patterns));
160     integerFormat = NULL;
161     numericDateFormatters = NULL;
162 }
163 
~MeasureFormatCacheData()164 MeasureFormatCacheData::~MeasureFormatCacheData() {
165     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
166         delete currencyFormats[i];
167     }
168     for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
169         for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
170             for (int32_t k = 0; k < PATTERN_COUNT; ++k) {
171                 delete patterns[i][j][k];
172             }
173         }
174     }
175     delete integerFormat;
176     delete numericDateFormatters;
177 }
178 
isCurrency(const MeasureUnit & unit)179 static UBool isCurrency(const MeasureUnit &unit) {
180     return (uprv_strcmp(unit.getType(), "currency") == 0);
181 }
182 
getString(const UResourceBundle * resource,UnicodeString & result,UErrorCode & status)183 static UBool getString(
184         const UResourceBundle *resource,
185         UnicodeString &result,
186         UErrorCode &status) {
187     int32_t len = 0;
188     const UChar *resStr = ures_getString(resource, &len, &status);
189     if (U_FAILURE(status)) {
190         return FALSE;
191     }
192     result.setTo(TRUE, resStr, len);
193     return TRUE;
194 }
195 
196 namespace {
197 
198 static const UChar g_LOCALE_units[] = {
199     0x2F, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x45, 0x2F,
200     0x75, 0x6E, 0x69, 0x74, 0x73
201 };
202 static const UChar gShort[] = { 0x53, 0x68, 0x6F, 0x72, 0x74 };
203 static const UChar gNarrow[] = { 0x4E, 0x61, 0x72, 0x72, 0x6F, 0x77 };
204 
205 /**
206  * Sink for enumerating all of the measurement unit display names.
207  * Contains inner sink classes, each one corresponding to a type of resource table.
208  * The outer sink handles the top-level units, unitsNarrow, and unitsShort tables.
209  *
210  * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
211  * Only store a value if it is still missing, that is, it has not been overridden.
212  *
213  * C++: Each inner sink class has a reference to the main outer sink.
214  * Java: Use non-static inner classes instead.
215  */
216 struct UnitDataSink : public ResourceTableSink {
217     /**
218      * Sink for a table of display patterns. For example,
219      * unitsShort/duration/hour contains other{"{0} hrs"}.
220      */
221     struct UnitPatternSink : public ResourceTableSink {
UnitPatternSink__anona245636e0111::UnitDataSink::UnitPatternSink222         UnitPatternSink(UnitDataSink &sink) : outer(sink) {}
223         ~UnitPatternSink();
224 
setFormatterIfAbsent__anona245636e0111::UnitDataSink::UnitPatternSink225         void setFormatterIfAbsent(int32_t index, const ResourceValue &value,
226                                   int32_t minPlaceholders, UErrorCode &errorCode) {
227             SimpleFormatter **patterns =
228                 &outer.cacheData.patterns[outer.unitIndex][outer.width][0];
229             if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
230                 patterns[index] = new SimpleFormatter(
231                        value.getUnicodeString(errorCode), minPlaceholders, 1, errorCode);
232                 if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
233                     errorCode = U_MEMORY_ALLOCATION_ERROR;
234                 }
235             }
236         }
237 
put__anona245636e0111::UnitDataSink::UnitPatternSink238         virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
239             if (U_FAILURE(errorCode)) { return; }
240             if (uprv_strcmp(key, "dnam") == 0) {
241                 // Skip the unit display name for now.
242             } else if (uprv_strcmp(key, "per") == 0) {
243                 // For example, "{0}/h".
244                 setFormatterIfAbsent(MeasureFormatCacheData::PER_UNIT_INDEX, value, 1, errorCode);
245             } else {
246                 // The key must be one of the plural form strings. For example:
247                 // one{"{0} hr"}
248                 // other{"{0} hrs"}
249                 setFormatterIfAbsent(StandardPlural::indexFromString(key, errorCode), value, 0,
250                                      errorCode);
251             }
252         }
253         UnitDataSink &outer;
254     } patternSink;
255 
256     /**
257      * Sink for a table of per-unit tables. For example,
258      * unitsShort/duration contains tables for duration-unit subtypes day & hour.
259      */
260     struct UnitSubtypeSink : public ResourceTableSink {
UnitSubtypeSink__anona245636e0111::UnitDataSink::UnitSubtypeSink261         UnitSubtypeSink(UnitDataSink &sink) : outer(sink) {}
262         ~UnitSubtypeSink();
getOrCreateTableSink__anona245636e0111::UnitDataSink::UnitSubtypeSink263         virtual ResourceTableSink *getOrCreateTableSink(
264                 const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
265             if (U_FAILURE(errorCode)) { return NULL; }
266             outer.unitIndex = MeasureUnit::internalGetIndexForTypeAndSubtype(outer.type, key);
267             if (outer.unitIndex >= 0) {
268                 return &outer.patternSink;
269             }
270             return NULL;
271         }
272         UnitDataSink &outer;
273     } subtypeSink;
274 
275     /**
276      * Sink for compound x-per-y display pattern. For example,
277      * unitsShort/compound/per may be "{0}/{1}".
278      */
279     struct UnitCompoundSink : public ResourceTableSink {
UnitCompoundSink__anona245636e0111::UnitDataSink::UnitCompoundSink280         UnitCompoundSink(UnitDataSink &sink) : outer(sink) {}
281         ~UnitCompoundSink();
put__anona245636e0111::UnitDataSink::UnitCompoundSink282         virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
283             if (U_SUCCESS(errorCode) && uprv_strcmp(key, "per") == 0) {
284                 outer.cacheData.perFormatters[outer.width].
285                         applyPatternMinMaxArguments(value.getUnicodeString(errorCode), 2, 2, errorCode);
286             }
287         }
288         UnitDataSink &outer;
289     } compoundSink;
290 
291     /**
292      * Sink for a table of unit type tables. For example,
293      * unitsShort contains tables for area & duration.
294      * It also contains a table for the compound/per pattern.
295      */
296     struct UnitTypeSink : public ResourceTableSink {
UnitTypeSink__anona245636e0111::UnitDataSink::UnitTypeSink297         UnitTypeSink(UnitDataSink &sink) : outer(sink) {}
298         ~UnitTypeSink();
getOrCreateTableSink__anona245636e0111::UnitDataSink::UnitTypeSink299         virtual ResourceTableSink *getOrCreateTableSink(
300                 const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
301             if (U_FAILURE(errorCode)) { return NULL; }
302             if (uprv_strcmp(key, "currency") == 0) {
303                 // Skip.
304             } else if (uprv_strcmp(key, "compound") == 0) {
305                 if (!outer.cacheData.hasPerFormatter(outer.width)) {
306                     return &outer.compoundSink;
307                 }
308             } else {
309                 outer.type = key;
310                 return &outer.subtypeSink;
311             }
312             return NULL;
313         }
314         UnitDataSink &outer;
315     } typeSink;
316 
UnitDataSink__anona245636e0111::UnitDataSink317     UnitDataSink(MeasureFormatCacheData &outputData)
318             : patternSink(*this), subtypeSink(*this), compoundSink(*this), typeSink(*this),
319               cacheData(outputData),
320               width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0) {}
321     ~UnitDataSink();
put__anona245636e0111::UnitDataSink322     virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
323         // Handle aliases like
324         // units:alias{"/LOCALE/unitsShort"}
325         // which should only occur in the root bundle.
326         if (U_FAILURE(errorCode) || value.getType() != URES_ALIAS) { return; }
327         UMeasureFormatWidth sourceWidth = widthFromKey(key);
328         if (sourceWidth == UMEASFMT_WIDTH_COUNT) {
329             // Alias from something we don't care about.
330             return;
331         }
332         UMeasureFormatWidth targetWidth = widthFromAlias(value, errorCode);
333         if (targetWidth == UMEASFMT_WIDTH_COUNT) {
334             // We do not recognize what to fall back to.
335             errorCode = U_INVALID_FORMAT_ERROR;
336             return;
337         }
338         // Check that we do not fall back to another fallback.
339         if (cacheData.widthFallback[targetWidth] != UMEASFMT_WIDTH_COUNT) {
340             errorCode = U_INVALID_FORMAT_ERROR;
341             return;
342         }
343         cacheData.widthFallback[sourceWidth] = targetWidth;
344     }
getOrCreateTableSink__anona245636e0111::UnitDataSink345     virtual ResourceTableSink *getOrCreateTableSink(
346             const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
347         if (U_SUCCESS(errorCode) && (width = widthFromKey(key)) != UMEASFMT_WIDTH_COUNT) {
348             return &typeSink;
349         }
350         return NULL;
351     }
352 
widthFromKey__anona245636e0111::UnitDataSink353     static UMeasureFormatWidth widthFromKey(const char *key) {
354         if (uprv_strncmp(key, "units", 5) == 0) {
355             key += 5;
356             if (*key == 0) {
357                 return UMEASFMT_WIDTH_WIDE;
358             } else if (uprv_strcmp(key, "Short") == 0) {
359                 return UMEASFMT_WIDTH_SHORT;
360             } else if (uprv_strcmp(key, "Narrow") == 0) {
361                 return UMEASFMT_WIDTH_NARROW;
362             }
363         }
364         return UMEASFMT_WIDTH_COUNT;
365     }
366 
widthFromAlias__anona245636e0111::UnitDataSink367     static UMeasureFormatWidth widthFromAlias(const ResourceValue &value, UErrorCode &errorCode) {
368         int32_t length;
369         const UChar *s = value.getAliasString(length, errorCode);
370         // For example: "/LOCALE/unitsShort"
371         if (U_SUCCESS(errorCode) && length >= 13 && u_memcmp(s, g_LOCALE_units, 13) == 0) {
372             s += 13;
373             length -= 13;
374             if (*s == 0) {
375                 return UMEASFMT_WIDTH_WIDE;
376             } else if (u_strCompare(s, length, gShort, 5, FALSE) == 0) {
377                 return UMEASFMT_WIDTH_SHORT;
378             } else if (u_strCompare(s, length, gNarrow, 6, FALSE) == 0) {
379                 return UMEASFMT_WIDTH_NARROW;
380             }
381         }
382         return UMEASFMT_WIDTH_COUNT;
383     }
384 
385     // Output data.
386     MeasureFormatCacheData &cacheData;
387 
388     // Path to current data.
389     UMeasureFormatWidth width;
390     const char *type;
391     int32_t unitIndex;
392 };
393 
394 // Virtual destructors must be defined out of line.
~UnitPatternSink()395 UnitDataSink::UnitPatternSink::~UnitPatternSink() {}
~UnitSubtypeSink()396 UnitDataSink::UnitSubtypeSink::~UnitSubtypeSink() {}
~UnitCompoundSink()397 UnitDataSink::UnitCompoundSink::~UnitCompoundSink() {}
~UnitTypeSink()398 UnitDataSink::UnitTypeSink::~UnitTypeSink() {}
~UnitDataSink()399 UnitDataSink::~UnitDataSink() {}
400 
401 }  // namespace
402 
loadMeasureUnitData(const UResourceBundle * resource,MeasureFormatCacheData & cacheData,UErrorCode & status)403 static UBool loadMeasureUnitData(
404         const UResourceBundle *resource,
405         MeasureFormatCacheData &cacheData,
406         UErrorCode &status) {
407     UnitDataSink sink(cacheData);
408     ures_getAllTableItemsWithFallback(resource, "", sink, status);
409     return U_SUCCESS(status);
410 }
411 
loadNumericDateFormatterPattern(const UResourceBundle * resource,const char * pattern,UErrorCode & status)412 static UnicodeString loadNumericDateFormatterPattern(
413         const UResourceBundle *resource,
414         const char *pattern,
415         UErrorCode &status) {
416     UnicodeString result;
417     if (U_FAILURE(status)) {
418         return result;
419     }
420     CharString chs;
421     chs.append("durationUnits", status)
422             .append("/", status).append(pattern, status);
423     LocalUResourceBundlePointer patternBundle(
424             ures_getByKeyWithFallback(
425                 resource,
426                 chs.data(),
427                 NULL,
428                 &status));
429     if (U_FAILURE(status)) {
430         return result;
431     }
432     getString(patternBundle.getAlias(), result, status);
433     // Replace 'h' with 'H'
434     int32_t len = result.length();
435     UChar *buffer = result.getBuffer(len);
436     for (int32_t i = 0; i < len; ++i) {
437         if (buffer[i] == 0x68) { // 'h'
438             buffer[i] = 0x48; // 'H'
439         }
440     }
441     result.releaseBuffer(len);
442     return result;
443 }
444 
loadNumericDateFormatters(const UResourceBundle * resource,UErrorCode & status)445 static NumericDateFormatters *loadNumericDateFormatters(
446         const UResourceBundle *resource,
447         UErrorCode &status) {
448     if (U_FAILURE(status)) {
449         return NULL;
450     }
451     NumericDateFormatters *result = new NumericDateFormatters(
452         loadNumericDateFormatterPattern(resource, "hm", status),
453         loadNumericDateFormatterPattern(resource, "ms", status),
454         loadNumericDateFormatterPattern(resource, "hms", status),
455         status);
456     if (U_FAILURE(status)) {
457         delete result;
458         return NULL;
459     }
460     return result;
461 }
462 
463 template<> U_I18N_API
createObject(const void *,UErrorCode & status) const464 const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
465         const void * /*unused*/, UErrorCode &status) const {
466     const char *localeId = fLoc.getName();
467     LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
468     static UNumberFormatStyle currencyStyles[] = {
469             UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
470     LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
471     if (U_FAILURE(status)) {
472         return NULL;
473     }
474     if (!loadMeasureUnitData(
475             unitsBundle.getAlias(),
476             *result,
477             status)) {
478         return NULL;
479     }
480     result->adoptNumericDateFormatters(loadNumericDateFormatters(
481             unitsBundle.getAlias(), status));
482     if (U_FAILURE(status)) {
483         return NULL;
484     }
485 
486     for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
487         result->adoptCurrencyFormat(i, NumberFormat::createInstance(
488                 localeId, currencyStyles[i], status));
489         if (U_FAILURE(status)) {
490             return NULL;
491         }
492     }
493     NumberFormat *inf = NumberFormat::createInstance(
494             localeId, UNUM_DECIMAL, status);
495     if (U_FAILURE(status)) {
496         return NULL;
497     }
498     inf->setMaximumFractionDigits(0);
499     DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
500     if (decfmt != NULL) {
501         decfmt->setRoundingMode(DecimalFormat::kRoundDown);
502     }
503     result->adoptIntegerFormat(inf);
504     result->addRef();
505     return result.orphan();
506 }
507 
isTimeUnit(const MeasureUnit & mu,const char * tu)508 static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
509     return uprv_strcmp(mu.getType(), "duration") == 0 &&
510             uprv_strcmp(mu.getSubtype(), tu) == 0;
511 }
512 
513 // Converts a composite measure into hours-minutes-seconds and stores at hms
514 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
515 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
516 // contains hours-minutes, this function would return 3.
517 //
518 // If measures cannot be converted into hours, minutes, seconds or if amounts
519 // are negative, or if hours, minutes, seconds are out of order, returns 0.
toHMS(const Measure * measures,int32_t measureCount,Formattable * hms,UErrorCode & status)520 static int32_t toHMS(
521         const Measure *measures,
522         int32_t measureCount,
523         Formattable *hms,
524         UErrorCode &status) {
525     if (U_FAILURE(status)) {
526         return 0;
527     }
528     int32_t result = 0;
529     if (U_FAILURE(status)) {
530         return 0;
531     }
532     // We use copy constructor to ensure that both sides of equality operator
533     // are instances of MeasureUnit base class and not a subclass. Otherwise,
534     // operator== will immediately return false.
535     for (int32_t i = 0; i < measureCount; ++i) {
536         if (isTimeUnit(measures[i].getUnit(), "hour")) {
537             // hour must come first
538             if (result >= 1) {
539                 return 0;
540             }
541             hms[0] = measures[i].getNumber();
542             if (hms[0].getDouble() < 0.0) {
543                 return 0;
544             }
545             result |= 1;
546         } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
547             // minute must come after hour
548             if (result >= 2) {
549                 return 0;
550             }
551             hms[1] = measures[i].getNumber();
552             if (hms[1].getDouble() < 0.0) {
553                 return 0;
554             }
555             result |= 2;
556         } else if (isTimeUnit(measures[i].getUnit(), "second")) {
557             // second must come after hour and minute
558             if (result >= 4) {
559                 return 0;
560             }
561             hms[2] = measures[i].getNumber();
562             if (hms[2].getDouble() < 0.0) {
563                 return 0;
564             }
565             result |= 4;
566         } else {
567             return 0;
568         }
569     }
570     return result;
571 }
572 
573 
MeasureFormat(const Locale & locale,UMeasureFormatWidth w,UErrorCode & status)574 MeasureFormat::MeasureFormat(
575         const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
576         : cache(NULL),
577           numberFormat(NULL),
578           pluralRules(NULL),
579           width(w),
580           listFormatter(NULL) {
581     initMeasureFormat(locale, w, NULL, status);
582 }
583 
MeasureFormat(const Locale & locale,UMeasureFormatWidth w,NumberFormat * nfToAdopt,UErrorCode & status)584 MeasureFormat::MeasureFormat(
585         const Locale &locale,
586         UMeasureFormatWidth w,
587         NumberFormat *nfToAdopt,
588         UErrorCode &status)
589         : cache(NULL),
590           numberFormat(NULL),
591           pluralRules(NULL),
592           width(w),
593           listFormatter(NULL) {
594     initMeasureFormat(locale, w, nfToAdopt, status);
595 }
596 
MeasureFormat(const MeasureFormat & other)597 MeasureFormat::MeasureFormat(const MeasureFormat &other) :
598         Format(other),
599         cache(other.cache),
600         numberFormat(other.numberFormat),
601         pluralRules(other.pluralRules),
602         width(other.width),
603         listFormatter(NULL) {
604     cache->addRef();
605     numberFormat->addRef();
606     pluralRules->addRef();
607     if (other.listFormatter != NULL) {
608         listFormatter = new ListFormatter(*other.listFormatter);
609     }
610 }
611 
operator =(const MeasureFormat & other)612 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
613     if (this == &other) {
614         return *this;
615     }
616     Format::operator=(other);
617     SharedObject::copyPtr(other.cache, cache);
618     SharedObject::copyPtr(other.numberFormat, numberFormat);
619     SharedObject::copyPtr(other.pluralRules, pluralRules);
620     width = other.width;
621     delete listFormatter;
622     if (other.listFormatter != NULL) {
623         listFormatter = new ListFormatter(*other.listFormatter);
624     } else {
625         listFormatter = NULL;
626     }
627     return *this;
628 }
629 
MeasureFormat()630 MeasureFormat::MeasureFormat() :
631         cache(NULL),
632         numberFormat(NULL),
633         pluralRules(NULL),
634         width(UMEASFMT_WIDTH_SHORT),
635         listFormatter(NULL) {
636 }
637 
~MeasureFormat()638 MeasureFormat::~MeasureFormat() {
639     if (cache != NULL) {
640         cache->removeRef();
641     }
642     if (numberFormat != NULL) {
643         numberFormat->removeRef();
644     }
645     if (pluralRules != NULL) {
646         pluralRules->removeRef();
647     }
648     delete listFormatter;
649 }
650 
operator ==(const Format & other) const651 UBool MeasureFormat::operator==(const Format &other) const {
652     if (this == &other) { // Same object, equal
653         return TRUE;
654     }
655     if (!Format::operator==(other)) {
656         return FALSE;
657     }
658     const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
659 
660     // Note: Since the ListFormatter depends only on Locale and width, we
661     // don't have to check it here.
662 
663     // differing widths aren't equivalent
664     if (width != rhs.width) {
665         return FALSE;
666     }
667     // Width the same check locales.
668     // We don't need to check locales if both objects have same cache.
669     if (cache != rhs.cache) {
670         UErrorCode status = U_ZERO_ERROR;
671         const char *localeId = getLocaleID(status);
672         const char *rhsLocaleId = rhs.getLocaleID(status);
673         if (U_FAILURE(status)) {
674             // On failure, assume not equal
675             return FALSE;
676         }
677         if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
678             return FALSE;
679         }
680     }
681     // Locales same, check NumberFormat if shared data differs.
682     return (
683             numberFormat == rhs.numberFormat ||
684             **numberFormat == **rhs.numberFormat);
685 }
686 
clone() const687 Format *MeasureFormat::clone() const {
688     return new MeasureFormat(*this);
689 }
690 
format(const Formattable & obj,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const691 UnicodeString &MeasureFormat::format(
692         const Formattable &obj,
693         UnicodeString &appendTo,
694         FieldPosition &pos,
695         UErrorCode &status) const {
696     if (U_FAILURE(status)) return appendTo;
697     if (obj.getType() == Formattable::kObject) {
698         const UObject* formatObj = obj.getObject();
699         const Measure* amount = dynamic_cast<const Measure*>(formatObj);
700         if (amount != NULL) {
701             return formatMeasure(
702                     *amount, **numberFormat, appendTo, pos, status);
703         }
704     }
705     status = U_ILLEGAL_ARGUMENT_ERROR;
706     return appendTo;
707 }
708 
parseObject(const UnicodeString &,Formattable &,ParsePosition &) const709 void MeasureFormat::parseObject(
710         const UnicodeString & /*source*/,
711         Formattable & /*result*/,
712         ParsePosition& /*pos*/) const {
713     return;
714 }
715 
formatMeasurePerUnit(const Measure & measure,const MeasureUnit & perUnit,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const716 UnicodeString &MeasureFormat::formatMeasurePerUnit(
717         const Measure &measure,
718         const MeasureUnit &perUnit,
719         UnicodeString &appendTo,
720         FieldPosition &pos,
721         UErrorCode &status) const {
722     if (U_FAILURE(status)) {
723         return appendTo;
724     }
725     MeasureUnit *resolvedUnit =
726             MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit);
727     if (resolvedUnit != NULL) {
728         Measure newMeasure(measure.getNumber(), resolvedUnit, status);
729         return formatMeasure(
730                 newMeasure, **numberFormat, appendTo, pos, status);
731     }
732     FieldPosition fpos(pos.getField());
733     UnicodeString result;
734     int32_t offset = withPerUnitAndAppend(
735             formatMeasure(
736                     measure, **numberFormat, result, fpos, status),
737             perUnit,
738             appendTo,
739             status);
740     if (U_FAILURE(status)) {
741         return appendTo;
742     }
743     if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
744         pos.setBeginIndex(fpos.getBeginIndex() + offset);
745         pos.setEndIndex(fpos.getEndIndex() + offset);
746     }
747     return appendTo;
748 }
749 
formatMeasures(const Measure * measures,int32_t measureCount,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const750 UnicodeString &MeasureFormat::formatMeasures(
751         const Measure *measures,
752         int32_t measureCount,
753         UnicodeString &appendTo,
754         FieldPosition &pos,
755         UErrorCode &status) const {
756     if (U_FAILURE(status)) {
757         return appendTo;
758     }
759     if (measureCount == 0) {
760         return appendTo;
761     }
762     if (measureCount == 1) {
763         return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
764     }
765     if (width == UMEASFMT_WIDTH_NUMERIC) {
766         Formattable hms[3];
767         int32_t bitMap = toHMS(measures, measureCount, hms, status);
768         if (bitMap > 0) {
769             return formatNumeric(hms, bitMap, appendTo, status);
770         }
771     }
772     if (pos.getField() != FieldPosition::DONT_CARE) {
773         return formatMeasuresSlowTrack(
774                 measures, measureCount, appendTo, pos, status);
775     }
776     UnicodeString *results = new UnicodeString[measureCount];
777     if (results == NULL) {
778         status = U_MEMORY_ALLOCATION_ERROR;
779         return appendTo;
780     }
781     for (int32_t i = 0; i < measureCount; ++i) {
782         const NumberFormat *nf = cache->getIntegerFormat();
783         if (i == measureCount - 1) {
784             nf = numberFormat->get();
785         }
786         formatMeasure(
787                 measures[i],
788                 *nf,
789                 results[i],
790                 pos,
791                 status);
792     }
793     listFormatter->format(results, measureCount, appendTo, status);
794     delete [] results;
795     return appendTo;
796 }
797 
initMeasureFormat(const Locale & locale,UMeasureFormatWidth w,NumberFormat * nfToAdopt,UErrorCode & status)798 void MeasureFormat::initMeasureFormat(
799         const Locale &locale,
800         UMeasureFormatWidth w,
801         NumberFormat *nfToAdopt,
802         UErrorCode &status) {
803     static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
804     LocalPointer<NumberFormat> nf(nfToAdopt);
805     if (U_FAILURE(status)) {
806         return;
807     }
808     const char *name = locale.getName();
809     setLocaleIDs(name, name);
810 
811     UnifiedCache::getByLocale(locale, cache, status);
812     if (U_FAILURE(status)) {
813         return;
814     }
815 
816     const SharedPluralRules *pr = PluralRules::createSharedInstance(
817             locale, UPLURAL_TYPE_CARDINAL, status);
818     if (U_FAILURE(status)) {
819         return;
820     }
821     SharedObject::copyPtr(pr, pluralRules);
822     pr->removeRef();
823     if (nf.isNull()) {
824         const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
825                 locale, UNUM_DECIMAL, status);
826         if (U_FAILURE(status)) {
827             return;
828         }
829         SharedObject::copyPtr(shared, numberFormat);
830         shared->removeRef();
831     } else {
832         adoptNumberFormat(nf.orphan(), status);
833         if (U_FAILURE(status)) {
834             return;
835         }
836     }
837     width = w;
838     delete listFormatter;
839     listFormatter = ListFormatter::createInstance(
840             locale,
841             listStyles[getRegularWidth(width)],
842             status);
843 }
844 
adoptNumberFormat(NumberFormat * nfToAdopt,UErrorCode & status)845 void MeasureFormat::adoptNumberFormat(
846         NumberFormat *nfToAdopt, UErrorCode &status) {
847     LocalPointer<NumberFormat> nf(nfToAdopt);
848     if (U_FAILURE(status)) {
849         return;
850     }
851     SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
852     if (shared == NULL) {
853         status = U_MEMORY_ALLOCATION_ERROR;
854         return;
855     }
856     nf.orphan();
857     SharedObject::copyPtr(shared, numberFormat);
858 }
859 
setMeasureFormatLocale(const Locale & locale,UErrorCode & status)860 UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
861     if (U_FAILURE(status) || locale == getLocale(status)) {
862         return FALSE;
863     }
864     initMeasureFormat(locale, width, NULL, status);
865     return U_SUCCESS(status);
866 }
867 
getNumberFormat() const868 const NumberFormat &MeasureFormat::getNumberFormat() const {
869     return **numberFormat;
870 }
871 
getPluralRules() const872 const PluralRules &MeasureFormat::getPluralRules() const {
873     return **pluralRules;
874 }
875 
getLocale(UErrorCode & status) const876 Locale MeasureFormat::getLocale(UErrorCode &status) const {
877     return Format::getLocale(ULOC_VALID_LOCALE, status);
878 }
879 
getLocaleID(UErrorCode & status) const880 const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
881     return Format::getLocaleID(ULOC_VALID_LOCALE, status);
882 }
883 
formatMeasure(const Measure & measure,const NumberFormat & nf,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const884 UnicodeString &MeasureFormat::formatMeasure(
885         const Measure &measure,
886         const NumberFormat &nf,
887         UnicodeString &appendTo,
888         FieldPosition &pos,
889         UErrorCode &status) const {
890     if (U_FAILURE(status)) {
891         return appendTo;
892     }
893     const Formattable& amtNumber = measure.getNumber();
894     const MeasureUnit& amtUnit = measure.getUnit();
895     if (isCurrency(amtUnit)) {
896         UChar isoCode[4];
897         u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
898         return cache->getCurrencyFormat(width)->format(
899                 new CurrencyAmount(amtNumber, isoCode, status),
900                 appendTo,
901                 pos,
902                 status);
903     }
904     UnicodeString formattedNumber;
905     StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
906             amtNumber, nf, **pluralRules, formattedNumber, pos, status);
907     const SimpleFormatter *formatter = getPluralFormatter(amtUnit, width, pluralForm, status);
908     return QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos, status);
909 }
910 
911 // Formats hours-minutes-seconds as 5:37:23 or similar.
formatNumeric(const Formattable * hms,int32_t bitMap,UnicodeString & appendTo,UErrorCode & status) const912 UnicodeString &MeasureFormat::formatNumeric(
913         const Formattable *hms,  // always length 3
914         int32_t bitMap,   // 1=hourset, 2=minuteset, 4=secondset
915         UnicodeString &appendTo,
916         UErrorCode &status) const {
917     if (U_FAILURE(status)) {
918         return appendTo;
919     }
920     UDate millis =
921         (UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
922              + uprv_trunc(hms[1].getDouble(status))) * 60.0
923                   + uprv_trunc(hms[2].getDouble(status))) * 1000.0);
924     switch (bitMap) {
925     case 5: // hs
926     case 7: // hms
927         return formatNumeric(
928                 millis,
929                 cache->getNumericDateFormatters()->hourMinuteSecond,
930                 UDAT_SECOND_FIELD,
931                 hms[2],
932                 appendTo,
933                 status);
934         break;
935     case 6: // ms
936         return formatNumeric(
937                 millis,
938                 cache->getNumericDateFormatters()->minuteSecond,
939                 UDAT_SECOND_FIELD,
940                 hms[2],
941                 appendTo,
942                 status);
943         break;
944     case 3: // hm
945         return formatNumeric(
946                 millis,
947                 cache->getNumericDateFormatters()->hourMinute,
948                 UDAT_MINUTE_FIELD,
949                 hms[1],
950                 appendTo,
951                 status);
952         break;
953     default:
954         status = U_INTERNAL_PROGRAM_ERROR;
955         return appendTo;
956         break;
957     }
958     return appendTo;
959 }
960 
appendRange(const UnicodeString & src,int32_t start,int32_t end,UnicodeString & dest)961 static void appendRange(
962         const UnicodeString &src,
963         int32_t start,
964         int32_t end,
965         UnicodeString &dest) {
966     dest.append(src, start, end - start);
967 }
968 
appendRange(const UnicodeString & src,int32_t end,UnicodeString & dest)969 static void appendRange(
970         const UnicodeString &src,
971         int32_t end,
972         UnicodeString &dest) {
973     dest.append(src, end, src.length() - end);
974 }
975 
976 // Formats time like 5:37:23
formatNumeric(UDate date,const DateFormat & dateFmt,UDateFormatField smallestField,const Formattable & smallestAmount,UnicodeString & appendTo,UErrorCode & status) const977 UnicodeString &MeasureFormat::formatNumeric(
978         UDate date, // Time since epoch 1:30:00 would be 5400000
979         const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
980         UDateFormatField smallestField, // seconds in 5:37:23.5
981         const Formattable &smallestAmount, // 23.5 for 5:37:23.5
982         UnicodeString &appendTo,
983         UErrorCode &status) const {
984     if (U_FAILURE(status)) {
985         return appendTo;
986     }
987     // Format the smallest amount with this object's NumberFormat
988     UnicodeString smallestAmountFormatted;
989 
990     // We keep track of the integer part of smallest amount so that
991     // we can replace it later so that we get '0:00:09.3' instead of
992     // '0:00:9.3'
993     FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
994     (*numberFormat)->format(
995             smallestAmount, smallestAmountFormatted, intFieldPosition, status);
996     if (
997             intFieldPosition.getBeginIndex() == 0 &&
998             intFieldPosition.getEndIndex() == 0) {
999         status = U_INTERNAL_PROGRAM_ERROR;
1000         return appendTo;
1001     }
1002 
1003     // Format time. draft becomes something like '5:30:45'
1004     FieldPosition smallestFieldPosition(smallestField);
1005     UnicodeString draft;
1006     dateFmt.format(date, draft, smallestFieldPosition, status);
1007 
1008     // If we find field for smallest amount replace it with the formatted
1009     // smallest amount from above taking care to replace the integer part
1010     // with what is in original time. For example, If smallest amount
1011     // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
1012     // and replacing yields 0:00:09.35
1013     if (smallestFieldPosition.getBeginIndex() != 0 ||
1014             smallestFieldPosition.getEndIndex() != 0) {
1015         appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
1016         appendRange(
1017                 smallestAmountFormatted,
1018                 0,
1019                 intFieldPosition.getBeginIndex(),
1020                 appendTo);
1021         appendRange(
1022                 draft,
1023                 smallestFieldPosition.getBeginIndex(),
1024                 smallestFieldPosition.getEndIndex(),
1025                 appendTo);
1026         appendRange(
1027                 smallestAmountFormatted,
1028                 intFieldPosition.getEndIndex(),
1029                 appendTo);
1030         appendRange(
1031                 draft,
1032                 smallestFieldPosition.getEndIndex(),
1033                 appendTo);
1034     } else {
1035         appendTo.append(draft);
1036     }
1037     return appendTo;
1038 }
1039 
getFormatterOrNull(const MeasureUnit & unit,UMeasureFormatWidth width,int32_t index) const1040 const SimpleFormatter *MeasureFormat::getFormatterOrNull(
1041         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index) const {
1042     width = getRegularWidth(width);
1043     SimpleFormatter *const (*unitPatterns)[MeasureFormatCacheData::PATTERN_COUNT] =
1044             &cache->patterns[unit.getIndex()][0];
1045     if (unitPatterns[width][index] != NULL) {
1046         return unitPatterns[width][index];
1047     }
1048     int32_t fallbackWidth = cache->widthFallback[width];
1049     if (fallbackWidth != UMEASFMT_WIDTH_COUNT && unitPatterns[fallbackWidth][index] != NULL) {
1050         return unitPatterns[fallbackWidth][index];
1051     }
1052     return NULL;
1053 }
1054 
getFormatter(const MeasureUnit & unit,UMeasureFormatWidth width,int32_t index,UErrorCode & errorCode) const1055 const SimpleFormatter *MeasureFormat::getFormatter(
1056         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
1057         UErrorCode &errorCode) const {
1058     if (U_FAILURE(errorCode)) {
1059         return NULL;
1060     }
1061     const SimpleFormatter *pattern = getFormatterOrNull(unit, width, index);
1062     if (pattern == NULL) {
1063         errorCode = U_MISSING_RESOURCE_ERROR;
1064     }
1065     return pattern;
1066 }
1067 
getPluralFormatter(const MeasureUnit & unit,UMeasureFormatWidth width,int32_t index,UErrorCode & errorCode) const1068 const SimpleFormatter *MeasureFormat::getPluralFormatter(
1069         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
1070         UErrorCode &errorCode) const {
1071     if (U_FAILURE(errorCode)) {
1072         return NULL;
1073     }
1074     if (index != StandardPlural::OTHER) {
1075         const SimpleFormatter *pattern = getFormatterOrNull(unit, width, index);
1076         if (pattern != NULL) {
1077             return pattern;
1078         }
1079     }
1080     return getFormatter(unit, width, StandardPlural::OTHER, errorCode);
1081 }
1082 
getPerFormatter(UMeasureFormatWidth width,UErrorCode & status) const1083 const SimpleFormatter *MeasureFormat::getPerFormatter(
1084         UMeasureFormatWidth width,
1085         UErrorCode &status) const {
1086     if (U_FAILURE(status)) {
1087         return NULL;
1088     }
1089     width = getRegularWidth(width);
1090     const SimpleFormatter * perFormatters = cache->perFormatters;
1091     if (perFormatters[width].getArgumentLimit() == 2) {
1092         return &perFormatters[width];
1093     }
1094     int32_t fallbackWidth = cache->widthFallback[width];
1095     if (fallbackWidth != UMEASFMT_WIDTH_COUNT &&
1096             perFormatters[fallbackWidth].getArgumentLimit() == 2) {
1097         return &perFormatters[fallbackWidth];
1098     }
1099     status = U_MISSING_RESOURCE_ERROR;
1100     return NULL;
1101 }
1102 
withPerUnitAndAppend(const UnicodeString & formatted,const MeasureUnit & perUnit,UnicodeString & appendTo,UErrorCode & status) const1103 int32_t MeasureFormat::withPerUnitAndAppend(
1104         const UnicodeString &formatted,
1105         const MeasureUnit &perUnit,
1106         UnicodeString &appendTo,
1107         UErrorCode &status) const {
1108     int32_t offset = -1;
1109     if (U_FAILURE(status)) {
1110         return offset;
1111     }
1112     const SimpleFormatter *perUnitFormatter =
1113             getFormatterOrNull(perUnit, width, MeasureFormatCacheData::PER_UNIT_INDEX);
1114     if (perUnitFormatter != NULL) {
1115         const UnicodeString *params[] = {&formatted};
1116         perUnitFormatter->formatAndAppend(
1117                 params,
1118                 UPRV_LENGTHOF(params),
1119                 appendTo,
1120                 &offset,
1121                 1,
1122                 status);
1123         return offset;
1124     }
1125     const SimpleFormatter *perFormatter = getPerFormatter(width, status);
1126     const SimpleFormatter *pattern =
1127             getPluralFormatter(perUnit, width, StandardPlural::ONE, status);
1128     if (U_FAILURE(status)) {
1129         return offset;
1130     }
1131     UnicodeString perUnitString = pattern->getTextWithNoArguments();
1132     perUnitString.trim();
1133     const UnicodeString *params[] = {&formatted, &perUnitString};
1134     perFormatter->formatAndAppend(
1135             params,
1136             UPRV_LENGTHOF(params),
1137             appendTo,
1138             &offset,
1139             1,
1140             status);
1141     return offset;
1142 }
1143 
formatMeasuresSlowTrack(const Measure * measures,int32_t measureCount,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const1144 UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
1145         const Measure *measures,
1146         int32_t measureCount,
1147         UnicodeString& appendTo,
1148         FieldPosition& pos,
1149         UErrorCode& status) const {
1150     if (U_FAILURE(status)) {
1151         return appendTo;
1152     }
1153     FieldPosition dontCare(FieldPosition::DONT_CARE);
1154     FieldPosition fpos(pos.getField());
1155     UnicodeString *results = new UnicodeString[measureCount];
1156     int32_t fieldPositionFoundIndex = -1;
1157     for (int32_t i = 0; i < measureCount; ++i) {
1158         const NumberFormat *nf = cache->getIntegerFormat();
1159         if (i == measureCount - 1) {
1160             nf = numberFormat->get();
1161         }
1162         if (fieldPositionFoundIndex == -1) {
1163             formatMeasure(measures[i], *nf, results[i], fpos, status);
1164             if (U_FAILURE(status)) {
1165                 delete [] results;
1166                 return appendTo;
1167             }
1168             if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
1169                 fieldPositionFoundIndex = i;
1170             }
1171         } else {
1172             formatMeasure(measures[i], *nf, results[i], dontCare, status);
1173         }
1174     }
1175     int32_t offset;
1176     listFormatter->format(
1177             results,
1178             measureCount,
1179             appendTo,
1180             fieldPositionFoundIndex,
1181             offset,
1182             status);
1183     if (U_FAILURE(status)) {
1184         delete [] results;
1185         return appendTo;
1186     }
1187     if (offset != -1) {
1188         pos.setBeginIndex(fpos.getBeginIndex() + offset);
1189         pos.setEndIndex(fpos.getEndIndex() + offset);
1190     }
1191     delete [] results;
1192     return appendTo;
1193 }
1194 
createCurrencyFormat(const Locale & locale,UErrorCode & ec)1195 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
1196                                                    UErrorCode& ec) {
1197     CurrencyFormat* fmt = NULL;
1198     if (U_SUCCESS(ec)) {
1199         fmt = new CurrencyFormat(locale, ec);
1200         if (U_FAILURE(ec)) {
1201             delete fmt;
1202             fmt = NULL;
1203         }
1204     }
1205     return fmt;
1206 }
1207 
createCurrencyFormat(UErrorCode & ec)1208 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
1209     if (U_FAILURE(ec)) {
1210         return NULL;
1211     }
1212     return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
1213 }
1214 
1215 U_NAMESPACE_END
1216 
1217 #endif /* #if !UCONFIG_NO_FORMATTING */
1218