2 *******************************************************************************
3 * Copyright (C) 2007-2014, 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"
36 #include "dtptngen_impl.h"
37 #include "shareddatetimepatterngenerator.h"
38 #include "unifiedcache.h"
40 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
42 * If we are on EBCDIC, use an iterator which will
43 * traverse the bundles in ASCII order.
45 #define U_USE_ASCII_BUNDLE_ITERATOR
46 #define U_SORT_ASCII_BUNDLE_ITERATOR
49 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
51 #include "unicode/ustring.h"
56 UResourceBundle
*item
;
59 struct UResourceBundleAIterator
{
60 UResourceBundle
*bund
;
66 /* Must be C linkage to pass function pointer to the sort function */
70 static int32_t U_CALLCONV
71 ures_a_codepointSort(const void *context
, const void *left
, const void *right
) {
72 //CompareContext *cmp=(CompareContext *)context;
73 return u_strcmp(((const UResAEntry
*)left
)->key
,
74 ((const UResAEntry
*)right
)->key
);
79 static void ures_a_open(UResourceBundleAIterator
*aiter
, UResourceBundle
*bund
, UErrorCode
*status
) {
80 if(U_FAILURE(*status
)) {
84 aiter
->num
= ures_getSize(aiter
->bund
);
86 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
87 aiter
->entries
= NULL
;
89 aiter
->entries
= (UResAEntry
*)uprv_malloc(sizeof(UResAEntry
)*aiter
->num
);
90 for(int i
=0;i
<aiter
->num
;i
++) {
91 aiter
->entries
[i
].item
= ures_getByIndex(aiter
->bund
, i
, NULL
, status
);
92 const char *akey
= ures_getKey(aiter
->entries
[i
].item
);
93 int32_t len
= uprv_strlen(akey
)+1;
94 aiter
->entries
[i
].key
= (UChar
*)uprv_malloc(len
*sizeof(UChar
));
95 u_charsToUChars(akey
, aiter
->entries
[i
].key
, len
);
97 uprv_sortArray(aiter
->entries
, aiter
->num
, sizeof(UResAEntry
), ures_a_codepointSort
, NULL
, TRUE
, status
);
101 static void ures_a_close(UResourceBundleAIterator
*aiter
) {
102 #if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
103 for(int i
=0;i
<aiter
->num
;i
++) {
104 uprv_free(aiter
->entries
[i
].key
);
105 ures_close(aiter
->entries
[i
].item
);
110 static const UChar
*ures_a_getNextString(UResourceBundleAIterator
*aiter
, int32_t *len
, const char **key
, UErrorCode
*err
) {
111 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
112 return ures_getNextString(aiter
->bund
, len
, key
, err
);
114 if(U_FAILURE(*err
)) return NULL
;
115 UResourceBundle
*item
= aiter
->entries
[aiter
->cursor
].item
;
116 const UChar
* ret
= ures_getString(item
, len
, err
);
117 *key
= ures_getKey(item
);
129 SharedDateTimePatternGenerator::~SharedDateTimePatternGenerator() {
133 template<> U_I18N_API
134 const SharedDateTimePatternGenerator
*LocaleCacheKey
<SharedDateTimePatternGenerator
>::createObject(
135 const void * /*creationContext*/, UErrorCode
&status
) const {
136 DateTimePatternGenerator
*fmt
= DateTimePatternGenerator::internalMakeInstance(fLoc
, status
);
137 if (U_FAILURE(status
)) {
140 SharedDateTimePatternGenerator
*result
= new SharedDateTimePatternGenerator(fmt
);
141 if (result
== NULL
) {
143 status
= U_MEMORY_ALLOCATION_ERROR
;
151 // *****************************************************************************
152 // class DateTimePatternGenerator
153 // *****************************************************************************
154 static const UChar Canonical_Items
[] = {
156 CAP_G
, LOW_Y
, CAP_Q
, CAP_M
, LOW_W
, CAP_W
, CAP_E
, LOW_D
, CAP_D
, CAP_F
,
157 CAP_H
, LOW_M
, LOW_S
, CAP_S
, LOW_V
, 0
160 static const dtTypeElem dtTypes
[] = {
161 // patternChar, field, type, minLen, weight
162 {CAP_G
, UDATPG_ERA_FIELD
, DT_SHORT
, 1, 3,},
163 {CAP_G
, UDATPG_ERA_FIELD
, DT_LONG
, 4, 0},
164 {LOW_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
, 1, 20},
165 {CAP_Y
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 20},
166 {LOW_U
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 20},
167 {LOW_R
, UDATPG_YEAR_FIELD
, DT_NUMERIC
+ 3*DT_DELTA
, 1, 20},
168 {CAP_U
, UDATPG_YEAR_FIELD
, DT_SHORT
, 1, 3},
169 {CAP_U
, UDATPG_YEAR_FIELD
, DT_LONG
, 4, 0},
170 {CAP_U
, UDATPG_YEAR_FIELD
, DT_NARROW
, 5, 0},
171 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_NUMERIC
, 1, 2},
172 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_SHORT
, 3, 0},
173 {CAP_Q
, UDATPG_QUARTER_FIELD
, DT_LONG
, 4, 0},
174 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
175 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_SHORT
+ DT_DELTA
, 3, 0},
176 {LOW_Q
, UDATPG_QUARTER_FIELD
, DT_LONG
+ DT_DELTA
, 4, 0},
177 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NUMERIC
, 1, 2},
178 {CAP_M
, UDATPG_MONTH_FIELD
, DT_SHORT
, 3, 0},
179 {CAP_M
, UDATPG_MONTH_FIELD
, DT_LONG
, 4, 0},
180 {CAP_M
, UDATPG_MONTH_FIELD
, DT_NARROW
, 5, 0},
181 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2},
182 {CAP_L
, UDATPG_MONTH_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
183 {CAP_L
, UDATPG_MONTH_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
184 {CAP_L
, UDATPG_MONTH_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
185 {LOW_L
, UDATPG_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 1},
186 {LOW_W
, UDATPG_WEEK_OF_YEAR_FIELD
, DT_NUMERIC
, 1, 2},
187 {CAP_W
, UDATPG_WEEK_OF_MONTH_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 0},
188 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
, 1, 3},
189 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
, 4, 0},
190 {CAP_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
, 5, 0},
191 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 2},
192 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- 2*DT_DELTA
, 3, 0},
193 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
194 {LOW_C
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- 2*DT_DELTA
, 5, 0},
195 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
196 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_SHORT
- DT_DELTA
, 3, 0},
197 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
198 {LOW_E
, UDATPG_WEEKDAY_FIELD
, DT_NARROW
- DT_DELTA
, 5, 0},
199 {LOW_D
, UDATPG_DAY_FIELD
, DT_NUMERIC
, 1, 2},
200 {CAP_D
, UDATPG_DAY_OF_YEAR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 3},
201 {CAP_F
, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 0},
202 {LOW_G
, UDATPG_DAY_FIELD
, DT_NUMERIC
+ 3*DT_DELTA
, 1, 20}, // really internal use, so we don't care
203 {LOW_A
, UDATPG_DAYPERIOD_FIELD
, DT_SHORT
, 1, 0},
204 {CAP_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 10*DT_DELTA
, 1, 2}, // 24 hour
205 {LOW_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ 11*DT_DELTA
, 1, 2}, // 24 hour
206 {LOW_H
, UDATPG_HOUR_FIELD
, DT_NUMERIC
, 1, 2}, // 12 hour
207 {CAP_K
, UDATPG_HOUR_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 2}, // 12 hour
208 {LOW_M
, UDATPG_MINUTE_FIELD
, DT_NUMERIC
, 1, 2},
209 {LOW_S
, UDATPG_SECOND_FIELD
, DT_NUMERIC
, 1, 2},
210 {CAP_S
, UDATPG_FRACTIONAL_SECOND_FIELD
, DT_NUMERIC
+ DT_DELTA
, 1, 1000},
211 {CAP_A
, UDATPG_SECOND_FIELD
, DT_NUMERIC
+ 2*DT_DELTA
, 1, 1000},
212 {LOW_V
, UDATPG_ZONE_FIELD
, DT_SHORT
- 2*DT_DELTA
, 1, 0},
213 {LOW_V
, UDATPG_ZONE_FIELD
, DT_LONG
- 2*DT_DELTA
, 4, 0},
214 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
, 1, 3},
215 {LOW_Z
, UDATPG_ZONE_FIELD
, DT_LONG
, 4, 0},
216 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_NARROW
- DT_DELTA
, 1, 3},
217 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
218 {CAP_Z
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 5, 0},
219 {CAP_O
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 1, 0},
220 {CAP_O
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
221 {CAP_V
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 1, 0},
222 {CAP_V
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 2, 0},
223 {CAP_X
, UDATPG_ZONE_FIELD
, DT_NARROW
- DT_DELTA
, 1, 0},
224 {CAP_X
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 2, 0},
225 {CAP_X
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
226 {LOW_X
, UDATPG_ZONE_FIELD
, DT_NARROW
- DT_DELTA
, 1, 0},
227 {LOW_X
, UDATPG_ZONE_FIELD
, DT_SHORT
- DT_DELTA
, 2, 0},
228 {LOW_X
, UDATPG_ZONE_FIELD
, DT_LONG
- DT_DELTA
, 4, 0},
229 {0, UDATPG_FIELD_COUNT
, 0, 0, 0} , // last row of dtTypes[]
232 static const char* const CLDR_FIELD_APPEND
[] = {
233 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
234 "Hour", "Minute", "Second", "*", "Timezone"
237 static const char* const CLDR_FIELD_NAME
[] = {
238 "era", "year", "quarter", "month", "week", "*", "weekday", "*", "*", "day", "dayperiod",
239 "hour", "minute", "second", "*", "zone"
242 static const char* const Resource_Fields
[] = {
243 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
244 "weekday", "year", "zone", "quarter" };
247 static const UChar UDATPG_ItemFormat
[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
248 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
250 //static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ"
252 static const char DT_DateTimePatternsTag
[]="DateTimePatterns";
253 static const char DT_DateTimeCalendarTag
[]="calendar";
254 static const char DT_DateTimeGregorianTag
[]="gregorian";
255 static const char DT_DateTimeAppendItemsTag
[]="appendItems";
256 static const char DT_DateTimeFieldsTag
[]="fields";
257 static const char DT_DateTimeAvailableFormatsTag
[]="availableFormats";
258 //static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
260 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator
)
261 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration
)
262 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration
)
264 DateTimePatternGenerator
* U_EXPORT2
265 DateTimePatternGenerator::createInstance(UErrorCode
& status
) {
266 return createInstance(Locale::getDefault(), status
);
269 DateTimePatternGenerator
* U_EXPORT2
270 DateTimePatternGenerator::createInstance(const Locale
& locale
, UErrorCode
& status
) {
271 const SharedDateTimePatternGenerator
*shared
= NULL
;
272 UnifiedCache::getByLocale(locale
, shared
, status
);
273 if (U_FAILURE(status
)) {
276 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(**shared
);
278 if (result
== NULL
) {
279 status
= U_MEMORY_ALLOCATION_ERROR
;
285 DateTimePatternGenerator
* U_EXPORT2
286 DateTimePatternGenerator::internalMakeInstance(const Locale
& locale
, UErrorCode
& status
) {
287 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(locale
, status
);
288 if (result
== NULL
) {
289 status
= U_MEMORY_ALLOCATION_ERROR
;
292 if (U_FAILURE(status
)) {
299 DateTimePatternGenerator
* U_EXPORT2
300 DateTimePatternGenerator::createEmptyInstance(UErrorCode
& status
) {
301 DateTimePatternGenerator
*result
= new DateTimePatternGenerator(status
);
302 if (result
== NULL
) {
303 status
= U_MEMORY_ALLOCATION_ERROR
;
305 if (U_FAILURE(status
)) {
312 DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode
&status
) :
314 fAvailableFormatKeyHash(NULL
)
316 fp
= new FormatParser();
317 dtMatcher
= new DateTimeMatcher();
318 distanceInfo
= new DistanceInfo();
319 patternMap
= new PatternMap();
320 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
321 status
= U_MEMORY_ALLOCATION_ERROR
;
325 DateTimePatternGenerator::DateTimePatternGenerator(const Locale
& locale
, UErrorCode
&status
) :
327 fAvailableFormatKeyHash(NULL
)
329 fp
= new FormatParser();
330 dtMatcher
= new DateTimeMatcher();
331 distanceInfo
= new DistanceInfo();
332 patternMap
= new PatternMap();
333 if (fp
== NULL
|| dtMatcher
== NULL
|| distanceInfo
== NULL
|| patternMap
== NULL
) {
334 status
= U_MEMORY_ALLOCATION_ERROR
;
337 initData(locale
, status
);
341 DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator
& other
) :
344 fAvailableFormatKeyHash(NULL
)
346 fp
= new FormatParser();
347 dtMatcher
= new DateTimeMatcher();
348 distanceInfo
= new DistanceInfo();
349 patternMap
= new PatternMap();
353 DateTimePatternGenerator
&
354 DateTimePatternGenerator::operator=(const DateTimePatternGenerator
& other
) {
356 if (&other
== this) {
359 pLocale
= other
.pLocale
;
360 fDefaultHourFormatChar
= other
.fDefaultHourFormatChar
;
362 dtMatcher
->copyFrom(other
.dtMatcher
->skeleton
);
363 *distanceInfo
= *(other
.distanceInfo
);
364 dateTimeFormat
= other
.dateTimeFormat
;
365 decimal
= other
.decimal
;
366 // NUL-terminate for the C API.
367 dateTimeFormat
.getTerminatedBuffer();
368 decimal
.getTerminatedBuffer();
370 if ( other
.skipMatcher
== NULL
) {
374 skipMatcher
= new DateTimeMatcher(*other
.skipMatcher
);
376 for (int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
377 appendItemFormats
[i
] = other
.appendItemFormats
[i
];
378 appendItemNames
[i
] = other
.appendItemNames
[i
];
379 // NUL-terminate for the C API.
380 appendItemFormats
[i
].getTerminatedBuffer();
381 appendItemNames
[i
].getTerminatedBuffer();
383 UErrorCode status
= U_ZERO_ERROR
;
384 patternMap
->copyFrom(*other
.patternMap
, status
);
385 copyHashtable(other
.fAvailableFormatKeyHash
, status
);
391 DateTimePatternGenerator::operator==(const DateTimePatternGenerator
& other
) const {
392 if (this == &other
) {
395 if ((pLocale
==other
.pLocale
) && (patternMap
->equals(*other
.patternMap
)) &&
396 (dateTimeFormat
==other
.dateTimeFormat
) && (decimal
==other
.decimal
)) {
397 for ( int32_t i
=0 ; i
<UDATPG_FIELD_COUNT
; ++i
) {
398 if ((appendItemFormats
[i
] != other
.appendItemFormats
[i
]) ||
399 (appendItemNames
[i
] != other
.appendItemNames
[i
]) ) {
411 DateTimePatternGenerator::operator!=(const DateTimePatternGenerator
& other
) const {
412 return !operator==(other
);
415 DateTimePatternGenerator::~DateTimePatternGenerator() {
416 if (fAvailableFormatKeyHash
!=NULL
) {
417 delete fAvailableFormatKeyHash
;
420 if (fp
!= NULL
) delete fp
;
421 if (dtMatcher
!= NULL
) delete dtMatcher
;
422 if (distanceInfo
!= NULL
) delete distanceInfo
;
423 if (patternMap
!= NULL
) delete patternMap
;
424 if (skipMatcher
!= NULL
) delete skipMatcher
;
428 DateTimePatternGenerator::initData(const Locale
& locale
, UErrorCode
&status
) {
429 //const char *baseLangName = locale.getBaseName(); // unused
432 fAvailableFormatKeyHash
=NULL
;
434 addICUPatterns(locale
, status
);
435 if (U_FAILURE(status
)) {
438 addCLDRData(locale
, status
);
439 setDateTimeFromCalendar(locale
, status
);
440 setDecimalSymbols(locale
, status
);
441 } // DateTimePatternGenerator::initData
444 DateTimePatternGenerator::getSkeleton(const UnicodeString
& pattern
, UErrorCode
&
446 dtMatcher
->set(pattern
, fp
);
447 return dtMatcher
->getSkeletonPtr()->getSkeleton();
451 DateTimePatternGenerator::getBaseSkeleton(const UnicodeString
& pattern
, UErrorCode
& /*status*/) {
452 dtMatcher
->set(pattern
, fp
);
453 return dtMatcher
->getSkeletonPtr()->getBaseSkeleton();
457 DateTimePatternGenerator::addICUPatterns(const Locale
& locale
, UErrorCode
& status
) {
458 UnicodeString dfPattern
;
459 UnicodeString conflictingString
;
462 if (U_FAILURE(status
)) {
466 // Load with ICU patterns
467 for (int32_t i
=DateFormat::kFull
; i
<=DateFormat::kShort
; i
++) {
468 DateFormat::EStyle style
= (DateFormat::EStyle
)i
;
469 df
= DateFormat::createDateInstance(style
, locale
);
470 SimpleDateFormat
* sdf
;
471 if (df
!= NULL
&& (sdf
= dynamic_cast<SimpleDateFormat
*>(df
)) != NULL
) {
472 addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
474 // TODO Maybe we should return an error when the date format isn't simple.
476 if (U_FAILURE(status
)) {
480 df
= DateFormat::createTimeInstance(style
, locale
);
481 if (df
!= NULL
&& (sdf
= dynamic_cast<SimpleDateFormat
*>(df
)) != NULL
) {
482 addPattern(sdf
->toPattern(dfPattern
), FALSE
, conflictingString
, status
);
484 if ( i
==DateFormat::kMedium
) {
485 hackPattern
= dfPattern
;
488 // TODO Maybe we should return an error when the date format isn't simple.
490 if (U_FAILURE(status
)) {
497 DateTimePatternGenerator::hackTimes(const UnicodeString
& hackPattern
, UErrorCode
& status
) {
498 UnicodeString conflictingString
;
500 fp
->set(hackPattern
);
503 for (int32_t i
=0; i
<fp
->itemNumber
; ++i
) {
504 UnicodeString field
= fp
->items
[i
];
505 if ( fp
->isQuoteLiteral(field
) ) {
507 UnicodeString quoteLiteral
;
508 fp
->getQuoteLiteral(quoteLiteral
, &i
);
509 mmss
+= quoteLiteral
;
513 if (fp
->isPatternSeparator(field
) && gotMm
) {
517 UChar ch
=field
.charAt(0);
528 addPattern(mmss
, FALSE
, conflictingString
, status
);
532 if (gotMm
|| ch
==LOW_Z
|| ch
==CAP_Z
|| ch
==LOW_V
|| ch
==CAP_V
) {
542 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
544 static const UChar hourFormatChars
[] = { CAP_H
, LOW_H
, CAP_K
, LOW_K
, 0 }; // HhKk, the hour format characters
547 DateTimePatternGenerator::addCLDRData(const Locale
& locale
, UErrorCode
& err
) {
548 UResourceBundle
*rb
, *calTypeBundle
, *calBundle
;
549 UResourceBundle
*patBundle
, *fieldBundle
, *fBundle
;
550 UnicodeString rbPattern
, value
, field
;
551 UnicodeString conflictingPattern
;
552 const char *key
=NULL
;
555 UnicodeString
defaultItemFormat(TRUE
, UDATPG_ItemFormat
, UPRV_LENGTHOF(UDATPG_ItemFormat
)-1); // Read-only alias.
559 fDefaultHourFormatChar
= 0;
560 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
561 appendItemNames
[i
]=CAP_F
;
563 appendItemNames
[i
]+=(UChar
)(i
+0x30);
566 appendItemNames
[i
]+=(UChar
)0x31;
567 appendItemNames
[i
]+=(UChar
)(i
-10 + 0x30);
569 // NUL-terminate for the C API.
570 appendItemNames
[i
].getTerminatedBuffer();
573 rb
= ures_open(NULL
, locale
.getName(), &err
);
574 if (rb
== NULL
|| U_FAILURE(err
)) {
577 const char *curLocaleName
=ures_getLocaleByType(rb
, ULOC_ACTUAL_LOCALE
, &err
);
578 const char * calendarTypeToUse
= DT_DateTimeGregorianTag
; // initial default
579 char calendarType
[ULOC_KEYWORDS_CAPACITY
]; // to be filled in with the type to use, if all goes well
580 if ( U_SUCCESS(err
) ) {
581 char localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
];
582 // obtain a locale that always has the calendar key value that should be used
583 (void)ures_getFunctionalEquivalent(localeWithCalendarKey
, ULOC_LOCALE_IDENTIFIER_CAPACITY
, NULL
,
584 "calendar", "calendar", locale
.getName(), NULL
, FALSE
, &err
);
585 localeWithCalendarKey
[ULOC_LOCALE_IDENTIFIER_CAPACITY
-1] = 0; // ensure null termination
586 // now get the calendar key value from that locale
587 int32_t calendarTypeLen
= uloc_getKeywordValue(localeWithCalendarKey
, "calendar", calendarType
, ULOC_KEYWORDS_CAPACITY
, &err
);
588 if (U_SUCCESS(err
) && calendarTypeLen
< ULOC_KEYWORDS_CAPACITY
) {
589 calendarTypeToUse
= calendarType
;
593 calBundle
= ures_getByKeyWithFallback(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
594 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &err
);
598 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimePatternsTag
, NULL
, &err
);
599 while (U_SUCCESS(err
)) {
600 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
602 if (rbPattern
.length()==0 ) {
603 break; // no more pattern
607 setDateTimeFormat(rbPattern
);
608 } else if (dtCount
==4) { // short time format
609 // set fDefaultHourFormatChar to the hour format character from this pattern
610 int32_t tfIdx
, tfLen
= rbPattern
.length();
611 UBool ignoreChars
= FALSE
;
612 for (tfIdx
= 0; tfIdx
< tfLen
; tfIdx
++) {
613 UChar tfChar
= rbPattern
.charAt(tfIdx
);
614 if ( tfChar
== SINGLE_QUOTE
) {
615 ignoreChars
= !ignoreChars
; // toggle (handle quoted literals & '' for single quote)
616 } else if ( !ignoreChars
&& u_strchr(hourFormatChars
, tfChar
) != NULL
) {
617 fDefaultHourFormatChar
= tfChar
;
624 ures_close(patBundle
);
627 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAppendItemsTag
, NULL
, &err
);
629 UnicodeString itemKey
;
630 while (U_SUCCESS(err
)) {
631 rbPattern
= ures_getNextUnicodeString(patBundle
, &key
, &err
);
632 if (rbPattern
.length()==0 ) {
633 break; // no more pattern
636 setAppendItemFormat(getAppendFormatNumber(key
), rbPattern
);
639 ures_close(patBundle
);
643 fBundle
= ures_getByKeyWithFallback(rb
, DT_DateTimeFieldsTag
, NULL
, &err
);
644 for (i
=0; i
<MAX_RESOURCE_FIELD
; ++i
) {
646 patBundle
= ures_getByKeyWithFallback(fBundle
, Resource_Fields
[i
], NULL
, &err
);
647 fieldBundle
= ures_getByKeyWithFallback(patBundle
, "dn", NULL
, &err
);
648 rbPattern
= ures_getNextUnicodeString(fieldBundle
, &key
, &err
);
649 ures_close(fieldBundle
);
650 ures_close(patBundle
);
651 if (rbPattern
.length()==0 ) {
655 setAppendItemName(getAppendNameNumber(Resource_Fields
[i
]), rbPattern
);
660 // add available formats
661 UBool firstTimeThrough
= TRUE
;
664 UBool override
= TRUE
;
666 // At the start of the loop:
667 // - rb is the open resource bundle for the current locale being processed,
668 // whose actual name is in curLocaleName.
669 // - if U_SUCCESS(err), then calBundle and calTypeBundle are open;
670 // process contents of calTypeBundle, then close calBundle and calTypeBundle.
671 if (U_SUCCESS(err
)) {
672 // process contents of calTypeBundle
673 patBundle
= ures_getByKeyWithFallback(calTypeBundle
, DT_DateTimeAvailableFormatsTag
, NULL
, &err
);
674 if (U_SUCCESS(err
)) {
675 int32_t numberKeys
= ures_getSize(patBundle
);
677 const UChar
*retPattern
;
679 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
680 UResourceBundleAIterator aiter
;
681 ures_a_open(&aiter
, patBundle
, &err
);
683 for(i
=0; i
<numberKeys
; ++i
) {
684 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
685 retPattern
=ures_a_getNextString(&aiter
, &len
, &key
, &err
);
687 retPattern
=ures_getNextString(patBundle
, &len
, &key
, &err
);
689 UnicodeString format
=UnicodeString(retPattern
);
690 UnicodeString retKey
=UnicodeString(key
, -1, US_INV
);
691 if ( firstTimeThrough
|| !isAvailableFormatSet(retKey
) ) {
692 setAvailableFormat(retKey
, err
);
693 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
694 // but not a previous availableFormats entry:
695 addPatternWithSkeleton(format
, &retKey
, override
, conflictingPattern
, err
);
698 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
699 ures_a_close(&aiter
);
701 ures_close(patBundle
);
703 firstTimeThrough
= FALSE
;
704 // close calBundle and calTypeBundle
705 ures_close(calTypeBundle
);
706 ures_close(calBundle
);
708 if (uprv_strcmp(curLocaleName
,"root")==0 || uprv_strlen(curLocaleName
)==0) {
709 // we just finished handling root, nothing more to check
713 // Find the name of the appropriate parent locale (from %%Parent if present, else
714 // uloc_getParent on the actual locale name)
715 // (It would be nice to have a ures function that did this...)
717 char parentLocale
[ULOC_FULLNAME_CAPACITY
];
719 const UChar
* parentUName
= ures_getStringByKey(rb
, "%%Parent", &locNameLen
, &err
);
720 if (U_SUCCESS(err
) && err
!= U_USING_FALLBACK_WARNING
&& locNameLen
< ULOC_FULLNAME_CAPACITY
) {
721 u_UCharsToChars(parentUName
, parentLocale
, locNameLen
+ 1);
724 uloc_getParent(curLocaleName
, parentLocale
, ULOC_FULLNAME_CAPACITY
, &err
);
725 if (U_FAILURE(err
) || err
== U_STRING_NOT_TERMINATED_WARNING
) {
726 // just fallback to root, since we are not already there
731 // Close current locale bundle
733 // And open its parent, which becomes the new current locale being processed
734 rb
= ures_open(NULL
, parentLocale
, &err
);
735 if ( U_FAILURE(err
) ) {
739 // Get the name of the parent / new current locale
740 curLocaleName
=ures_getLocaleByType(rb
, ULOC_ACTUAL_LOCALE
, &err
);
741 if ( U_FAILURE(err
) ) {
742 curLocaleName
= parentLocale
;
745 if (uprv_strcmp(curLocaleName
,"root")==0 || uprv_strlen(curLocaleName
)==0) {
748 // Open calBundle and calTypeBundle
749 calBundle
= ures_getByKeyWithFallback(rb
, DT_DateTimeCalendarTag
, NULL
, &err
);
750 if (U_SUCCESS(err
)) {
751 calTypeBundle
= ures_getByKeyWithFallback(calBundle
, calendarTypeToUse
, NULL
, &err
);
752 if ( U_FAILURE(err
) ) {
753 ures_close(calBundle
);
756 // Go to the top of the loop to process contents of calTypeBundle
759 if (hackPattern
.length()>0) {
760 hackTimes(hackPattern
, err
);
765 DateTimePatternGenerator::initHashtable(UErrorCode
& err
) {
766 if (fAvailableFormatKeyHash
!=NULL
) {
769 if ((fAvailableFormatKeyHash
= new Hashtable(FALSE
, err
))==NULL
) {
770 err
=U_MEMORY_ALLOCATION_ERROR
;
777 DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field
, const UnicodeString
& value
) {
778 appendItemFormats
[field
] = value
;
779 // NUL-terminate for the C API.
780 appendItemFormats
[field
].getTerminatedBuffer();
784 DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field
) const {
785 return appendItemFormats
[field
];
789 DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field
, const UnicodeString
& value
) {
790 appendItemNames
[field
] = value
;
791 // NUL-terminate for the C API.
792 appendItemNames
[field
].getTerminatedBuffer();
796 DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field
) const {
797 return appendItemNames
[field
];
801 DateTimePatternGenerator::getAppendName(UDateTimePatternField field
, UnicodeString
& value
) {
802 value
= SINGLE_QUOTE
;
803 value
+= appendItemNames
[field
];
804 value
+= SINGLE_QUOTE
;
808 DateTimePatternGenerator::getBestPattern(const UnicodeString
& patternForm
, UErrorCode
& status
) {
809 return getBestPattern(patternForm
, UDATPG_MATCH_NO_OPTIONS
, status
);
813 DateTimePatternGenerator::getBestPattern(const UnicodeString
& patternForm
, UDateTimePatternMatchOptions options
, UErrorCode
& status
) {
814 const UnicodeString
*bestPattern
=NULL
;
815 UnicodeString dtFormat
;
816 UnicodeString resultPattern
;
817 int32_t flags
= kDTPGNoFlags
;
819 int32_t dateMask
=(1<<UDATPG_DAYPERIOD_FIELD
) - 1;
820 int32_t timeMask
=(1<<UDATPG_FIELD_COUNT
) - 1 - dateMask
;
822 // Replace hour metacharacters 'j' and 'J', set flags as necessary
823 UnicodeString patternFormCopy
= UnicodeString(patternForm
);
824 UChar hourFormatSkeletonCharForLowJ
= fDefaultHourFormatChar
;
825 switch (options
& UADATPG_FORCE_HOUR_CYCLE_MASK
) {
826 case UADATPG_FORCE_12_HOUR_CYCLE
: hourFormatSkeletonCharForLowJ
= LOW_H
; break;
827 case UADATPG_FORCE_24_HOUR_CYCLE
: hourFormatSkeletonCharForLowJ
= CAP_H
; break;
830 int32_t patPos
, patLen
= patternFormCopy
.length();
831 UBool inQuoted
= FALSE
;
832 for (patPos
= 0; patPos
< patLen
; patPos
++) {
833 UChar patChr
= patternFormCopy
.charAt(patPos
);
834 if (patChr
== SINGLE_QUOTE
) {
835 inQuoted
= !inQuoted
;
836 } else if (!inQuoted
) {
837 if (patChr
== LOW_J
) {
838 patternFormCopy
.setCharAt(patPos
, hourFormatSkeletonCharForLowJ
);
839 } else if (patChr
== CAP_J
) {
840 // Get pattern for skeleton with H, then in adjustFieldTypes
841 // replace hour pattern characters as necessary.
842 patternFormCopy
.setCharAt(patPos
, CAP_H
);
843 flags
|= kDTPGSkeletonUsesCapJ
;
848 resultPattern
.remove();
849 dtMatcher
->set(patternFormCopy
, fp
);
850 const PtnSkeleton
* specifiedSkeleton
=NULL
;
851 bestPattern
=getBestRaw(*dtMatcher
, -1, distanceInfo
, &specifiedSkeleton
);
852 if ( distanceInfo
->missingFieldMask
==0 && distanceInfo
->extraFieldMask
==0 ) {
853 resultPattern
= adjustFieldTypes(*bestPattern
, specifiedSkeleton
, flags
, options
);
855 return resultPattern
;
857 int32_t neededFields
= dtMatcher
->getFieldMask();
858 UnicodeString datePattern
=getBestAppending(neededFields
& dateMask
, flags
, options
);
859 UnicodeString timePattern
=getBestAppending(neededFields
& timeMask
, flags
, options
);
860 if (datePattern
.length()==0) {
861 if (timePattern
.length()==0) {
862 resultPattern
.remove();
868 if (timePattern
.length()==0) {
871 resultPattern
.remove();
872 status
= U_ZERO_ERROR
;
873 dtFormat
=getDateTimeFormat();
874 Formattable dateTimeObject
[] = { timePattern
, datePattern
};
875 resultPattern
= MessageFormat::format(dtFormat
, dateTimeObject
, 2, resultPattern
, status
);
876 return resultPattern
;
880 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString
& pattern
,
881 const UnicodeString
& skeleton
,
882 UErrorCode
& status
) {
883 return replaceFieldTypes(pattern
, skeleton
, UDATPG_MATCH_NO_OPTIONS
, status
);
887 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString
& pattern
,
888 const UnicodeString
& skeleton
,
889 UDateTimePatternMatchOptions options
,
890 UErrorCode
& /*status*/) {
891 dtMatcher
->set(skeleton
, fp
);
892 UnicodeString result
= adjustFieldTypes(pattern
, NULL
, kDTPGNoFlags
, options
);
897 DateTimePatternGenerator::setDecimal(const UnicodeString
& newDecimal
) {
898 this->decimal
= newDecimal
;
899 // NUL-terminate for the C API.
900 this->decimal
.getTerminatedBuffer();
904 DateTimePatternGenerator::getDecimal() const {
909 DateTimePatternGenerator::addCanonicalItems() {
910 UnicodeString conflictingPattern
;
911 UErrorCode status
= U_ZERO_ERROR
;
913 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; i
++) {
914 addPattern(UnicodeString(Canonical_Items
[i
]), FALSE
, conflictingPattern
, status
);
919 DateTimePatternGenerator::setDateTimeFormat(const UnicodeString
& dtFormat
) {
920 dateTimeFormat
= dtFormat
;
921 // NUL-terminate for the C API.
922 dateTimeFormat
.getTerminatedBuffer();
926 DateTimePatternGenerator::getDateTimeFormat() const {
927 return dateTimeFormat
;
931 DateTimePatternGenerator::setDateTimeFromCalendar(const Locale
& locale
, UErrorCode
& status
) {
933 int32_t resStrLen
= 0;
935 Calendar
* fCalendar
= Calendar::createInstance(locale
, status
);
936 CalendarData
calData(locale
, fCalendar
?fCalendar
->getType():NULL
, status
);
937 UResourceBundle
*dateTimePatterns
= calData
.getByKey(DT_DateTimePatternsTag
, status
);
938 if (U_FAILURE(status
)) return;
940 if (ures_getSize(dateTimePatterns
) <= DateFormat::kDateTime
)
942 status
= U_INVALID_FORMAT_ERROR
;
945 resStr
= ures_getStringByIndex(dateTimePatterns
, (int32_t)DateFormat::kDateTime
, &resStrLen
, &status
);
946 setDateTimeFormat(UnicodeString(TRUE
, resStr
, resStrLen
));
952 DateTimePatternGenerator::setDecimalSymbols(const Locale
& locale
, UErrorCode
& status
) {
953 DecimalFormatSymbols dfs
= DecimalFormatSymbols(locale
, status
);
954 if(U_SUCCESS(status
)) {
955 decimal
= dfs
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
956 // NUL-terminate for the C API.
957 decimal
.getTerminatedBuffer();
961 UDateTimePatternConflict
962 DateTimePatternGenerator::addPattern(
963 const UnicodeString
& pattern
,
965 UnicodeString
&conflictingPattern
,
968 return addPatternWithSkeleton(pattern
, NULL
, override
, conflictingPattern
, status
);
971 // For DateTimePatternGenerator::addPatternWithSkeleton -
972 // If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
973 // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
974 // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
975 // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
976 // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
977 // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
978 // derived (i.e. entries derived from the standard date/time patters for the specified locale).
979 // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
980 // specified skeleton (which sets a new field in the PtnElem in the PatternMap).
981 UDateTimePatternConflict
982 DateTimePatternGenerator::addPatternWithSkeleton(
983 const UnicodeString
& pattern
,
984 const UnicodeString
* skeletonToUse
,
986 UnicodeString
& conflictingPattern
,
990 UnicodeString basePattern
;
991 PtnSkeleton skeleton
;
992 UDateTimePatternConflict conflictingStatus
= UDATPG_NO_CONFLICT
;
994 DateTimeMatcher matcher
;
995 if ( skeletonToUse
== NULL
) {
996 matcher
.set(pattern
, fp
, skeleton
);
997 matcher
.getBasePattern(basePattern
);
999 matcher
.set(*skeletonToUse
, fp
, skeleton
); // no longer trims skeleton fields to max len 3, per #7930
1000 matcher
.getBasePattern(basePattern
); // or perhaps instead: basePattern = *skeletonToUse;
1002 // We only care about base conflicts - and replacing the pattern associated with a base - if:
1003 // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous
1004 // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or
1005 // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen
1006 // if we are getting here from a subsequent call to addPattern).
1007 // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking
1008 // availableFormats items from root, which should not override any previous entry with the same base.
1009 UBool entryHadSpecifiedSkeleton
;
1010 const UnicodeString
*duplicatePattern
= patternMap
->getPatternFromBasePattern(basePattern
, entryHadSpecifiedSkeleton
);
1011 if (duplicatePattern
!= NULL
&& (!entryHadSpecifiedSkeleton
|| (skeletonToUse
!= NULL
&& !override
))) {
1012 conflictingStatus
= UDATPG_BASE_CONFLICT
;
1013 conflictingPattern
= *duplicatePattern
;
1015 return conflictingStatus
;
1018 // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats
1019 // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with
1020 // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for
1021 // the previously-specified conflicting item.
1022 const PtnSkeleton
* entrySpecifiedSkeleton
= NULL
;
1023 duplicatePattern
= patternMap
->getPatternFromSkeleton(skeleton
, &entrySpecifiedSkeleton
);
1024 if (duplicatePattern
!= NULL
) {
1025 conflictingStatus
= UDATPG_CONFLICT
;
1026 conflictingPattern
= *duplicatePattern
;
1027 if (!override
|| (skeletonToUse
!= NULL
&& entrySpecifiedSkeleton
!= NULL
)) {
1028 return conflictingStatus
;
1031 patternMap
->add(basePattern
, skeleton
, pattern
, skeletonToUse
!= NULL
, status
);
1032 if(U_FAILURE(status
)) {
1033 return conflictingStatus
;
1036 return UDATPG_NO_CONFLICT
;
1040 UDateTimePatternField
1041 DateTimePatternGenerator::getAppendFormatNumber(const char* field
) const {
1042 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1043 if (uprv_strcmp(CLDR_FIELD_APPEND
[i
], field
)==0) {
1044 return (UDateTimePatternField
)i
;
1047 return UDATPG_FIELD_COUNT
;
1050 UDateTimePatternField
1051 DateTimePatternGenerator::getAppendNameNumber(const char* field
) const {
1052 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1053 if (uprv_strcmp(CLDR_FIELD_NAME
[i
],field
)==0) {
1054 return (UDateTimePatternField
)i
;
1057 return UDATPG_FIELD_COUNT
;
1060 const UnicodeString
*
1061 DateTimePatternGenerator::getBestRaw(DateTimeMatcher
& source
,
1062 int32_t includeMask
,
1063 DistanceInfo
* missingFields
,
1064 const PtnSkeleton
** specifiedSkeletonPtr
) {
1065 int32_t bestDistance
= 0x7fffffff;
1066 DistanceInfo tempInfo
;
1067 const UnicodeString
*bestPattern
=NULL
;
1068 const PtnSkeleton
* specifiedSkeleton
=NULL
;
1070 PatternMapIterator it
;
1071 for (it
.set(*patternMap
); it
.hasNext(); ) {
1072 DateTimeMatcher trial
= it
.next();
1073 if (trial
.equals(skipMatcher
)) {
1076 int32_t distance
=source
.getDistance(trial
, includeMask
, tempInfo
);
1077 if (distance
<bestDistance
) {
1078 bestDistance
=distance
;
1079 bestPattern
=patternMap
->getPatternFromSkeleton(*trial
.getSkeletonPtr(), &specifiedSkeleton
);
1080 missingFields
->setTo(tempInfo
);
1087 // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
1088 // then return it too. This generally happens when the caller needs to pass that skeleton
1089 // through to adjustFieldTypes so the latter can do a better job.
1090 if (bestPattern
&& specifiedSkeletonPtr
) {
1091 *specifiedSkeletonPtr
= specifiedSkeleton
;
1097 DateTimePatternGenerator::adjustFieldTypes(const UnicodeString
& pattern
,
1098 const PtnSkeleton
* specifiedSkeleton
,
1100 UDateTimePatternMatchOptions options
) {
1101 UnicodeString newPattern
;
1103 for (int32_t i
=0; i
< fp
->itemNumber
; i
++) {
1104 UnicodeString field
= fp
->items
[i
];
1105 if ( fp
->isQuoteLiteral(field
) ) {
1107 UnicodeString quoteLiteral
;
1108 fp
->getQuoteLiteral(quoteLiteral
, &i
);
1109 newPattern
+= quoteLiteral
;
1112 if (fp
->isPatternSeparator(field
)) {
1116 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
1117 if (canonicalIndex
< 0) {
1119 continue; // don't adjust
1121 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
1122 int32_t typeValue
= row
->field
;
1123 if ((flags
& kDTPGFixFractionalSeconds
) != 0 && typeValue
== UDATPG_SECOND_FIELD
) {
1124 UnicodeString newField
=dtMatcher
->skeleton
.original
[UDATPG_FRACTIONAL_SECOND_FIELD
];
1125 field
= field
+ decimal
+ newField
;
1126 } else if (dtMatcher
->skeleton
.type
[typeValue
]!=0) {
1128 // - "reqField" is the field from the originally requested skeleton, with length
1130 // - "field" is the field from the found pattern.
1132 // The adjusted field should consist of characters from the originally requested
1133 // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or
1134 // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist
1135 // of characters from the found pattern.
1137 // The length of the adjusted field (adjFieldLen) should match that in the originally
1138 // requested skeleton, except that in the following cases the length of the adjusted field
1139 // should match that in the found pattern (i.e. the length of this pattern field should
1140 // not be adjusted):
1141 // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is
1142 // not set (ticket #7180). Note, we may want to implement a similar change for other
1143 // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for
1144 // field length, but options bits can be used to override this.
1145 // 2. There is a specified skeleton for the found pattern and one of the following is true:
1146 // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
1147 // b) The pattern field is numeric and the skeleton field is not, or vice versa.
1149 UnicodeString reqField
= dtMatcher
->skeleton
.original
[typeValue
];
1150 int32_t reqFieldLen
= reqField
.length();
1151 if (reqField
.charAt(0) == CAP_E
&& reqFieldLen
< 3)
1152 reqFieldLen
= 3; // 1-3 for E are equivalent to 3 for c,e
1153 int32_t adjFieldLen
= reqFieldLen
;
1154 if ( (typeValue
==UDATPG_HOUR_FIELD
&& (options
& UDATPG_MATCH_HOUR_FIELD_LENGTH
)==0) ||
1155 (typeValue
==UDATPG_MINUTE_FIELD
&& (options
& UDATPG_MATCH_MINUTE_FIELD_LENGTH
)==0) ||
1156 (typeValue
==UDATPG_SECOND_FIELD
&& (options
& UDATPG_MATCH_SECOND_FIELD_LENGTH
)==0) ) {
1157 adjFieldLen
= field
.length();
1158 } else if (specifiedSkeleton
) {
1159 UnicodeString skelField
= specifiedSkeleton
->original
[typeValue
];
1160 int32_t skelFieldLen
= skelField
.length();
1161 UBool patFieldIsNumeric
= (row
->type
> 0);
1162 UBool skelFieldIsNumeric
= (specifiedSkeleton
->type
[typeValue
] > 0);
1163 if (skelFieldLen
== reqFieldLen
|| (patFieldIsNumeric
&& !skelFieldIsNumeric
) || (skelFieldIsNumeric
&& !patFieldIsNumeric
)) {
1164 // don't adjust the field length in the found pattern
1165 adjFieldLen
= field
.length();
1168 UChar c
= (typeValue
!= UDATPG_HOUR_FIELD
&& typeValue
!= UDATPG_MONTH_FIELD
&&
1169 typeValue
!= UDATPG_WEEKDAY_FIELD
&& (typeValue
!= UDATPG_YEAR_FIELD
|| reqField
.charAt(0)==CAP_Y
))?
1170 reqField
.charAt(0): field
.charAt(0);
1171 if (typeValue
== UDATPG_HOUR_FIELD
&& (flags
& kDTPGSkeletonUsesCapJ
) != 0) {
1172 c
= fDefaultHourFormatChar
;
1173 switch (options
& UADATPG_FORCE_HOUR_CYCLE_MASK
) {
1174 case UADATPG_FORCE_12_HOUR_CYCLE
:
1175 if (c
== CAP_H
|| c
== LOW_K
) {
1176 // Have 24-hour cycle, change to 12-hour cycle.
1177 // Should have better way to pick 'h' or 'K'.
1181 case UADATPG_FORCE_24_HOUR_CYCLE
:
1182 if (c
== LOW_H
|| c
== CAP_K
) {
1183 // Have 12-hour cycle, change to 24-hour cycle.
1184 // Should have better way to pick 'H' or 'k'.
1193 for (int32_t i
=adjFieldLen
; i
>0; --i
) {
1204 DateTimePatternGenerator::getBestAppending(int32_t missingFields
, int32_t flags
, UDateTimePatternMatchOptions options
) {
1205 UnicodeString resultPattern
, tempPattern
;
1206 UErrorCode err
=U_ZERO_ERROR
;
1207 int32_t lastMissingFieldMask
=0;
1208 if (missingFields
!=0) {
1209 resultPattern
=UnicodeString();
1210 const PtnSkeleton
* specifiedSkeleton
=NULL
;
1211 tempPattern
= *getBestRaw(*dtMatcher
, missingFields
, distanceInfo
, &specifiedSkeleton
);
1212 resultPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, flags
, options
);
1213 if ( distanceInfo
->missingFieldMask
==0 ) {
1214 return resultPattern
;
1216 while (distanceInfo
->missingFieldMask
!=0) { // precondition: EVERY single field must work!
1217 if ( lastMissingFieldMask
== distanceInfo
->missingFieldMask
) {
1218 break; // cannot find the proper missing field
1220 if (((distanceInfo
->missingFieldMask
& UDATPG_SECOND_AND_FRACTIONAL_MASK
)==UDATPG_FRACTIONAL_MASK
) &&
1221 ((missingFields
& UDATPG_SECOND_AND_FRACTIONAL_MASK
) == UDATPG_SECOND_AND_FRACTIONAL_MASK
)) {
1222 resultPattern
= adjustFieldTypes(resultPattern
, specifiedSkeleton
, flags
| kDTPGFixFractionalSeconds
, options
);
1223 distanceInfo
->missingFieldMask
&= ~UDATPG_FRACTIONAL_MASK
;
1226 int32_t startingMask
= distanceInfo
->missingFieldMask
;
1227 tempPattern
= *getBestRaw(*dtMatcher
, distanceInfo
->missingFieldMask
, distanceInfo
, &specifiedSkeleton
);
1228 tempPattern
= adjustFieldTypes(tempPattern
, specifiedSkeleton
, flags
, options
);
1229 int32_t foundMask
=startingMask
& ~distanceInfo
->missingFieldMask
;
1230 int32_t topField
=getTopBitNumber(foundMask
);
1231 UnicodeString appendName
;
1232 getAppendName((UDateTimePatternField
)topField
, appendName
);
1233 const Formattable formatPattern
[] = {
1238 UnicodeString emptyStr
;
1239 resultPattern
= MessageFormat::format(appendItemFormats
[topField
], formatPattern
, 3, emptyStr
, err
);
1240 lastMissingFieldMask
= distanceInfo
->missingFieldMask
;
1243 return resultPattern
;
1247 DateTimePatternGenerator::getTopBitNumber(int32_t foundMask
) {
1248 if ( foundMask
==0 ) {
1252 while (foundMask
!=0) {
1256 if (i
-1 >UDATPG_ZONE_FIELD
) {
1257 return UDATPG_ZONE_FIELD
;
1264 DateTimePatternGenerator::setAvailableFormat(const UnicodeString
&key
, UErrorCode
& err
)
1266 fAvailableFormatKeyHash
->puti(key
, 1, err
);
1270 DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString
&key
) const {
1271 return (UBool
)(fAvailableFormatKeyHash
->geti(key
) == 1);
1275 DateTimePatternGenerator::copyHashtable(Hashtable
*other
, UErrorCode
&status
) {
1277 if (other
== NULL
) {
1280 if (fAvailableFormatKeyHash
!= NULL
) {
1281 delete fAvailableFormatKeyHash
;
1282 fAvailableFormatKeyHash
= NULL
;
1284 initHashtable(status
);
1285 if(U_FAILURE(status
)){
1288 int32_t pos
= UHASH_FIRST
;
1289 const UHashElement
* elem
= NULL
;
1290 // walk through the hash table and create a deep clone
1291 while((elem
= other
->nextElement(pos
))!= NULL
){
1292 const UHashTok otherKeyTok
= elem
->key
;
1293 UnicodeString
* otherKey
= (UnicodeString
*)otherKeyTok
.pointer
;
1294 fAvailableFormatKeyHash
->puti(*otherKey
, 1, status
);
1295 if(U_FAILURE(status
)){
1302 DateTimePatternGenerator::getSkeletons(UErrorCode
& status
) const {
1303 StringEnumeration
* skeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_SKELETON
, status
);
1304 return skeletonEnumerator
;
1307 const UnicodeString
&
1308 DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString
& skeleton
) const {
1311 if (skeleton
.length() ==0) {
1314 curElem
= patternMap
->getHeader(skeleton
.charAt(0));
1315 while ( curElem
!= NULL
) {
1316 if ( curElem
->skeleton
->getSkeleton()==skeleton
) {
1317 return curElem
->pattern
;
1319 curElem
=curElem
->next
;
1325 DateTimePatternGenerator::getBaseSkeletons(UErrorCode
& status
) const {
1326 StringEnumeration
* baseSkeletonEnumerator
= new DTSkeletonEnumeration(*patternMap
, DT_BASESKELETON
, status
);
1327 return baseSkeletonEnumerator
;
1331 DateTimePatternGenerator::getRedundants(UErrorCode
& status
) {
1332 StringEnumeration
* output
= new DTRedundantEnumeration();
1333 const UnicodeString
*pattern
;
1334 PatternMapIterator it
;
1335 for (it
.set(*patternMap
); it
.hasNext(); ) {
1336 DateTimeMatcher current
= it
.next();
1337 pattern
= patternMap
->getPatternFromSkeleton(*(it
.getSkeleton()));
1338 if ( isCanonicalItem(*pattern
) ) {
1341 if ( skipMatcher
== NULL
) {
1342 skipMatcher
= new DateTimeMatcher(current
);
1345 *skipMatcher
= current
;
1347 UnicodeString trial
= getBestPattern(current
.getPattern(), status
);
1348 if (trial
== *pattern
) {
1349 ((DTRedundantEnumeration
*)output
)->add(*pattern
, status
);
1351 if (current
.equals(skipMatcher
)) {
1359 DateTimePatternGenerator::isCanonicalItem(const UnicodeString
& item
) const {
1360 if ( item
.length() != 1 ) {
1363 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1364 if (item
.charAt(0)==Canonical_Items
[i
]) {
1372 DateTimePatternGenerator
*
1373 DateTimePatternGenerator::clone() const {
1374 return new DateTimePatternGenerator(*this);
1377 PatternMap::PatternMap() {
1378 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1381 isDupAllowed
= TRUE
;
1385 PatternMap::copyFrom(const PatternMap
& other
, UErrorCode
& status
) {
1386 this->isDupAllowed
= other
.isDupAllowed
;
1387 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1388 PtnElem
*curElem
, *otherElem
, *prevElem
=NULL
;
1389 otherElem
= other
.boot
[bootIndex
];
1390 while (otherElem
!=NULL
) {
1391 if ((curElem
= new PtnElem(otherElem
->basePattern
, otherElem
->pattern
))==NULL
) {
1393 status
= U_MEMORY_ALLOCATION_ERROR
;
1396 if ( this->boot
[bootIndex
]== NULL
) {
1397 this->boot
[bootIndex
] = curElem
;
1399 if ((curElem
->skeleton
=new PtnSkeleton(*(otherElem
->skeleton
))) == NULL
) {
1401 status
= U_MEMORY_ALLOCATION_ERROR
;
1404 curElem
->skeletonWasSpecified
= otherElem
->skeletonWasSpecified
;
1405 if (prevElem
!=NULL
) {
1406 prevElem
->next
=curElem
;
1410 otherElem
= otherElem
->next
;
1417 PatternMap::getHeader(UChar baseChar
) {
1420 if ( (baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
) ) {
1421 curElem
= boot
[baseChar
-CAP_A
];
1424 if ( (baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
) ) {
1425 curElem
= boot
[26+baseChar
-LOW_A
];
1434 PatternMap::~PatternMap() {
1435 for (int32_t i
=0; i
< MAX_PATTERN_ENTRIES
; ++i
) {
1436 if (boot
[i
]!=NULL
) {
1441 } // PatternMap destructor
1444 PatternMap::add(const UnicodeString
& basePattern
,
1445 const PtnSkeleton
& skeleton
,
1446 const UnicodeString
& value
,// mapped pattern value
1447 UBool skeletonWasSpecified
,
1448 UErrorCode
&status
) {
1449 UChar baseChar
= basePattern
.charAt(0);
1450 PtnElem
*curElem
, *baseElem
;
1451 status
= U_ZERO_ERROR
;
1453 // the baseChar must be A-Z or a-z
1454 if ((baseChar
>= CAP_A
) && (baseChar
<= CAP_Z
)) {
1455 baseElem
= boot
[baseChar
-CAP_A
];
1458 if ((baseChar
>=LOW_A
) && (baseChar
<= LOW_Z
)) {
1459 baseElem
= boot
[26+baseChar
-LOW_A
];
1462 status
= U_ILLEGAL_CHARACTER
;
1467 if (baseElem
== NULL
) {
1468 if ((curElem
= new PtnElem(basePattern
, value
)) == NULL
) {
1470 status
= U_MEMORY_ALLOCATION_ERROR
;
1473 if (baseChar
>= LOW_A
) {
1474 boot
[26 + (baseChar
-LOW_A
)] = curElem
;
1477 boot
[baseChar
-CAP_A
] = curElem
;
1479 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1480 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1482 if ( baseElem
!= NULL
) {
1483 curElem
= getDuplicateElem(basePattern
, skeleton
, baseElem
);
1485 if (curElem
== NULL
) {
1486 // add new element to the list.
1488 while( curElem
-> next
!= NULL
)
1490 curElem
= curElem
->next
;
1492 if ((curElem
->next
= new PtnElem(basePattern
, value
)) == NULL
) {
1494 status
= U_MEMORY_ALLOCATION_ERROR
;
1497 curElem
=curElem
->next
;
1498 curElem
->skeleton
= new PtnSkeleton(skeleton
);
1499 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1502 // Pattern exists in the list already.
1503 if ( !isDupAllowed
) {
1506 // Overwrite the value.
1507 curElem
->pattern
= value
;
1508 // It was a bug that we were not doing the following previously,
1509 // though that bug hid other problems by making things partly work.
1510 curElem
->skeletonWasSpecified
= skeletonWasSpecified
;
1513 } // PatternMap::add
1515 // Find the pattern from the given basePattern string.
1516 const UnicodeString
*
1517 PatternMap::getPatternFromBasePattern(UnicodeString
& basePattern
, UBool
& skeletonWasSpecified
) { // key to search for
1520 if ((curElem
=getHeader(basePattern
.charAt(0)))==NULL
) {
1521 return NULL
; // no match
1525 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1526 skeletonWasSpecified
= curElem
->skeletonWasSpecified
;
1527 return &(curElem
->pattern
);
1529 curElem
=curElem
->next
;
1530 }while (curElem
!= NULL
);
1533 } // PatternMap::getFromBasePattern
1536 // Find the pattern from the given skeleton.
1537 // At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
1538 // the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
1539 // and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
1540 // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
1541 // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
1542 const UnicodeString
*
1543 PatternMap::getPatternFromSkeleton(PtnSkeleton
& skeleton
, const PtnSkeleton
** specifiedSkeletonPtr
) { // key to search for
1546 if (specifiedSkeletonPtr
) {
1547 *specifiedSkeletonPtr
= NULL
;
1551 UChar baseChar
='\0';
1552 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1553 if (skeleton
.baseOriginal
[i
].length() !=0 ) {
1554 baseChar
= skeleton
.baseOriginal
[i
].charAt(0);
1559 if ((curElem
=getHeader(baseChar
))==NULL
) {
1560 return NULL
; // no match
1565 if (specifiedSkeletonPtr
!= NULL
) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
1566 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1567 if (curElem
->skeleton
->original
[i
].compare(skeleton
.original
[i
]) != 0 )
1572 } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
1573 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1574 if (curElem
->skeleton
->baseOriginal
[i
].compare(skeleton
.baseOriginal
[i
]) != 0 )
1580 if (i
== UDATPG_FIELD_COUNT
) {
1581 if (specifiedSkeletonPtr
&& curElem
->skeletonWasSpecified
) {
1582 *specifiedSkeletonPtr
= curElem
->skeleton
;
1584 return &(curElem
->pattern
);
1586 curElem
=curElem
->next
;
1587 }while (curElem
!= NULL
);
1593 PatternMap::equals(const PatternMap
& other
) {
1594 if ( this==&other
) {
1597 for (int32_t bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
1598 if ( boot
[bootIndex
]==other
.boot
[bootIndex
] ) {
1601 if ( (boot
[bootIndex
]==NULL
)||(other
.boot
[bootIndex
]==NULL
) ) {
1604 PtnElem
*otherElem
= other
.boot
[bootIndex
];
1605 PtnElem
*myElem
= boot
[bootIndex
];
1606 while ((otherElem
!=NULL
) || (myElem
!=NULL
)) {
1607 if ( myElem
== otherElem
) {
1610 if ((otherElem
==NULL
) || (myElem
==NULL
)) {
1613 if ( (myElem
->basePattern
!= otherElem
->basePattern
) ||
1614 (myElem
->pattern
!= otherElem
->pattern
) ) {
1617 if ((myElem
->skeleton
!=otherElem
->skeleton
)&&
1618 !myElem
->skeleton
->equals(*(otherElem
->skeleton
))) {
1621 myElem
= myElem
->next
;
1622 otherElem
=otherElem
->next
;
1628 // find any key existing in the mapping table already.
1629 // return TRUE if there is an existing key, otherwise return FALSE.
1631 PatternMap::getDuplicateElem(
1632 const UnicodeString
&basePattern
,
1633 const PtnSkeleton
&skeleton
,
1634 PtnElem
*baseElem
) {
1637 if ( baseElem
== (PtnElem
*)NULL
) {
1638 return (PtnElem
*)NULL
;
1644 if ( basePattern
.compare(curElem
->basePattern
)==0 ) {
1646 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1647 if (curElem
->skeleton
->type
[i
] != skeleton
.type
[i
] ) {
1656 curElem
= curElem
->next
;
1657 } while( curElem
!= (PtnElem
*)NULL
);
1660 return (PtnElem
*)NULL
;
1662 } // PatternMap::getDuplicateElem
1664 DateTimeMatcher::DateTimeMatcher(void) {
1667 DateTimeMatcher::~DateTimeMatcher() {}
1669 DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher
& other
) {
1670 copyFrom(other
.skeleton
);
1675 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
) {
1676 PtnSkeleton localSkeleton
;
1677 return set(pattern
, fp
, localSkeleton
);
1681 DateTimeMatcher::set(const UnicodeString
& pattern
, FormatParser
* fp
, PtnSkeleton
& skeletonResult
) {
1683 for (i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1684 skeletonResult
.type
[i
]=NONE
;
1687 for (i
=0; i
< fp
->itemNumber
; i
++) {
1688 UnicodeString field
= fp
->items
[i
];
1689 if ( field
.charAt(0) == LOW_A
) {
1690 continue; // skip 'a'
1693 if ( fp
->isQuoteLiteral(field
) ) {
1694 UnicodeString quoteLiteral
;
1695 fp
->getQuoteLiteral(quoteLiteral
, &i
);
1698 int32_t canonicalIndex
= fp
->getCanonicalIndex(field
);
1699 if (canonicalIndex
< 0 ) {
1702 const dtTypeElem
*row
= &dtTypes
[canonicalIndex
];
1703 int32_t typeValue
= row
->field
;
1704 skeletonResult
.original
[typeValue
]=field
;
1705 UChar repeatChar
= row
->patternChar
;
1706 int32_t repeatCount
= row
->minLen
; // #7930 removes cap at 3
1707 while (repeatCount
-- > 0) {
1708 skeletonResult
.baseOriginal
[typeValue
] += repeatChar
;
1710 int16_t subTypeValue
= row
->type
;
1711 if ( row
->type
> 0) {
1712 subTypeValue
+= field
.length();
1714 skeletonResult
.type
[typeValue
] = subTypeValue
;
1716 copyFrom(skeletonResult
);
1720 DateTimeMatcher::getBasePattern(UnicodeString
&result
) {
1721 result
.remove(); // Reset the result first.
1722 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1723 if (skeleton
.baseOriginal
[i
].length()!=0) {
1724 result
+= skeleton
.baseOriginal
[i
];
1730 DateTimeMatcher::getPattern() {
1731 UnicodeString result
;
1733 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1734 if (skeleton
.original
[i
].length()!=0) {
1735 result
+= skeleton
.original
[i
];
1742 DateTimeMatcher::getDistance(const DateTimeMatcher
& other
, int32_t includeMask
, DistanceInfo
& distanceInfo
) {
1744 distanceInfo
.clear();
1745 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1746 int32_t myType
= (includeMask
&(1<<i
))==0 ? 0 : skeleton
.type
[i
];
1747 int32_t otherType
= other
.skeleton
.type
[i
];
1748 if (myType
==otherType
) {
1751 if (myType
==0) {// and other is not
1752 result
+= EXTRA_FIELD
;
1753 distanceInfo
.addExtra(i
);
1757 result
+= MISSING_FIELD
;
1758 distanceInfo
.addMissing(i
);
1761 result
+= abs(myType
- otherType
);
1770 DateTimeMatcher::copyFrom(const PtnSkeleton
& newSkeleton
) {
1771 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1772 this->skeleton
.type
[i
]=newSkeleton
.type
[i
];
1773 this->skeleton
.original
[i
]=newSkeleton
.original
[i
];
1774 this->skeleton
.baseOriginal
[i
]=newSkeleton
.baseOriginal
[i
];
1779 DateTimeMatcher::copyFrom() {
1781 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1782 this->skeleton
.type
[i
]=0;
1783 this->skeleton
.original
[i
].remove();
1784 this->skeleton
.baseOriginal
[i
].remove();
1789 DateTimeMatcher::equals(const DateTimeMatcher
* other
) const {
1793 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1794 if (this->skeleton
.original
[i
]!=other
->skeleton
.original
[i
] ) {
1802 DateTimeMatcher::getFieldMask() {
1805 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
1806 if (skeleton
.type
[i
]!=0) {
1814 DateTimeMatcher::getSkeletonPtr() {
1818 FormatParser::FormatParser () {
1824 FormatParser::~FormatParser () {
1828 // Find the next token with the starting position and length
1829 // Note: the startPos may
1830 FormatParser::TokenStatus
1831 FormatParser::setTokens(const UnicodeString
& pattern
, int32_t startPos
, int32_t *len
) {
1832 int32_t curLoc
= startPos
;
1833 if ( curLoc
>= pattern
.length()) {
1836 // check the current char is between A-Z or a-z
1838 UChar c
=pattern
.charAt(curLoc
);
1839 if ( (c
>=CAP_A
&& c
<=CAP_Z
) || (c
>=LOW_A
&& c
<=LOW_Z
) ) {
1848 if ( pattern
.charAt(curLoc
)!= pattern
.charAt(startPos
) ) {
1849 break; // not the same token
1851 } while(curLoc
<= pattern
.length());
1852 *len
= curLoc
-startPos
;
1857 FormatParser::set(const UnicodeString
& pattern
) {
1859 TokenStatus result
=START
;
1864 result
= setTokens( pattern
, startPos
, &len
);
1865 if ( result
== ADD_TOKEN
)
1867 items
[itemNumber
++] = UnicodeString(pattern
, startPos
, len
);
1873 } while (result
==ADD_TOKEN
&& itemNumber
< MAX_DT_TOKEN
);
1877 FormatParser::getCanonicalIndex(const UnicodeString
& s
, UBool strict
) {
1878 int32_t len
= s
.length();
1882 UChar ch
= s
.charAt(0);
1884 // Verify that all are the same character.
1885 for (int32_t l
= 1; l
< len
; l
++) {
1886 if (ch
!= s
.charAt(l
)) {
1891 int32_t bestRow
= -1;
1892 while (dtTypes
[i
].patternChar
!= '\0') {
1893 if ( dtTypes
[i
].patternChar
!= ch
) {
1898 if (dtTypes
[i
].patternChar
!= dtTypes
[i
+1].patternChar
) {
1901 if (dtTypes
[i
+1].minLen
<= len
) {
1907 return strict
? -1 : bestRow
;
1911 FormatParser::isQuoteLiteral(const UnicodeString
& s
) const {
1912 return (UBool
)(s
.charAt(0)==SINGLE_QUOTE
);
1915 // This function aussumes the current itemIndex points to the quote literal.
1916 // Please call isQuoteLiteral prior to this function.
1918 FormatParser::getQuoteLiteral(UnicodeString
& quote
, int32_t *itemIndex
) {
1919 int32_t i
=*itemIndex
;
1922 if (items
[i
].charAt(0)==SINGLE_QUOTE
) {
1926 while ( i
< itemNumber
) {
1927 if ( items
[i
].charAt(0)==SINGLE_QUOTE
) {
1928 if ( (i
+1<itemNumber
) && (items
[i
+1].charAt(0)==SINGLE_QUOTE
)) {
1929 // two single quotes e.g. 'o''clock'
1930 quote
+= items
[i
++];
1931 quote
+= items
[i
++];
1948 FormatParser::isPatternSeparator(UnicodeString
& field
) {
1949 for (int32_t i
=0; i
<field
.length(); ++i
) {
1950 UChar c
= field
.charAt(i
);
1951 if ( (c
==SINGLE_QUOTE
) || (c
==BACKSLASH
) || (c
==SPACE
) || (c
==COLON
) ||
1952 (c
==QUOTATION_MARK
) || (c
==COMMA
) || (c
==HYPHEN
) ||(items
[i
].charAt(0)==DOT
) ) {
1962 DistanceInfo::~DistanceInfo() {}
1965 DistanceInfo::setTo(DistanceInfo
&other
) {
1966 missingFieldMask
= other
.missingFieldMask
;
1967 extraFieldMask
= other
.extraFieldMask
;
1970 PatternMapIterator::PatternMapIterator() {
1974 matcher
= new DateTimeMatcher();
1978 PatternMapIterator::~PatternMapIterator() {
1983 PatternMapIterator::set(PatternMap
& newPatternMap
) {
1984 this->patternMap
=&newPatternMap
;
1988 PatternMapIterator::getSkeleton() {
1989 if ( nodePtr
== NULL
) {
1993 return nodePtr
->skeleton
;
1998 PatternMapIterator::hasNext() {
1999 int32_t headIndex
=bootIndex
;
2000 PtnElem
*curPtr
=nodePtr
;
2002 if (patternMap
==NULL
) {
2005 while ( headIndex
< MAX_PATTERN_ENTRIES
) {
2006 if ( curPtr
!= NULL
) {
2007 if ( curPtr
->next
!= NULL
) {
2017 if ( patternMap
->boot
[headIndex
] != NULL
) {
2031 PatternMapIterator::next() {
2032 while ( bootIndex
< MAX_PATTERN_ENTRIES
) {
2033 if ( nodePtr
!= NULL
) {
2034 if ( nodePtr
->next
!= NULL
) {
2035 nodePtr
= nodePtr
->next
;
2045 if ( patternMap
->boot
[bootIndex
] != NULL
) {
2046 nodePtr
= patternMap
->boot
[bootIndex
];
2055 if (nodePtr
!=NULL
) {
2056 matcher
->copyFrom(*nodePtr
->skeleton
);
2059 matcher
->copyFrom();
2064 PtnSkeleton::PtnSkeleton() {
2068 PtnSkeleton::PtnSkeleton(const PtnSkeleton
& other
) {
2069 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2070 this->type
[i
]=other
.type
[i
];
2071 this->original
[i
]=other
.original
[i
];
2072 this->baseOriginal
[i
]=other
.baseOriginal
[i
];
2077 PtnSkeleton::equals(const PtnSkeleton
& other
) {
2078 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2079 if ( (type
[i
]!= other
.type
[i
]) ||
2080 (original
[i
]!=other
.original
[i
]) ||
2081 (baseOriginal
[i
]!=other
.baseOriginal
[i
]) ) {
2089 PtnSkeleton::getSkeleton() {
2090 UnicodeString result
;
2092 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
2093 if (original
[i
].length()!=0) {
2094 result
+= original
[i
];
2101 PtnSkeleton::getBaseSkeleton() {
2102 UnicodeString result
;
2104 for(int32_t i
=0; i
< UDATPG_FIELD_COUNT
; ++i
) {
2105 if (baseOriginal
[i
].length()!=0) {
2106 result
+= baseOriginal
[i
];
2112 PtnSkeleton::~PtnSkeleton() {
2115 PtnElem::PtnElem(const UnicodeString
&basePat
, const UnicodeString
&pat
) :
2116 basePattern(basePat
),
2123 PtnElem::~PtnElem() {
2131 DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap
&patternMap
, dtStrEnum type
, UErrorCode
& status
) {
2133 PtnSkeleton
*curSkeleton
;
2138 fSkeletons
= new UVector(status
);
2139 if (U_FAILURE(status
)) {
2143 for (bootIndex
=0; bootIndex
<MAX_PATTERN_ENTRIES
; ++bootIndex
) {
2144 curElem
= patternMap
.boot
[bootIndex
];
2145 while (curElem
!=NULL
) {
2147 case DT_BASESKELETON
:
2148 s
=curElem
->basePattern
;
2154 curSkeleton
=curElem
->skeleton
;
2155 s
=curSkeleton
->getSkeleton();
2158 if ( !isCanonicalItem(s
) ) {
2159 fSkeletons
->addElement(new UnicodeString(s
), status
);
2160 if (U_FAILURE(status
)) {
2166 curElem
= curElem
->next
;
2169 if ((bootIndex
==MAX_PATTERN_ENTRIES
) && (curElem
!=NULL
) ) {
2170 status
= U_BUFFER_OVERFLOW_ERROR
;
2174 const UnicodeString
*
2175 DTSkeletonEnumeration::snext(UErrorCode
& status
) {
2176 if (U_SUCCESS(status
) && pos
< fSkeletons
->size()) {
2177 return (const UnicodeString
*)fSkeletons
->elementAt(pos
++);
2183 DTSkeletonEnumeration::reset(UErrorCode
& /*status*/) {
2188 DTSkeletonEnumeration::count(UErrorCode
& /*status*/) const {
2189 return (fSkeletons
==NULL
) ? 0 : fSkeletons
->size();
2193 DTSkeletonEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2194 if ( item
.length() != 1 ) {
2197 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2198 if (item
.charAt(0)==Canonical_Items
[i
]) {
2205 DTSkeletonEnumeration::~DTSkeletonEnumeration() {
2207 for (int32_t i
=0; i
<fSkeletons
->size(); ++i
) {
2208 if ((s
=(UnicodeString
*)fSkeletons
->elementAt(i
))!=NULL
) {
2215 DTRedundantEnumeration::DTRedundantEnumeration() {
2221 DTRedundantEnumeration::add(const UnicodeString
& pattern
, UErrorCode
& status
) {
2222 if (U_FAILURE(status
)) return;
2223 if (fPatterns
== NULL
) {
2224 fPatterns
= new UVector(status
);
2225 if (U_FAILURE(status
)) {
2231 fPatterns
->addElement(new UnicodeString(pattern
), status
);
2232 if (U_FAILURE(status
)) {
2239 const UnicodeString
*
2240 DTRedundantEnumeration::snext(UErrorCode
& status
) {
2241 if (U_SUCCESS(status
) && pos
< fPatterns
->size()) {
2242 return (const UnicodeString
*)fPatterns
->elementAt(pos
++);
2248 DTRedundantEnumeration::reset(UErrorCode
& /*status*/) {
2253 DTRedundantEnumeration::count(UErrorCode
& /*status*/) const {
2254 return (fPatterns
==NULL
) ? 0 : fPatterns
->size();
2258 DTRedundantEnumeration::isCanonicalItem(const UnicodeString
& item
) {
2259 if ( item
.length() != 1 ) {
2262 for (int32_t i
=0; i
<UDATPG_FIELD_COUNT
; ++i
) {
2263 if (item
.charAt(0)==Canonical_Items
[i
]) {
2270 DTRedundantEnumeration::~DTRedundantEnumeration() {
2272 for (int32_t i
=0; i
<fPatterns
->size(); ++i
) {
2273 if ((s
=(UnicodeString
*)fPatterns
->elementAt(i
))!=NULL
) {
2283 #endif /* #if !UCONFIG_NO_FORMATTING */