2 *******************************************************************************
3 * Copyright (C) 2007-2009, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
9 *******************************************************************************
12 #include "unicode/utypes.h"
13 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/datefmt.h"
16 #include "unicode/decimfmt.h"
17 #include "unicode/dtfmtsym.h"
18 #include "unicode/dtptngen.h"
19 #include "unicode/msgfmt.h"
20 #include "unicode/smpdtfmt.h"
21 #include "unicode/udat.h"
22 #include "unicode/udatpg.h"
23 #include "unicode/uniset.h"
24 #include "unicode/uloc.h"
25 #include "unicode/ures.h"
26 #include "unicode/ustring.h"
27 #include "unicode/rep.h"
37 #include "dtptngen_impl.h"
39 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
41 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
43 * If we are on EBCDIC, use an iterator which will
44 * traverse the bundles in ASCII order.
46 #define U_USE_ASCII_BUNDLE_ITERATOR
47 #define U_SORT_ASCII_BUNDLE_ITERATOR
50 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
52 #include "unicode/ustring.h"
57 UResourceBundle
*item
;
60 struct UResourceBundleAIterator
{
61 UResourceBundle
*bund
;
67 /* Must be C linkage to pass function pointer to the sort function */
69 extern "C" static int32_t U_CALLCONV
70 ures_a_codepointSort(const void *context
, const void *left
, const void *right
) {
71 //CompareContext *cmp=(CompareContext *)context;
72 return u_strcmp(((const UResAEntry
*)left
)->key
,
73 ((const UResAEntry
*)right
)->key
);
77 static void ures_a_open(UResourceBundleAIterator
*aiter
, UResourceBundle
*bund
, UErrorCode
*status
) {
78 if(U_FAILURE(*status
)) {
82 aiter
->num
= ures_getSize(aiter
->bund
);
84 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
85 aiter
->entries
= NULL
;
87 aiter
->entries
= (UResAEntry
*)uprv_malloc(sizeof(UResAEntry
)*aiter
->num
);
88 for(int i
=0;i
<aiter
->num
;i
++) {
89 aiter
->entries
[i
].item
= ures_getByIndex(aiter
->bund
, i
, NULL
, status
);
90 const char *akey
= ures_getKey(aiter
->entries
[i
].item
);
91 int32_t len
= uprv_strlen(akey
)+1;
92 aiter
->entries
[i
].key
= (UChar
*)uprv_malloc(len
*sizeof(UChar
));
93 u_charsToUChars(akey
, aiter
->entries
[i
].key
, len
);
95 uprv_sortArray(aiter
->entries
, aiter
->num
, sizeof(UResAEntry
), ures_a_codepointSort
, NULL
, TRUE
, status
);
99 static void ures_a_close(UResourceBundleAIterator
*aiter
) {
100 #if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
101 for(int i
=0;i
<aiter
->num
;i
++) {
102 uprv_free(aiter
->entries
[i
].key
);
103 ures_close(aiter
->entries
[i
].item
);
108 static const UChar
*ures_a_getNextString(UResourceBundleAIterator
*aiter
, int32_t *len
, const char **key
, UErrorCode
*err
) {
109 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
110 return ures_getNextString(aiter
->bund
, len
, key
, err
);
112 if(U_FAILURE(*err
)) return NULL
;
113 UResourceBundle
*item
= aiter
->entries
[aiter
->cursor
].item
;
114 const UChar
* ret
= ures_getString(item
, len
, err
);
115 *key
= ures_getKey(item
);
128 // *****************************************************************************
129 // class DateTimePatternGenerator
130 // *****************************************************************************
131 static const UChar Canonical_Items
[] = {
133 CAP_G
, LOW_Y
, CAP_Q
, CAP_M
, LOW_W
, CAP_W
, LOW_E
, LOW_D
, CAP_D
, CAP_F
,
134 CAP_H
, LOW_M
, LOW_S
, CAP_S
, LOW_V
, 0
137 static const dtTypeElem dtTypes
[] = {
138 // patternChar, field, type, minLen, weight
139 {CAP_G
, UDATPG_ERA_FIELD
, DT_SHORT
, 1, 3,},
140 {CAP_G
, UDATPG_ERA_FIELD
, DT_LONG
, 4, 0},
141 {LOW_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
, 1, 20},
142 {CAP_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 20},
143 {LOW_U
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 20},
144 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_NUMERIC
, 1, 2},
145 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_SHORT
, 3, 0},
146 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_LONG
, 4, 0},
147 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NUMERIC
, 1, 2},
148 {CAP_M
, UDATPG_MONTH_FIELD
, DT_SHORT
, 3, 0},
149 {CAP_M
, UDATPG_MONTH_FIELD
, DT_LONG
, 4, 0},
150 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NARROW
, 5, 0},
151 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
152 {CAP_L
, UDATPG_MONTH_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
153 {CAP_L
, UDATPG_MONTH_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
154 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
155 {LOW_W
, UDATPG_WEEK_OF_YEAR_FIELD
, DT_NUMERIC
, 1, 2},
156 {CAP_W
, UDATPG_WEEK_OF_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 0},
157 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
158 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
159 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
160 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
161 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
, 1, 3},
162 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
, 4, 0},
163 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
, 5, 0},
164 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 2},
165 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- 2*DT_DELTA
, 3, 0},
166 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
167 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- 2*DT_DELTA
, 5, 0},
168 {LOW_D
, UDATPG_DAY_FIELD
, DT_NUMERIC
, 1, 2},
169 {CAP_D
, UDATPG_DAY_OF_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 3},
170 {CAP_F
, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 0},
171 {LOW_G
, UDATPG_DAY_FIELD
, DT_NUMERIC
+ 3*DT_DELTA
, 1, 20}, // really internal use, so we don't care
172 {LOW_A
, UDATPG_DAYPERIOD_FIELD
, DT_SHORT
, 1, 0},
173 {CAP_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 10*DT_DELTA
, 1, 2}, // 24 hour
174 {LOW_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 11*DT_DELTA
, 1, 2},
175 {LOW_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
, 1, 2}, // 12 hour
176 {LOW_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
177 {LOW_M
, UDATPG_MINUTE_FIELD
, DT_NUMERIC
, 1, 2},
178 {LOW_S
, UDATPG_SECOND_FIELD
, DT_NUMERIC
, 1, 2},
179 {CAP_S
, UDATPG_FRACTIONAL_SECOND_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 1000},
180 {CAP_A
, UDATPG_SECOND_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 1000},
181 {LOW_V
, UDATPG_ZONE_FIELD
, DT_SHORT
- 2*DT_DELTA
, 1, 0},
182 {LOW_V
, UDATPG_ZONE_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
183 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
, 1, 3},
184 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_LONG
, 4, 0},
185 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 1, 3},
186 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
187 {0, UDATPG_FIELD_COUNT
, 0, 0, 0} , // last row of dtTypes[]
190 static const char* const CLDR_FIELD_APPEND
[] = {
191 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
192 "Hour", "Minute", "Second", "*", "Timezone"
195 static const char* const CLDR_FIELD_NAME
[] = {
196 "era", "year", "quarter", "month", "week", "*", "weekday", "day", "*", "*", "dayperiod",
197 "hour", "minute", "second", "*", "zone"
200 static const char* const Resource_Fields
[] = {
201 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
202 "weekday", "year", "zone", "quarter" };
205 static const UChar UDATPG_ItemFormat
[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
206 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
208 static const UChar repeatedPatterns
[6]={CAP_G
, CAP_E
, LOW_Z
, LOW_V
, CAP_Q
, 0}; // "GEzvQ"
210 static const char DT_DateTimePatternsTag
[]="DateTimePatterns";
211 static const char DT_DateTimeCalendarTag
[]="calendar";
212 static const char DT_DateTimeGregorianTag
[]="gregorian";
213 static const char DT_DateTimeAppendItemsTag
[]="appendItems";
214 static const char DT_DateTimeFieldsTag
[]="fields";
215 static const char DT_DateTimeAvailableFormatsTag
[]="availableFormats";
216 //static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
218 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator
)
219 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration
)
220 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration
)
222 DateTimePatternGenerator
* U_EXPORT2
223 DateTimePatternGenerator::createInstance(UErrorCode
& status
) {
224 return createInstance(Locale::getDefault(), status
);
227 DateTimePatternGenerator
* U_EXPORT2
228 DateTimePatternGenerator::createInstance(const Locale
& locale
, UErrorCode
& status
) {
229 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(locale
, status
);
230 if (result
== NULL
) {
231 status
= U_MEMORY_ALLOCATION_ERROR
;
233 if (U_FAILURE(status
)) {
240 DateTimePatternGenerator
* U_EXPORT2
241 DateTimePatternGenerator::createEmptyInstance(UErrorCode
& status
) {
242 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(status
);
243 if (result
== NULL
) {
244 status
= U_MEMORY_ALLOCATION_ERROR
;
246 if (U_FAILURE(status
)) {
253 DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode
&status
) :
255 fAvailableFormatKeyHash(NULL
)
257 fp
= new FormatParser();
258 dtMatcher
= new DateTimeMatcher();
259 distanceInfo
= new DistanceInfo();
260 patternMap
= new PatternMap();
261 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
262 status
= U_MEMORY_ALLOCATION_ERROR
;
266 DateTimePatternGenerator::DateTimePatternGenerator(const Locale
& locale
, UErrorCode
&status
) :
268 fAvailableFormatKeyHash(NULL
)
270 fp
= new FormatParser();
271 dtMatcher
= new DateTimeMatcher();
272 distanceInfo
= new DistanceInfo();
273 patternMap
= new PatternMap();
274 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
275 status
= U_MEMORY_ALLOCATION_ERROR
;
278 initData(locale
, status
);
282 DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator
& other
) :
285 fAvailableFormatKeyHash(NULL
)
287 fp
= new FormatParser();
288 dtMatcher
= new DateTimeMatcher();
289 distanceInfo
= new DistanceInfo();
290 patternMap
= new PatternMap();
294 DateTimePatternGenerator
&
295 DateTimePatternGenerator::operator=(const DateTimePatternGenerator
& other
) {
296 pLocale
= other
.pLocale
;
297 fDefaultHourFormatChar
= other
.fDefaultHourFormatChar
;
299 dtMatcher
->copyFrom(other
.dtMatcher
->skeleton
);
300 *distanceInfo
= *(other
.distanceInfo
);
301 dateTimeFormat
= other
.dateTimeFormat
;
302 decimal
= other
.decimal
;
303 // NUL-terminate for the C API.
304 dateTimeFormat
.getTerminatedBuffer();
305 decimal
.getTerminatedBuffer();
307 if ( other
.skipMatcher
== NULL
) {
311 skipMatcher
= new DateTimeMatcher(*other
.skipMatcher
);
313 for (int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
314 appendItemFormats
[i
] = other
.appendItemFormats
[i
];
315 appendItemNames
[i
] = other
.appendItemNames
[i
];
316 // NUL-terminate for the C API.
317 appendItemFormats
[i
].getTerminatedBuffer();
318 appendItemNames
[i
].getTerminatedBuffer();
320 UErrorCode status
= U_ZERO_ERROR
;
321 patternMap
->copyFrom(*other
.patternMap
, status
);
322 copyHashtable(other
.fAvailableFormatKeyHash
, status
);
328 DateTimePatternGenerator::operator==(const DateTimePatternGenerator
& other
) const {
329 if (this == &other
) {
332 if ((pLocale
==other
.pLocale
) && (patternMap
->equals(*other
.patternMap
)) &&
333 (dateTimeFormat
==other
.dateTimeFormat
) && (decimal
==other
.decimal
)) {
334 for ( int32_t i
=0 ; i
<UDATPG_FIELD_COUNT
; ++i
) {
335 if ((appendItemFormats
[i
] != other
.appendItemFormats
[i
]) ||
336 (appendItemNames
[i
] != other
.appendItemNames
[i
]) ) {
348 DateTimePatternGenerator::operator!=(const DateTimePatternGenerator
& other
) const {
349 return !operator==(other
);
352 DateTimePatternGenerator::~DateTimePatternGenerator() {
353 if (fAvailableFormatKeyHash
!=NULL
) {
354 delete fAvailableFormatKeyHash
;
357 if (fp
!= NULL
) delete fp
;
358 if (dtMatcher
!= NULL
) delete dtMatcher
;
359 if (distanceInfo
!= NULL
) delete distanceInfo
;
360 if (patternMap
!= NULL
) delete patternMap
;
361 if (skipMatcher
!= NULL
) delete skipMatcher
;
365 DateTimePatternGenerator::initData(const Locale
& locale
, UErrorCode
&status
) {
366 //const char *baseLangName = locale.getBaseName(); // unused
369 fAvailableFormatKeyHash
=NULL
;
371 addICUPatterns(locale
, status
);
372 if (U_FAILURE(status
)) {
376 setDateTimeFromCalendar(locale
, status
);
377 setDecimalSymbols(locale
, status
);
378 } // DateTimePatternGenerator::initData
381 DateTimePatternGenerator::getSkeleton(const UnicodeString
& pattern
, UErrorCode
&
383 dtMatcher
->set(pattern
, fp
);
384 return dtMatcher
->getSkeletonPtr()->getSkeleton();
388 DateTimePatternGenerator::getBaseSkeleton(const UnicodeString
& pattern
, UErrorCode
& /*status*/) {
389 dtMatcher
->set(pattern
, fp
);
390 return dtMatcher
->getSkeletonPtr()->getBaseSkeleton();
394 DateTimePatternGenerator::addICUPatterns(const Locale
& locale
, UErrorCode
& status
) {
395 UnicodeString dfPattern
;
396 UnicodeString conflictingString
;
397 UDateTimePatternConflict conflictingStatus
;
400 if (U_FAILURE(status
)) {
404 // Load with ICU patterns
405 for (int32_t i
=DateFormat::kFull
; i
<=DateFormat::kShort
; i
++) {
406 DateFormat::EStyle style
= (DateFormat::EStyle
)i
;
407 df
= DateFormat::createDateInstance(style
, locale
);
408 if (df
!= NULL
&& df
->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
409 SimpleDateFormat
* sdf
= (SimpleDateFormat
*)df
;
410 conflictingStatus
= addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
412 // TODO Maybe we should return an error when the date format isn't simple.
414 if (U_FAILURE(status
)) {
418 df
= DateFormat::createTimeInstance(style
, locale
);
419 if (df
!= NULL
&& df
->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
420 SimpleDateFormat
* sdf
= (SimpleDateFormat
*)df
;
421 conflictingStatus
= addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
423 if ( i
==DateFormat::kMedium
) {
424 hackPattern
= dfPattern
;
427 // TODO Maybe we should return an error when the date format isn't simple.
429 if (U_FAILURE(status
)) {
436 DateTimePatternGenerator::hackTimes(const UnicodeString
& hackPattern
, UErrorCode
& status
) {
437 UDateTimePatternConflict conflictingStatus
;
438 UnicodeString conflictingString
;
440 fp
->set(hackPattern
);
443 for (int32_t i
=0; i
<fp
->itemNumber
; ++i
) {
444 UnicodeString field
= fp
->items
[i
];
445 if ( fp
->isQuoteLiteral(field
) ) {
447 UnicodeString quoteLiteral
;
448 fp
->getQuoteLiteral(quoteLiteral
, &i
);
449 mmss
+= quoteLiteral
;
453 if (fp
->isPatternSeparator(field
) && gotMm
) {
457 UChar ch
=field
.charAt(0);
468 conflictingStatus
= addPattern(mmss
, FALSE
, conflictingString
, status
);
472 if (gotMm
|| ch
==LOW_Z
|| ch
==CAP_Z
|| ch
==LOW_V
|| ch
==CAP_V
) {
482 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
484 static const UChar hourFormatChars
[] = { CAP_H
, LOW_H
, CAP_K
, LOW_K
, 0 }; // HhKk, the hour format characters
487 DateTimePatternGenerator::addCLDRData(const Locale
& locale
) {
488 UErrorCode err
= U_ZERO_ERROR
;
489 UResourceBundle
*rb
, *calTypeBundle
, *calBundle
;
490 UResourceBundle
*patBundle
, *fieldBundle
, *fBundle
;
491 UnicodeString rbPattern
, value
, field
;
492 UnicodeString conflictingPattern
;
493 UDateTimePatternConflict conflictingStatus
;
494 const char *key
=NULL
;
497 UnicodeString
defaultItemFormat(TRUE
, UDATPG_ItemFormat
, LENGTHOF(UDATPG_ItemFormat
)-1); // Read-only alias.
499 fDefaultHourFormatChar
= 0;
500 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
501 appendItemNames
[i
]=CAP_F
;
503 appendItemNames
[i
]+=(UChar
)(i
+0x30);
506 appendItemNames
[i
]+=(UChar
)0x31;
507 appendItemNames
[i
]+=(UChar
)(i
-10 + 0x30);
509 // NUL-terminate for the C API.
510 appendItemNames
[i
].getTerminatedBuffer();
513 rb
= ures_open(NULL
, locale
.getName(), &err
);
514 const char *curLocaleName
=ures_getLocale(rb
, &err
);
515 const char * calendarTypeToUse
= DT_DateTimeGregorianTag
; // initial default
516 char calendarType
[ULOC_KEYWORDS_CAPACITY
]; // to be filled in with the type to use, if all goes well
517 if ( U_SUCCESS(err
) ) {
518 char localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
519 // obtain a locale that always has the calendar key value that should be used
520 (void)ures_getFunctionalEquivalent(localeWithCalendarKey
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, NULL
,
521 "calendar", "calendar", locale
.getName(), NULL
, FALSE
, &err
);
522 localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
-1] = 0; // ensure null termination
523 // now get the calendar key value from that locale
524 int32_t calendarTypeLen
= uloc_getKeywordValue(localeWithCalendarKey
, "calendar", calendarType
, ULOC_KEYWORDS_CAPACITY
, &err
);
525 if (U_SUCCESS(err
) && calendarTypeLen
< ULOC_KEYWORDS_CAPACITY
) {
526 calendarTypeToUse
= calendarType
;
530 calBundle
= ures_getByKeyWithFallback(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
531 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &err
);
535 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimePatternsTag
, NULL
, &err
);
536 while (U_SUCCESS(err
)) {
537 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
539 if (rbPattern
.length()==0 ) {
540 break; // no more pattern
544 setDateTimeFormat(rbPattern
);
545 } else if (dtCount
==4) { // short time format
546 // set fDefaultHourFormatChar to the hour format character from this pattern
547 int32_t tfIdx
, tfLen
= rbPattern
.length();
548 for (tfIdx
= 0; tfIdx
< tfLen
; tfIdx
++) {
549 UChar tfChar
= rbPattern
.charAt(tfIdx
);
550 if ( u_strchr(hourFormatChars
, tfChar
) != NULL
) {
551 fDefaultHourFormatChar
= tfChar
;
558 ures_close(patBundle
);
561 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAppendItemsTag
, NULL
, &err
);
563 UnicodeString itemKey
;
564 while (U_SUCCESS(err
)) {
565 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
566 if (rbPattern
.length()==0 ) {
567 break; // no more pattern
570 setAppendItemFormat(getAppendFormatNumber(key
), rbPattern
);
573 ures_close(patBundle
);
577 fBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeFieldsTag
, NULL
, &err
);
578 for (i
=0; i
<MAX_RESOURCE_FIELD
; ++i
) {
580 patBundle
= ures_getByKeyWithFallback(fBundle
, Resource_Fields
[i
], NULL
, &err
);
581 fieldBundle
= ures_getByKeyWithFallback(patBundle
, "dn", NULL
, &err
);
582 rbPattern
= ures_getNextUnicodeString(fieldBundle
, &key
, &err
);
583 ures_close(fieldBundle
);
584 ures_close(patBundle
);
585 if (rbPattern
.length()==0 ) {
589 setAppendItemName(getAppendNameNumber(Resource_Fields
[i
]), rbPattern
);
594 // add available formats
597 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAvailableFormatsTag
, NULL
, &err
);
598 if (U_SUCCESS(err
)) {
599 int32_t numberKeys
= ures_getSize(patBundle
);
601 const UChar
*retPattern
;
603 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
604 UResourceBundleAIterator aiter
;
605 ures_a_open(&aiter
, patBundle
, &err
);
607 for(i
=0; i
<numberKeys
; ++i
) {
608 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
609 retPattern
=ures_a_getNextString(&aiter
, &len
, &key
, &err
);
611 retPattern
=ures_getNextString(patBundle
, &len
, &key
, &err
);
613 UnicodeString format
=UnicodeString(retPattern
);
614 UnicodeString retKey
=UnicodeString(key
, -1, US_INV
);
615 setAvailableFormat(retKey
, err
);
616 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
617 // but not a previous availableFormats entry:
618 conflictingStatus
= addPatternWithSkeleton(format
, &retKey
, TRUE
, conflictingPattern
, err
);
620 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
621 ures_a_close(&aiter
);
624 ures_close(patBundle
);
625 ures_close(calTypeBundle
);
626 ures_close(calBundle
);
630 char parentLocale
[50];
631 int32_t localeNameLen
=0;
632 uprv_strcpy(parentLocale
, curLocaleName
);
633 while((localeNameLen
=uloc_getParent(parentLocale
, parentLocale
, 50, &err
))>=0 ) {
634 rb
= ures_open(NULL
, parentLocale
, &err
);
635 curLocaleName
=ures_getLocale(rb
, &err
);
636 uprv_strcpy(parentLocale
, curLocaleName
);
637 calBundle
= ures_getByKey(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
638 calTypeBundle
= ures_getByKey(calBundle
, calendarTypeToUse
, NULL
, &err
);
639 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAvailableFormatsTag
, NULL
, &err
);
640 if (U_SUCCESS(err
)) {
641 int32_t numberKeys
= ures_getSize(patBundle
);
643 const UChar
*retPattern
;
645 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
646 UResourceBundleAIterator aiter
;
647 ures_a_open(&aiter
, patBundle
, &err
);
649 for(i
=0; i
<numberKeys
; ++i
) {
650 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
651 retPattern
=ures_a_getNextString(&aiter
, &len
, &key
, &err
);
653 retPattern
=ures_getNextString(patBundle
, &len
, &key
, &err
);
655 UnicodeString format
=UnicodeString(retPattern
);
656 UnicodeString retKey
=UnicodeString(key
, -1, US_INV
);
657 if ( !isAvailableFormatSet(retKey
) ) {
658 setAvailableFormat(retKey
, err
);
659 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
660 // but not a previous availableFormats entry:
661 conflictingStatus
= addPatternWithSkeleton(format
, &retKey
, TRUE
, conflictingPattern
, err
);
664 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
665 ures_a_close(&aiter
);
668 err
= U_ZERO_ERROR
; // reset; if this locale lacks the necessary data, need to keep checking up to root.
669 ures_close(patBundle
);
670 ures_close(calTypeBundle
);
671 ures_close(calBundle
);
673 if (localeNameLen
==0) {
678 if (hackPattern
.length()>0) {
679 hackTimes(hackPattern
, err
);
684 DateTimePatternGenerator::initHashtable(UErrorCode
& err
) {
685 if (fAvailableFormatKeyHash
!=NULL
) {
688 if ((fAvailableFormatKeyHash
= new Hashtable(FALSE
, err
))==NULL
) {
689 err
=U_MEMORY_ALLOCATION_ERROR
;
696 DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field
, const UnicodeString
& value
) {
697 appendItemFormats
[field
] = value
;
698 // NUL-terminate for the C API.
699 appendItemFormats
[field
].getTerminatedBuffer();
703 DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field
) const {
704 return appendItemFormats
[field
];
708 DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field
, const UnicodeString
& value
) {
709 appendItemNames
[field
] = value
;
710 // NUL-terminate for the C API.
711 appendItemNames
[field
].getTerminatedBuffer();
715 DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field
) const {
716 return appendItemNames
[field
];
720 DateTimePatternGenerator::getAppendName(UDateTimePatternField field
, UnicodeString
& value
) {
721 value
= SINGLE_QUOTE
;
722 value
+= appendItemNames
[field
];
723 value
+= SINGLE_QUOTE
;
727 DateTimePatternGenerator::getBestPattern(const UnicodeString
& patternForm
, UErrorCode
& status
) {
728 const UnicodeString
*bestPattern
=NULL
;
729 UnicodeString dtFormat
;
730 UnicodeString resultPattern
;
732 int32_t dateMask
=(1<<UDATPG_DAYPERIOD_FIELD
) - 1;
733 int32_t timeMask
=(1<<UDATPG_FIELD_COUNT
) - 1 - dateMask
;
735 UnicodeString patternFormCopy
= UnicodeString(patternForm
);
736 patternFormCopy
.findAndReplace(UnicodeString(LOW_J
), UnicodeString(fDefaultHourFormatChar
));
738 resultPattern
.remove();
739 dtMatcher
->set(patternFormCopy
, fp
);
740 const PtnSkeleton
* specifiedSkeleton
=NULL
;
741 bestPattern
=getBestRaw(*dtMatcher
, -1, distanceInfo
, &specifiedSkeleton
);
742 if ( distanceInfo
->missingFieldMask
==0 && distanceInfo
->extraFieldMask
==0 ) {
743 resultPattern
= adjustFieldTypes(*bestPattern
, specifiedSkeleton
, FALSE
);
745 return resultPattern
;
747 int32_t neededFields
= dtMatcher
->getFieldMask();
748 UnicodeString datePattern
=getBestAppending(neededFields
& dateMask
);
749 UnicodeString timePattern
=getBestAppending(neededFields
& timeMask
);
750 if (datePattern
.length()==0) {
751 if (timePattern
.length()==0) {
752 resultPattern
.remove();
758 if (timePattern
.length()==0) {
761 resultPattern
.remove();
762 status
= U_ZERO_ERROR
;
763 dtFormat
=getDateTimeFormat();
764 Formattable dateTimeObject
[] = { timePattern
, datePattern
};
765 resultPattern
= MessageFormat::format(dtFormat
, dateTimeObject
, 2, resultPattern
, status
);
766 return resultPattern
;
770 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString
& pattern
,
771 const UnicodeString
& skeleton
,
772 UErrorCode
& /*status*/) {
773 dtMatcher
->set(skeleton
, fp
);
774 UnicodeString result
= adjustFieldTypes(pattern
, NULL
, FALSE
);
779 DateTimePatternGenerator::setDecimal(const UnicodeString
& newDecimal
) {
780 this->decimal
= newDecimal
;
781 // NUL-terminate for the C API.
782 this->decimal
.getTerminatedBuffer();
786 DateTimePatternGenerator::getDecimal() const {
791 DateTimePatternGenerator::addCanonicalItems() {
792 UnicodeString conflictingPattern
;
793 UDateTimePatternConflict conflictingStatus
;
794 UErrorCode status
= U_ZERO_ERROR
;
796 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; i
++) {
797 conflictingStatus
= addPattern(UnicodeString(Canonical_Items
[i
]), FALSE
, conflictingPattern
, status
);
802 DateTimePatternGenerator::setDateTimeFormat(const UnicodeString
& dtFormat
) {
803 dateTimeFormat
= dtFormat
;
804 // NUL-terminate for the C API.
805 dateTimeFormat
.getTerminatedBuffer();
809 DateTimePatternGenerator::getDateTimeFormat() const {
810 return dateTimeFormat
;
814 DateTimePatternGenerator::setDateTimeFromCalendar(const Locale
& locale
, UErrorCode
& status
) {
816 int32_t resStrLen
= 0;
818 Calendar
* fCalendar
= Calendar::createInstance(locale
, status
);
819 CalendarData
calData(locale
, fCalendar
?fCalendar
->getType():NULL
, status
);
820 UResourceBundle
*dateTimePatterns
= calData
.getByKey(DT_DateTimePatternsTag
, status
);
821 if (U_FAILURE(status
)) return;
823 if (ures_getSize(dateTimePatterns
) <= DateFormat::kDateTime
)
825 status
= U_INVALID_FORMAT_ERROR
;
828 resStr
= ures_getStringByIndex(dateTimePatterns
, (int32_t)DateFormat::kDateTime
, &resStrLen
, &status
);
829 setDateTimeFormat(UnicodeString(TRUE
, resStr
, resStrLen
));
835 DateTimePatternGenerator::setDecimalSymbols(const Locale
& locale
, UErrorCode
& status
) {
836 DecimalFormatSymbols dfs
= DecimalFormatSymbols(locale
, status
);
837 if(U_SUCCESS(status
)) {
838 decimal
= dfs
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
839 // NUL-terminate for the C API.
840 decimal
.getTerminatedBuffer();
844 UDateTimePatternConflict
845 DateTimePatternGenerator::addPattern(
846 const UnicodeString
& pattern
,
848 UnicodeString
&conflictingPattern
,
851 return addPatternWithSkeleton(pattern
, NULL
, override
, conflictingPattern
, status
);
854 // For DateTimePatternGenerator::addPatternWithSkeleton -
855 // If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
856 // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
857 // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
858 // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
859 // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
860 // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
861 // derived (i.e. entries derived from the standard date/time patters for the specified locale).
862 // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
863 // specified skeleton (which sets a new field in the PtnElem in the PatternMap).
864 UDateTimePatternConflict
865 DateTimePatternGenerator::addPatternWithSkeleton(
866 const UnicodeString
& pattern
,
867 const UnicodeString
* skeletonToUse
,
869 UnicodeString
& conflictingPattern
,
873 UnicodeString basePattern
;
874 PtnSkeleton skeleton
;
875 UDateTimePatternConflict conflictingStatus
= UDATPG_NO_CONFLICT
;
877 DateTimeMatcher matcher
;
878 if ( skeletonToUse
== NULL
) {
879 matcher
.set(pattern
, fp
, skeleton
);
880 matcher
.getBasePattern(basePattern
);
882 matcher
.set(*skeletonToUse
, fp
, skeleton
); // this still trims skeleton fields to max len 3, may need to change it.
883 matcher
.getBasePattern(basePattern
); // or perhaps instead: basePattern = *skeletonToUse;
885 UBool entryHadSpecifiedSkeleton
;
886 const UnicodeString
*duplicatePattern
= patternMap
->getPatternFromBasePattern(basePattern
, entryHadSpecifiedSkeleton
);
887 if (duplicatePattern
!= NULL
) {
888 conflictingStatus
= UDATPG_BASE_CONFLICT
;
889 conflictingPattern
= *duplicatePattern
;
890 if (!override
|| (skeletonToUse
!= NULL
&& entryHadSpecifiedSkeleton
)) {
891 return conflictingStatus
;
894 const PtnSkeleton
* entrySpecifiedSkeleton
= NULL
;
895 duplicatePattern
= patternMap
->getPatternFromSkeleton(skeleton
, &entrySpecifiedSkeleton
);
896 if (duplicatePattern
!= NULL
) {
897 conflictingStatus
= UDATPG_CONFLICT
;
898 conflictingPattern
= *duplicatePattern
;
899 if (!override
|| (skeletonToUse
!= NULL
&& entrySpecifiedSkeleton
!= NULL
)) {
900 return conflictingStatus
;
903 patternMap
->add(basePattern
, skeleton
, pattern
, skeletonToUse
!= NULL
, status
);
904 if(U_FAILURE(status
)) {
905 return conflictingStatus
;
908 return UDATPG_NO_CONFLICT
;
912 UDateTimePatternField
913 DateTimePatternGenerator::getAppendFormatNumber(const char* field
) const {
914 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
915 if (uprv_strcmp(CLDR_FIELD_APPEND
[i
], field
)==0) {
916 return (UDateTimePatternField
)i
;
919 return UDATPG_FIELD_COUNT
;
922 UDateTimePatternField
923 DateTimePatternGenerator::getAppendNameNumber(const char* field
) const {
924 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
925 if (uprv_strcmp(CLDR_FIELD_NAME
[i
],field
)==0) {
926 return (UDateTimePatternField
)i
;
929 return UDATPG_FIELD_COUNT
;
933 DateTimePatternGenerator::getBestRaw(DateTimeMatcher
& source
,
935 DistanceInfo
* missingFields
,
936 const PtnSkeleton
** specifiedSkeletonPtr
) {
937 int32_t bestDistance
= 0x7fffffff;
938 DistanceInfo tempInfo
;
939 const UnicodeString
*bestPattern
=NULL
;
940 const PtnSkeleton
* specifiedSkeleton
=NULL
;
942 PatternMapIterator it
;
943 for (it
.set(*patternMap
); it
.hasNext(); ) {
944 DateTimeMatcher trial
= it
.next();
945 if (trial
.equals(skipMatcher
)) {
948 int32_t distance
=source
.getDistance(trial
, includeMask
, tempInfo
);
949 if (distance
<bestDistance
) {
950 bestDistance
=distance
;
951 bestPattern
=patternMap
->getPatternFromSkeleton(*trial
.getSkeletonPtr(), &specifiedSkeleton
);
952 missingFields
->setTo(tempInfo
);
959 // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
960 // then return it too. This generally happens when the caller needs to pass that skeleton
961 // through to adjustFieldTypes so the latter can do a better job.
962 if (bestPattern
&& specifiedSkeletonPtr
) {
963 *specifiedSkeletonPtr
= specifiedSkeleton
;
969 DateTimePatternGenerator::adjustFieldTypes(const UnicodeString
& pattern
,
970 const PtnSkeleton
* specifiedSkeleton
,
971 UBool fixFractionalSeconds
) {
972 UnicodeString newPattern
;
974 for (int32_t i
=0; i
< fp
->itemNumber
; i
++) {
975 UnicodeString field
= fp
->items
[i
];
976 if ( fp
->isQuoteLiteral(field
) ) {
978 UnicodeString quoteLiteral
;
979 fp
->getQuoteLiteral(quoteLiteral
, &i
);
980 newPattern
+= quoteLiteral
;
983 if (fp
->isPatternSeparator(field
)) {
987 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
988 if (canonicalIndex
< 0) {
990 continue; // don't adjust
992 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
993 int32_t typeValue
= row
->field
;
994 if (fixFractionalSeconds
&& typeValue
== UDATPG_SECOND_FIELD
) {
995 UnicodeString newField
=dtMatcher
->skeleton
.original
[UDATPG_FRACTIONAL_SECOND_FIELD
];
996 field
= field
+ decimal
+ newField
;
999 if (dtMatcher
->skeleton
.type
[typeValue
]!=0) {
1001 // - "reqField" is the field from the originally requested skeleton, with length
1003 // - "field" is the field from the found pattern.
1005 // The adjusted field should consist of characters from the originally requested
1006 // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD, in
1007 // which case it should consist of characters from the found pattern.
1009 // The length of the adjusted field (adjFieldLen) should match that in the originally
1010 // requested skeleton, except that if there is a specified skeleton for the found pattern
1011 // and one of the following is true, then the length of the adjusted field should match
1012 // that in the found pattern (i.e. the length of this pattern field should not be adjusted):
1013 // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
1014 // b) The pattern field is numeric and the skeleton field is not, or vice versa.
1016 UnicodeString reqField
= dtMatcher
->skeleton
.original
[typeValue
];
1017 int32_t reqFieldLen
= reqField
.length();
1018 int32_t adjFieldLen
= reqFieldLen
;
1019 if (specifiedSkeleton
) {
1020 UnicodeString skelField
= specifiedSkeleton
->original
[typeValue
];
1021 int32_t skelFieldLen
= skelField
.length();
1022 UBool patFieldIsNumeric
= (row
->type
> 0);
1023 UBool skelFieldIsNumeric
= (specifiedSkeleton
->type
[typeValue
] > 0);
1024 if (skelFieldLen
== reqFieldLen
|| (patFieldIsNumeric
&& !skelFieldIsNumeric
) || (skelFieldIsNumeric
&& !patFieldIsNumeric
)) {
1025 // don't adjust the field length in the found pattern
1026 adjFieldLen
= field
.length();
1029 UChar c
= (typeValue
!= UDATPG_HOUR_FIELD
&& typeValue
!= UDATPG_MONTH_FIELD
)? reqField
.charAt(0): field
.charAt(0);
1031 for (int32_t i
=adjFieldLen
; i
>0; --i
) {
1043 DateTimePatternGenerator::getBestAppending(int32_t missingFields
) {
1044 UnicodeString resultPattern
, tempPattern
, formattedPattern
;
1045 UErrorCode err
=U_ZERO_ERROR
;
1046 int32_t lastMissingFieldMask
=0;
1047 if (missingFields
!=0) {
1048 resultPattern
=UnicodeString();
1049 const PtnSkeleton
* specifiedSkeleton
=NULL
;
1050 tempPattern
= *getBestRaw(*dtMatcher
, missingFields
, distanceInfo
, &specifiedSkeleton
);
1051 resultPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, FALSE
);
1052 if ( distanceInfo
->missingFieldMask
==0 ) {
1053 return resultPattern
;
1055 while (distanceInfo
->missingFieldMask
!=0) { // precondition: EVERY single field must work!
1056 if ( lastMissingFieldMask
== distanceInfo
->missingFieldMask
) {
1057 break; // cannot find the proper missing field
1059 if (((distanceInfo
->missingFieldMask
& UDATPG_SECOND_AND_FRACTIONAL_MASK
)==UDATPG_FRACTIONAL_MASK
) &&
1060 ((missingFields
& UDATPG_SECOND_AND_FRACTIONAL_MASK
) == UDATPG_SECOND_AND_FRACTIONAL_MASK
)) {
1061 resultPattern
= adjustFieldTypes(resultPattern
, specifiedSkeleton
, FALSE
);
1062 //resultPattern = tempPattern;
1063 distanceInfo
->missingFieldMask
&= ~UDATPG_FRACTIONAL_MASK
;
1066 int32_t startingMask
= distanceInfo
->missingFieldMask
;
1067 tempPattern
= *getBestRaw(*dtMatcher
, distanceInfo
->missingFieldMask
, distanceInfo
, &specifiedSkeleton
);
1068 tempPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, FALSE
);
1069 int32_t foundMask
=startingMask
& ~distanceInfo
->missingFieldMask
;
1070 int32_t topField
=getTopBitNumber(foundMask
);
1071 UnicodeString appendName
;
1072 getAppendName((UDateTimePatternField
)topField
, appendName
);
1073 const Formattable formatPattern
[] = {
1078 UnicodeString emptyStr
;
1079 formattedPattern
= MessageFormat::format(appendItemFormats
[topField
], formatPattern
, 3, emptyStr
, err
);
1080 lastMissingFieldMask
= distanceInfo
->missingFieldMask
;
1083 return formattedPattern
;
1087 DateTimePatternGenerator::getTopBitNumber(int32_t foundMask
) {
1088 if ( foundMask
==0 ) {
1092 while (foundMask
!=0) {
1096 if (i
-1 >UDATPG_ZONE_FIELD
) {
1097 return UDATPG_ZONE_FIELD
;
1104 DateTimePatternGenerator::setAvailableFormat(const UnicodeString
&key
, UErrorCode
& err
)
1106 fAvailableFormatKeyHash
->puti(key
, 1, err
);
1110 DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString
&key
) const {
1111 return (UBool
)(fAvailableFormatKeyHash
->geti(key
) == 1);
1115 DateTimePatternGenerator::copyHashtable(Hashtable
*other
, UErrorCode
&status
) {
1117 if (other
== NULL
) {
1120 if (fAvailableFormatKeyHash
!= NULL
) {
1121 delete fAvailableFormatKeyHash
;
1122 fAvailableFormatKeyHash
= NULL
;
1124 initHashtable(status
);
1125 if(U_FAILURE(status
)){
1129 const UHashElement
* elem
= NULL
;
1130 // walk through the hash table and create a deep clone
1131 while((elem
= other
->nextElement(pos
))!= NULL
){
1132 const UHashTok otherKeyTok
= elem
->key
;
1133 UnicodeString
* otherKey
= (UnicodeString
*)otherKeyTok
.pointer
;
1134 fAvailableFormatKeyHash
->puti(*otherKey
, 1, status
);
1135 if(U_FAILURE(status
)){
1142 DateTimePatternGenerator::getSkeletons(UErrorCode
& status
) const {
1143 StringEnumeration
* skeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_SKELETON
, status
);
1144 return skeletonEnumerator
;
1147 const UnicodeString
&
1148 DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString
& skeleton
) const {
1151 if (skeleton
.length() ==0) {
1154 curElem
= patternMap
->getHeader(skeleton
.charAt(0));
1155 while ( curElem
!= NULL
) {
1156 if ( curElem
->skeleton
->getSkeleton()==skeleton
) {
1157 return curElem
->pattern
;
1159 curElem
=curElem
->next
;
1165 DateTimePatternGenerator::getBaseSkeletons(UErrorCode
& status
) const {
1166 StringEnumeration
* baseSkeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_BASESKELETON
, status
);
1167 return baseSkeletonEnumerator
;
1171 DateTimePatternGenerator::getRedundants(UErrorCode
& status
) {
1172 StringEnumeration
* output
= new DTRedundantEnumeration();
1173 const UnicodeString
*pattern
;
1174 PatternMapIterator it
;
1175 for (it
.set(*patternMap
); it
.hasNext(); ) {
1176 DateTimeMatcher current
= it
.next();
1177 pattern
= patternMap
->getPatternFromSkeleton(*(it
.getSkeleton()));
1178 if ( isCanonicalItem(*pattern
) ) {
1181 if ( skipMatcher
== NULL
) {
1182 skipMatcher
= new DateTimeMatcher(current
);
1185 *skipMatcher
= current
;
1187 UnicodeString trial
= getBestPattern(current
.getPattern(), status
);
1188 if (trial
== *pattern
) {
1189 ((DTRedundantEnumeration
*)output
)->add(*pattern
, status
);
1191 if (current
.equals(skipMatcher
)) {
1199 DateTimePatternGenerator::isCanonicalItem(const UnicodeString
& item
) const {
1200 if ( item
.length() != 1 ) {
1203 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1204 if (item
.charAt(0)==Canonical_Items
[i
]) {
1212 DateTimePatternGenerator
*
1213 DateTimePatternGenerator::clone() const {
1214 return new DateTimePatternGenerator(*this);
1217 PatternMap::PatternMap() {
1218 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1221 isDupAllowed
= TRUE
;
1225 PatternMap::copyFrom(const PatternMap
& other
, UErrorCode
& status
) {
1226 this->isDupAllowed
= other
.isDupAllowed
;
1227 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1228 PtnElem
*curElem
, *otherElem
, *prevElem
=NULL
;
1229 otherElem
= other
.boot
[bootIndex
];
1230 while (otherElem
!=NULL
) {
1231 if ((curElem
= new PtnElem(otherElem
->basePattern
, otherElem
->pattern
))==NULL
) {
1233 status
= U_MEMORY_ALLOCATION_ERROR
;
1236 if ( this->boot
[bootIndex
]== NULL
) {
1237 this->boot
[bootIndex
] = curElem
;
1239 if ((curElem
->skeleton
=new PtnSkeleton(*(otherElem
->skeleton
))) == NULL
) {
1241 status
= U_MEMORY_ALLOCATION_ERROR
;
1245 if (prevElem
!=NULL
) {
1246 prevElem
->next
=curElem
;
1250 otherElem
= otherElem
->next
;
1257 PatternMap::getHeader(UChar baseChar
) {
1260 if ( (baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
) ) {
1261 curElem
= boot
[baseChar
-CAP_A
];
1264 if ( (baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
) ) {
1265 curElem
= boot
[26+baseChar
-LOW_A
];
1274 PatternMap::~PatternMap() {
1275 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1276 if (boot
[i
]!=NULL
) {
1281 } // PatternMap destructor
1284 PatternMap::add(const UnicodeString
& basePattern
,
1285 const PtnSkeleton
& skeleton
,
1286 const UnicodeString
& value
,// mapped pattern value
1287 UBool skeletonWasSpecified
,
1288 UErrorCode
&status
) {
1289 UChar baseChar
= basePattern
.charAt(0);
1290 PtnElem
*curElem
, *baseElem
;
1291 status
= U_ZERO_ERROR
;
1293 // the baseChar must be A-Z or a-z
1294 if ((baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
)) {
1295 baseElem
= boot
[baseChar
-CAP_A
];
1298 if ((baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
)) {
1299 baseElem
= boot
[26+baseChar
-LOW_A
];
1302 status
= U_ILLEGAL_CHARACTER
;
1307 if (baseElem
== NULL
) {
1308 if ((curElem
= new PtnElem(basePattern
, value
)) == NULL
) {
1310 status
= U_MEMORY_ALLOCATION_ERROR
;
1313 if (baseChar
>= LOW_A
) {
1314 boot
[26 + (baseChar
-LOW_A
)] = curElem
;
1317 boot
[baseChar
-CAP_A
] = curElem
;
1319 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1320 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1322 if ( baseElem
!= NULL
) {
1323 curElem
= getDuplicateElem(basePattern
, skeleton
, baseElem
);
1325 if (curElem
== NULL
) {
1326 // add new element to the list.
1328 while( curElem
-> next
!= NULL
)
1330 curElem
= curElem
->next
;
1332 if ((curElem
->next
= new PtnElem(basePattern
, value
)) == NULL
) {
1334 status
= U_MEMORY_ALLOCATION_ERROR
;
1337 curElem
=curElem
->next
;
1338 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1339 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1342 // Pattern exists in the list already.
1343 if ( !isDupAllowed
) {
1346 // Overwrite the value.
1347 curElem
->pattern
= value
;
1350 } // PatternMap::add
1352 // Find the pattern from the given basePattern string.
1353 const UnicodeString
*
1354 PatternMap::getPatternFromBasePattern(UnicodeString
& basePattern
, UBool
& skeletonWasSpecified
) { // key to search for
1357 if ((curElem
=getHeader(basePattern
.charAt(0)))==NULL
) {
1358 return NULL
; // no match
1362 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1363 skeletonWasSpecified
= curElem
->skeletonWasSpecified
;
1364 return &(curElem
->pattern
);
1366 curElem
=curElem
->next
;
1367 }while (curElem
!= NULL
);
1370 } // PatternMap::getFromBasePattern
1373 // Find the pattern from the given skeleton.
1374 // At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
1375 // the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
1376 // and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
1377 // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
1378 // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
1379 const UnicodeString
*
1380 PatternMap::getPatternFromSkeleton(PtnSkeleton
& skeleton
, const PtnSkeleton
** specifiedSkeletonPtr
) { // key to search for
1383 if (specifiedSkeletonPtr
) {
1384 *specifiedSkeletonPtr
= NULL
;
1388 UChar baseChar
='\0';
1389 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1390 if (skeleton
.baseOriginal
[i
].length() !=0 ) {
1391 baseChar
= skeleton
.baseOriginal
[i
].charAt(0);
1396 if ((curElem
=getHeader(baseChar
))==NULL
) {
1397 return NULL
; // no match
1402 if (specifiedSkeletonPtr
!= NULL
) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
1403 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1404 if (curElem
->skeleton
->original
[i
].compare(skeleton
.original
[i
]) != 0 )
1409 } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
1410 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1411 if (curElem
->skeleton
->baseOriginal
[i
].compare(skeleton
.baseOriginal
[i
]) != 0 )
1417 if (i
== UDATPG_FIELD_COUNT
) {
1418 if (specifiedSkeletonPtr
&& curElem
->skeletonWasSpecified
) {
1419 *specifiedSkeletonPtr
= curElem
->skeleton
;
1421 return &(curElem
->pattern
);
1423 curElem
=curElem
->next
;
1424 }while (curElem
!= NULL
);
1430 PatternMap::equals(const PatternMap
& other
) {
1431 if ( this==&other
) {
1434 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1435 if ( boot
[bootIndex
]==other
.boot
[bootIndex
] ) {
1438 if ( (boot
[bootIndex
]==NULL
)||(other
.boot
[bootIndex
]==NULL
) ) {
1441 PtnElem
*otherElem
= other
.boot
[bootIndex
];
1442 PtnElem
*myElem
= boot
[bootIndex
];
1443 while ((otherElem
!=NULL
) || (myElem
!=NULL
)) {
1444 if ( myElem
== otherElem
) {
1447 if ((otherElem
==NULL
) || (myElem
==NULL
)) {
1450 if ( (myElem
->basePattern
!= otherElem
->basePattern
) ||
1451 (myElem
->pattern
!= otherElem
->pattern
) ) {
1454 if ((myElem
->skeleton
!=otherElem
->skeleton
)&&
1455 !myElem
->skeleton
->equals(*(otherElem
->skeleton
))) {
1458 myElem
= myElem
->next
;
1459 otherElem
=otherElem
->next
;
1465 // find any key existing in the mapping table already.
1466 // return TRUE if there is an existing key, otherwise return FALSE.
1468 PatternMap::getDuplicateElem(
1469 const UnicodeString
&basePattern
,
1470 const PtnSkeleton
&skeleton
,
1471 PtnElem
*baseElem
) {
1474 if ( baseElem
== (PtnElem
*)NULL
) {
1475 return (PtnElem
*)NULL
;
1481 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1483 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1484 if (curElem
->skeleton
->type
[i
] != skeleton
.type
[i
] ) {
1493 curElem
= curElem
->next
;
1494 } while( curElem
!= (PtnElem
*)NULL
);
1497 return (PtnElem
*)NULL
;
1499 } // PatternMap::getDuplicateElem
1501 DateTimeMatcher::DateTimeMatcher(void) {
1504 DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher
& other
) {
1505 copyFrom(other
.skeleton
);
1510 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
) {
1511 PtnSkeleton localSkeleton
;
1512 return set(pattern
, fp
, localSkeleton
);
1516 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
, PtnSkeleton
& skeletonResult
) {
1518 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1519 skeletonResult
.type
[i
]=NONE
;
1522 for (i
=0; i
< fp
->itemNumber
; i
++) {
1523 UnicodeString field
= fp
->items
[i
];
1524 if ( field
.charAt(0) == LOW_A
) {
1525 continue; // skip 'a'
1528 if ( fp
->isQuoteLiteral(field
) ) {
1529 UnicodeString quoteLiteral
;
1530 fp
->getQuoteLiteral(quoteLiteral
, &i
);
1533 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
1534 if (canonicalIndex
< 0 ) {
1537 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
1538 int32_t typeValue
= row
->field
;
1539 skeletonResult
.original
[typeValue
]=field
;
1540 UChar repeatChar
= row
->patternChar
;
1541 int32_t repeatCount
= row
->minLen
> 3 ? 3: row
->minLen
;
1542 while (repeatCount
-- > 0) {
1543 skeletonResult
.baseOriginal
[typeValue
] += repeatChar
;
1545 int16_t subTypeValue
= row
->type
;
1546 if ( row
->type
> 0) {
1547 subTypeValue
+= field
.length();
1549 skeletonResult
.type
[typeValue
] = subTypeValue
;
1551 copyFrom(skeletonResult
);
1555 DateTimeMatcher::getBasePattern(UnicodeString
&result
) {
1556 result
.remove(); // Reset the result first.
1557 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1558 if (skeleton
.baseOriginal
[i
].length()!=0) {
1559 result
+= skeleton
.baseOriginal
[i
];
1565 DateTimeMatcher::getPattern() {
1566 UnicodeString result
;
1568 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1569 if (skeleton
.original
[i
].length()!=0) {
1570 result
+= skeleton
.original
[i
];
1577 DateTimeMatcher::getDistance(const DateTimeMatcher
& other
, int32_t includeMask
, DistanceInfo
& distanceInfo
) {
1579 distanceInfo
.clear();
1580 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1581 int32_t myType
= (includeMask
&(1<<i
))==0 ? 0 : skeleton
.type
[i
];
1582 int32_t otherType
= other
.skeleton
.type
[i
];
1583 if (myType
==otherType
) {
1586 if (myType
==0) {// and other is not
1587 result
+= EXTRA_FIELD
;
1588 distanceInfo
.addExtra(i
);
1592 result
+= MISSING_FIELD
;
1593 distanceInfo
.addMissing(i
);
1596 result
+= abs(myType
- otherType
);
1605 DateTimeMatcher::copyFrom(const PtnSkeleton
& newSkeleton
) {
1606 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1607 this->skeleton
.type
[i
]=newSkeleton
.type
[i
];
1608 this->skeleton
.original
[i
]=newSkeleton
.original
[i
];
1609 this->skeleton
.baseOriginal
[i
]=newSkeleton
.baseOriginal
[i
];
1614 DateTimeMatcher::copyFrom() {
1616 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1617 this->skeleton
.type
[i
]=0;
1618 this->skeleton
.original
[i
].remove();
1619 this->skeleton
.baseOriginal
[i
].remove();
1624 DateTimeMatcher::equals(const DateTimeMatcher
* other
) const {
1628 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1629 if (this->skeleton
.original
[i
]!=other
->skeleton
.original
[i
] ) {
1637 DateTimeMatcher::getFieldMask() {
1640 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1641 if (skeleton
.type
[i
]!=0) {
1649 DateTimeMatcher::getSkeletonPtr() {
1653 FormatParser::FormatParser () {
1659 FormatParser::~FormatParser () {
1663 // Find the next token with the starting position and length
1664 // Note: the startPos may
1665 FormatParser::TokenStatus
1666 FormatParser::setTokens(const UnicodeString
& pattern
, int32_t startPos
, int32_t *len
) {
1667 int32_t curLoc
= startPos
;
1668 if ( curLoc
>= pattern
.length()) {
1671 // check the current char is between A-Z or a-z
1673 UChar c
=pattern
.charAt(curLoc
);
1674 if ( (c
>=CAP_A
&& c
<=CAP_Z
) || (c
>=LOW_A
&& c
<=LOW_Z
) ) {
1683 if ( pattern
.charAt(curLoc
)!= pattern
.charAt(startPos
) ) {
1684 break; // not the same token
1686 } while(curLoc
<= pattern
.length());
1687 *len
= curLoc
-startPos
;
1692 FormatParser::set(const UnicodeString
& pattern
) {
1694 TokenStatus result
=START
;
1699 result
= setTokens( pattern
, startPos
, &len
);
1700 if ( result
== ADD_TOKEN
)
1702 items
[itemNumber
++] = UnicodeString(pattern
, startPos
, len
);
1708 } while (result
==ADD_TOKEN
&& itemNumber
< MAX_DT_TOKEN
);
1712 FormatParser::getCanonicalIndex(const UnicodeString
& s
) {
1713 int32_t len
= s
.length();
1714 UChar ch
= s
.charAt(0);
1717 while (dtTypes
[i
].patternChar
!='\0') {
1718 if ( dtTypes
[i
].patternChar
!=ch
) {
1722 if (dtTypes
[i
].patternChar
!=dtTypes
[i
+1].patternChar
) {
1725 if (dtTypes
[i
+1].minLen
<= len
) {
1735 FormatParser::isQuoteLiteral(const UnicodeString
& s
) const {
1736 return (UBool
)(s
.charAt(0)==SINGLE_QUOTE
);
1739 // This function aussumes the current itemIndex points to the quote literal.
1740 // Please call isQuoteLiteral prior to this function.
1742 FormatParser::getQuoteLiteral(UnicodeString
& quote
, int32_t *itemIndex
) {
1743 int32_t i
=*itemIndex
;
1746 if (items
[i
].charAt(0)==SINGLE_QUOTE
) {
1750 while ( i
< itemNumber
) {
1751 if ( items
[i
].charAt(0)==SINGLE_QUOTE
) {
1752 if ( (i
+1<itemNumber
) && (items
[i
+1].charAt(0)==SINGLE_QUOTE
)) {
1753 // two single quotes e.g. 'o''clock'
1754 quote
+= items
[i
++];
1755 quote
+= items
[i
++];
1772 FormatParser::isPatternSeparator(UnicodeString
& field
) {
1773 for (int32_t i
=0; i
<field
.length(); ++i
) {
1774 UChar c
= field
.charAt(i
);
1775 if ( (c
==SINGLE_QUOTE
) || (c
==BACKSLASH
) || (c
==SPACE
) || (c
==COLON
) ||
1776 (c
==QUOTATION_MARK
) || (c
==COMMA
) || (c
==HYPHEN
) ||(items
[i
].charAt(0)==DOT
) ) {
1787 DistanceInfo::setTo(DistanceInfo
&other
) {
1788 missingFieldMask
= other
.missingFieldMask
;
1789 extraFieldMask
= other
.extraFieldMask
;
1792 PatternMapIterator::PatternMapIterator() {
1796 matcher
= new DateTimeMatcher();
1800 PatternMapIterator::~PatternMapIterator() {
1805 PatternMapIterator::set(PatternMap
& newPatternMap
) {
1806 this->patternMap
=&newPatternMap
;
1810 PatternMapIterator::getSkeleton() {
1811 if ( nodePtr
== NULL
) {
1815 return nodePtr
->skeleton
;
1820 PatternMapIterator::hasNext() {
1821 int32_t headIndex
=bootIndex
;
1822 PtnElem
*curPtr
=nodePtr
;
1824 if (patternMap
==NULL
) {
1827 while ( headIndex
< MAX_PATTERN_ENTRIES
) {
1828 if ( curPtr
!= NULL
) {
1829 if ( curPtr
->next
!= NULL
) {
1839 if ( patternMap
->boot
[headIndex
] != NULL
) {
1853 PatternMapIterator::next() {
1854 while ( bootIndex
< MAX_PATTERN_ENTRIES
) {
1855 if ( nodePtr
!= NULL
) {
1856 if ( nodePtr
->next
!= NULL
) {
1857 nodePtr
= nodePtr
->next
;
1867 if ( patternMap
->boot
[bootIndex
] != NULL
) {
1868 nodePtr
= patternMap
->boot
[bootIndex
];
1877 if (nodePtr
!=NULL
) {
1878 matcher
->copyFrom(*nodePtr
->skeleton
);
1881 matcher
->copyFrom();
1886 PtnSkeleton::PtnSkeleton() {
1890 PtnSkeleton::PtnSkeleton(const PtnSkeleton
& other
) {
1891 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1892 this->type
[i
]=other
.type
[i
];
1893 this->original
[i
]=other
.original
[i
];
1894 this->baseOriginal
[i
]=other
.baseOriginal
[i
];
1899 PtnSkeleton::equals(const PtnSkeleton
& other
) {
1900 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1901 if ( (type
[i
]!= other
.type
[i
]) ||
1902 (original
[i
]!=other
.original
[i
]) ||
1903 (baseOriginal
[i
]!=other
.baseOriginal
[i
]) ) {
1911 PtnSkeleton::getSkeleton() {
1912 UnicodeString result
;
1914 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
1915 if (original
[i
].length()!=0) {
1916 result
+= original
[i
];
1923 PtnSkeleton::getBaseSkeleton() {
1924 UnicodeString result
;
1926 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
1927 if (baseOriginal
[i
].length()!=0) {
1928 result
+= baseOriginal
[i
];
1934 PtnSkeleton::~PtnSkeleton() {
1937 PtnElem::PtnElem(const UnicodeString
&basePat
, const UnicodeString
&pat
) :
1938 basePattern(basePat
),
1945 PtnElem::~PtnElem() {
1953 DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap
&patternMap
, dtStrEnum type
, UErrorCode
& status
) {
1955 PtnSkeleton
*curSkeleton
;
1960 fSkeletons
= new UVector(status
);
1961 if (U_FAILURE(status
)) {
1965 for (bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1966 curElem
= patternMap
.boot
[bootIndex
];
1967 while (curElem
!=NULL
) {
1969 case DT_BASESKELETON
:
1970 s
=curElem
->basePattern
;
1976 curSkeleton
=curElem
->skeleton
;
1977 s
=curSkeleton
->getSkeleton();
1980 if ( !isCanonicalItem(s
) ) {
1981 fSkeletons
->addElement(new UnicodeString(s
), status
);
1982 if (U_FAILURE(status
)) {
1988 curElem
= curElem
->next
;
1991 if ((bootIndex
==MAX_PATTERN_ENTRIES
) && (curElem
!=NULL
) ) {
1992 status
= U_BUFFER_OVERFLOW_ERROR
;
1996 const UnicodeString
*
1997 DTSkeletonEnumeration::snext(UErrorCode
& status
) {
1998 if (U_SUCCESS(status
) && pos
< fSkeletons
->size()) {
1999 return (const UnicodeString
*)fSkeletons
->elementAt(pos
++);
2005 DTSkeletonEnumeration::reset(UErrorCode
& /*status*/) {
2010 DTSkeletonEnumeration::count(UErrorCode
& /*status*/) const {
2011 return (fSkeletons
==NULL
) ? 0 : fSkeletons
->size();
2015 DTSkeletonEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2016 if ( item
.length() != 1 ) {
2019 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2020 if (item
.charAt(0)==Canonical_Items
[i
]) {
2027 DTSkeletonEnumeration::~DTSkeletonEnumeration() {
2029 for (int32_t i
=0; i
<fSkeletons
->size(); ++i
) {
2030 if ((s
=(UnicodeString
*)fSkeletons
->elementAt(i
))!=NULL
) {
2037 DTRedundantEnumeration::DTRedundantEnumeration() {
2043 DTRedundantEnumeration::add(const UnicodeString
& pattern
, UErrorCode
& status
) {
2044 if (U_FAILURE(status
)) return;
2045 if (fPatterns
== NULL
) {
2046 fPatterns
= new UVector(status
);
2047 if (U_FAILURE(status
)) {
2053 fPatterns
->addElement(new UnicodeString(pattern
), status
);
2054 if (U_FAILURE(status
)) {
2061 const UnicodeString
*
2062 DTRedundantEnumeration::snext(UErrorCode
& status
) {
2063 if (U_SUCCESS(status
) && pos
< fPatterns
->size()) {
2064 return (const UnicodeString
*)fPatterns
->elementAt(pos
++);
2070 DTRedundantEnumeration::reset(UErrorCode
& /*status*/) {
2075 DTRedundantEnumeration::count(UErrorCode
& /*status*/) const {
2076 return (fPatterns
==NULL
) ? 0 : fPatterns
->size();
2080 DTRedundantEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2081 if ( item
.length() != 1 ) {
2084 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2085 if (item
.charAt(0)==Canonical_Items
[i
]) {
2092 DTRedundantEnumeration::~DTRedundantEnumeration() {
2094 for (int32_t i
=0; i
<fPatterns
->size(); ++i
) {
2095 if ((s
=(UnicodeString
*)fPatterns
->elementAt(i
))!=NULL
) {
2105 #endif /* #if !UCONFIG_NO_FORMATTING */