2 *******************************************************************************
3 * Copyright (C) 2007-2011, 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 #if !defined (OS390) && !defined (OS400)
72 static int32_t U_CALLCONV
73 ures_a_codepointSort(const void *context
, const void *left
, const void *right
) {
74 //CompareContext *cmp=(CompareContext *)context;
75 return u_strcmp(((const UResAEntry
*)left
)->key
,
76 ((const UResAEntry
*)right
)->key
);
80 static void ures_a_open(UResourceBundleAIterator
*aiter
, UResourceBundle
*bund
, UErrorCode
*status
) {
81 if(U_FAILURE(*status
)) {
85 aiter
->num
= ures_getSize(aiter
->bund
);
87 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
88 aiter
->entries
= NULL
;
90 aiter
->entries
= (UResAEntry
*)uprv_malloc(sizeof(UResAEntry
)*aiter
->num
);
91 for(int i
=0;i
<aiter
->num
;i
++) {
92 aiter
->entries
[i
].item
= ures_getByIndex(aiter
->bund
, i
, NULL
, status
);
93 const char *akey
= ures_getKey(aiter
->entries
[i
].item
);
94 int32_t len
= uprv_strlen(akey
)+1;
95 aiter
->entries
[i
].key
= (UChar
*)uprv_malloc(len
*sizeof(UChar
));
96 u_charsToUChars(akey
, aiter
->entries
[i
].key
, len
);
98 uprv_sortArray(aiter
->entries
, aiter
->num
, sizeof(UResAEntry
), ures_a_codepointSort
, NULL
, TRUE
, status
);
102 static void ures_a_close(UResourceBundleAIterator
*aiter
) {
103 #if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
104 for(int i
=0;i
<aiter
->num
;i
++) {
105 uprv_free(aiter
->entries
[i
].key
);
106 ures_close(aiter
->entries
[i
].item
);
111 static const UChar
*ures_a_getNextString(UResourceBundleAIterator
*aiter
, int32_t *len
, const char **key
, UErrorCode
*err
) {
112 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
113 return ures_getNextString(aiter
->bund
, len
, key
, err
);
115 if(U_FAILURE(*err
)) return NULL
;
116 UResourceBundle
*item
= aiter
->entries
[aiter
->cursor
].item
;
117 const UChar
* ret
= ures_getString(item
, len
, err
);
118 *key
= ures_getKey(item
);
131 // *****************************************************************************
132 // class DateTimePatternGenerator
133 // *****************************************************************************
134 static const UChar Canonical_Items
[] = {
136 CAP_G
, LOW_Y
, CAP_Q
, CAP_M
, LOW_W
, CAP_W
, CAP_E
, LOW_D
, CAP_D
, CAP_F
,
137 CAP_H
, LOW_M
, LOW_S
, CAP_S
, LOW_V
, 0
140 static const dtTypeElem dtTypes
[] = {
141 // patternChar, field, type, minLen, weight
142 {CAP_G
, UDATPG_ERA_FIELD
, DT_SHORT
, 1, 3,},
143 {CAP_G
, UDATPG_ERA_FIELD
, DT_LONG
, 4, 0},
144 {LOW_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
, 1, 20},
145 {CAP_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 20},
146 {LOW_U
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 20},
147 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_NUMERIC
, 1, 2},
148 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_SHORT
, 3, 0},
149 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_LONG
, 4, 0},
150 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
151 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_SHORT
+ DT_DELTA
, 3, 0},
152 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_LONG
+ DT_DELTA
, 4, 0},
153 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NUMERIC
, 1, 2},
154 {CAP_M
, UDATPG_MONTH_FIELD
, DT_SHORT
, 3, 0},
155 {CAP_M
, UDATPG_MONTH_FIELD
, DT_LONG
, 4, 0},
156 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NARROW
, 5, 0},
157 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
158 {CAP_L
, UDATPG_MONTH_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
159 {CAP_L
, UDATPG_MONTH_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
160 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
161 {LOW_W
, UDATPG_WEEK_OF_YEAR_FIELD
, DT_NUMERIC
, 1, 2},
162 {CAP_W
, UDATPG_WEEK_OF_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 0},
163 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
, 1, 3},
164 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
, 4, 0},
165 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
, 5, 0},
166 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 2},
167 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- 2*DT_DELTA
, 3, 0},
168 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
169 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- 2*DT_DELTA
, 5, 0},
170 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
171 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
172 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
173 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
174 {LOW_D
, UDATPG_DAY_FIELD
, DT_NUMERIC
, 1, 2},
175 {CAP_D
, UDATPG_DAY_OF_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 3},
176 {CAP_F
, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 0},
177 {LOW_G
, UDATPG_DAY_FIELD
, DT_NUMERIC
+ 3*DT_DELTA
, 1, 20}, // really internal use, so we don't care
178 {LOW_A
, UDATPG_DAYPERIOD_FIELD
, DT_SHORT
, 1, 0},
179 {CAP_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 10*DT_DELTA
, 1, 2}, // 24 hour
180 {LOW_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 11*DT_DELTA
, 1, 2},
181 {LOW_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
, 1, 2}, // 12 hour
182 {LOW_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
183 {LOW_M
, UDATPG_MINUTE_FIELD
, DT_NUMERIC
, 1, 2},
184 {LOW_S
, UDATPG_SECOND_FIELD
, DT_NUMERIC
, 1, 2},
185 {CAP_S
, UDATPG_FRACTIONAL_SECOND_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 1000},
186 {CAP_A
, UDATPG_SECOND_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 1000},
187 {LOW_V
, UDATPG_ZONE_FIELD
, DT_SHORT
- 2*DT_DELTA
, 1, 0},
188 {LOW_V
, UDATPG_ZONE_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
189 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
, 1, 3},
190 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_LONG
, 4, 0},
191 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 1, 3},
192 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
193 {CAP_V
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 1, 3},
194 {CAP_V
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
195 {0, UDATPG_FIELD_COUNT
, 0, 0, 0} , // last row of dtTypes[]
198 static const char* const CLDR_FIELD_APPEND
[] = {
199 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
200 "Hour", "Minute", "Second", "*", "Timezone"
203 static const char* const CLDR_FIELD_NAME
[] = {
204 "era", "year", "quarter", "month", "week", "*", "weekday", "day", "*", "*", "dayperiod",
205 "hour", "minute", "second", "*", "zone"
208 static const char* const Resource_Fields
[] = {
209 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
210 "weekday", "year", "zone", "quarter" };
213 static const UChar UDATPG_ItemFormat
[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
214 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
216 static const UChar repeatedPatterns
[6]={CAP_G
, CAP_E
, LOW_Z
, LOW_V
, CAP_Q
, 0}; // "GEzvQ"
218 static const char DT_DateTimePatternsTag
[]="DateTimePatterns";
219 static const char DT_DateTimeCalendarTag
[]="calendar";
220 static const char DT_DateTimeGregorianTag
[]="gregorian";
221 static const char DT_DateTimeAppendItemsTag
[]="appendItems";
222 static const char DT_DateTimeFieldsTag
[]="fields";
223 static const char DT_DateTimeAvailableFormatsTag
[]="availableFormats";
224 //static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
226 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator
)
227 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration
)
228 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration
)
230 DateTimePatternGenerator
* U_EXPORT2
231 DateTimePatternGenerator::createInstance(UErrorCode
& status
) {
232 return createInstance(Locale::getDefault(), status
);
235 DateTimePatternGenerator
* U_EXPORT2
236 DateTimePatternGenerator::createInstance(const Locale
& locale
, UErrorCode
& status
) {
237 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(locale
, status
);
238 if (result
== NULL
) {
239 status
= U_MEMORY_ALLOCATION_ERROR
;
241 if (U_FAILURE(status
)) {
248 DateTimePatternGenerator
* U_EXPORT2
249 DateTimePatternGenerator::createEmptyInstance(UErrorCode
& status
) {
250 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(status
);
251 if (result
== NULL
) {
252 status
= U_MEMORY_ALLOCATION_ERROR
;
254 if (U_FAILURE(status
)) {
261 DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode
&status
) :
263 fAvailableFormatKeyHash(NULL
)
265 fp
= new FormatParser();
266 dtMatcher
= new DateTimeMatcher();
267 distanceInfo
= new DistanceInfo();
268 patternMap
= new PatternMap();
269 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
270 status
= U_MEMORY_ALLOCATION_ERROR
;
274 DateTimePatternGenerator::DateTimePatternGenerator(const Locale
& locale
, UErrorCode
&status
) :
276 fAvailableFormatKeyHash(NULL
)
278 fp
= new FormatParser();
279 dtMatcher
= new DateTimeMatcher();
280 distanceInfo
= new DistanceInfo();
281 patternMap
= new PatternMap();
282 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
283 status
= U_MEMORY_ALLOCATION_ERROR
;
286 initData(locale
, status
);
290 DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator
& other
) :
293 fAvailableFormatKeyHash(NULL
)
295 fp
= new FormatParser();
296 dtMatcher
= new DateTimeMatcher();
297 distanceInfo
= new DistanceInfo();
298 patternMap
= new PatternMap();
302 DateTimePatternGenerator
&
303 DateTimePatternGenerator::operator=(const DateTimePatternGenerator
& other
) {
304 pLocale
= other
.pLocale
;
305 fDefaultHourFormatChar
= other
.fDefaultHourFormatChar
;
307 dtMatcher
->copyFrom(other
.dtMatcher
->skeleton
);
308 *distanceInfo
= *(other
.distanceInfo
);
309 dateTimeFormat
= other
.dateTimeFormat
;
310 decimal
= other
.decimal
;
311 // NUL-terminate for the C API.
312 dateTimeFormat
.getTerminatedBuffer();
313 decimal
.getTerminatedBuffer();
315 if ( other
.skipMatcher
== NULL
) {
319 skipMatcher
= new DateTimeMatcher(*other
.skipMatcher
);
321 for (int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
322 appendItemFormats
[i
] = other
.appendItemFormats
[i
];
323 appendItemNames
[i
] = other
.appendItemNames
[i
];
324 // NUL-terminate for the C API.
325 appendItemFormats
[i
].getTerminatedBuffer();
326 appendItemNames
[i
].getTerminatedBuffer();
328 UErrorCode status
= U_ZERO_ERROR
;
329 patternMap
->copyFrom(*other
.patternMap
, status
);
330 copyHashtable(other
.fAvailableFormatKeyHash
, status
);
336 DateTimePatternGenerator::operator==(const DateTimePatternGenerator
& other
) const {
337 if (this == &other
) {
340 if ((pLocale
==other
.pLocale
) && (patternMap
->equals(*other
.patternMap
)) &&
341 (dateTimeFormat
==other
.dateTimeFormat
) && (decimal
==other
.decimal
)) {
342 for ( int32_t i
=0 ; i
<UDATPG_FIELD_COUNT
; ++i
) {
343 if ((appendItemFormats
[i
] != other
.appendItemFormats
[i
]) ||
344 (appendItemNames
[i
] != other
.appendItemNames
[i
]) ) {
356 DateTimePatternGenerator::operator!=(const DateTimePatternGenerator
& other
) const {
357 return !operator==(other
);
360 DateTimePatternGenerator::~DateTimePatternGenerator() {
361 if (fAvailableFormatKeyHash
!=NULL
) {
362 delete fAvailableFormatKeyHash
;
365 if (fp
!= NULL
) delete fp
;
366 if (dtMatcher
!= NULL
) delete dtMatcher
;
367 if (distanceInfo
!= NULL
) delete distanceInfo
;
368 if (patternMap
!= NULL
) delete patternMap
;
369 if (skipMatcher
!= NULL
) delete skipMatcher
;
373 DateTimePatternGenerator::initData(const Locale
& locale
, UErrorCode
&status
) {
374 //const char *baseLangName = locale.getBaseName(); // unused
377 fAvailableFormatKeyHash
=NULL
;
379 addICUPatterns(locale
, status
);
380 if (U_FAILURE(status
)) {
383 addCLDRData(locale
, status
);
384 setDateTimeFromCalendar(locale
, status
);
385 setDecimalSymbols(locale
, status
);
386 } // DateTimePatternGenerator::initData
389 DateTimePatternGenerator::getSkeleton(const UnicodeString
& pattern
, UErrorCode
&
391 dtMatcher
->set(pattern
, fp
);
392 return dtMatcher
->getSkeletonPtr()->getSkeleton();
396 DateTimePatternGenerator::getBaseSkeleton(const UnicodeString
& pattern
, UErrorCode
& /*status*/) {
397 dtMatcher
->set(pattern
, fp
);
398 return dtMatcher
->getSkeletonPtr()->getBaseSkeleton();
402 DateTimePatternGenerator::addICUPatterns(const Locale
& locale
, UErrorCode
& status
) {
403 UnicodeString dfPattern
;
404 UnicodeString conflictingString
;
405 UDateTimePatternConflict conflictingStatus
;
408 if (U_FAILURE(status
)) {
412 // Load with ICU patterns
413 for (int32_t i
=DateFormat::kFull
; i
<=DateFormat::kShort
; i
++) {
414 DateFormat::EStyle style
= (DateFormat::EStyle
)i
;
415 df
= DateFormat::createDateInstance(style
, locale
);
416 SimpleDateFormat
* sdf
;
417 if (df
!= NULL
&& (sdf
= dynamic_cast<SimpleDateFormat
*>(df
)) != NULL
) {
418 conflictingStatus
= addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
420 // TODO Maybe we should return an error when the date format isn't simple.
422 if (U_FAILURE(status
)) {
426 df
= DateFormat::createTimeInstance(style
, locale
);
427 if (df
!= NULL
&& (sdf
= dynamic_cast<SimpleDateFormat
*>(df
)) != NULL
) {
428 conflictingStatus
= addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
430 if ( i
==DateFormat::kMedium
) {
431 hackPattern
= dfPattern
;
434 // TODO Maybe we should return an error when the date format isn't simple.
436 if (U_FAILURE(status
)) {
443 DateTimePatternGenerator::hackTimes(const UnicodeString
& hackPattern
, UErrorCode
& status
) {
444 UDateTimePatternConflict conflictingStatus
;
445 UnicodeString conflictingString
;
447 fp
->set(hackPattern
);
450 for (int32_t i
=0; i
<fp
->itemNumber
; ++i
) {
451 UnicodeString field
= fp
->items
[i
];
452 if ( fp
->isQuoteLiteral(field
) ) {
454 UnicodeString quoteLiteral
;
455 fp
->getQuoteLiteral(quoteLiteral
, &i
);
456 mmss
+= quoteLiteral
;
460 if (fp
->isPatternSeparator(field
) && gotMm
) {
464 UChar ch
=field
.charAt(0);
475 conflictingStatus
= addPattern(mmss
, FALSE
, conflictingString
, status
);
479 if (gotMm
|| ch
==LOW_Z
|| ch
==CAP_Z
|| ch
==LOW_V
|| ch
==CAP_V
) {
489 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
491 static const UChar hourFormatChars
[] = { CAP_H
, LOW_H
, CAP_K
, LOW_K
, 0 }; // HhKk, the hour format characters
494 DateTimePatternGenerator::addCLDRData(const Locale
& locale
, UErrorCode
& err
) {
495 UResourceBundle
*rb
, *calTypeBundle
, *calBundle
;
496 UResourceBundle
*patBundle
, *fieldBundle
, *fBundle
;
497 UnicodeString rbPattern
, value
, field
;
498 UnicodeString conflictingPattern
;
499 UDateTimePatternConflict conflictingStatus
;
500 const char *key
=NULL
;
503 UnicodeString
defaultItemFormat(TRUE
, UDATPG_ItemFormat
, LENGTHOF(UDATPG_ItemFormat
)-1); // Read-only alias.
507 fDefaultHourFormatChar
= 0;
508 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
509 appendItemNames
[i
]=CAP_F
;
511 appendItemNames
[i
]+=(UChar
)(i
+0x30);
514 appendItemNames
[i
]+=(UChar
)0x31;
515 appendItemNames
[i
]+=(UChar
)(i
-10 + 0x30);
517 // NUL-terminate for the C API.
518 appendItemNames
[i
].getTerminatedBuffer();
521 rb
= ures_open(NULL
, locale
.getName(), &err
);
522 if (rb
== NULL
|| U_FAILURE(err
)) {
525 const char *curLocaleName
=ures_getLocaleByType(rb
, ULOC_ACTUAL_LOCALE
, &err
);
526 const char * calendarTypeToUse
= DT_DateTimeGregorianTag
; // initial default
527 char calendarType
[ULOC_KEYWORDS_CAPACITY
]; // to be filled in with the type to use, if all goes well
528 if ( U_SUCCESS(err
) ) {
529 char localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
530 // obtain a locale that always has the calendar key value that should be used
531 (void)ures_getFunctionalEquivalent(localeWithCalendarKey
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, NULL
,
532 "calendar", "calendar", locale
.getName(), NULL
, FALSE
, &err
);
533 localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
-1] = 0; // ensure null termination
534 // now get the calendar key value from that locale
535 int32_t calendarTypeLen
= uloc_getKeywordValue(localeWithCalendarKey
, "calendar", calendarType
, ULOC_KEYWORDS_CAPACITY
, &err
);
536 if (U_SUCCESS(err
) && calendarTypeLen
< ULOC_KEYWORDS_CAPACITY
) {
537 calendarTypeToUse
= calendarType
;
541 calBundle
= ures_getByKeyWithFallback(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
542 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &err
);
546 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimePatternsTag
, NULL
, &err
);
547 while (U_SUCCESS(err
)) {
548 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
550 if (rbPattern
.length()==0 ) {
551 break; // no more pattern
555 setDateTimeFormat(rbPattern
);
556 } else if (dtCount
==4) { // short time format
557 // set fDefaultHourFormatChar to the hour format character from this pattern
558 int32_t tfIdx
, tfLen
= rbPattern
.length();
559 UBool ignoreChars
= FALSE
;
560 for (tfIdx
= 0; tfIdx
< tfLen
; tfIdx
++) {
561 UChar tfChar
= rbPattern
.charAt(tfIdx
);
562 if ( tfChar
== SINGLE_QUOTE
) {
563 ignoreChars
= !ignoreChars
; // toggle (handle quoted literals & '' for single quote)
564 } else if ( !ignoreChars
&& u_strchr(hourFormatChars
, tfChar
) != NULL
) {
565 fDefaultHourFormatChar
= tfChar
;
572 ures_close(patBundle
);
575 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAppendItemsTag
, NULL
, &err
);
577 UnicodeString itemKey
;
578 while (U_SUCCESS(err
)) {
579 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
580 if (rbPattern
.length()==0 ) {
581 break; // no more pattern
584 setAppendItemFormat(getAppendFormatNumber(key
), rbPattern
);
587 ures_close(patBundle
);
591 fBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeFieldsTag
, NULL
, &err
);
592 for (i
=0; i
<MAX_RESOURCE_FIELD
; ++i
) {
594 patBundle
= ures_getByKeyWithFallback(fBundle
, Resource_Fields
[i
], NULL
, &err
);
595 fieldBundle
= ures_getByKeyWithFallback(patBundle
, "dn", NULL
, &err
);
596 rbPattern
= ures_getNextUnicodeString(fieldBundle
, &key
, &err
);
597 ures_close(fieldBundle
);
598 ures_close(patBundle
);
599 if (rbPattern
.length()==0 ) {
603 setAppendItemName(getAppendNameNumber(Resource_Fields
[i
]), rbPattern
);
608 // add available formats
611 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAvailableFormatsTag
, NULL
, &err
);
612 if (U_SUCCESS(err
)) {
613 int32_t numberKeys
= ures_getSize(patBundle
);
615 const UChar
*retPattern
;
617 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
618 UResourceBundleAIterator aiter
;
619 ures_a_open(&aiter
, patBundle
, &err
);
621 for(i
=0; i
<numberKeys
; ++i
) {
622 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
623 retPattern
=ures_a_getNextString(&aiter
, &len
, &key
, &err
);
625 retPattern
=ures_getNextString(patBundle
, &len
, &key
, &err
);
627 UnicodeString format
=UnicodeString(retPattern
);
628 UnicodeString retKey
=UnicodeString(key
, -1, US_INV
);
629 setAvailableFormat(retKey
, err
);
630 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
631 // but not a previous availableFormats entry:
632 conflictingStatus
= addPatternWithSkeleton(format
, &retKey
, TRUE
, conflictingPattern
, err
);
634 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
635 ures_a_close(&aiter
);
638 ures_close(patBundle
);
639 ures_close(calTypeBundle
);
640 ures_close(calBundle
);
644 char parentLocale
[50];
645 int32_t localeNameLen
=0;
646 uprv_strcpy(parentLocale
, curLocaleName
);
647 while((localeNameLen
=uloc_getParent(parentLocale
, parentLocale
, 50, &err
))>=0 ) {
648 rb
= ures_open(NULL
, parentLocale
, &err
);
649 curLocaleName
=ures_getLocaleByType(rb
, ULOC_ACTUAL_LOCALE
, &err
);
650 uprv_strcpy(parentLocale
, curLocaleName
);
651 calBundle
= ures_getByKey(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
652 calTypeBundle
= ures_getByKey(calBundle
, calendarTypeToUse
, NULL
, &err
);
653 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAvailableFormatsTag
, NULL
, &err
);
654 if (U_SUCCESS(err
)) {
655 int32_t numberKeys
= ures_getSize(patBundle
);
657 const UChar
*retPattern
;
659 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
660 UResourceBundleAIterator aiter
;
661 ures_a_open(&aiter
, patBundle
, &err
);
663 for(i
=0; i
<numberKeys
; ++i
) {
664 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
665 retPattern
=ures_a_getNextString(&aiter
, &len
, &key
, &err
);
667 retPattern
=ures_getNextString(patBundle
, &len
, &key
, &err
);
669 UnicodeString format
=UnicodeString(retPattern
);
670 UnicodeString retKey
=UnicodeString(key
, -1, US_INV
);
671 if ( !isAvailableFormatSet(retKey
) ) {
672 setAvailableFormat(retKey
, err
);
673 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
674 // but not a previous availableFormats entry:
675 conflictingStatus
= addPatternWithSkeleton(format
, &retKey
, TRUE
, conflictingPattern
, err
);
678 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
679 ures_a_close(&aiter
);
682 err
= U_ZERO_ERROR
; // reset; if this locale lacks the necessary data, need to keep checking up to root.
683 ures_close(patBundle
);
684 ures_close(calTypeBundle
);
685 ures_close(calBundle
);
687 if (localeNameLen
==0) {
692 if (hackPattern
.length()>0) {
693 hackTimes(hackPattern
, err
);
698 DateTimePatternGenerator::initHashtable(UErrorCode
& err
) {
699 if (fAvailableFormatKeyHash
!=NULL
) {
702 if ((fAvailableFormatKeyHash
= new Hashtable(FALSE
, err
))==NULL
) {
703 err
=U_MEMORY_ALLOCATION_ERROR
;
710 DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field
, const UnicodeString
& value
) {
711 appendItemFormats
[field
] = value
;
712 // NUL-terminate for the C API.
713 appendItemFormats
[field
].getTerminatedBuffer();
717 DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field
) const {
718 return appendItemFormats
[field
];
722 DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field
, const UnicodeString
& value
) {
723 appendItemNames
[field
] = value
;
724 // NUL-terminate for the C API.
725 appendItemNames
[field
].getTerminatedBuffer();
729 DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field
) const {
730 return appendItemNames
[field
];
734 DateTimePatternGenerator::getAppendName(UDateTimePatternField field
, UnicodeString
& value
) {
735 value
= SINGLE_QUOTE
;
736 value
+= appendItemNames
[field
];
737 value
+= SINGLE_QUOTE
;
741 DateTimePatternGenerator::getBestPattern(const UnicodeString
& patternForm
, UErrorCode
& status
) {
742 return getBestPattern(patternForm
, UDATPG_MATCH_NO_OPTIONS
, status
);
746 DateTimePatternGenerator::getBestPattern(const UnicodeString
& patternForm
, UDateTimePatternMatchOptions options
, UErrorCode
& status
) {
747 const UnicodeString
*bestPattern
=NULL
;
748 UnicodeString dtFormat
;
749 UnicodeString resultPattern
;
751 int32_t dateMask
=(1<<UDATPG_DAYPERIOD_FIELD
) - 1;
752 int32_t timeMask
=(1<<UDATPG_FIELD_COUNT
) - 1 - dateMask
;
754 UnicodeString patternFormCopy
= UnicodeString(patternForm
);
755 patternFormCopy
.findAndReplace(UnicodeString(LOW_J
), UnicodeString(fDefaultHourFormatChar
));
757 resultPattern
.remove();
758 dtMatcher
->set(patternFormCopy
, fp
);
759 const PtnSkeleton
* specifiedSkeleton
=NULL
;
760 bestPattern
=getBestRaw(*dtMatcher
, -1, distanceInfo
, &specifiedSkeleton
);
761 if ( distanceInfo
->missingFieldMask
==0 && distanceInfo
->extraFieldMask
==0 ) {
762 resultPattern
= adjustFieldTypes(*bestPattern
, specifiedSkeleton
, FALSE
, options
);
764 return resultPattern
;
766 int32_t neededFields
= dtMatcher
->getFieldMask();
767 UnicodeString datePattern
=getBestAppending(neededFields
& dateMask
, options
);
768 UnicodeString timePattern
=getBestAppending(neededFields
& timeMask
, options
);
769 if (datePattern
.length()==0) {
770 if (timePattern
.length()==0) {
771 resultPattern
.remove();
777 if (timePattern
.length()==0) {
780 resultPattern
.remove();
781 status
= U_ZERO_ERROR
;
782 dtFormat
=getDateTimeFormat();
783 Formattable dateTimeObject
[] = { timePattern
, datePattern
};
784 resultPattern
= MessageFormat::format(dtFormat
, dateTimeObject
, 2, resultPattern
, status
);
785 return resultPattern
;
789 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString
& pattern
,
790 const UnicodeString
& skeleton
,
791 UErrorCode
& status
) {
792 return replaceFieldTypes(pattern
, skeleton
, UDATPG_MATCH_NO_OPTIONS
, status
);
796 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString
& pattern
,
797 const UnicodeString
& skeleton
,
798 UDateTimePatternMatchOptions options
,
799 UErrorCode
& /*status*/) {
800 dtMatcher
->set(skeleton
, fp
);
801 UnicodeString result
= adjustFieldTypes(pattern
, NULL
, FALSE
, options
);
806 DateTimePatternGenerator::setDecimal(const UnicodeString
& newDecimal
) {
807 this->decimal
= newDecimal
;
808 // NUL-terminate for the C API.
809 this->decimal
.getTerminatedBuffer();
813 DateTimePatternGenerator::getDecimal() const {
818 DateTimePatternGenerator::addCanonicalItems() {
819 UnicodeString conflictingPattern
;
820 UDateTimePatternConflict conflictingStatus
;
821 UErrorCode status
= U_ZERO_ERROR
;
823 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; i
++) {
824 conflictingStatus
= addPattern(UnicodeString(Canonical_Items
[i
]), FALSE
, conflictingPattern
, status
);
829 DateTimePatternGenerator::setDateTimeFormat(const UnicodeString
& dtFormat
) {
830 dateTimeFormat
= dtFormat
;
831 // NUL-terminate for the C API.
832 dateTimeFormat
.getTerminatedBuffer();
836 DateTimePatternGenerator::getDateTimeFormat() const {
837 return dateTimeFormat
;
841 DateTimePatternGenerator::setDateTimeFromCalendar(const Locale
& locale
, UErrorCode
& status
) {
843 int32_t resStrLen
= 0;
845 Calendar
* fCalendar
= Calendar::createInstance(locale
, status
);
846 CalendarData
calData(locale
, fCalendar
?fCalendar
->getType():NULL
, status
);
847 UResourceBundle
*dateTimePatterns
= calData
.getByKey(DT_DateTimePatternsTag
, status
);
848 if (U_FAILURE(status
)) return;
850 if (ures_getSize(dateTimePatterns
) <= DateFormat::kDateTime
)
852 status
= U_INVALID_FORMAT_ERROR
;
855 resStr
= ures_getStringByIndex(dateTimePatterns
, (int32_t)DateFormat::kDateTime
, &resStrLen
, &status
);
856 setDateTimeFormat(UnicodeString(TRUE
, resStr
, resStrLen
));
862 DateTimePatternGenerator::setDecimalSymbols(const Locale
& locale
, UErrorCode
& status
) {
863 DecimalFormatSymbols dfs
= DecimalFormatSymbols(locale
, status
);
864 if(U_SUCCESS(status
)) {
865 decimal
= dfs
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
866 // NUL-terminate for the C API.
867 decimal
.getTerminatedBuffer();
871 UDateTimePatternConflict
872 DateTimePatternGenerator::addPattern(
873 const UnicodeString
& pattern
,
875 UnicodeString
&conflictingPattern
,
878 return addPatternWithSkeleton(pattern
, NULL
, override
, conflictingPattern
, status
);
881 // For DateTimePatternGenerator::addPatternWithSkeleton -
882 // If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
883 // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
884 // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
885 // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
886 // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
887 // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
888 // derived (i.e. entries derived from the standard date/time patters for the specified locale).
889 // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
890 // specified skeleton (which sets a new field in the PtnElem in the PatternMap).
891 UDateTimePatternConflict
892 DateTimePatternGenerator::addPatternWithSkeleton(
893 const UnicodeString
& pattern
,
894 const UnicodeString
* skeletonToUse
,
896 UnicodeString
& conflictingPattern
,
900 UnicodeString basePattern
;
901 PtnSkeleton skeleton
;
902 UDateTimePatternConflict conflictingStatus
= UDATPG_NO_CONFLICT
;
904 DateTimeMatcher matcher
;
905 if ( skeletonToUse
== NULL
) {
906 matcher
.set(pattern
, fp
, skeleton
);
907 matcher
.getBasePattern(basePattern
);
909 matcher
.set(*skeletonToUse
, fp
, skeleton
); // this still trims skeleton fields to max len 3, may need to change it.
910 matcher
.getBasePattern(basePattern
); // or perhaps instead: basePattern = *skeletonToUse;
912 UBool entryHadSpecifiedSkeleton
;
913 const UnicodeString
*duplicatePattern
= patternMap
->getPatternFromBasePattern(basePattern
, entryHadSpecifiedSkeleton
);
914 if (duplicatePattern
!= NULL
) {
915 conflictingStatus
= UDATPG_BASE_CONFLICT
;
916 conflictingPattern
= *duplicatePattern
;
917 if (!override
|| (skeletonToUse
!= NULL
&& entryHadSpecifiedSkeleton
)) {
918 return conflictingStatus
;
921 const PtnSkeleton
* entrySpecifiedSkeleton
= NULL
;
922 duplicatePattern
= patternMap
->getPatternFromSkeleton(skeleton
, &entrySpecifiedSkeleton
);
923 if (duplicatePattern
!= NULL
) {
924 conflictingStatus
= UDATPG_CONFLICT
;
925 conflictingPattern
= *duplicatePattern
;
926 if (!override
|| (skeletonToUse
!= NULL
&& entrySpecifiedSkeleton
!= NULL
)) {
927 return conflictingStatus
;
930 patternMap
->add(basePattern
, skeleton
, pattern
, skeletonToUse
!= NULL
, status
);
931 if(U_FAILURE(status
)) {
932 return conflictingStatus
;
935 return UDATPG_NO_CONFLICT
;
939 UDateTimePatternField
940 DateTimePatternGenerator::getAppendFormatNumber(const char* field
) const {
941 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
942 if (uprv_strcmp(CLDR_FIELD_APPEND
[i
], field
)==0) {
943 return (UDateTimePatternField
)i
;
946 return UDATPG_FIELD_COUNT
;
949 UDateTimePatternField
950 DateTimePatternGenerator::getAppendNameNumber(const char* field
) const {
951 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
952 if (uprv_strcmp(CLDR_FIELD_NAME
[i
],field
)==0) {
953 return (UDateTimePatternField
)i
;
956 return UDATPG_FIELD_COUNT
;
960 DateTimePatternGenerator::getBestRaw(DateTimeMatcher
& source
,
962 DistanceInfo
* missingFields
,
963 const PtnSkeleton
** specifiedSkeletonPtr
) {
964 int32_t bestDistance
= 0x7fffffff;
965 DistanceInfo tempInfo
;
966 const UnicodeString
*bestPattern
=NULL
;
967 const PtnSkeleton
* specifiedSkeleton
=NULL
;
969 PatternMapIterator it
;
970 for (it
.set(*patternMap
); it
.hasNext(); ) {
971 DateTimeMatcher trial
= it
.next();
972 if (trial
.equals(skipMatcher
)) {
975 int32_t distance
=source
.getDistance(trial
, includeMask
, tempInfo
);
976 if (distance
<bestDistance
) {
977 bestDistance
=distance
;
978 bestPattern
=patternMap
->getPatternFromSkeleton(*trial
.getSkeletonPtr(), &specifiedSkeleton
);
979 missingFields
->setTo(tempInfo
);
986 // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
987 // then return it too. This generally happens when the caller needs to pass that skeleton
988 // through to adjustFieldTypes so the latter can do a better job.
989 if (bestPattern
&& specifiedSkeletonPtr
) {
990 *specifiedSkeletonPtr
= specifiedSkeleton
;
996 DateTimePatternGenerator::adjustFieldTypes(const UnicodeString
& pattern
,
997 const PtnSkeleton
* specifiedSkeleton
,
998 UBool fixFractionalSeconds
,
999 UDateTimePatternMatchOptions options
) {
1000 UnicodeString newPattern
;
1002 for (int32_t i
=0; i
< fp
->itemNumber
; i
++) {
1003 UnicodeString field
= fp
->items
[i
];
1004 if ( fp
->isQuoteLiteral(field
) ) {
1006 UnicodeString quoteLiteral
;
1007 fp
->getQuoteLiteral(quoteLiteral
, &i
);
1008 newPattern
+= quoteLiteral
;
1011 if (fp
->isPatternSeparator(field
)) {
1015 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
1016 if (canonicalIndex
< 0) {
1018 continue; // don't adjust
1020 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
1021 int32_t typeValue
= row
->field
;
1022 if (fixFractionalSeconds
&& typeValue
== UDATPG_SECOND_FIELD
) {
1023 UnicodeString newField
=dtMatcher
->skeleton
.original
[UDATPG_FRACTIONAL_SECOND_FIELD
];
1024 field
= field
+ decimal
+ newField
;
1025 } else if (dtMatcher
->skeleton
.type
[typeValue
]!=0) {
1027 // - "reqField" is the field from the originally requested skeleton, with length
1029 // - "field" is the field from the found pattern.
1031 // The adjusted field should consist of characters from the originally requested
1032 // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or
1033 // UDATPG_WEEKDAY_FIELD, in which case it should consist of characters from the
1036 // The length of the adjusted field (adjFieldLen) should match that in the originally
1037 // requested skeleton, except that in the following cases the length of the adjusted field
1038 // should match that in the found pattern (i.e. the length of this pattern field should
1039 // not be adjusted):
1040 // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is
1041 // not set (ticket #7180). Note, we may want to implement a similar change for other
1042 // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for
1043 // field length, but options bits can be used to override this.
1044 // 2. There is a specified skeleton for the found pattern and one of the following is true:
1045 // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
1046 // b) The pattern field is numeric and the skeleton field is not, or vice versa.
1048 UnicodeString reqField
= dtMatcher
->skeleton
.original
[typeValue
];
1049 int32_t reqFieldLen
= reqField
.length();
1050 if (reqField
.charAt(0) == CAP_E
&& reqFieldLen
< 3)
1051 reqFieldLen
= 3; // 1-3 for E are equivalent to 3 for c,e
1052 int32_t adjFieldLen
= reqFieldLen
;
1053 if ( (typeValue
==UDATPG_HOUR_FIELD
&& (options
& UDATPG_MATCH_HOUR_FIELD_LENGTH
)==0) ||
1054 (typeValue
==UDATPG_MINUTE_FIELD
&& (options
& UDATPG_MATCH_MINUTE_FIELD_LENGTH
)==0) ||
1055 (typeValue
==UDATPG_SECOND_FIELD
&& (options
& UDATPG_MATCH_SECOND_FIELD_LENGTH
)==0) ) {
1056 adjFieldLen
= field
.length();
1057 } else if (specifiedSkeleton
) {
1058 UnicodeString skelField
= specifiedSkeleton
->original
[typeValue
];
1059 int32_t skelFieldLen
= skelField
.length();
1060 UBool patFieldIsNumeric
= (row
->type
> 0);
1061 UBool skelFieldIsNumeric
= (specifiedSkeleton
->type
[typeValue
] > 0);
1062 if (skelFieldLen
== reqFieldLen
|| (patFieldIsNumeric
&& !skelFieldIsNumeric
) || (skelFieldIsNumeric
&& !patFieldIsNumeric
)) {
1063 // don't adjust the field length in the found pattern
1064 adjFieldLen
= field
.length();
1067 UChar c
= (typeValue
!= UDATPG_HOUR_FIELD
&& typeValue
!= UDATPG_MONTH_FIELD
&& typeValue
!= UDATPG_WEEKDAY_FIELD
)?
1068 reqField
.charAt(0): field
.charAt(0);
1070 for (int32_t i
=adjFieldLen
; i
>0; --i
) {
1081 DateTimePatternGenerator::getBestAppending(int32_t missingFields
, UDateTimePatternMatchOptions options
) {
1082 UnicodeString resultPattern
, tempPattern
;
1083 UErrorCode err
=U_ZERO_ERROR
;
1084 int32_t lastMissingFieldMask
=0;
1085 if (missingFields
!=0) {
1086 resultPattern
=UnicodeString();
1087 const PtnSkeleton
* specifiedSkeleton
=NULL
;
1088 tempPattern
= *getBestRaw(*dtMatcher
, missingFields
, distanceInfo
, &specifiedSkeleton
);
1089 resultPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, FALSE
, options
);
1090 if ( distanceInfo
->missingFieldMask
==0 ) {
1091 return resultPattern
;
1093 while (distanceInfo
->missingFieldMask
!=0) { // precondition: EVERY single field must work!
1094 if ( lastMissingFieldMask
== distanceInfo
->missingFieldMask
) {
1095 break; // cannot find the proper missing field
1097 if (((distanceInfo
->missingFieldMask
& UDATPG_SECOND_AND_FRACTIONAL_MASK
)==UDATPG_FRACTIONAL_MASK
) &&
1098 ((missingFields
& UDATPG_SECOND_AND_FRACTIONAL_MASK
) == UDATPG_SECOND_AND_FRACTIONAL_MASK
)) {
1099 resultPattern
= adjustFieldTypes(resultPattern
, specifiedSkeleton
, TRUE
, options
);
1100 distanceInfo
->missingFieldMask
&= ~UDATPG_FRACTIONAL_MASK
;
1103 int32_t startingMask
= distanceInfo
->missingFieldMask
;
1104 tempPattern
= *getBestRaw(*dtMatcher
, distanceInfo
->missingFieldMask
, distanceInfo
, &specifiedSkeleton
);
1105 tempPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, FALSE
, options
);
1106 int32_t foundMask
=startingMask
& ~distanceInfo
->missingFieldMask
;
1107 int32_t topField
=getTopBitNumber(foundMask
);
1108 UnicodeString appendName
;
1109 getAppendName((UDateTimePatternField
)topField
, appendName
);
1110 const Formattable formatPattern
[] = {
1115 UnicodeString emptyStr
;
1116 resultPattern
= MessageFormat::format(appendItemFormats
[topField
], formatPattern
, 3, emptyStr
, err
);
1117 lastMissingFieldMask
= distanceInfo
->missingFieldMask
;
1120 return resultPattern
;
1124 DateTimePatternGenerator::getTopBitNumber(int32_t foundMask
) {
1125 if ( foundMask
==0 ) {
1129 while (foundMask
!=0) {
1133 if (i
-1 >UDATPG_ZONE_FIELD
) {
1134 return UDATPG_ZONE_FIELD
;
1141 DateTimePatternGenerator::setAvailableFormat(const UnicodeString
&key
, UErrorCode
& err
)
1143 fAvailableFormatKeyHash
->puti(key
, 1, err
);
1147 DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString
&key
) const {
1148 return (UBool
)(fAvailableFormatKeyHash
->geti(key
) == 1);
1152 DateTimePatternGenerator::copyHashtable(Hashtable
*other
, UErrorCode
&status
) {
1154 if (other
== NULL
) {
1157 if (fAvailableFormatKeyHash
!= NULL
) {
1158 delete fAvailableFormatKeyHash
;
1159 fAvailableFormatKeyHash
= NULL
;
1161 initHashtable(status
);
1162 if(U_FAILURE(status
)){
1166 const UHashElement
* elem
= NULL
;
1167 // walk through the hash table and create a deep clone
1168 while((elem
= other
->nextElement(pos
))!= NULL
){
1169 const UHashTok otherKeyTok
= elem
->key
;
1170 UnicodeString
* otherKey
= (UnicodeString
*)otherKeyTok
.pointer
;
1171 fAvailableFormatKeyHash
->puti(*otherKey
, 1, status
);
1172 if(U_FAILURE(status
)){
1179 DateTimePatternGenerator::getSkeletons(UErrorCode
& status
) const {
1180 StringEnumeration
* skeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_SKELETON
, status
);
1181 return skeletonEnumerator
;
1184 const UnicodeString
&
1185 DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString
& skeleton
) const {
1188 if (skeleton
.length() ==0) {
1191 curElem
= patternMap
->getHeader(skeleton
.charAt(0));
1192 while ( curElem
!= NULL
) {
1193 if ( curElem
->skeleton
->getSkeleton()==skeleton
) {
1194 return curElem
->pattern
;
1196 curElem
=curElem
->next
;
1202 DateTimePatternGenerator::getBaseSkeletons(UErrorCode
& status
) const {
1203 StringEnumeration
* baseSkeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_BASESKELETON
, status
);
1204 return baseSkeletonEnumerator
;
1208 DateTimePatternGenerator::getRedundants(UErrorCode
& status
) {
1209 StringEnumeration
* output
= new DTRedundantEnumeration();
1210 const UnicodeString
*pattern
;
1211 PatternMapIterator it
;
1212 for (it
.set(*patternMap
); it
.hasNext(); ) {
1213 DateTimeMatcher current
= it
.next();
1214 pattern
= patternMap
->getPatternFromSkeleton(*(it
.getSkeleton()));
1215 if ( isCanonicalItem(*pattern
) ) {
1218 if ( skipMatcher
== NULL
) {
1219 skipMatcher
= new DateTimeMatcher(current
);
1222 *skipMatcher
= current
;
1224 UnicodeString trial
= getBestPattern(current
.getPattern(), status
);
1225 if (trial
== *pattern
) {
1226 ((DTRedundantEnumeration
*)output
)->add(*pattern
, status
);
1228 if (current
.equals(skipMatcher
)) {
1236 DateTimePatternGenerator::isCanonicalItem(const UnicodeString
& item
) const {
1237 if ( item
.length() != 1 ) {
1240 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1241 if (item
.charAt(0)==Canonical_Items
[i
]) {
1249 DateTimePatternGenerator
*
1250 DateTimePatternGenerator::clone() const {
1251 return new DateTimePatternGenerator(*this);
1254 PatternMap::PatternMap() {
1255 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1258 isDupAllowed
= TRUE
;
1262 PatternMap::copyFrom(const PatternMap
& other
, UErrorCode
& status
) {
1263 this->isDupAllowed
= other
.isDupAllowed
;
1264 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1265 PtnElem
*curElem
, *otherElem
, *prevElem
=NULL
;
1266 otherElem
= other
.boot
[bootIndex
];
1267 while (otherElem
!=NULL
) {
1268 if ((curElem
= new PtnElem(otherElem
->basePattern
, otherElem
->pattern
))==NULL
) {
1270 status
= U_MEMORY_ALLOCATION_ERROR
;
1273 if ( this->boot
[bootIndex
]== NULL
) {
1274 this->boot
[bootIndex
] = curElem
;
1276 if ((curElem
->skeleton
=new PtnSkeleton(*(otherElem
->skeleton
))) == NULL
) {
1278 status
= U_MEMORY_ALLOCATION_ERROR
;
1282 if (prevElem
!=NULL
) {
1283 prevElem
->next
=curElem
;
1287 otherElem
= otherElem
->next
;
1294 PatternMap::getHeader(UChar baseChar
) {
1297 if ( (baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
) ) {
1298 curElem
= boot
[baseChar
-CAP_A
];
1301 if ( (baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
) ) {
1302 curElem
= boot
[26+baseChar
-LOW_A
];
1311 PatternMap::~PatternMap() {
1312 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1313 if (boot
[i
]!=NULL
) {
1318 } // PatternMap destructor
1321 PatternMap::add(const UnicodeString
& basePattern
,
1322 const PtnSkeleton
& skeleton
,
1323 const UnicodeString
& value
,// mapped pattern value
1324 UBool skeletonWasSpecified
,
1325 UErrorCode
&status
) {
1326 UChar baseChar
= basePattern
.charAt(0);
1327 PtnElem
*curElem
, *baseElem
;
1328 status
= U_ZERO_ERROR
;
1330 // the baseChar must be A-Z or a-z
1331 if ((baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
)) {
1332 baseElem
= boot
[baseChar
-CAP_A
];
1335 if ((baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
)) {
1336 baseElem
= boot
[26+baseChar
-LOW_A
];
1339 status
= U_ILLEGAL_CHARACTER
;
1344 if (baseElem
== NULL
) {
1345 if ((curElem
= new PtnElem(basePattern
, value
)) == NULL
) {
1347 status
= U_MEMORY_ALLOCATION_ERROR
;
1350 if (baseChar
>= LOW_A
) {
1351 boot
[26 + (baseChar
-LOW_A
)] = curElem
;
1354 boot
[baseChar
-CAP_A
] = curElem
;
1356 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1357 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1359 if ( baseElem
!= NULL
) {
1360 curElem
= getDuplicateElem(basePattern
, skeleton
, baseElem
);
1362 if (curElem
== NULL
) {
1363 // add new element to the list.
1365 while( curElem
-> next
!= NULL
)
1367 curElem
= curElem
->next
;
1369 if ((curElem
->next
= new PtnElem(basePattern
, value
)) == NULL
) {
1371 status
= U_MEMORY_ALLOCATION_ERROR
;
1374 curElem
=curElem
->next
;
1375 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1376 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1379 // Pattern exists in the list already.
1380 if ( !isDupAllowed
) {
1383 // Overwrite the value.
1384 curElem
->pattern
= value
;
1387 } // PatternMap::add
1389 // Find the pattern from the given basePattern string.
1390 const UnicodeString
*
1391 PatternMap::getPatternFromBasePattern(UnicodeString
& basePattern
, UBool
& skeletonWasSpecified
) { // key to search for
1394 if ((curElem
=getHeader(basePattern
.charAt(0)))==NULL
) {
1395 return NULL
; // no match
1399 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1400 skeletonWasSpecified
= curElem
->skeletonWasSpecified
;
1401 return &(curElem
->pattern
);
1403 curElem
=curElem
->next
;
1404 }while (curElem
!= NULL
);
1407 } // PatternMap::getFromBasePattern
1410 // Find the pattern from the given skeleton.
1411 // At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
1412 // the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
1413 // and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
1414 // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
1415 // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
1416 const UnicodeString
*
1417 PatternMap::getPatternFromSkeleton(PtnSkeleton
& skeleton
, const PtnSkeleton
** specifiedSkeletonPtr
) { // key to search for
1420 if (specifiedSkeletonPtr
) {
1421 *specifiedSkeletonPtr
= NULL
;
1425 UChar baseChar
='\0';
1426 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1427 if (skeleton
.baseOriginal
[i
].length() !=0 ) {
1428 baseChar
= skeleton
.baseOriginal
[i
].charAt(0);
1433 if ((curElem
=getHeader(baseChar
))==NULL
) {
1434 return NULL
; // no match
1439 if (specifiedSkeletonPtr
!= NULL
) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
1440 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1441 if (curElem
->skeleton
->original
[i
].compare(skeleton
.original
[i
]) != 0 )
1446 } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
1447 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1448 if (curElem
->skeleton
->baseOriginal
[i
].compare(skeleton
.baseOriginal
[i
]) != 0 )
1454 if (i
== UDATPG_FIELD_COUNT
) {
1455 if (specifiedSkeletonPtr
&& curElem
->skeletonWasSpecified
) {
1456 *specifiedSkeletonPtr
= curElem
->skeleton
;
1458 return &(curElem
->pattern
);
1460 curElem
=curElem
->next
;
1461 }while (curElem
!= NULL
);
1467 PatternMap::equals(const PatternMap
& other
) {
1468 if ( this==&other
) {
1471 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1472 if ( boot
[bootIndex
]==other
.boot
[bootIndex
] ) {
1475 if ( (boot
[bootIndex
]==NULL
)||(other
.boot
[bootIndex
]==NULL
) ) {
1478 PtnElem
*otherElem
= other
.boot
[bootIndex
];
1479 PtnElem
*myElem
= boot
[bootIndex
];
1480 while ((otherElem
!=NULL
) || (myElem
!=NULL
)) {
1481 if ( myElem
== otherElem
) {
1484 if ((otherElem
==NULL
) || (myElem
==NULL
)) {
1487 if ( (myElem
->basePattern
!= otherElem
->basePattern
) ||
1488 (myElem
->pattern
!= otherElem
->pattern
) ) {
1491 if ((myElem
->skeleton
!=otherElem
->skeleton
)&&
1492 !myElem
->skeleton
->equals(*(otherElem
->skeleton
))) {
1495 myElem
= myElem
->next
;
1496 otherElem
=otherElem
->next
;
1502 // find any key existing in the mapping table already.
1503 // return TRUE if there is an existing key, otherwise return FALSE.
1505 PatternMap::getDuplicateElem(
1506 const UnicodeString
&basePattern
,
1507 const PtnSkeleton
&skeleton
,
1508 PtnElem
*baseElem
) {
1511 if ( baseElem
== (PtnElem
*)NULL
) {
1512 return (PtnElem
*)NULL
;
1518 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1520 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1521 if (curElem
->skeleton
->type
[i
] != skeleton
.type
[i
] ) {
1530 curElem
= curElem
->next
;
1531 } while( curElem
!= (PtnElem
*)NULL
);
1534 return (PtnElem
*)NULL
;
1536 } // PatternMap::getDuplicateElem
1538 DateTimeMatcher::DateTimeMatcher(void) {
1541 DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher
& other
) {
1542 copyFrom(other
.skeleton
);
1547 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
) {
1548 PtnSkeleton localSkeleton
;
1549 return set(pattern
, fp
, localSkeleton
);
1553 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
, PtnSkeleton
& skeletonResult
) {
1555 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1556 skeletonResult
.type
[i
]=NONE
;
1559 for (i
=0; i
< fp
->itemNumber
; i
++) {
1560 UnicodeString field
= fp
->items
[i
];
1561 if ( field
.charAt(0) == LOW_A
) {
1562 continue; // skip 'a'
1565 if ( fp
->isQuoteLiteral(field
) ) {
1566 UnicodeString quoteLiteral
;
1567 fp
->getQuoteLiteral(quoteLiteral
, &i
);
1570 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
1571 if (canonicalIndex
< 0 ) {
1574 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
1575 int32_t typeValue
= row
->field
;
1576 skeletonResult
.original
[typeValue
]=field
;
1577 UChar repeatChar
= row
->patternChar
;
1578 int32_t repeatCount
= row
->minLen
> 3 ? 3: row
->minLen
;
1579 while (repeatCount
-- > 0) {
1580 skeletonResult
.baseOriginal
[typeValue
] += repeatChar
;
1582 int16_t subTypeValue
= row
->type
;
1583 if ( row
->type
> 0) {
1584 subTypeValue
+= field
.length();
1586 skeletonResult
.type
[typeValue
] = subTypeValue
;
1588 copyFrom(skeletonResult
);
1592 DateTimeMatcher::getBasePattern(UnicodeString
&result
) {
1593 result
.remove(); // Reset the result first.
1594 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1595 if (skeleton
.baseOriginal
[i
].length()!=0) {
1596 result
+= skeleton
.baseOriginal
[i
];
1602 DateTimeMatcher::getPattern() {
1603 UnicodeString result
;
1605 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1606 if (skeleton
.original
[i
].length()!=0) {
1607 result
+= skeleton
.original
[i
];
1614 DateTimeMatcher::getDistance(const DateTimeMatcher
& other
, int32_t includeMask
, DistanceInfo
& distanceInfo
) {
1616 distanceInfo
.clear();
1617 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1618 int32_t myType
= (includeMask
&(1<<i
))==0 ? 0 : skeleton
.type
[i
];
1619 int32_t otherType
= other
.skeleton
.type
[i
];
1620 if (myType
==otherType
) {
1623 if (myType
==0) {// and other is not
1624 result
+= EXTRA_FIELD
;
1625 distanceInfo
.addExtra(i
);
1629 result
+= MISSING_FIELD
;
1630 distanceInfo
.addMissing(i
);
1633 result
+= abs(myType
- otherType
);
1642 DateTimeMatcher::copyFrom(const PtnSkeleton
& newSkeleton
) {
1643 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1644 this->skeleton
.type
[i
]=newSkeleton
.type
[i
];
1645 this->skeleton
.original
[i
]=newSkeleton
.original
[i
];
1646 this->skeleton
.baseOriginal
[i
]=newSkeleton
.baseOriginal
[i
];
1651 DateTimeMatcher::copyFrom() {
1653 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1654 this->skeleton
.type
[i
]=0;
1655 this->skeleton
.original
[i
].remove();
1656 this->skeleton
.baseOriginal
[i
].remove();
1661 DateTimeMatcher::equals(const DateTimeMatcher
* other
) const {
1665 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1666 if (this->skeleton
.original
[i
]!=other
->skeleton
.original
[i
] ) {
1674 DateTimeMatcher::getFieldMask() {
1677 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1678 if (skeleton
.type
[i
]!=0) {
1686 DateTimeMatcher::getSkeletonPtr() {
1690 FormatParser::FormatParser () {
1696 FormatParser::~FormatParser () {
1700 // Find the next token with the starting position and length
1701 // Note: the startPos may
1702 FormatParser::TokenStatus
1703 FormatParser::setTokens(const UnicodeString
& pattern
, int32_t startPos
, int32_t *len
) {
1704 int32_t curLoc
= startPos
;
1705 if ( curLoc
>= pattern
.length()) {
1708 // check the current char is between A-Z or a-z
1710 UChar c
=pattern
.charAt(curLoc
);
1711 if ( (c
>=CAP_A
&& c
<=CAP_Z
) || (c
>=LOW_A
&& c
<=LOW_Z
) ) {
1720 if ( pattern
.charAt(curLoc
)!= pattern
.charAt(startPos
) ) {
1721 break; // not the same token
1723 } while(curLoc
<= pattern
.length());
1724 *len
= curLoc
-startPos
;
1729 FormatParser::set(const UnicodeString
& pattern
) {
1731 TokenStatus result
=START
;
1736 result
= setTokens( pattern
, startPos
, &len
);
1737 if ( result
== ADD_TOKEN
)
1739 items
[itemNumber
++] = UnicodeString(pattern
, startPos
, len
);
1745 } while (result
==ADD_TOKEN
&& itemNumber
< MAX_DT_TOKEN
);
1749 FormatParser::getCanonicalIndex(const UnicodeString
& s
, UBool strict
) {
1750 int32_t len
= s
.length();
1754 UChar ch
= s
.charAt(0);
1756 // Verify that all are the same character.
1757 for (int32_t l
= 1; l
< len
; l
++) {
1758 if (ch
!= s
.charAt(l
)) {
1763 int32_t bestRow
= -1;
1764 while (dtTypes
[i
].patternChar
!= '\0') {
1765 if ( dtTypes
[i
].patternChar
!= ch
) {
1770 if (dtTypes
[i
].patternChar
!= dtTypes
[i
+1].patternChar
) {
1773 if (dtTypes
[i
+1].minLen
<= len
) {
1779 return strict
? -1 : bestRow
;
1783 FormatParser::isQuoteLiteral(const UnicodeString
& s
) const {
1784 return (UBool
)(s
.charAt(0)==SINGLE_QUOTE
);
1787 // This function aussumes the current itemIndex points to the quote literal.
1788 // Please call isQuoteLiteral prior to this function.
1790 FormatParser::getQuoteLiteral(UnicodeString
& quote
, int32_t *itemIndex
) {
1791 int32_t i
=*itemIndex
;
1794 if (items
[i
].charAt(0)==SINGLE_QUOTE
) {
1798 while ( i
< itemNumber
) {
1799 if ( items
[i
].charAt(0)==SINGLE_QUOTE
) {
1800 if ( (i
+1<itemNumber
) && (items
[i
+1].charAt(0)==SINGLE_QUOTE
)) {
1801 // two single quotes e.g. 'o''clock'
1802 quote
+= items
[i
++];
1803 quote
+= items
[i
++];
1820 FormatParser::isPatternSeparator(UnicodeString
& field
) {
1821 for (int32_t i
=0; i
<field
.length(); ++i
) {
1822 UChar c
= field
.charAt(i
);
1823 if ( (c
==SINGLE_QUOTE
) || (c
==BACKSLASH
) || (c
==SPACE
) || (c
==COLON
) ||
1824 (c
==QUOTATION_MARK
) || (c
==COMMA
) || (c
==HYPHEN
) ||(items
[i
].charAt(0)==DOT
) ) {
1835 DistanceInfo::setTo(DistanceInfo
&other
) {
1836 missingFieldMask
= other
.missingFieldMask
;
1837 extraFieldMask
= other
.extraFieldMask
;
1840 PatternMapIterator::PatternMapIterator() {
1844 matcher
= new DateTimeMatcher();
1848 PatternMapIterator::~PatternMapIterator() {
1853 PatternMapIterator::set(PatternMap
& newPatternMap
) {
1854 this->patternMap
=&newPatternMap
;
1858 PatternMapIterator::getSkeleton() {
1859 if ( nodePtr
== NULL
) {
1863 return nodePtr
->skeleton
;
1868 PatternMapIterator::hasNext() {
1869 int32_t headIndex
=bootIndex
;
1870 PtnElem
*curPtr
=nodePtr
;
1872 if (patternMap
==NULL
) {
1875 while ( headIndex
< MAX_PATTERN_ENTRIES
) {
1876 if ( curPtr
!= NULL
) {
1877 if ( curPtr
->next
!= NULL
) {
1887 if ( patternMap
->boot
[headIndex
] != NULL
) {
1901 PatternMapIterator::next() {
1902 while ( bootIndex
< MAX_PATTERN_ENTRIES
) {
1903 if ( nodePtr
!= NULL
) {
1904 if ( nodePtr
->next
!= NULL
) {
1905 nodePtr
= nodePtr
->next
;
1915 if ( patternMap
->boot
[bootIndex
] != NULL
) {
1916 nodePtr
= patternMap
->boot
[bootIndex
];
1925 if (nodePtr
!=NULL
) {
1926 matcher
->copyFrom(*nodePtr
->skeleton
);
1929 matcher
->copyFrom();
1934 PtnSkeleton::PtnSkeleton() {
1938 PtnSkeleton::PtnSkeleton(const PtnSkeleton
& other
) {
1939 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1940 this->type
[i
]=other
.type
[i
];
1941 this->original
[i
]=other
.original
[i
];
1942 this->baseOriginal
[i
]=other
.baseOriginal
[i
];
1947 PtnSkeleton::equals(const PtnSkeleton
& other
) {
1948 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1949 if ( (type
[i
]!= other
.type
[i
]) ||
1950 (original
[i
]!=other
.original
[i
]) ||
1951 (baseOriginal
[i
]!=other
.baseOriginal
[i
]) ) {
1959 PtnSkeleton::getSkeleton() {
1960 UnicodeString result
;
1962 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
1963 if (original
[i
].length()!=0) {
1964 result
+= original
[i
];
1971 PtnSkeleton::getBaseSkeleton() {
1972 UnicodeString result
;
1974 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
1975 if (baseOriginal
[i
].length()!=0) {
1976 result
+= baseOriginal
[i
];
1982 PtnSkeleton::~PtnSkeleton() {
1985 PtnElem::PtnElem(const UnicodeString
&basePat
, const UnicodeString
&pat
) :
1986 basePattern(basePat
),
1993 PtnElem::~PtnElem() {
2001 DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap
&patternMap
, dtStrEnum type
, UErrorCode
& status
) {
2003 PtnSkeleton
*curSkeleton
;
2008 fSkeletons
= new UVector(status
);
2009 if (U_FAILURE(status
)) {
2013 for (bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
2014 curElem
= patternMap
.boot
[bootIndex
];
2015 while (curElem
!=NULL
) {
2017 case DT_BASESKELETON
:
2018 s
=curElem
->basePattern
;
2024 curSkeleton
=curElem
->skeleton
;
2025 s
=curSkeleton
->getSkeleton();
2028 if ( !isCanonicalItem(s
) ) {
2029 fSkeletons
->addElement(new UnicodeString(s
), status
);
2030 if (U_FAILURE(status
)) {
2036 curElem
= curElem
->next
;
2039 if ((bootIndex
==MAX_PATTERN_ENTRIES
) && (curElem
!=NULL
) ) {
2040 status
= U_BUFFER_OVERFLOW_ERROR
;
2044 const UnicodeString
*
2045 DTSkeletonEnumeration::snext(UErrorCode
& status
) {
2046 if (U_SUCCESS(status
) && pos
< fSkeletons
->size()) {
2047 return (const UnicodeString
*)fSkeletons
->elementAt(pos
++);
2053 DTSkeletonEnumeration::reset(UErrorCode
& /*status*/) {
2058 DTSkeletonEnumeration::count(UErrorCode
& /*status*/) const {
2059 return (fSkeletons
==NULL
) ? 0 : fSkeletons
->size();
2063 DTSkeletonEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2064 if ( item
.length() != 1 ) {
2067 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2068 if (item
.charAt(0)==Canonical_Items
[i
]) {
2075 DTSkeletonEnumeration::~DTSkeletonEnumeration() {
2077 for (int32_t i
=0; i
<fSkeletons
->size(); ++i
) {
2078 if ((s
=(UnicodeString
*)fSkeletons
->elementAt(i
))!=NULL
) {
2085 DTRedundantEnumeration::DTRedundantEnumeration() {
2091 DTRedundantEnumeration::add(const UnicodeString
& pattern
, UErrorCode
& status
) {
2092 if (U_FAILURE(status
)) return;
2093 if (fPatterns
== NULL
) {
2094 fPatterns
= new UVector(status
);
2095 if (U_FAILURE(status
)) {
2101 fPatterns
->addElement(new UnicodeString(pattern
), status
);
2102 if (U_FAILURE(status
)) {
2109 const UnicodeString
*
2110 DTRedundantEnumeration::snext(UErrorCode
& status
) {
2111 if (U_SUCCESS(status
) && pos
< fPatterns
->size()) {
2112 return (const UnicodeString
*)fPatterns
->elementAt(pos
++);
2118 DTRedundantEnumeration::reset(UErrorCode
& /*status*/) {
2123 DTRedundantEnumeration::count(UErrorCode
& /*status*/) const {
2124 return (fPatterns
==NULL
) ? 0 : fPatterns
->size();
2128 DTRedundantEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2129 if ( item
.length() != 1 ) {
2132 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2133 if (item
.charAt(0)==Canonical_Items
[i
]) {
2140 DTRedundantEnumeration::~DTRedundantEnumeration() {
2142 for (int32_t i
=0; i
<fPatterns
->size(); ++i
) {
2143 if ((s
=(UnicodeString
*)fPatterns
->elementAt(i
))!=NULL
) {
2153 #endif /* #if !UCONFIG_NO_FORMATTING */