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