• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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