1 /*
2 *******************************************************************************
3 * Copyright (C) 2007, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 *
7 * File DTPTNGEN.CPP
8 *
9 *******************************************************************************
10 */
11
12 #include "unicode/utypes.h"
13 #if !UCONFIG_NO_FORMATTING
14
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/ures.h"
25 #include "unicode/rep.h"
26 #include "cpputils.h"
27 #include "ucln_in.h"
28 #include "mutex.h"
29 #include "cmemory.h"
30 #include "cstring.h"
31 #include "locbased.h"
32 #include "gregoimp.h"
33 #include "hash.h"
34 #include "uresimp.h"
35 #include "dtptngen_impl.h"
36
37
38 #if defined U_DEBUG_DTPTN
39 #include <stdio.h>
40 #endif
41
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43
44 U_NAMESPACE_BEGIN
45
46 // *****************************************************************************
47 // class DateTimePatternGenerator
48 // *****************************************************************************
49 static const UChar Canonical_Items[] = {
50 // GyQMwWedDFHmsSv
51 CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, LOW_E, LOW_D, CAP_D, CAP_F,
52 CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
53 };
54
55 static const dtTypeElem dtTypes[] = {
56 // patternChar, field, type, minLen, weight
57 {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,},
58 {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
59 {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20},
60 {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20},
61 {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20},
62 {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2},
63 {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0},
64 {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0},
65 {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2},
66 {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0},
67 {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0},
68 {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0},
69 {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
70 {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0},
71 {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0},
72 {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0},
73 {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
74 {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 0},
75 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
76 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0},
77 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0},
78 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0},
79 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3},
80 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0},
81 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0},
82 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2},
83 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0},
84 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
85 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0},
86 {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2},
87 {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 3},
88 {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 0},
89 {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, // really internal use, so we d'ont care
90 {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 0},
91 {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
92 {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2},
93 {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
94 {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
95 {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2},
96 {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2},
97 {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
98 {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 1000},
99 {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0},
100 {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
101 {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3},
102 {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0},
103 {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 3},
104 {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
105 {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
106 };
107
108 static const char* CLDR_FIELD_APPEND[] = {
109 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
110 "Hour", "Minute", "Second", "*", "Timezone"
111 };
112
113 static const char* CLDR_FIELD_NAME[] = {
114 "era", "year", "quarter", "month", "week", "*", "weekday", "day", "*", "*", "dayperiod",
115 "hour", "minute", "second", "*", "zone"
116 };
117
118 static const char* Resource_Fields[] = {
119 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
120 "weekday", "year", "zone", "quarter" };
121
122 // For appendItems
123 static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
124 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
125
126 static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ"
127
128 static const char DT_DateTimePatternsTag[]="DateTimePatterns";
129 static const char DT_DateTimeCalendarTag[]="calendar";
130 static const char DT_DateTimeGregorianTag[]="gregorian";
131 static const char DT_DateTimeAppendItemsTag[]="appendItems";
132 static const char DT_DateTimeFieldsTag[]="fields";
133 static const char DT_DateTimeAvailableFormatsTag[]="availableFormats";
134 static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
135
136 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)137 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)
138 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration)
139
140 DateTimePatternGenerator* U_EXPORT2
141 DateTimePatternGenerator::createInstance(UErrorCode& status) {
142 return createInstance(Locale::getDefault(), status);
143 }
144
145 DateTimePatternGenerator* U_EXPORT2
createInstance(const Locale & locale,UErrorCode & status)146 DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
147 return new DateTimePatternGenerator(locale, status);
148 }
149
150 DateTimePatternGenerator* U_EXPORT2
createEmptyInstance(UErrorCode & status)151 DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
152 return new DateTimePatternGenerator(status);
153 }
154
DateTimePatternGenerator(UErrorCode & status)155 DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) : UObject()
156 {
157 fStatus = U_ZERO_ERROR;
158 skipMatcher = NULL;
159 fAvailableFormatKeyHash=NULL;
160 fp = new FormatParser();
161 dtMatcher = new DateTimeMatcher();
162 distanceInfo = new DistanceInfo();
163 patternMap = new PatternMap();
164 if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
165 status = U_MEMORY_ALLOCATION_ERROR;
166 }
167 }
168
DateTimePatternGenerator(const Locale & locale,UErrorCode & status)169 DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) : UObject()
170 {
171 fp = new FormatParser();
172 dtMatcher = new DateTimeMatcher();
173 distanceInfo = new DistanceInfo();
174 patternMap = new PatternMap();
175 if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
176 status = U_MEMORY_ALLOCATION_ERROR;
177 }
178 else {
179 initData(locale);
180 status = getStatus();
181 }
182 }
183
DateTimePatternGenerator(const DateTimePatternGenerator & other)184 DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) : UObject() {
185 fStatus = U_ZERO_ERROR;
186 skipMatcher = NULL;
187 fAvailableFormatKeyHash=NULL;
188 fp = new FormatParser();
189 dtMatcher = new DateTimeMatcher();
190 distanceInfo = new DistanceInfo();
191 patternMap = new PatternMap();
192 *this=other;
193 }
194
195 DateTimePatternGenerator&
operator =(const DateTimePatternGenerator & other)196 DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
197 fStatus = U_ZERO_ERROR;
198 pLocale = other.pLocale;
199 *fp = *(other.fp);
200 dtMatcher->copyFrom(other.dtMatcher->skeleton);
201 *distanceInfo = *(other.distanceInfo);
202 dateTimeFormat = other.dateTimeFormat;
203 decimal = other.decimal;
204 // NUL-terminate for the C API.
205 dateTimeFormat.getTerminatedBuffer();
206 decimal.getTerminatedBuffer();
207 delete skipMatcher;
208 if ( other.skipMatcher == NULL ) {
209 skipMatcher = NULL;
210 }
211 else {
212 skipMatcher = new DateTimeMatcher(*other.skipMatcher);
213 }
214 for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
215 appendItemFormats[i] = other.appendItemFormats[i];
216 appendItemNames[i] = other.appendItemNames[i];
217 // NUL-terminate for the C API.
218 appendItemFormats[i].getTerminatedBuffer();
219 appendItemNames[i].getTerminatedBuffer();
220 }
221 patternMap->copyFrom(*other.patternMap, fStatus);
222 copyHashtable(other.fAvailableFormatKeyHash);
223 return *this;
224 }
225
226
227 UBool
operator ==(const DateTimePatternGenerator & other) const228 DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const {
229 if (this == &other) {
230 return TRUE;
231 }
232 if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
233 (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
234 for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
235 if ((appendItemFormats[i] != other.appendItemFormats[i]) ||
236 (appendItemNames[i] != other.appendItemNames[i]) ) {
237 return FALSE;
238 }
239 }
240 return TRUE;
241 }
242 else {
243 return FALSE;
244 }
245 }
246
247 UBool
operator !=(const DateTimePatternGenerator & other) const248 DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const {
249 return !operator==(other);
250 }
251
~DateTimePatternGenerator()252 DateTimePatternGenerator::~DateTimePatternGenerator() {
253 if (fAvailableFormatKeyHash!=NULL) {
254 delete fAvailableFormatKeyHash;
255 fAvailableFormatKeyHash=NULL;
256 }
257
258 if (fp != NULL) delete fp;
259 if (dtMatcher != NULL) delete dtMatcher;
260 if (distanceInfo != NULL) delete distanceInfo;
261 if (patternMap != NULL) delete patternMap;
262 if (skipMatcher != NULL) delete skipMatcher;
263 }
264
265 void
initData(const Locale & locale)266 DateTimePatternGenerator::initData(const Locale& locale) {
267 fStatus = U_ZERO_ERROR;
268 skipMatcher = NULL;
269 fAvailableFormatKeyHash=NULL;
270
271 addCanonicalItems();
272 addICUPatterns(locale, fStatus);
273 if (U_FAILURE(fStatus)) {
274 return;
275 }
276 addCLDRData(locale);
277 setDateTimeFromCalendar(locale, fStatus);
278 setDecimalSymbols(locale, fStatus);
279 } // DateTimePatternGenerator::initData
280
281 UnicodeString
getSkeleton(const UnicodeString & pattern,UErrorCode & status)282 DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& status) {
283 dtMatcher->set(pattern, fp);
284 return dtMatcher->getSkeletonPtr()->getSkeleton();
285 }
286
287 UnicodeString
getBaseSkeleton(const UnicodeString & pattern,UErrorCode & status)288 DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& status) {
289 dtMatcher->set(pattern, fp);
290 return dtMatcher->getSkeletonPtr()->getBaseSkeleton();
291 }
292
293 void
addICUPatterns(const Locale & locale,UErrorCode & status)294 DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) {
295 UnicodeString dfPattern;
296 UnicodeString conflictingString;
297 UDateTimePatternConflict conflictingStatus;
298 SimpleDateFormat* df;
299
300 // Load with ICU patterns
301 for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) {
302 if ((df = (SimpleDateFormat*)DateFormat::createDateInstance((DateFormat::EStyle)i, locale))!= NULL) {
303 conflictingStatus = addPattern(df->toPattern(dfPattern), FALSE, conflictingString, status);
304 delete df;
305 if (U_FAILURE(status)) {
306 return;
307 }
308 }
309
310 if ((df = (SimpleDateFormat*)DateFormat::createTimeInstance((DateFormat::EStyle)i, locale)) != NULL) {
311 conflictingStatus = addPattern(df->toPattern(dfPattern), FALSE, conflictingString, status);
312 delete df;
313 if (U_FAILURE(status)) {
314 return;
315 }
316 // HACK for hh:ss
317 if ( i==DateFormat::kMedium ) {
318 hackPattern = dfPattern;
319 }
320 }
321 }
322 }
323
324 void
hackTimes(const UnicodeString & hackPattern,UErrorCode & status)325 DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status) {
326 UDateTimePatternConflict conflictingStatus;
327 UnicodeString conflictingString;
328
329 fp->set(hackPattern);
330 UnicodeString mmss;
331 UBool gotMm=FALSE;
332 for (int32_t i=0; i<fp->itemNumber; ++i) {
333 UnicodeString field = fp->items[i];
334 if ( fp->isQuoteLiteral(field) ) {
335 if ( gotMm ) {
336 UnicodeString quoteLiteral;
337 fp->getQuoteLiteral(quoteLiteral, &i);
338 mmss += quoteLiteral;
339 }
340 }
341 else {
342 if (fp->isPatternSeparator(field) && gotMm) {
343 mmss+=field;
344 }
345 else {
346 UChar ch=field.charAt(0);
347 if (ch==LOW_M) {
348 gotMm=TRUE;
349 mmss+=field;
350 }
351 else {
352 if (ch==LOW_S) {
353 if (!gotMm) {
354 break;
355 }
356 mmss+= field;
357 conflictingStatus = addPattern(mmss, FALSE, conflictingString, status);
358 break;
359 }
360 else {
361 if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) {
362 break;
363 }
364 }
365 }
366 }
367 }
368 }
369 }
370
371 void
addCLDRData(const Locale & locale)372 DateTimePatternGenerator::addCLDRData(const Locale& locale) {
373 UErrorCode err = U_ZERO_ERROR;
374 UResourceBundle *rb, *gregorianBundle, *calBundle;
375 UResourceBundle *patBundle, *fieldBundle, *fBundle;
376 UnicodeString rbPattern, value, field;
377 UnicodeString conflictingPattern;
378 UDateTimePatternConflict conflictingStatus;
379 const char *key=NULL;
380 int32_t i;
381
382 UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias.
383
384 for (i=0; i<UDATPG_FIELD_COUNT; ++i ) {
385 appendItemNames[i]=CAP_F;
386 if (i<10) {
387 appendItemNames[i]+=(UChar)(i+0x30);
388 }
389 else {
390 appendItemNames[i]+=(UChar)0x31;
391 appendItemNames[i]+=(UChar)(i-10 + 0x30);
392 }
393 // NUL-terminate for the C API.
394 appendItemNames[i].getTerminatedBuffer();
395 }
396
397 rb = ures_open(NULL, locale.getName(), &err);
398 calBundle = ures_getByKey(rb, DT_DateTimeCalendarTag, NULL, &err);
399 gregorianBundle = ures_getByKey(calBundle, DT_DateTimeGregorianTag, NULL, &err);
400
401 key=NULL;
402 int32_t dtCount=0;
403 patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimePatternsTag, NULL, &err);
404 while (U_SUCCESS(err)) {
405 rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
406 dtCount++;
407 if (rbPattern.length()==0 ) {
408 break; // no more pattern
409 }
410 else {
411 if (dtCount==9) {
412 setDateTimeFormat(rbPattern);
413 }
414 }
415 };
416 ures_close(patBundle);
417
418 err = U_ZERO_ERROR;
419 patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAppendItemsTag, NULL, &err);
420 key=NULL;
421 UnicodeString itemKey;
422 while (U_SUCCESS(err)) {
423 rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
424 if (rbPattern.length()==0 ) {
425 break; // no more pattern
426 }
427 else {
428 setAppendItemFormat(getAppendFormatNumber(key), rbPattern);
429 }
430 }
431 ures_close(patBundle);
432
433 key=NULL;
434 err = U_ZERO_ERROR;
435 fBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeFieldsTag, NULL, &err);
436 for (i=0; i<MAX_RESOURCE_FIELD; ++i) {
437 err = U_ZERO_ERROR;
438 patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err);
439 fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err);
440 rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err);
441 ures_close(fieldBundle);
442 ures_close(patBundle);
443 if (rbPattern.length()==0 ) {
444 continue;
445 }
446 else {
447 setAppendItemName(getAppendNameNumber(Resource_Fields[i]), rbPattern);
448 }
449 }
450 ures_close(fBundle);
451
452 // add available formats
453 err = U_ZERO_ERROR;
454 initHashtable(err);
455 patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
456 if (U_SUCCESS(err)) {
457 int32_t numberKeys = ures_getSize(patBundle);
458 int32_t len;
459 const UChar *retPattern;
460 key=NULL;
461 for(i=0; i<numberKeys; ++i) {
462 retPattern=ures_getNextString(patBundle, &len, &key, &err);
463 UnicodeString format=UnicodeString(retPattern);
464 UnicodeString retKey=UnicodeString(key, -1, US_INV);
465 setAvailableFormat(retKey, err);
466 conflictingStatus = addPattern(format, FALSE, conflictingPattern, err);
467 }
468 }
469 ures_close(patBundle);
470 ures_close(gregorianBundle);
471 ures_close(calBundle);
472 ures_close(rb);
473
474 err = U_ZERO_ERROR;
475 char parentLocale[50];
476 const char *curLocaleName=locale.getName();
477 int32_t localeNameLen=0;
478 uprv_strcpy(parentLocale, curLocaleName);
479 while((localeNameLen=uloc_getParent(parentLocale, parentLocale, 50, &err))>=0 ) {
480 rb = ures_open(NULL, parentLocale, &err);
481 calBundle = ures_getByKey(rb, DT_DateTimeCalendarTag, NULL, &err);
482 gregorianBundle = ures_getByKey(calBundle, DT_DateTimeGregorianTag, NULL, &err);
483 patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
484 if (U_SUCCESS(err)) {
485 int32_t numberKeys = ures_getSize(patBundle);
486 int32_t len;
487 const UChar *retPattern;
488 key=NULL;
489
490 for(i=0; i<numberKeys; ++i) {
491 retPattern=ures_getNextString(patBundle, &len, &key, &err);
492 UnicodeString format=UnicodeString(retPattern);
493 UnicodeString retKey=UnicodeString(key, -1, US_INV);
494 if ( !isAvailableFormatSet(retKey) ) {
495 setAvailableFormat(retKey, err);
496 conflictingStatus = addPattern(format, FALSE, conflictingPattern, err);
497 }
498 }
499 }
500 ures_close(patBundle);
501 ures_close(gregorianBundle);
502 ures_close(calBundle);
503 ures_close(rb);
504 if (localeNameLen==0) {
505 break;
506 }
507 }
508
509 if (hackPattern.length()>0) {
510 hackTimes(hackPattern, err);
511 }
512 }
513
514 void
initHashtable(UErrorCode & err)515 DateTimePatternGenerator::initHashtable(UErrorCode& err) {
516 if (fAvailableFormatKeyHash!=NULL) {
517 return;
518 }
519 if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) {
520 err=U_MEMORY_ALLOCATION_ERROR;
521 return;
522 }
523 }
524
525
526 void
setAppendItemFormat(UDateTimePatternField field,const UnicodeString & value)527 DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) {
528 appendItemFormats[field] = value;
529 // NUL-terminate for the C API.
530 appendItemFormats[field].getTerminatedBuffer();
531 }
532
533 const UnicodeString&
getAppendItemFormat(UDateTimePatternField field) const534 DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const {
535 return appendItemFormats[field];
536 }
537
538 void
setAppendItemName(UDateTimePatternField field,const UnicodeString & value)539 DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) {
540 appendItemNames[field] = value;
541 // NUL-terminate for the C API.
542 appendItemNames[field].getTerminatedBuffer();
543 }
544
545 const UnicodeString&
getAppendItemName(UDateTimePatternField field) const546 DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const {
547 return appendItemNames[field];
548 }
549
550 void
getAppendName(UDateTimePatternField field,UnicodeString & value)551 DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
552 value = SINGLE_QUOTE;
553 value += appendItemNames[field];
554 value += SINGLE_QUOTE;
555 }
556
557 UnicodeString
getBestPattern(const UnicodeString & patternForm,UErrorCode & status)558 DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) {
559 const UnicodeString *bestPattern=NULL;
560 UnicodeString dtFormat;
561 UnicodeString resultPattern;
562
563 int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1;
564 int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;
565
566 resultPattern.remove();
567 dtMatcher->set(patternForm, fp);
568 bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo);
569 if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
570 resultPattern = adjustFieldTypes(*bestPattern, FALSE);
571
572 return resultPattern;
573 }
574 int32_t neededFields = dtMatcher->getFieldMask();
575 UnicodeString datePattern=getBestAppending(neededFields & dateMask);
576 UnicodeString timePattern=getBestAppending(neededFields & timeMask);
577 if (datePattern.length()==0) {
578 if (timePattern.length()==0) {
579 resultPattern.remove();
580 }
581 else {
582 return timePattern;
583 }
584 }
585 if (timePattern.length()==0) {
586 return datePattern;
587 }
588 resultPattern.remove();
589 status = U_ZERO_ERROR;
590 dtFormat=getDateTimeFormat();
591 Formattable dateTimeObject[] = { datePattern, timePattern };
592 resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status );
593 return resultPattern;
594 }
595
596 UnicodeString
replaceFieldTypes(const UnicodeString & pattern,const UnicodeString & skeleton,UErrorCode & status)597 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
598 const UnicodeString& skeleton,
599 UErrorCode& status) {
600 dtMatcher->set(skeleton, fp);
601 UnicodeString result = adjustFieldTypes(pattern, FALSE);
602 return result;
603 }
604
605 void
setDecimal(const UnicodeString & newDecimal)606 DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) {
607 this->decimal = newDecimal;
608 // NUL-terminate for the C API.
609 this->decimal.getTerminatedBuffer();
610 }
611
612 const UnicodeString&
getDecimal() const613 DateTimePatternGenerator::getDecimal() const {
614 return decimal;
615 }
616
617 void
addCanonicalItems()618 DateTimePatternGenerator::addCanonicalItems() {
619 UnicodeString conflictingPattern;
620 UDateTimePatternConflict conflictingStatus;
621 UErrorCode status = U_ZERO_ERROR;
622
623 for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) {
624 conflictingStatus = addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status);
625 }
626 }
627
628 void
setDateTimeFormat(const UnicodeString & dtFormat)629 DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) {
630 dateTimeFormat = dtFormat;
631 // NUL-terminate for the C API.
632 dateTimeFormat.getTerminatedBuffer();
633 }
634
635 const UnicodeString&
getDateTimeFormat() const636 DateTimePatternGenerator::getDateTimeFormat() const {
637 return dateTimeFormat;
638 }
639
640 void
setDateTimeFromCalendar(const Locale & locale,UErrorCode & status)641 DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
642 const UChar *resStr;
643 int32_t resStrLen = 0;
644
645 Calendar* fCalendar = Calendar::createInstance(locale, status);
646 CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
647 UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status);
648 if (U_FAILURE(status)) return;
649
650 if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime)
651 {
652 status = U_INVALID_FORMAT_ERROR;
653 return;
654 }
655 resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
656 setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
657
658 delete fCalendar;
659 }
660
661 void
setDecimalSymbols(const Locale & locale,UErrorCode & status)662 DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) {
663 DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status);
664 if(U_SUCCESS(status)) {
665 decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
666 // NUL-terminate for the C API.
667 decimal.getTerminatedBuffer();
668 }
669 }
670
671 UDateTimePatternConflict
addPattern(const UnicodeString & pattern,UBool override,UnicodeString & conflictingPattern,UErrorCode & status)672 DateTimePatternGenerator::addPattern(
673 const UnicodeString& pattern,
674 UBool override,
675 UnicodeString &conflictingPattern,
676 UErrorCode& status)
677 {
678
679 UnicodeString basePattern;
680 PtnSkeleton skeleton;
681 UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
682
683 DateTimeMatcher matcher;
684 matcher.set(pattern, fp, skeleton);
685 matcher.getBasePattern(basePattern);
686 const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern);
687 if (duplicatePattern != NULL ) {
688 conflictingStatus = UDATPG_BASE_CONFLICT;
689 conflictingPattern = *duplicatePattern;
690 if (!override) {
691 return conflictingStatus;
692 }
693 }
694 duplicatePattern = patternMap->getPatternFromSkeleton(skeleton);
695 if (duplicatePattern != NULL ) {
696 conflictingStatus = UDATPG_CONFLICT;
697 conflictingPattern = *duplicatePattern;
698 if (!override) {
699 return conflictingStatus;
700 }
701 }
702 patternMap->add(basePattern, skeleton, pattern, status);
703 if(U_FAILURE(status)) {
704 return conflictingStatus;
705 }
706
707 return UDATPG_NO_CONFLICT;
708 }
709
710
711 UDateTimePatternField
getAppendFormatNumber(const char * field) const712 DateTimePatternGenerator::getAppendFormatNumber(const char* field) const {
713 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
714 if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) {
715 return (UDateTimePatternField)i;
716 }
717 }
718 return UDATPG_FIELD_COUNT;
719 }
720
721 UDateTimePatternField
getAppendNameNumber(const char * field) const722 DateTimePatternGenerator::getAppendNameNumber(const char* field) const {
723 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
724 if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) {
725 return (UDateTimePatternField)i;
726 }
727 }
728 return UDATPG_FIELD_COUNT;
729 }
730
731 const UnicodeString*
getBestRaw(DateTimeMatcher & source,int32_t includeMask,DistanceInfo * missingFields)732 DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
733 int32_t includeMask,
734 DistanceInfo* missingFields) {
735 int32_t bestDistance = 0x7fffffff;
736 DistanceInfo tempInfo;
737 const UnicodeString *bestPattern=NULL;
738
739 PatternMapIterator it;
740 for (it.set(*patternMap); it.hasNext(); ) {
741 DateTimeMatcher trial = it.next();
742 if (trial.equals(skipMatcher)) {
743 continue;
744 }
745 int32_t distance=source.getDistance(trial, includeMask, tempInfo);
746 if (distance<bestDistance) {
747 bestDistance=distance;
748 bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr());
749 missingFields->setTo(tempInfo);
750 if (distance==0) {
751 break;
752 }
753 }
754 }
755
756 return bestPattern;
757 }
758
759 UnicodeString
adjustFieldTypes(const UnicodeString & pattern,UBool fixFractionalSeconds)760 DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
761 UBool fixFractionalSeconds) {
762 UnicodeString newPattern;
763 fp->set(pattern);
764 for (int32_t i=0; i < fp->itemNumber; i++) {
765 UnicodeString field = fp->items[i];
766 if ( fp->isQuoteLiteral(field) ) {
767
768 UnicodeString quoteLiteral;
769 fp->getQuoteLiteral(quoteLiteral, &i);
770 newPattern += quoteLiteral;
771 }
772 else {
773 if (fp->isPatternSeparator(field)) {
774 newPattern+=field;
775 continue;
776 }
777 int32_t canonicalIndex = fp->getCanonicalIndex(field);
778 if (canonicalIndex < 0) {
779 newPattern+=field;
780 continue; // don't adjust
781 }
782 const dtTypeElem *row = &dtTypes[canonicalIndex];
783 int32_t typeValue = row->field;
784 if (fixFractionalSeconds && typeValue == UDATPG_SECOND_FIELD) {
785 UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD];
786 field = field + decimal + newField;
787 }
788 else {
789 if (dtMatcher->skeleton.type[typeValue]!=0) {
790 UnicodeString newField=dtMatcher->skeleton.original[typeValue];
791 if (typeValue!= UDATPG_HOUR_FIELD) {
792 field=newField;
793 }
794 else {
795 if (field.length()!=newField.length()) {
796 UChar c=field.charAt(0);
797 field.remove();
798 for (int32_t i=newField.length(); i>0; --i) {
799 field+=c;
800 }
801 }
802 }
803 }
804 newPattern+=field;
805 }
806 }
807 }
808 return newPattern;
809 }
810
811 UnicodeString
getBestAppending(int32_t missingFields)812 DateTimePatternGenerator::getBestAppending(int32_t missingFields) {
813 UnicodeString resultPattern, tempPattern, formattedPattern;
814 UErrorCode err=U_ZERO_ERROR;
815 int32_t lastMissingFieldMask=0;
816 if (missingFields!=0) {
817 resultPattern=UnicodeString();
818 tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo);
819 resultPattern = adjustFieldTypes(tempPattern, FALSE);
820 if ( distanceInfo->missingFieldMask==0 ) {
821 return resultPattern;
822 }
823 while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work!
824 if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) {
825 break; // cannot find the proper missing field
826 }
827 if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) &&
828 ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) {
829 resultPattern = adjustFieldTypes(resultPattern, FALSE);
830 //resultPattern = tempPattern;
831 distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;
832 continue;
833 }
834 int32_t startingMask = distanceInfo->missingFieldMask;
835 tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo);
836 tempPattern = adjustFieldTypes(tempPattern, FALSE);
837 int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
838 int32_t topField=getTopBitNumber(foundMask);
839 UnicodeString appendName;
840 getAppendName((UDateTimePatternField)topField, appendName);
841 const Formattable formatPattern[] = {
842 resultPattern,
843 tempPattern,
844 appendName
845 };
846 formattedPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, resultPattern, err);
847 lastMissingFieldMask = distanceInfo->missingFieldMask;
848 }
849 }
850 return formattedPattern;
851 }
852
853 int32_t
getTopBitNumber(int32_t foundMask)854 DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
855 if ( foundMask==0 ) {
856 return 0;
857 }
858 int32_t i=0;
859 while (foundMask!=0) {
860 foundMask >>=1;
861 ++i;
862 }
863 if (i-1 >UDATPG_ZONE_FIELD) {
864 return UDATPG_ZONE_FIELD;
865 }
866 else
867 return i-1;
868 }
869
870 void
setAvailableFormat(const UnicodeString & key,UErrorCode & err)871 DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)
872 {
873 fAvailableFormatKeyHash->puti(key, 1, err);
874 }
875
876 UBool
isAvailableFormatSet(const UnicodeString & key) const877 DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
878 return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);
879 }
880
881 void
copyHashtable(Hashtable * other)882 DateTimePatternGenerator::copyHashtable(Hashtable *other) {
883
884 if (fAvailableFormatKeyHash !=NULL) {
885 delete fAvailableFormatKeyHash;
886 }
887 if (other == NULL) {
888 fAvailableFormatKeyHash = NULL;
889 return;
890 }
891 initHashtable(fStatus);
892 if(U_FAILURE(fStatus)){
893 return;
894 }
895 int32_t pos = -1;
896 const UHashElement* elem = NULL;
897 // walk through the hash table and create a deep clone
898 while((elem = other->nextElement(pos))!= NULL){
899 const UHashTok otherKeyTok = elem->key;
900 UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
901 fAvailableFormatKeyHash->puti(*otherKey, 1, fStatus);
902 if(U_FAILURE(fStatus)){
903 return;
904 }
905 }
906 }
907
908 StringEnumeration*
getSkeletons(UErrorCode & status) const909 DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
910 StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status);
911 return skeletonEnumerator;
912 }
913
914 const UnicodeString&
getPatternForSkeleton(const UnicodeString & skeleton) const915 DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const {
916 PtnElem *curElem;
917
918 if (skeleton.length() ==0) {
919 return emptyString;
920 }
921 curElem = patternMap->getHeader(skeleton.charAt(0));
922 while ( curElem != NULL ) {
923 if ( curElem->skeleton->getSkeleton()==skeleton ) {
924 return curElem->pattern;
925 }
926 curElem=curElem->next;
927 }
928 return emptyString;
929 }
930
931 StringEnumeration*
getBaseSkeletons(UErrorCode & status) const932 DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
933 StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status);
934 return baseSkeletonEnumerator;
935 }
936
937 StringEnumeration*
getRedundants(UErrorCode & status)938 DateTimePatternGenerator::getRedundants(UErrorCode& status) {
939 StringEnumeration* output = new DTRedundantEnumeration();
940 const UnicodeString *pattern;
941 PatternMapIterator it;
942 for (it.set(*patternMap); it.hasNext(); ) {
943 DateTimeMatcher current = it.next();
944 pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
945 if ( isCanonicalItem(*pattern) ) {
946 continue;
947 }
948 if ( skipMatcher == NULL ) {
949 skipMatcher = new DateTimeMatcher(current);
950 }
951 else {
952 *skipMatcher = current;
953 }
954 UnicodeString trial = getBestPattern(current.getPattern(), status);
955 if (trial == *pattern) {
956 ((DTRedundantEnumeration *)output)->add(*pattern, status);
957 }
958 if (current.equals(skipMatcher)) {
959 continue;
960 }
961 }
962 return output;
963 }
964
965 UBool
isCanonicalItem(const UnicodeString & item) const966 DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const {
967 if ( item.length() != 1 ) {
968 return FALSE;
969 }
970 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
971 if (item.charAt(0)==Canonical_Items[i]) {
972 return TRUE;
973 }
974 }
975 return FALSE;
976 }
977
978
979 DateTimePatternGenerator*
clone() const980 DateTimePatternGenerator::clone() const {
981 return new DateTimePatternGenerator(*this);
982 }
983
PatternMap()984 PatternMap::PatternMap() {
985 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
986 boot[i]=NULL;
987 }
988 isDupAllowed = TRUE;
989 }
990
991 void
copyFrom(const PatternMap & other,UErrorCode & status)992 PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
993 this->isDupAllowed = other.isDupAllowed;
994 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
995 PtnElem *curElem, *otherElem, *prevElem=NULL;
996 otherElem = other.boot[bootIndex];
997 while (otherElem!=NULL) {
998 if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) {
999 // out of memory
1000 status = U_MEMORY_ALLOCATION_ERROR;
1001 return;
1002 }
1003 if ( this->boot[bootIndex]== NULL ) {
1004 this->boot[bootIndex] = curElem;
1005 }
1006 if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) {
1007 // out of memory
1008 status = U_MEMORY_ALLOCATION_ERROR;
1009 return;
1010 }
1011
1012 if (prevElem!=NULL) {
1013 prevElem->next=curElem;
1014 }
1015 curElem->next=NULL;
1016 prevElem = curElem;
1017 otherElem = otherElem->next;
1018 }
1019
1020 }
1021 }
1022
1023 PtnElem*
getHeader(UChar baseChar)1024 PatternMap::getHeader(UChar baseChar) {
1025 PtnElem* curElem;
1026
1027 if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
1028 curElem = boot[baseChar-CAP_A];
1029 }
1030 else {
1031 if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) {
1032 curElem = boot[26+baseChar-LOW_A];
1033 }
1034 else {
1035 return NULL;
1036 }
1037 }
1038 return curElem;
1039 }
1040
~PatternMap()1041 PatternMap::~PatternMap() {
1042 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
1043 if (boot[i]!=NULL ) {
1044 delete boot[i];
1045 boot[i]=NULL;
1046 }
1047 }
1048 } // PatternMap destructor
1049
1050 void
add(const UnicodeString & basePattern,const PtnSkeleton & skeleton,const UnicodeString & value,UErrorCode & status)1051 PatternMap::add(const UnicodeString& basePattern,
1052 const PtnSkeleton& skeleton,
1053 const UnicodeString& value,// mapped pattern value
1054 UErrorCode &status) {
1055 UChar baseChar = basePattern.charAt(0);
1056 PtnElem *curElem, *baseElem;
1057 status = U_ZERO_ERROR;
1058
1059 // the baseChar must be A-Z or a-z
1060 if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) {
1061 baseElem = boot[baseChar-CAP_A];
1062 }
1063 else {
1064 if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) {
1065 baseElem = boot[26+baseChar-LOW_A];
1066 }
1067 else {
1068 status = U_ILLEGAL_CHARACTER;
1069 return;
1070 }
1071 }
1072
1073 if (baseElem == NULL) {
1074 if ((curElem = new PtnElem(basePattern, value)) == NULL ) {
1075 // out of memory
1076 status = U_MEMORY_ALLOCATION_ERROR;
1077 return;
1078 }
1079 if (baseChar >= LOW_A) {
1080 boot[26 + (baseChar-LOW_A)] = curElem;
1081 }
1082 else {
1083 boot[baseChar-CAP_A] = curElem;
1084 }
1085 curElem->skeleton = new PtnSkeleton(skeleton);
1086 }
1087 if ( baseElem != NULL ) {
1088 curElem = getDuplicateElem(basePattern, skeleton, baseElem);
1089
1090 if (curElem == NULL) {
1091 // add new element to the list.
1092 curElem = baseElem;
1093 while( curElem -> next != NULL )
1094 {
1095 curElem = curElem->next;
1096 }
1097 if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) {
1098 // out of memory
1099 status = U_MEMORY_ALLOCATION_ERROR;
1100 return;
1101 }
1102 curElem=curElem->next;
1103 curElem->skeleton = new PtnSkeleton(skeleton);
1104 }
1105 else {
1106 // Pattern exists in the list already.
1107 if ( !isDupAllowed ) {
1108 return;
1109 }
1110 // Overwrite the value.
1111 curElem->pattern = value;
1112 }
1113 }
1114 } // PatternMap::add
1115
1116 // Find the pattern from the given basePattern string.
1117 const UnicodeString *
getPatternFromBasePattern(UnicodeString & basePattern)1118 PatternMap::getPatternFromBasePattern(UnicodeString& basePattern) { // key to search for
1119 PtnElem *curElem;
1120
1121 if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
1122 return NULL; // no match
1123 }
1124
1125 do {
1126 if ( basePattern.compare(curElem->basePattern)==0 ) {
1127 return &(curElem->pattern);
1128 }
1129 curElem=curElem->next;
1130 }while (curElem != NULL);
1131
1132 return NULL;
1133 } // PatternMap::getFromBasePattern
1134
1135
1136 // Find the pattern from the given skeleton.
1137 const UnicodeString *
getPatternFromSkeleton(PtnSkeleton & skeleton)1138 PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton) { // key to search for
1139 PtnElem *curElem;
1140
1141 // find boot entry
1142 UChar baseChar='\0';
1143 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1144 if (skeleton.baseOriginal[i].length() !=0 ) {
1145 baseChar = skeleton.baseOriginal[i].charAt(0);
1146 break;
1147 }
1148 }
1149
1150 if ((curElem=getHeader(baseChar))==NULL) {
1151 return NULL; // no match
1152 }
1153
1154 do {
1155 int32_t i=0;
1156 for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
1157 if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 )
1158 {
1159 break;
1160 }
1161 }
1162 if (i == UDATPG_FIELD_COUNT) {
1163 return &(curElem->pattern);
1164 }
1165 curElem=curElem->next;
1166 }while (curElem != NULL);
1167
1168 return NULL;
1169 }
1170
1171 UBool
equals(const PatternMap & other)1172 PatternMap::equals(const PatternMap& other) {
1173 if ( this==&other ) {
1174 return TRUE;
1175 }
1176 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
1177 if ( boot[bootIndex]==other.boot[bootIndex] ) {
1178 continue;
1179 }
1180 if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) {
1181 return FALSE;
1182 }
1183 PtnElem *otherElem = other.boot[bootIndex];
1184 PtnElem *myElem = boot[bootIndex];
1185 while ((otherElem!=NULL) || (myElem!=NULL)) {
1186 if ( myElem == otherElem ) {
1187 break;
1188 }
1189 if ((otherElem==NULL) || (myElem==NULL)) {
1190 return FALSE;
1191 }
1192 if ( (myElem->basePattern != otherElem->basePattern) ||
1193 (myElem->pattern != otherElem->pattern) ) {
1194 return FALSE;
1195 }
1196 if ((myElem->skeleton!=otherElem->skeleton)&&
1197 !myElem->skeleton->equals(*(otherElem->skeleton))) {
1198 return FALSE;
1199 }
1200 myElem = myElem->next;
1201 otherElem=otherElem->next;
1202 }
1203 }
1204 return TRUE;
1205 }
1206
1207 // find any key existing in the mapping table already.
1208 // return TRUE if there is an existing key, otherwise return FALSE.
1209 PtnElem*
getDuplicateElem(const UnicodeString & basePattern,const PtnSkeleton & skeleton,PtnElem * baseElem)1210 PatternMap::getDuplicateElem(
1211 const UnicodeString &basePattern,
1212 const PtnSkeleton &skeleton,
1213 PtnElem *baseElem) {
1214 PtnElem *curElem;
1215
1216 if ( baseElem == (PtnElem *)NULL ) {
1217 return (PtnElem*)NULL;
1218 }
1219 else {
1220 curElem = baseElem;
1221 }
1222 do {
1223 if ( basePattern.compare(curElem->basePattern)==0 ) {
1224 UBool isEqual=TRUE;
1225 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1226 if (curElem->skeleton->type[i] != skeleton.type[i] ) {
1227 isEqual=FALSE;
1228 break;
1229 }
1230 }
1231 if (isEqual) {
1232 return curElem;
1233 }
1234 }
1235 curElem = curElem->next;
1236 } while( curElem != (PtnElem *)NULL );
1237
1238 // end of the list
1239 return (PtnElem*)NULL;
1240
1241 } // PatternMap::getDuplicateElem
1242
DateTimeMatcher(void)1243 DateTimeMatcher::DateTimeMatcher(void) {
1244 }
1245
DateTimeMatcher(const DateTimeMatcher & other)1246 DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) {
1247 copyFrom(other.skeleton);
1248 }
1249
1250
1251 void
set(const UnicodeString & pattern,FormatParser * fp)1252 DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) {
1253 PtnSkeleton localSkeleton;
1254 return set(pattern, fp, localSkeleton);
1255 }
1256
1257 void
set(const UnicodeString & pattern,FormatParser * fp,PtnSkeleton & skeletonResult)1258 DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) {
1259 int32_t i;
1260 for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
1261 skeletonResult.type[i]=NONE;
1262 }
1263 fp->set(pattern);
1264 for (i=0; i < fp->itemNumber; i++) {
1265 UnicodeString field = fp->items[i];
1266 if ( field.charAt(0) == LOW_A ) {
1267 continue; // skip 'a'
1268 }
1269
1270 if ( fp->isQuoteLiteral(field) ) {
1271 UnicodeString quoteLiteral;
1272 fp->getQuoteLiteral(quoteLiteral, &i);
1273 continue;
1274 }
1275 int32_t canonicalIndex = fp->getCanonicalIndex(field);
1276 if (canonicalIndex < 0 ) {
1277 continue;
1278 }
1279 const dtTypeElem *row = &dtTypes[canonicalIndex];
1280 int32_t typeValue = row->field;
1281 skeletonResult.original[typeValue]=field;
1282 UChar repeatChar = row->patternChar;
1283 int32_t repeatCount = row->minLen > 3 ? 3: row->minLen;
1284 while (repeatCount-- > 0) {
1285 skeletonResult.baseOriginal[typeValue] += repeatChar;
1286 }
1287 int16_t subTypeValue = row->type;
1288 if ( row->type > 0) {
1289 subTypeValue += field.length();
1290 }
1291 skeletonResult.type[typeValue] = (int8_t)subTypeValue;
1292 }
1293 copyFrom(skeletonResult);
1294 }
1295
1296 void
getBasePattern(UnicodeString & result)1297 DateTimeMatcher::getBasePattern(UnicodeString &result ) {
1298 result.remove(); // Reset the result first.
1299 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1300 if (skeleton.baseOriginal[i].length()!=0) {
1301 result += skeleton.baseOriginal[i];
1302 }
1303 }
1304 }
1305
1306 UnicodeString
getPattern()1307 DateTimeMatcher::getPattern() {
1308 UnicodeString result;
1309
1310 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1311 if (skeleton.original[i].length()!=0) {
1312 result += skeleton.original[i];
1313 }
1314 }
1315 return result;
1316 }
1317
1318 int32_t
getDistance(const DateTimeMatcher & other,int32_t includeMask,DistanceInfo & distanceInfo)1319 DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) {
1320 int32_t result=0;
1321 distanceInfo.clear();
1322 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1323 int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
1324 int32_t otherType = other.skeleton.type[i];
1325 if (myType==otherType) {
1326 continue;
1327 }
1328 if (myType==0) {// and other is not
1329 result += EXTRA_FIELD;
1330 distanceInfo.addExtra(i);
1331 }
1332 else {
1333 if (otherType==0) {
1334 result += MISSING_FIELD;
1335 distanceInfo.addMissing(i);
1336 }
1337 else {
1338 result += abs(myType - otherType);
1339 }
1340 }
1341
1342 }
1343 return result;
1344 }
1345
1346 void
copyFrom(const PtnSkeleton & newSkeleton)1347 DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) {
1348 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1349 this->skeleton.type[i]=newSkeleton.type[i];
1350 this->skeleton.original[i]=newSkeleton.original[i];
1351 this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i];
1352 }
1353 }
1354
1355 void
copyFrom()1356 DateTimeMatcher::copyFrom() {
1357 // same as clear
1358 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1359 this->skeleton.type[i]=0;
1360 this->skeleton.original[i].remove();
1361 this->skeleton.baseOriginal[i].remove();
1362 }
1363 }
1364
1365 UBool
equals(const DateTimeMatcher * other) const1366 DateTimeMatcher::equals(const DateTimeMatcher* other) const {
1367 if (other==NULL) {
1368 return FALSE;
1369 }
1370 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1371 if (this->skeleton.original[i]!=other->skeleton.original[i] ) {
1372 return FALSE;
1373 }
1374 }
1375 return TRUE;
1376 }
1377
1378 int32_t
getFieldMask()1379 DateTimeMatcher::getFieldMask() {
1380 int32_t result=0;
1381
1382 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1383 if (skeleton.type[i]!=0) {
1384 result |= (1<<i);
1385 }
1386 }
1387 return result;
1388 }
1389
1390 PtnSkeleton*
getSkeletonPtr()1391 DateTimeMatcher::getSkeletonPtr() {
1392 return &skeleton;
1393 }
1394
FormatParser()1395 FormatParser::FormatParser () {
1396 status = START;
1397 itemNumber=0;
1398 }
1399
1400
~FormatParser()1401 FormatParser::~FormatParser () {
1402 }
1403
1404
1405 // Find the next token with the starting position and length
1406 // Note: the startPos may
1407 FormatParser::TokenStatus
setTokens(const UnicodeString & pattern,int32_t startPos,int32_t * len)1408 FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
1409 int32_t curLoc = startPos;
1410 if ( curLoc >= pattern.length()) {
1411 return DONE;
1412 }
1413 // check the current char is between A-Z or a-z
1414 do {
1415 UChar c=pattern.charAt(curLoc);
1416 if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) {
1417 curLoc++;
1418 }
1419 else {
1420 startPos = curLoc;
1421 *len=1;
1422 return ADD_TOKEN;
1423 }
1424
1425 if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) {
1426 break; // not the same token
1427 }
1428 } while(curLoc <= pattern.length());
1429 *len = curLoc-startPos;
1430 return ADD_TOKEN;
1431 }
1432
1433 void
set(const UnicodeString & pattern)1434 FormatParser::set(const UnicodeString& pattern) {
1435 int32_t startPos=0;
1436 TokenStatus result=START;
1437 int32_t len=0;
1438 itemNumber =0;
1439
1440 do {
1441 result = setTokens( pattern, startPos, &len );
1442 if ( result == ADD_TOKEN )
1443 {
1444 items[itemNumber++] = UnicodeString(pattern, startPos, len );
1445 startPos += len;
1446 }
1447 else {
1448 break;
1449 }
1450 } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN);
1451 }
1452
1453 int32_t
getCanonicalIndex(const UnicodeString & s)1454 FormatParser::getCanonicalIndex(const UnicodeString& s) {
1455 int32_t len = s.length();
1456 UChar ch = s.charAt(0);
1457 int32_t i=0;
1458
1459 while (dtTypes[i].patternChar!='\0') {
1460 if ( dtTypes[i].patternChar!=ch ) {
1461 ++i;
1462 continue;
1463 }
1464 if (dtTypes[i].patternChar!=dtTypes[i+1].patternChar) {
1465 return i;
1466 }
1467 if (dtTypes[i+1].minLen <= len) {
1468 ++i;
1469 continue;
1470 }
1471 return i;
1472 }
1473 return -1;
1474 }
1475
1476 UBool
isQuoteLiteral(const UnicodeString & s) const1477 FormatParser::isQuoteLiteral(const UnicodeString& s) const {
1478 return (UBool)(s.charAt(0)==SINGLE_QUOTE);
1479 }
1480
1481 // This function aussumes the current itemIndex points to the quote literal.
1482 // Please call isQuoteLiteral prior to this function.
1483 void
getQuoteLiteral(UnicodeString & quote,int32_t * itemIndex)1484 FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
1485 int32_t i=*itemIndex;
1486
1487 quote.remove();
1488 if (items[i].charAt(0)==SINGLE_QUOTE) {
1489 quote += items[i];
1490 ++i;
1491 }
1492 while ( i < itemNumber ) {
1493 if ( items[i].charAt(0)==SINGLE_QUOTE ) {
1494 if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) {
1495 // two single quotes e.g. 'o''clock'
1496 quote += items[i++];
1497 quote += items[i++];
1498 continue;
1499 }
1500 else {
1501 quote += items[i];
1502 break;
1503 }
1504 }
1505 else {
1506 quote += items[i];
1507 }
1508 ++i;
1509 }
1510 *itemIndex=i;
1511 }
1512
1513 UBool
isPatternSeparator(UnicodeString & field)1514 FormatParser::isPatternSeparator(UnicodeString& field) {
1515 for (int32_t i=0; i<field.length(); ++i ) {
1516 UChar c= field.charAt(i);
1517 if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
1518 (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) {
1519 continue;
1520 }
1521 else {
1522 return FALSE;
1523 }
1524 }
1525 return TRUE;
1526 }
1527
1528 void
setTo(DistanceInfo & other)1529 DistanceInfo::setTo(DistanceInfo &other) {
1530 missingFieldMask = other.missingFieldMask;
1531 extraFieldMask= other.extraFieldMask;
1532 }
1533
PatternMapIterator()1534 PatternMapIterator::PatternMapIterator() {
1535 bootIndex = 0;
1536 nodePtr = NULL;
1537 patternMap=NULL;
1538 matcher= new DateTimeMatcher();
1539 }
1540
1541
~PatternMapIterator()1542 PatternMapIterator::~PatternMapIterator() {
1543 delete matcher;
1544 }
1545
1546 void
set(PatternMap & newPatternMap)1547 PatternMapIterator::set(PatternMap& newPatternMap) {
1548 this->patternMap=&newPatternMap;
1549 }
1550
1551 PtnSkeleton*
getSkeleton()1552 PatternMapIterator::getSkeleton() {
1553 if ( nodePtr == NULL ) {
1554 return NULL;
1555 }
1556 else {
1557 return nodePtr->skeleton;
1558 }
1559 }
1560
1561 UBool
hasNext()1562 PatternMapIterator::hasNext() {
1563 int32_t headIndex=bootIndex;
1564 PtnElem *curPtr=nodePtr;
1565
1566 if (patternMap==NULL) {
1567 return FALSE;
1568 }
1569 while ( headIndex < MAX_PATTERN_ENTRIES ) {
1570 if ( curPtr != NULL ) {
1571 if ( curPtr->next != NULL ) {
1572 return TRUE;
1573 }
1574 else {
1575 headIndex++;
1576 curPtr=NULL;
1577 continue;
1578 }
1579 }
1580 else {
1581 if ( patternMap->boot[headIndex] != NULL ) {
1582 return TRUE;
1583 }
1584 else {
1585 headIndex++;
1586 continue;
1587 }
1588 }
1589
1590 }
1591 return FALSE;
1592 }
1593
1594 DateTimeMatcher&
next()1595 PatternMapIterator::next() {
1596 while ( bootIndex < MAX_PATTERN_ENTRIES ) {
1597 if ( nodePtr != NULL ) {
1598 if ( nodePtr->next != NULL ) {
1599 nodePtr = nodePtr->next;
1600 break;
1601 }
1602 else {
1603 bootIndex++;
1604 nodePtr=NULL;
1605 continue;
1606 }
1607 }
1608 else {
1609 if ( patternMap->boot[bootIndex] != NULL ) {
1610 nodePtr = patternMap->boot[bootIndex];
1611 break;
1612 }
1613 else {
1614 bootIndex++;
1615 continue;
1616 }
1617 }
1618 }
1619 if (nodePtr!=NULL) {
1620 matcher->copyFrom(*nodePtr->skeleton);
1621 }
1622 else {
1623 matcher->copyFrom();
1624 }
1625 return *matcher;
1626 }
1627
PtnSkeleton()1628 PtnSkeleton::PtnSkeleton() {
1629 }
1630
1631
PtnSkeleton(const PtnSkeleton & other)1632 PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) {
1633 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1634 this->type[i]=other.type[i];
1635 this->original[i]=other.original[i];
1636 this->baseOriginal[i]=other.baseOriginal[i];
1637 }
1638 }
1639
1640 UBool
equals(const PtnSkeleton & other)1641 PtnSkeleton::equals(const PtnSkeleton& other) {
1642 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1643 if ( (type[i]!= other.type[i]) ||
1644 (original[i]!=other.original[i]) ||
1645 (baseOriginal[i]!=other.baseOriginal[i]) ) {
1646 return FALSE;
1647 }
1648 }
1649 return TRUE;
1650 }
1651
1652 UnicodeString
getSkeleton()1653 PtnSkeleton::getSkeleton() {
1654 UnicodeString result;
1655
1656 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
1657 if (original[i].length()!=0) {
1658 result += original[i];
1659 }
1660 }
1661 return result;
1662 }
1663
1664 UnicodeString
getBaseSkeleton()1665 PtnSkeleton::getBaseSkeleton() {
1666 UnicodeString result;
1667
1668 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
1669 if (baseOriginal[i].length()!=0) {
1670 result += baseOriginal[i];
1671 }
1672 }
1673 return result;
1674 }
1675
~PtnSkeleton()1676 PtnSkeleton::~PtnSkeleton() {
1677 }
1678
PtnElem(const UnicodeString & basePat,const UnicodeString & pat)1679 PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
1680 basePattern(basePat),
1681 skeleton(NULL),
1682 pattern(pat),
1683 next(NULL)
1684 {
1685 }
1686
~PtnElem()1687 PtnElem::~PtnElem() {
1688
1689 if (next!=NULL) {
1690 delete next;
1691 }
1692 delete skeleton;
1693 }
1694
DTSkeletonEnumeration(PatternMap & patternMap,dtStrEnum type,UErrorCode & status)1695 DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) {
1696 PtnElem *curElem;
1697 PtnSkeleton *curSkeleton;
1698 UnicodeString s;
1699 int32_t bootIndex;
1700
1701 pos=0;
1702 fSkeletons = new UVector(status);
1703 if (U_FAILURE(status)) {
1704 delete fSkeletons;
1705 return;
1706 }
1707 for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
1708 curElem = patternMap.boot[bootIndex];
1709 while (curElem!=NULL) {
1710 switch(type) {
1711 case DT_BASESKELETON:
1712 s=curElem->basePattern;
1713 break;
1714 case DT_PATTERN:
1715 s=curElem->pattern;
1716 break;
1717 case DT_SKELETON:
1718 curSkeleton=curElem->skeleton;
1719 s=curSkeleton->getSkeleton();
1720 break;
1721 }
1722 if ( !isCanonicalItem(s) ) {
1723 fSkeletons->addElement(new UnicodeString(s), status);
1724 if (U_FAILURE(status)) {
1725 delete fSkeletons;
1726 fSkeletons = NULL;
1727 return;
1728 }
1729 }
1730 curElem = curElem->next;
1731 }
1732 }
1733 if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) {
1734 status = U_BUFFER_OVERFLOW_ERROR;
1735 }
1736 }
1737
1738 const UnicodeString*
snext(UErrorCode & status)1739 DTSkeletonEnumeration::snext(UErrorCode& status) {
1740 if (U_SUCCESS(status) && pos < fSkeletons->size()) {
1741 return (const UnicodeString*)fSkeletons->elementAt(pos++);
1742 }
1743 return NULL;
1744 }
1745
1746 void
reset(UErrorCode &)1747 DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
1748 pos=0;
1749 }
1750
1751 int32_t
count(UErrorCode &) const1752 DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
1753 return (fSkeletons==NULL) ? 0 : fSkeletons->size();
1754 }
1755
1756 UBool
isCanonicalItem(const UnicodeString & item)1757 DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
1758 if ( item.length() != 1 ) {
1759 return FALSE;
1760 }
1761 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1762 if (item.charAt(0)==Canonical_Items[i]) {
1763 return TRUE;
1764 }
1765 }
1766 return FALSE;
1767 }
1768
~DTSkeletonEnumeration()1769 DTSkeletonEnumeration::~DTSkeletonEnumeration() {
1770 UnicodeString *s;
1771 for (int32_t i=0; i<fSkeletons->size(); ++i) {
1772 if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) {
1773 delete s;
1774 }
1775 }
1776 delete fSkeletons;
1777 }
1778
DTRedundantEnumeration()1779 DTRedundantEnumeration::DTRedundantEnumeration() {
1780 pos=0;
1781 fPatterns = NULL;
1782 }
1783
1784 void
add(const UnicodeString & pattern,UErrorCode & status)1785 DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
1786 if (U_FAILURE(status)) return;
1787 if (fPatterns == NULL) {
1788 fPatterns = new UVector(status);
1789 if (U_FAILURE(status)) {
1790 delete fPatterns;
1791 fPatterns = NULL;
1792 return;
1793 }
1794 }
1795 fPatterns->addElement(new UnicodeString(pattern), status);
1796 if (U_FAILURE(status)) {
1797 delete fPatterns;
1798 fPatterns = NULL;
1799 return;
1800 }
1801 }
1802
1803 const UnicodeString*
snext(UErrorCode & status)1804 DTRedundantEnumeration::snext(UErrorCode& status) {
1805 if (U_SUCCESS(status) && pos < fPatterns->size()) {
1806 return (const UnicodeString*)fPatterns->elementAt(pos++);
1807 }
1808 return NULL;
1809 }
1810
1811 void
reset(UErrorCode &)1812 DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
1813 pos=0;
1814 }
1815
1816 int32_t
count(UErrorCode &) const1817 DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
1818 return (fPatterns==NULL) ? 0 : fPatterns->size();
1819 }
1820
1821 UBool
isCanonicalItem(const UnicodeString & item)1822 DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
1823 if ( item.length() != 1 ) {
1824 return FALSE;
1825 }
1826 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1827 if (item.charAt(0)==Canonical_Items[i]) {
1828 return TRUE;
1829 }
1830 }
1831 return FALSE;
1832 }
1833
~DTRedundantEnumeration()1834 DTRedundantEnumeration::~DTRedundantEnumeration() {
1835 UnicodeString *s;
1836 for (int32_t i=0; i<fPatterns->size(); ++i) {
1837 if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) {
1838 delete s;
1839 }
1840 }
1841 delete fPatterns;
1842 }
1843
1844 U_NAMESPACE_END
1845
1846
1847 #endif /* #if !UCONFIG_NO_FORMATTING */
1848
1849 //eof
1850