intl/icu/source/i18n/dtptngen.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/dtptngen.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2219 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +* Copyright (C) 2007-2013, International Business Machines Corporation and
     1.7 +* others. All Rights Reserved.
     1.8 +*******************************************************************************
     1.9 +*
    1.10 +* File DTPTNGEN.CPP
    1.11 +*
    1.12 +*******************************************************************************
    1.13 +*/
    1.14 +
    1.15 +#include "unicode/utypes.h"
    1.16 +#if !UCONFIG_NO_FORMATTING
    1.17 +
    1.18 +#include "unicode/datefmt.h"
    1.19 +#include "unicode/decimfmt.h"
    1.20 +#include "unicode/dtfmtsym.h"
    1.21 +#include "unicode/dtptngen.h"
    1.22 +#include "unicode/msgfmt.h"
    1.23 +#include "unicode/smpdtfmt.h"
    1.24 +#include "unicode/udat.h"
    1.25 +#include "unicode/udatpg.h"
    1.26 +#include "unicode/uniset.h"
    1.27 +#include "unicode/uloc.h"
    1.28 +#include "unicode/ures.h"
    1.29 +#include "unicode/ustring.h"
    1.30 +#include "unicode/rep.h"
    1.31 +#include "cpputils.h"
    1.32 +#include "ucln_in.h"
    1.33 +#include "mutex.h"
    1.34 +#include "cmemory.h"
    1.35 +#include "cstring.h"
    1.36 +#include "locbased.h"
    1.37 +#include "gregoimp.h"
    1.38 +#include "hash.h"
    1.39 +#include "uresimp.h"
    1.40 +#include "dtptngen_impl.h"
    1.41 +
    1.42 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
    1.43 +
    1.44 +#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
    1.45 +/**
    1.46 + * If we are on EBCDIC, use an iterator which will
    1.47 + * traverse the bundles in ASCII order.
    1.48 + */
    1.49 +#define U_USE_ASCII_BUNDLE_ITERATOR
    1.50 +#define U_SORT_ASCII_BUNDLE_ITERATOR
    1.51 +#endif
    1.52 +
    1.53 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
    1.54 +
    1.55 +#include "unicode/ustring.h"
    1.56 +#include "uarrsort.h"
    1.57 +
    1.58 +struct UResAEntry {
    1.59 +    UChar *key;
    1.60 +    UResourceBundle *item;
    1.61 +};
    1.62 +
    1.63 +struct UResourceBundleAIterator {
    1.64 +    UResourceBundle  *bund;
    1.65 +    UResAEntry *entries;
    1.66 +    int32_t num;
    1.67 +    int32_t cursor;
    1.68 +};
    1.69 +
    1.70 +/* Must be C linkage to pass function pointer to the sort function */
    1.71 +
    1.72 +U_CDECL_BEGIN
    1.73 +
    1.74 +static int32_t U_CALLCONV
    1.75 +ures_a_codepointSort(const void *context, const void *left, const void *right) {
    1.76 +    //CompareContext *cmp=(CompareContext *)context;
    1.77 +    return u_strcmp(((const UResAEntry *)left)->key,
    1.78 +                    ((const UResAEntry *)right)->key);
    1.79 +}
    1.80 +
    1.81 +U_CDECL_END
    1.82 +
    1.83 +static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, UErrorCode *status) {
    1.84 +    if(U_FAILURE(*status)) {
    1.85 +        return;
    1.86 +    }
    1.87 +    aiter->bund = bund;
    1.88 +    aiter->num = ures_getSize(aiter->bund);
    1.89 +    aiter->cursor = 0;
    1.90 +#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
    1.91 +    aiter->entries = NULL;
    1.92 +#else
    1.93 +    aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);
    1.94 +    for(int i=0;i<aiter->num;i++) {
    1.95 +        aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status);
    1.96 +        const char *akey = ures_getKey(aiter->entries[i].item);
    1.97 +        int32_t len = uprv_strlen(akey)+1;
    1.98 +        aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));
    1.99 +        u_charsToUChars(akey, aiter->entries[i].key, len);
   1.100 +    }
   1.101 +    uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status);
   1.102 +#endif
   1.103 +}
   1.104 +
   1.105 +static void ures_a_close(UResourceBundleAIterator *aiter) {
   1.106 +#if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
   1.107 +    for(int i=0;i<aiter->num;i++) {
   1.108 +        uprv_free(aiter->entries[i].key);
   1.109 +        ures_close(aiter->entries[i].item);
   1.110 +    }
   1.111 +#endif
   1.112 +}
   1.113 +
   1.114 +static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_t *len, const char **key, UErrorCode *err) {
   1.115 +#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
   1.116 +    return ures_getNextString(aiter->bund, len, key, err);
   1.117 +#else
   1.118 +    if(U_FAILURE(*err)) return NULL;
   1.119 +    UResourceBundle *item = aiter->entries[aiter->cursor].item;
   1.120 +    const UChar* ret = ures_getString(item, len, err);
   1.121 +    *key = ures_getKey(item);
   1.122 +    aiter->cursor++;
   1.123 +    return ret;
   1.124 +#endif
   1.125 +}
   1.126 +
   1.127 +
   1.128 +#endif
   1.129 +
   1.130 +
   1.131 +U_NAMESPACE_BEGIN
   1.132 +
   1.133 +
   1.134 +// *****************************************************************************
   1.135 +// class DateTimePatternGenerator
   1.136 +// *****************************************************************************
   1.137 +static const UChar Canonical_Items[] = {
   1.138 +    // GyQMwWEdDFHmsSv
   1.139 +    CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E, LOW_D, CAP_D, CAP_F,
   1.140 +    CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
   1.141 +};
   1.142 +
   1.143 +static const dtTypeElem dtTypes[] = {
   1.144 +    // patternChar, field, type, minLen, weight
   1.145 +    {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,},
   1.146 +    {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
   1.147 +    {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20},
   1.148 +    {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20},
   1.149 +    {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20},
   1.150 +    {CAP_U, UDATPG_YEAR_FIELD, DT_SHORT, 1, 3},
   1.151 +    {CAP_U, UDATPG_YEAR_FIELD, DT_LONG, 4, 0},
   1.152 +    {CAP_U, UDATPG_YEAR_FIELD, DT_NARROW, 5, 0},
   1.153 +    {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2},
   1.154 +    {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0},
   1.155 +    {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0},
   1.156 +    {LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
   1.157 +    {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT + DT_DELTA, 3, 0},
   1.158 +    {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG + DT_DELTA, 4, 0},
   1.159 +    {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2},
   1.160 +    {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0},
   1.161 +    {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0},
   1.162 +    {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0},
   1.163 +    {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
   1.164 +    {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0},
   1.165 +    {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.166 +    {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0},
   1.167 +    {LOW_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1},
   1.168 +    {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
   1.169 +    {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 0},
   1.170 +    {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3},
   1.171 +    {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0},
   1.172 +    {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0},
   1.173 +    {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2},
   1.174 +    {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0},
   1.175 +    {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
   1.176 +    {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0},
   1.177 +    {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
   1.178 +    {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0},
   1.179 +    {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.180 +    {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0},
   1.181 +    {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2},
   1.182 +    {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 3},
   1.183 +    {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 0},
   1.184 +    {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, // really internal use, so we don't care
   1.185 +    {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 0},
   1.186 +    {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
   1.187 +    {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour
   1.188 +    {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
   1.189 +    {CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour
   1.190 +    {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2},
   1.191 +    {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2},
   1.192 +    {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
   1.193 +    {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 1000},
   1.194 +    {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0},
   1.195 +    {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
   1.196 +    {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3},
   1.197 +    {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0},
   1.198 +    {CAP_Z, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 3},
   1.199 +    {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.200 +    {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 5, 0},
   1.201 +    {CAP_O, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0},
   1.202 +    {CAP_O, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.203 +    {CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0},
   1.204 +    {CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 2, 0},
   1.205 +    {CAP_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
   1.206 +    {CAP_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
   1.207 +    {CAP_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.208 +    {LOW_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
   1.209 +    {LOW_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
   1.210 +    {LOW_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
   1.211 +    {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
   1.212 + };
   1.213 +
   1.214 +static const char* const CLDR_FIELD_APPEND[] = {
   1.215 +    "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
   1.216 +    "Hour", "Minute", "Second", "*", "Timezone"
   1.217 +};
   1.218 +
   1.219 +static const char* const CLDR_FIELD_NAME[] = {
   1.220 +    "era", "year", "quarter", "month", "week", "*", "weekday", "*", "*", "day", "dayperiod",
   1.221 +    "hour", "minute", "second", "*", "zone"
   1.222 +};
   1.223 +
   1.224 +static const char* const Resource_Fields[] = {
   1.225 +    "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
   1.226 +    "weekday", "year", "zone", "quarter" };
   1.227 +
   1.228 +// For appendItems
   1.229 +static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
   1.230 +    0x20, 0x7B, 0x31, 0x7D, 0x2524, 0};  // {0} \u251C{2}: {1}\u2524
   1.231 +
   1.232 +//static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ"
   1.233 +
   1.234 +static const char DT_DateTimePatternsTag[]="DateTimePatterns";
   1.235 +static const char DT_DateTimeCalendarTag[]="calendar";
   1.236 +static const char DT_DateTimeGregorianTag[]="gregorian";
   1.237 +static const char DT_DateTimeAppendItemsTag[]="appendItems";
   1.238 +static const char DT_DateTimeFieldsTag[]="fields";
   1.239 +static const char DT_DateTimeAvailableFormatsTag[]="availableFormats";
   1.240 +//static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
   1.241 +
   1.242 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator)
   1.243 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)
   1.244 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration)
   1.245 +
   1.246 +DateTimePatternGenerator*  U_EXPORT2
   1.247 +DateTimePatternGenerator::createInstance(UErrorCode& status) {
   1.248 +    return createInstance(Locale::getDefault(), status);
   1.249 +}
   1.250 +
   1.251 +DateTimePatternGenerator* U_EXPORT2
   1.252 +DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
   1.253 +    DateTimePatternGenerator *result = new DateTimePatternGenerator(locale, status);
   1.254 +    if (result == NULL) {
   1.255 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.256 +    }
   1.257 +    if (U_FAILURE(status)) {
   1.258 +        delete result;
   1.259 +        result = NULL;
   1.260 +    }
   1.261 +    return result;
   1.262 +}
   1.263 +
   1.264 +DateTimePatternGenerator*  U_EXPORT2
   1.265 +DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
   1.266 +    DateTimePatternGenerator *result = new DateTimePatternGenerator(status);
   1.267 +    if (result == NULL) {
   1.268 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.269 +    }
   1.270 +    if (U_FAILURE(status)) {
   1.271 +        delete result;
   1.272 +        result = NULL;
   1.273 +    }
   1.274 +    return result;
   1.275 +}
   1.276 +
   1.277 +DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :
   1.278 +    skipMatcher(NULL),
   1.279 +    fAvailableFormatKeyHash(NULL)
   1.280 +{
   1.281 +    fp = new FormatParser();
   1.282 +    dtMatcher = new DateTimeMatcher();
   1.283 +    distanceInfo = new DistanceInfo();
   1.284 +    patternMap = new PatternMap();
   1.285 +    if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
   1.286 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.287 +    }
   1.288 +}
   1.289 +
   1.290 +DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) :
   1.291 +    skipMatcher(NULL),
   1.292 +    fAvailableFormatKeyHash(NULL)
   1.293 +{
   1.294 +    fp = new FormatParser();
   1.295 +    dtMatcher = new DateTimeMatcher();
   1.296 +    distanceInfo = new DistanceInfo();
   1.297 +    patternMap = new PatternMap();
   1.298 +    if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
   1.299 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.300 +    }
   1.301 +    else {
   1.302 +        initData(locale, status);
   1.303 +    }
   1.304 +}
   1.305 +
   1.306 +DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :
   1.307 +    UObject(),
   1.308 +    skipMatcher(NULL),
   1.309 +    fAvailableFormatKeyHash(NULL)
   1.310 +{
   1.311 +    fp = new FormatParser();
   1.312 +    dtMatcher = new DateTimeMatcher();
   1.313 +    distanceInfo = new DistanceInfo();
   1.314 +    patternMap = new PatternMap();
   1.315 +    *this=other;
   1.316 +}
   1.317 +
   1.318 +DateTimePatternGenerator&
   1.319 +DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
   1.320 +    pLocale = other.pLocale;
   1.321 +    fDefaultHourFormatChar = other.fDefaultHourFormatChar;
   1.322 +    *fp = *(other.fp);
   1.323 +    dtMatcher->copyFrom(other.dtMatcher->skeleton);
   1.324 +    *distanceInfo = *(other.distanceInfo);
   1.325 +    dateTimeFormat = other.dateTimeFormat;
   1.326 +    decimal = other.decimal;
   1.327 +    // NUL-terminate for the C API.
   1.328 +    dateTimeFormat.getTerminatedBuffer();
   1.329 +    decimal.getTerminatedBuffer();
   1.330 +    delete skipMatcher;
   1.331 +    if ( other.skipMatcher == NULL ) {
   1.332 +        skipMatcher = NULL;
   1.333 +    }
   1.334 +    else {
   1.335 +        skipMatcher = new DateTimeMatcher(*other.skipMatcher);
   1.336 +    }
   1.337 +    for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
   1.338 +        appendItemFormats[i] = other.appendItemFormats[i];
   1.339 +        appendItemNames[i] = other.appendItemNames[i];
   1.340 +        // NUL-terminate for the C API.
   1.341 +        appendItemFormats[i].getTerminatedBuffer();
   1.342 +        appendItemNames[i].getTerminatedBuffer();
   1.343 +    }
   1.344 +    UErrorCode status = U_ZERO_ERROR;
   1.345 +    patternMap->copyFrom(*other.patternMap, status);
   1.346 +    copyHashtable(other.fAvailableFormatKeyHash, status);
   1.347 +    return *this;
   1.348 +}
   1.349 +
   1.350 +
   1.351 +UBool
   1.352 +DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const {
   1.353 +    if (this == &other) {
   1.354 +        return TRUE;
   1.355 +    }
   1.356 +    if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
   1.357 +        (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
   1.358 +        for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
   1.359 +           if ((appendItemFormats[i] != other.appendItemFormats[i]) ||
   1.360 +               (appendItemNames[i] != other.appendItemNames[i]) ) {
   1.361 +               return FALSE;
   1.362 +           }
   1.363 +        }
   1.364 +        return TRUE;
   1.365 +    }
   1.366 +    else {
   1.367 +        return FALSE;
   1.368 +    }
   1.369 +}
   1.370 +
   1.371 +UBool
   1.372 +DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const {
   1.373 +    return  !operator==(other);
   1.374 +}
   1.375 +
   1.376 +DateTimePatternGenerator::~DateTimePatternGenerator() {
   1.377 +    if (fAvailableFormatKeyHash!=NULL) {
   1.378 +        delete fAvailableFormatKeyHash;
   1.379 +    }
   1.380 +
   1.381 +    if (fp != NULL) delete fp;
   1.382 +    if (dtMatcher != NULL) delete dtMatcher;
   1.383 +    if (distanceInfo != NULL) delete distanceInfo;
   1.384 +    if (patternMap != NULL) delete patternMap;
   1.385 +    if (skipMatcher != NULL) delete skipMatcher;
   1.386 +}
   1.387 +
   1.388 +void
   1.389 +DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
   1.390 +    //const char *baseLangName = locale.getBaseName(); // unused
   1.391 +
   1.392 +    skipMatcher = NULL;
   1.393 +    fAvailableFormatKeyHash=NULL;
   1.394 +    addCanonicalItems();
   1.395 +    addICUPatterns(locale, status);
   1.396 +    if (U_FAILURE(status)) {
   1.397 +        return;
   1.398 +    }
   1.399 +    addCLDRData(locale, status);
   1.400 +    setDateTimeFromCalendar(locale, status);
   1.401 +    setDecimalSymbols(locale, status);
   1.402 +} // DateTimePatternGenerator::initData
   1.403 +
   1.404 +UnicodeString
   1.405 +DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&
   1.406 +/*status*/) {
   1.407 +    dtMatcher->set(pattern, fp);
   1.408 +    return dtMatcher->getSkeletonPtr()->getSkeleton();
   1.409 +}
   1.410 +
   1.411 +UnicodeString
   1.412 +DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) {
   1.413 +    dtMatcher->set(pattern, fp);
   1.414 +    return dtMatcher->getSkeletonPtr()->getBaseSkeleton();
   1.415 +}
   1.416 +
   1.417 +void
   1.418 +DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) {
   1.419 +    UnicodeString dfPattern;
   1.420 +    UnicodeString conflictingString;
   1.421 +    DateFormat* df;
   1.422 +
   1.423 +    if (U_FAILURE(status)) {
   1.424 +        return;
   1.425 +    }
   1.426 +
   1.427 +    // Load with ICU patterns
   1.428 +    for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) {
   1.429 +        DateFormat::EStyle style = (DateFormat::EStyle)i;
   1.430 +        df = DateFormat::createDateInstance(style, locale);
   1.431 +        SimpleDateFormat* sdf;
   1.432 +        if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
   1.433 +            addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
   1.434 +        }
   1.435 +        // TODO Maybe we should return an error when the date format isn't simple.
   1.436 +        delete df;
   1.437 +        if (U_FAILURE(status)) {
   1.438 +            return;
   1.439 +        }
   1.440 +
   1.441 +        df = DateFormat::createTimeInstance(style, locale);
   1.442 +        if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
   1.443 +            addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
   1.444 +            // HACK for hh:ss
   1.445 +            if ( i==DateFormat::kMedium ) {
   1.446 +                hackPattern = dfPattern;
   1.447 +            }
   1.448 +        }
   1.449 +        // TODO Maybe we should return an error when the date format isn't simple.
   1.450 +        delete df;
   1.451 +        if (U_FAILURE(status)) {
   1.452 +            return;
   1.453 +        }
   1.454 +    }
   1.455 +}
   1.456 +
   1.457 +void
   1.458 +DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status)  {
   1.459 +    UnicodeString conflictingString;
   1.460 +
   1.461 +    fp->set(hackPattern);
   1.462 +    UnicodeString mmss;
   1.463 +    UBool gotMm=FALSE;
   1.464 +    for (int32_t i=0; i<fp->itemNumber; ++i) {
   1.465 +        UnicodeString field = fp->items[i];
   1.466 +        if ( fp->isQuoteLiteral(field) ) {
   1.467 +            if ( gotMm ) {
   1.468 +               UnicodeString quoteLiteral;
   1.469 +               fp->getQuoteLiteral(quoteLiteral, &i);
   1.470 +               mmss += quoteLiteral;
   1.471 +            }
   1.472 +        }
   1.473 +        else {
   1.474 +            if (fp->isPatternSeparator(field) && gotMm) {
   1.475 +                mmss+=field;
   1.476 +            }
   1.477 +            else {
   1.478 +                UChar ch=field.charAt(0);
   1.479 +                if (ch==LOW_M) {
   1.480 +                    gotMm=TRUE;
   1.481 +                    mmss+=field;
   1.482 +                }
   1.483 +                else {
   1.484 +                    if (ch==LOW_S) {
   1.485 +                        if (!gotMm) {
   1.486 +                            break;
   1.487 +                        }
   1.488 +                        mmss+= field;
   1.489 +                        addPattern(mmss, FALSE, conflictingString, status);
   1.490 +                        break;
   1.491 +                    }
   1.492 +                    else {
   1.493 +                        if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) {
   1.494 +                            break;
   1.495 +                        }
   1.496 +                    }
   1.497 +                }
   1.498 +            }
   1.499 +        }
   1.500 +    }
   1.501 +}
   1.502 +
   1.503 +#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
   1.504 +
   1.505 +static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters
   1.506 +
   1.507 +void
   1.508 +DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) {
   1.509 +    UResourceBundle *rb, *calTypeBundle, *calBundle;
   1.510 +    UResourceBundle *patBundle, *fieldBundle, *fBundle;
   1.511 +    UnicodeString rbPattern, value, field;
   1.512 +    UnicodeString conflictingPattern;
   1.513 +    const char *key=NULL;
   1.514 +    int32_t i;
   1.515 +
   1.516 +    UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, LENGTHOF(UDATPG_ItemFormat)-1);  // Read-only alias.
   1.517 +
   1.518 +    err = U_ZERO_ERROR;
   1.519 +    
   1.520 +    fDefaultHourFormatChar = 0;
   1.521 +    for (i=0; i<UDATPG_FIELD_COUNT; ++i ) {
   1.522 +        appendItemNames[i]=CAP_F;
   1.523 +        if (i<10) {
   1.524 +            appendItemNames[i]+=(UChar)(i+0x30);
   1.525 +        }
   1.526 +        else {
   1.527 +            appendItemNames[i]+=(UChar)0x31;
   1.528 +            appendItemNames[i]+=(UChar)(i-10 + 0x30);
   1.529 +        }
   1.530 +        // NUL-terminate for the C API.
   1.531 +        appendItemNames[i].getTerminatedBuffer();
   1.532 +    }
   1.533 +
   1.534 +    rb = ures_open(NULL, locale.getName(), &err);
   1.535 +    if (rb == NULL || U_FAILURE(err)) {
   1.536 +        return;
   1.537 +    }
   1.538 +    const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
   1.539 +    const char * calendarTypeToUse = DT_DateTimeGregorianTag; // initial default
   1.540 +    char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
   1.541 +    if ( U_SUCCESS(err) ) {
   1.542 +        char    localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
   1.543 +        // obtain a locale that always has the calendar key value that should be used
   1.544 +        (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
   1.545 +                                            "calendar", "calendar", locale.getName(), NULL, FALSE, &err);
   1.546 +        localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
   1.547 +        // now get the calendar key value from that locale
   1.548 +        int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &err);
   1.549 +        if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
   1.550 +            calendarTypeToUse = calendarType;
   1.551 +        }
   1.552 +        err = U_ZERO_ERROR;
   1.553 +    }
   1.554 +    calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err);
   1.555 +    calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err);
   1.556 +
   1.557 +    key=NULL;
   1.558 +    int32_t dtCount=0;
   1.559 +    patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimePatternsTag, NULL, &err);
   1.560 +    while (U_SUCCESS(err)) {
   1.561 +        rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
   1.562 +        dtCount++;
   1.563 +        if (rbPattern.length()==0 ) {
   1.564 +            break;  // no more pattern
   1.565 +        }
   1.566 +        else {
   1.567 +            if (dtCount==9) {
   1.568 +                setDateTimeFormat(rbPattern);
   1.569 +            } else if (dtCount==4) { // short time format
   1.570 +                // set fDefaultHourFormatChar to the hour format character from this pattern
   1.571 +                int32_t tfIdx, tfLen = rbPattern.length();
   1.572 +                UBool ignoreChars = FALSE;
   1.573 +                for (tfIdx = 0; tfIdx < tfLen; tfIdx++) {
   1.574 +                    UChar tfChar = rbPattern.charAt(tfIdx);
   1.575 +                    if ( tfChar == SINGLE_QUOTE ) {
   1.576 +                        ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote)
   1.577 +                    } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) {
   1.578 +                        fDefaultHourFormatChar = tfChar;
   1.579 +                        break;
   1.580 +                    }
   1.581 +                }
   1.582 +            }
   1.583 +        }
   1.584 +    }
   1.585 +    ures_close(patBundle);
   1.586 +
   1.587 +    err = U_ZERO_ERROR;
   1.588 +    patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAppendItemsTag, NULL, &err);
   1.589 +    key=NULL;
   1.590 +    UnicodeString itemKey;
   1.591 +    while (U_SUCCESS(err)) {
   1.592 +        rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
   1.593 +        if (rbPattern.length()==0 ) {
   1.594 +            break;  // no more pattern
   1.595 +        }
   1.596 +        else {
   1.597 +            setAppendItemFormat(getAppendFormatNumber(key), rbPattern);
   1.598 +        }
   1.599 +    }
   1.600 +    ures_close(patBundle);
   1.601 +
   1.602 +    key=NULL;
   1.603 +    err = U_ZERO_ERROR;
   1.604 +    fBundle = ures_getByKeyWithFallback(rb, DT_DateTimeFieldsTag, NULL, &err);
   1.605 +    for (i=0; i<MAX_RESOURCE_FIELD; ++i) {
   1.606 +        err = U_ZERO_ERROR;
   1.607 +        patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err);
   1.608 +        fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err);
   1.609 +        rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err);
   1.610 +        ures_close(fieldBundle);
   1.611 +        ures_close(patBundle);
   1.612 +        if (rbPattern.length()==0 ) {
   1.613 +            continue;
   1.614 +        }
   1.615 +        else {
   1.616 +            setAppendItemName(getAppendNameNumber(Resource_Fields[i]), rbPattern);
   1.617 +        }
   1.618 +    }
   1.619 +    ures_close(fBundle);
   1.620 +
   1.621 +    // add available formats
   1.622 +    UBool firstTimeThrough = TRUE;
   1.623 +    err = U_ZERO_ERROR;
   1.624 +    initHashtable(err);
   1.625 +    UBool override = TRUE;
   1.626 +    while (TRUE) {
   1.627 +        // At the start of the loop:
   1.628 +        // - rb is the open resource bundle for the current locale being processed,
   1.629 +        //   whose actual name is in curLocaleName.
   1.630 +        // - if U_SUCCESS(err), then calBundle and calTypeBundle are open;
   1.631 +        //   process contents of calTypeBundle, then close calBundle and calTypeBundle.
   1.632 +        if (U_SUCCESS(err)) {
   1.633 +            // process contents of calTypeBundle
   1.634 +            patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
   1.635 +            if (U_SUCCESS(err)) {
   1.636 +                int32_t numberKeys = ures_getSize(patBundle);
   1.637 +                int32_t len;
   1.638 +                const UChar *retPattern;
   1.639 +                key=NULL;
   1.640 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
   1.641 +                UResourceBundleAIterator aiter;
   1.642 +                ures_a_open(&aiter, patBundle, &err);
   1.643 +#endif
   1.644 +                for(i=0; i<numberKeys; ++i) {
   1.645 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
   1.646 +                    retPattern=ures_a_getNextString(&aiter, &len, &key, &err);
   1.647 +#else
   1.648 +                    retPattern=ures_getNextString(patBundle, &len, &key, &err);
   1.649 +#endif
   1.650 +                    UnicodeString format=UnicodeString(retPattern);
   1.651 +                    UnicodeString retKey=UnicodeString(key, -1, US_INV);
   1.652 +                    if ( firstTimeThrough || !isAvailableFormatSet(retKey) ) {
   1.653 +                        setAvailableFormat(retKey, err);
   1.654 +                        // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
   1.655 +                        // but not a previous availableFormats entry:
   1.656 +                        addPatternWithSkeleton(format, &retKey, override, conflictingPattern, err);
   1.657 +                    }
   1.658 +                }
   1.659 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR)
   1.660 +                ures_a_close(&aiter);
   1.661 +#endif
   1.662 +                ures_close(patBundle);
   1.663 +            }
   1.664 +            firstTimeThrough = FALSE;
   1.665 +            // close calBundle and calTypeBundle
   1.666 +            ures_close(calTypeBundle);
   1.667 +            ures_close(calBundle);
   1.668 +        }
   1.669 +        if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) {
   1.670 +            // we just finished handling root, nothing more to check
   1.671 +            ures_close(rb);
   1.672 +            break;
   1.673 +        }
   1.674 +        // Find the name of the appropriate parent locale (from %%Parent if present, else
   1.675 +        // uloc_getParent on the actual locale name)
   1.676 +        // (It would be nice to have a ures function that did this...)
   1.677 +        err = U_ZERO_ERROR;
   1.678 +        char parentLocale[ULOC_FULLNAME_CAPACITY];
   1.679 +        int32_t locNameLen;
   1.680 +        const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &err);
   1.681 +        if (U_SUCCESS(err) && err != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
   1.682 +            u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
   1.683 +        } else {
   1.684 +            err = U_ZERO_ERROR;
   1.685 +            uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &err);
   1.686 +            if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
   1.687 +                // just fallback to root, since we are not already there
   1.688 +                parentLocale[0] = 0;
   1.689 +                err = U_ZERO_ERROR;
   1.690 +            }
   1.691 +        }
   1.692 +        // Close current locale bundle
   1.693 +        ures_close(rb);
   1.694 +        // And open its parent, which becomes the new current locale being processed
   1.695 +        rb = ures_open(NULL, parentLocale, &err);
   1.696 +        if ( U_FAILURE(err) ) {
   1.697 +            err = U_ZERO_ERROR;
   1.698 +            break;
   1.699 +        }
   1.700 +        // Get the name of the parent / new current locale
   1.701 +        curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
   1.702 +        if ( U_FAILURE(err) ) {
   1.703 +            curLocaleName = parentLocale;
   1.704 +            err = U_ZERO_ERROR;
   1.705 +        }
   1.706 +        if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) {
   1.707 +            override = FALSE;
   1.708 +        }
   1.709 +        // Open calBundle and calTypeBundle
   1.710 +        calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err);
   1.711 +        if (U_SUCCESS(err)) {
   1.712 +            calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err);
   1.713 +            if ( U_FAILURE(err) ) {
   1.714 +                ures_close(calBundle);
   1.715 +            }
   1.716 +        }
   1.717 +        // Go to the top of the loop to process contents of calTypeBundle
   1.718 +    }    
   1.719 +
   1.720 +    if (hackPattern.length()>0) {
   1.721 +        hackTimes(hackPattern, err);
   1.722 +    }
   1.723 +}
   1.724 +
   1.725 +void
   1.726 +DateTimePatternGenerator::initHashtable(UErrorCode& err) {
   1.727 +    if (fAvailableFormatKeyHash!=NULL) {
   1.728 +        return;
   1.729 +    }
   1.730 +    if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) {
   1.731 +        err=U_MEMORY_ALLOCATION_ERROR;
   1.732 +        return;
   1.733 +    }
   1.734 +}
   1.735 +
   1.736 +
   1.737 +void
   1.738 +DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) {
   1.739 +    appendItemFormats[field] = value;
   1.740 +    // NUL-terminate for the C API.
   1.741 +    appendItemFormats[field].getTerminatedBuffer();
   1.742 +}
   1.743 +
   1.744 +const UnicodeString&
   1.745 +DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const {
   1.746 +    return appendItemFormats[field];
   1.747 +}
   1.748 +
   1.749 +void
   1.750 +DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) {
   1.751 +    appendItemNames[field] = value;
   1.752 +    // NUL-terminate for the C API.
   1.753 +    appendItemNames[field].getTerminatedBuffer();
   1.754 +}
   1.755 +
   1.756 +const UnicodeString&
   1.757 +DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const {
   1.758 +    return appendItemNames[field];
   1.759 +}
   1.760 +
   1.761 +void
   1.762 +DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
   1.763 +    value = SINGLE_QUOTE;
   1.764 +    value += appendItemNames[field];
   1.765 +    value += SINGLE_QUOTE;
   1.766 +}
   1.767 +
   1.768 +UnicodeString
   1.769 +DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) {
   1.770 +    return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status);
   1.771 +}
   1.772 +
   1.773 +UnicodeString
   1.774 +DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) {
   1.775 +    const UnicodeString *bestPattern=NULL;
   1.776 +    UnicodeString dtFormat;
   1.777 +    UnicodeString resultPattern;
   1.778 +    int32_t flags = kDTPGNoFlags;
   1.779 +
   1.780 +    int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1;
   1.781 +    int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;
   1.782 +
   1.783 +    // Replace hour metacharacters 'j' and 'J', set flags as necessary
   1.784 +    UnicodeString patternFormCopy = UnicodeString(patternForm);
   1.785 +    int32_t patPos, patLen = patternFormCopy.length();
   1.786 +    UBool inQuoted = FALSE;
   1.787 +    for (patPos = 0; patPos < patLen; patPos++) {
   1.788 +        UChar patChr = patternFormCopy.charAt(patPos);
   1.789 +        if (patChr == SINGLE_QUOTE) {
   1.790 +            inQuoted = !inQuoted;
   1.791 +        } else if (!inQuoted) {
   1.792 +            if (patChr == LOW_J) {
   1.793 +                patternFormCopy.setCharAt(patPos, fDefaultHourFormatChar);
   1.794 +            } else if (patChr == CAP_J) {
   1.795 +                // Get pattern for skeleton with H, then replace H or k
   1.796 +                // with fDefaultHourFormatChar (if different)
   1.797 +                patternFormCopy.setCharAt(patPos, CAP_H);
   1.798 +                flags |= kDTPGSkeletonUsesCapJ;
   1.799 +            }
   1.800 +        }
   1.801 +    }
   1.802 +
   1.803 +    resultPattern.remove();
   1.804 +    dtMatcher->set(patternFormCopy, fp);
   1.805 +    const PtnSkeleton* specifiedSkeleton=NULL;
   1.806 +    bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton);
   1.807 +    if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
   1.808 +        resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options);
   1.809 +
   1.810 +        return resultPattern;
   1.811 +    }
   1.812 +    int32_t neededFields = dtMatcher->getFieldMask();
   1.813 +    UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options);
   1.814 +    UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options);
   1.815 +    if (datePattern.length()==0) {
   1.816 +        if (timePattern.length()==0) {
   1.817 +            resultPattern.remove();
   1.818 +        }
   1.819 +        else {
   1.820 +            return timePattern;
   1.821 +        }
   1.822 +    }
   1.823 +    if (timePattern.length()==0) {
   1.824 +        return datePattern;
   1.825 +    }
   1.826 +    resultPattern.remove();
   1.827 +    status = U_ZERO_ERROR;
   1.828 +    dtFormat=getDateTimeFormat();
   1.829 +    Formattable dateTimeObject[] = { timePattern, datePattern };
   1.830 +    resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status );
   1.831 +    return resultPattern;
   1.832 +}
   1.833 +
   1.834 +UnicodeString
   1.835 +DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
   1.836 +                                            const UnicodeString& skeleton,
   1.837 +                                            UErrorCode& status) {
   1.838 +    return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status);
   1.839 +}
   1.840 +
   1.841 +UnicodeString
   1.842 +DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
   1.843 +                                            const UnicodeString& skeleton,
   1.844 +                                            UDateTimePatternMatchOptions options,
   1.845 +                                            UErrorCode& /*status*/) {
   1.846 +    dtMatcher->set(skeleton, fp);
   1.847 +    UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options);
   1.848 +    return result;
   1.849 +}
   1.850 +
   1.851 +void
   1.852 +DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) {
   1.853 +    this->decimal = newDecimal;
   1.854 +    // NUL-terminate for the C API.
   1.855 +    this->decimal.getTerminatedBuffer();
   1.856 +}
   1.857 +
   1.858 +const UnicodeString&
   1.859 +DateTimePatternGenerator::getDecimal() const {
   1.860 +    return decimal;
   1.861 +}
   1.862 +
   1.863 +void
   1.864 +DateTimePatternGenerator::addCanonicalItems() {
   1.865 +    UnicodeString  conflictingPattern;
   1.866 +    UErrorCode status = U_ZERO_ERROR;
   1.867 +
   1.868 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) {
   1.869 +        addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status);
   1.870 +    }
   1.871 +}
   1.872 +
   1.873 +void
   1.874 +DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) {
   1.875 +    dateTimeFormat = dtFormat;
   1.876 +    // NUL-terminate for the C API.
   1.877 +    dateTimeFormat.getTerminatedBuffer();
   1.878 +}
   1.879 +
   1.880 +const UnicodeString&
   1.881 +DateTimePatternGenerator::getDateTimeFormat() const {
   1.882 +    return dateTimeFormat;
   1.883 +}
   1.884 +
   1.885 +void
   1.886 +DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
   1.887 +    const UChar *resStr;
   1.888 +    int32_t resStrLen = 0;
   1.889 +
   1.890 +    Calendar* fCalendar = Calendar::createInstance(locale, status);
   1.891 +    CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
   1.892 +    UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status);
   1.893 +    if (U_FAILURE(status)) return;
   1.894 +
   1.895 +    if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime)
   1.896 +    {
   1.897 +        status = U_INVALID_FORMAT_ERROR;
   1.898 +        return;
   1.899 +    }
   1.900 +    resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
   1.901 +    setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
   1.902 +
   1.903 +    delete fCalendar;
   1.904 +}
   1.905 +
   1.906 +void
   1.907 +DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) {
   1.908 +    DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status);
   1.909 +    if(U_SUCCESS(status)) {
   1.910 +        decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
   1.911 +        // NUL-terminate for the C API.
   1.912 +        decimal.getTerminatedBuffer();
   1.913 +    }
   1.914 +}
   1.915 +
   1.916 +UDateTimePatternConflict
   1.917 +DateTimePatternGenerator::addPattern(
   1.918 +    const UnicodeString& pattern,
   1.919 +    UBool override,
   1.920 +    UnicodeString &conflictingPattern,
   1.921 +    UErrorCode& status)
   1.922 +{
   1.923 +    return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status);
   1.924 +}
   1.925 +
   1.926 +// For DateTimePatternGenerator::addPatternWithSkeleton -
   1.927 +// If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
   1.928 +// 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
   1.929 +// 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
   1.930 +// (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
   1.931 +// parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
   1.932 +// specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
   1.933 +// derived (i.e. entries derived from the standard date/time patters for the specified locale).
   1.934 +// 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
   1.935 +// specified skeleton (which sets a new field in the PtnElem in the PatternMap).
   1.936 +UDateTimePatternConflict
   1.937 +DateTimePatternGenerator::addPatternWithSkeleton(
   1.938 +    const UnicodeString& pattern,
   1.939 +    const UnicodeString* skeletonToUse,
   1.940 +    UBool override,
   1.941 +    UnicodeString& conflictingPattern,
   1.942 +    UErrorCode& status)
   1.943 +{
   1.944 +
   1.945 +    UnicodeString basePattern;
   1.946 +    PtnSkeleton   skeleton;
   1.947 +    UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
   1.948 +
   1.949 +    DateTimeMatcher matcher;
   1.950 +    if ( skeletonToUse == NULL ) {
   1.951 +        matcher.set(pattern, fp, skeleton);
   1.952 +        matcher.getBasePattern(basePattern);
   1.953 +    } else {
   1.954 +        matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930
   1.955 +        matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse;
   1.956 +    }
   1.957 +    // We only care about base conflicts - and replacing the pattern associated with a base - if:
   1.958 +    // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous
   1.959 +    // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or
   1.960 +    // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen
   1.961 +    // if we are getting here from a subsequent call to addPattern).
   1.962 +    // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking
   1.963 +    // availableFormats items from root, which should not override any previous entry with the same base.
   1.964 +    UBool entryHadSpecifiedSkeleton;
   1.965 +    const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);
   1.966 +    if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) {
   1.967 +        conflictingStatus = UDATPG_BASE_CONFLICT;
   1.968 +        conflictingPattern = *duplicatePattern;
   1.969 +        if (!override) {
   1.970 +            return conflictingStatus;
   1.971 +        }
   1.972 +    }
   1.973 +    // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats
   1.974 +    // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with
   1.975 +    // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for
   1.976 +    // the previously-specified conflicting item.
   1.977 +    const PtnSkeleton* entrySpecifiedSkeleton = NULL;
   1.978 +    duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);
   1.979 +    if (duplicatePattern != NULL ) {
   1.980 +        conflictingStatus = UDATPG_CONFLICT;
   1.981 +        conflictingPattern = *duplicatePattern;
   1.982 +        if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) {
   1.983 +            return conflictingStatus;
   1.984 +        }
   1.985 +    }
   1.986 +    patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status);
   1.987 +    if(U_FAILURE(status)) {
   1.988 +        return conflictingStatus;
   1.989 +    }
   1.990 +
   1.991 +    return UDATPG_NO_CONFLICT;
   1.992 +}
   1.993 +
   1.994 +
   1.995 +UDateTimePatternField
   1.996 +DateTimePatternGenerator::getAppendFormatNumber(const char* field) const {
   1.997 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
   1.998 +        if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) {
   1.999 +            return (UDateTimePatternField)i;
  1.1000 +        }
  1.1001 +    }
  1.1002 +    return UDATPG_FIELD_COUNT;
  1.1003 +}
  1.1004 +
  1.1005 +UDateTimePatternField
  1.1006 +DateTimePatternGenerator::getAppendNameNumber(const char* field) const {
  1.1007 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
  1.1008 +        if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) {
  1.1009 +            return (UDateTimePatternField)i;
  1.1010 +        }
  1.1011 +    }
  1.1012 +    return UDATPG_FIELD_COUNT;
  1.1013 +}
  1.1014 +
  1.1015 +const UnicodeString*
  1.1016 +DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
  1.1017 +                                     int32_t includeMask,
  1.1018 +                                     DistanceInfo* missingFields,
  1.1019 +                                     const PtnSkeleton** specifiedSkeletonPtr) {
  1.1020 +    int32_t bestDistance = 0x7fffffff;
  1.1021 +    DistanceInfo tempInfo;
  1.1022 +    const UnicodeString *bestPattern=NULL;
  1.1023 +    const PtnSkeleton* specifiedSkeleton=NULL;
  1.1024 +
  1.1025 +    PatternMapIterator it;
  1.1026 +    for (it.set(*patternMap); it.hasNext(); ) {
  1.1027 +        DateTimeMatcher trial = it.next();
  1.1028 +        if (trial.equals(skipMatcher)) {
  1.1029 +            continue;
  1.1030 +        }
  1.1031 +        int32_t distance=source.getDistance(trial, includeMask, tempInfo);
  1.1032 +        if (distance<bestDistance) {
  1.1033 +            bestDistance=distance;
  1.1034 +            bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton);
  1.1035 +            missingFields->setTo(tempInfo);
  1.1036 +            if (distance==0) {
  1.1037 +                break;
  1.1038 +            }
  1.1039 +        }
  1.1040 +    }
  1.1041 +
  1.1042 +    // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
  1.1043 +    // then return it too. This generally happens when the caller needs to pass that skeleton
  1.1044 +    // through to adjustFieldTypes so the latter can do a better job.
  1.1045 +    if (bestPattern && specifiedSkeletonPtr) {
  1.1046 +        *specifiedSkeletonPtr = specifiedSkeleton;
  1.1047 +    }
  1.1048 +    return bestPattern;
  1.1049 +}
  1.1050 +
  1.1051 +UnicodeString
  1.1052 +DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
  1.1053 +                                           const PtnSkeleton* specifiedSkeleton,
  1.1054 +                                           int32_t flags,
  1.1055 +                                           UDateTimePatternMatchOptions options) {
  1.1056 +    UnicodeString newPattern;
  1.1057 +    fp->set(pattern);
  1.1058 +    for (int32_t i=0; i < fp->itemNumber; i++) {
  1.1059 +        UnicodeString field = fp->items[i];
  1.1060 +        if ( fp->isQuoteLiteral(field) ) {
  1.1061 +
  1.1062 +            UnicodeString quoteLiteral;
  1.1063 +            fp->getQuoteLiteral(quoteLiteral, &i);
  1.1064 +            newPattern += quoteLiteral;
  1.1065 +        }
  1.1066 +        else {
  1.1067 +            if (fp->isPatternSeparator(field)) {
  1.1068 +                newPattern+=field;
  1.1069 +                continue;
  1.1070 +            }
  1.1071 +            int32_t canonicalIndex = fp->getCanonicalIndex(field);
  1.1072 +            if (canonicalIndex < 0) {
  1.1073 +                newPattern+=field;
  1.1074 +                continue;  // don't adjust
  1.1075 +            }
  1.1076 +            const dtTypeElem *row = &dtTypes[canonicalIndex];
  1.1077 +            int32_t typeValue = row->field;
  1.1078 +            if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) {
  1.1079 +                UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD];
  1.1080 +                field = field + decimal + newField;
  1.1081 +            } else if (dtMatcher->skeleton.type[typeValue]!=0) {
  1.1082 +                    // Here:
  1.1083 +                    // - "reqField" is the field from the originally requested skeleton, with length
  1.1084 +                    // "reqFieldLen".
  1.1085 +                    // - "field" is the field from the found pattern.
  1.1086 +                    //
  1.1087 +                    // The adjusted field should consist of characters from the originally requested
  1.1088 +                    // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or
  1.1089 +                    // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist
  1.1090 +                    // of characters from the  found pattern.
  1.1091 +                    //
  1.1092 +                    // The length of the adjusted field (adjFieldLen) should match that in the originally
  1.1093 +                    // requested skeleton, except that in the following cases the length of the adjusted field
  1.1094 +                    // should match that in the found pattern (i.e. the length of this pattern field should
  1.1095 +                    // not be adjusted):
  1.1096 +                    // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is
  1.1097 +                    //    not set (ticket #7180). Note, we may want to implement a similar change for other
  1.1098 +                    //    numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for
  1.1099 +                    //    field length, but options bits can be used to override this.
  1.1100 +                    // 2. There is a specified skeleton for the found pattern and one of the following is true:
  1.1101 +                    //    a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
  1.1102 +                    //    b) The pattern field is numeric and the skeleton field is not, or vice versa.
  1.1103 +
  1.1104 +                    UnicodeString reqField = dtMatcher->skeleton.original[typeValue];
  1.1105 +                    int32_t reqFieldLen = reqField.length();
  1.1106 +                    if (reqField.charAt(0) == CAP_E && reqFieldLen < 3)
  1.1107 +                        reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e
  1.1108 +                    int32_t adjFieldLen = reqFieldLen;
  1.1109 +                    if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) ||
  1.1110 +                         (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) ||
  1.1111 +                         (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) {
  1.1112 +                         adjFieldLen = field.length();
  1.1113 +                    } else if (specifiedSkeleton) {
  1.1114 +                        UnicodeString skelField = specifiedSkeleton->original[typeValue];
  1.1115 +                        int32_t skelFieldLen = skelField.length();
  1.1116 +                        UBool patFieldIsNumeric = (row->type > 0);
  1.1117 +                        UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0);
  1.1118 +                        if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) {
  1.1119 +                            // don't adjust the field length in the found pattern
  1.1120 +                            adjFieldLen = field.length();
  1.1121 +                        }
  1.1122 +                    }
  1.1123 +                    UChar c = (typeValue!= UDATPG_HOUR_FIELD && typeValue!= UDATPG_MONTH_FIELD &&
  1.1124 +                               typeValue!= UDATPG_WEEKDAY_FIELD && (typeValue!= UDATPG_YEAR_FIELD || reqField.charAt(0)==CAP_Y))?
  1.1125 +                        reqField.charAt(0): field.charAt(0);
  1.1126 +                    if (typeValue == UDATPG_HOUR_FIELD && (flags & kDTPGSkeletonUsesCapJ) != 0) {
  1.1127 +                        c = fDefaultHourFormatChar;
  1.1128 +                    }
  1.1129 +                    field.remove();
  1.1130 +                    for (int32_t i=adjFieldLen; i>0; --i) {
  1.1131 +                        field+=c;
  1.1132 +                    }
  1.1133 +            }
  1.1134 +            newPattern+=field;
  1.1135 +        }
  1.1136 +    }
  1.1137 +    return newPattern;
  1.1138 +}
  1.1139 +
  1.1140 +UnicodeString
  1.1141 +DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) {
  1.1142 +    UnicodeString  resultPattern, tempPattern;
  1.1143 +    UErrorCode err=U_ZERO_ERROR;
  1.1144 +    int32_t lastMissingFieldMask=0;
  1.1145 +    if (missingFields!=0) {
  1.1146 +        resultPattern=UnicodeString();
  1.1147 +        const PtnSkeleton* specifiedSkeleton=NULL;
  1.1148 +        tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton);
  1.1149 +        resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
  1.1150 +        if ( distanceInfo->missingFieldMask==0 ) {
  1.1151 +            return resultPattern;
  1.1152 +        }
  1.1153 +        while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work!
  1.1154 +            if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) {
  1.1155 +                break;  // cannot find the proper missing field
  1.1156 +            }
  1.1157 +            if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) &&
  1.1158 +                ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) {
  1.1159 +                resultPattern = adjustFieldTypes(resultPattern, specifiedSkeleton, flags | kDTPGFixFractionalSeconds, options);
  1.1160 +                distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;
  1.1161 +                continue;
  1.1162 +            }
  1.1163 +            int32_t startingMask = distanceInfo->missingFieldMask;
  1.1164 +            tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton);
  1.1165 +            tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
  1.1166 +            int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
  1.1167 +            int32_t topField=getTopBitNumber(foundMask);
  1.1168 +            UnicodeString appendName;
  1.1169 +            getAppendName((UDateTimePatternField)topField, appendName);
  1.1170 +            const Formattable formatPattern[] = {
  1.1171 +                resultPattern,
  1.1172 +                tempPattern,
  1.1173 +                appendName
  1.1174 +            };
  1.1175 +            UnicodeString emptyStr;
  1.1176 +            resultPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, emptyStr, err);
  1.1177 +            lastMissingFieldMask = distanceInfo->missingFieldMask;
  1.1178 +        }
  1.1179 +    }
  1.1180 +    return resultPattern;
  1.1181 +}
  1.1182 +
  1.1183 +int32_t
  1.1184 +DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
  1.1185 +    if ( foundMask==0 ) {
  1.1186 +        return 0;
  1.1187 +    }
  1.1188 +    int32_t i=0;
  1.1189 +    while (foundMask!=0) {
  1.1190 +        foundMask >>=1;
  1.1191 +        ++i;
  1.1192 +    }
  1.1193 +    if (i-1 >UDATPG_ZONE_FIELD) {
  1.1194 +        return UDATPG_ZONE_FIELD;
  1.1195 +    }
  1.1196 +    else
  1.1197 +        return i-1;
  1.1198 +}
  1.1199 +
  1.1200 +void
  1.1201 +DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)
  1.1202 +{
  1.1203 +    fAvailableFormatKeyHash->puti(key, 1, err);
  1.1204 +}
  1.1205 +
  1.1206 +UBool
  1.1207 +DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
  1.1208 +    return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);
  1.1209 +}
  1.1210 +
  1.1211 +void
  1.1212 +DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
  1.1213 +
  1.1214 +    if (other == NULL) {
  1.1215 +        return;
  1.1216 +    }
  1.1217 +    if (fAvailableFormatKeyHash != NULL) {
  1.1218 +        delete fAvailableFormatKeyHash;
  1.1219 +        fAvailableFormatKeyHash = NULL;
  1.1220 +    }
  1.1221 +    initHashtable(status);
  1.1222 +    if(U_FAILURE(status)){
  1.1223 +        return;
  1.1224 +    }
  1.1225 +    int32_t pos = -1;
  1.1226 +    const UHashElement* elem = NULL;
  1.1227 +    // walk through the hash table and create a deep clone
  1.1228 +    while((elem = other->nextElement(pos))!= NULL){
  1.1229 +        const UHashTok otherKeyTok = elem->key;
  1.1230 +        UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
  1.1231 +        fAvailableFormatKeyHash->puti(*otherKey, 1, status);
  1.1232 +        if(U_FAILURE(status)){
  1.1233 +            return;
  1.1234 +        }
  1.1235 +    }
  1.1236 +}
  1.1237 +
  1.1238 +StringEnumeration*
  1.1239 +DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
  1.1240 +    StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status);
  1.1241 +    return skeletonEnumerator;
  1.1242 +}
  1.1243 +
  1.1244 +const UnicodeString&
  1.1245 +DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const {
  1.1246 +    PtnElem *curElem;
  1.1247 +
  1.1248 +    if (skeleton.length() ==0) {
  1.1249 +        return emptyString;
  1.1250 +    }
  1.1251 +    curElem = patternMap->getHeader(skeleton.charAt(0));
  1.1252 +    while ( curElem != NULL ) {
  1.1253 +        if ( curElem->skeleton->getSkeleton()==skeleton ) {
  1.1254 +            return curElem->pattern;
  1.1255 +        }
  1.1256 +        curElem=curElem->next;
  1.1257 +    }
  1.1258 +    return emptyString;
  1.1259 +}
  1.1260 +
  1.1261 +StringEnumeration*
  1.1262 +DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
  1.1263 +    StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status);
  1.1264 +    return baseSkeletonEnumerator;
  1.1265 +}
  1.1266 +
  1.1267 +StringEnumeration*
  1.1268 +DateTimePatternGenerator::getRedundants(UErrorCode& status) {
  1.1269 +    StringEnumeration* output = new DTRedundantEnumeration();
  1.1270 +    const UnicodeString *pattern;
  1.1271 +    PatternMapIterator it;
  1.1272 +    for (it.set(*patternMap); it.hasNext(); ) {
  1.1273 +        DateTimeMatcher current = it.next();
  1.1274 +        pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
  1.1275 +        if ( isCanonicalItem(*pattern) ) {
  1.1276 +            continue;
  1.1277 +        }
  1.1278 +        if ( skipMatcher == NULL ) {
  1.1279 +            skipMatcher = new DateTimeMatcher(current);
  1.1280 +        }
  1.1281 +        else {
  1.1282 +            *skipMatcher = current;
  1.1283 +        }
  1.1284 +        UnicodeString trial = getBestPattern(current.getPattern(), status);
  1.1285 +        if (trial == *pattern) {
  1.1286 +            ((DTRedundantEnumeration *)output)->add(*pattern, status);
  1.1287 +        }
  1.1288 +        if (current.equals(skipMatcher)) {
  1.1289 +            continue;
  1.1290 +        }
  1.1291 +    }
  1.1292 +    return output;
  1.1293 +}
  1.1294 +
  1.1295 +UBool
  1.1296 +DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const {
  1.1297 +    if ( item.length() != 1 ) {
  1.1298 +        return FALSE;
  1.1299 +    }
  1.1300 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1301 +        if (item.charAt(0)==Canonical_Items[i]) {
  1.1302 +            return TRUE;
  1.1303 +        }
  1.1304 +    }
  1.1305 +    return FALSE;
  1.1306 +}
  1.1307 +
  1.1308 +
  1.1309 +DateTimePatternGenerator*
  1.1310 +DateTimePatternGenerator::clone() const {
  1.1311 +    return new DateTimePatternGenerator(*this);
  1.1312 +}
  1.1313 +
  1.1314 +PatternMap::PatternMap() {
  1.1315 +   for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
  1.1316 +      boot[i]=NULL;
  1.1317 +   }
  1.1318 +   isDupAllowed = TRUE;
  1.1319 +}
  1.1320 +
  1.1321 +void
  1.1322 +PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
  1.1323 +    this->isDupAllowed = other.isDupAllowed;
  1.1324 +    for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
  1.1325 +        PtnElem *curElem, *otherElem, *prevElem=NULL;
  1.1326 +        otherElem = other.boot[bootIndex];
  1.1327 +        while (otherElem!=NULL) {
  1.1328 +            if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) {
  1.1329 +                // out of memory
  1.1330 +                status = U_MEMORY_ALLOCATION_ERROR;
  1.1331 +                return;
  1.1332 +            }
  1.1333 +            if ( this->boot[bootIndex]== NULL ) {
  1.1334 +                this->boot[bootIndex] = curElem;
  1.1335 +            }
  1.1336 +            if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) {
  1.1337 +                // out of memory
  1.1338 +                status = U_MEMORY_ALLOCATION_ERROR;
  1.1339 +                return;
  1.1340 +            }
  1.1341 +
  1.1342 +            if (prevElem!=NULL) {
  1.1343 +                prevElem->next=curElem;
  1.1344 +            }
  1.1345 +            curElem->next=NULL;
  1.1346 +            prevElem = curElem;
  1.1347 +            otherElem = otherElem->next;
  1.1348 +        }
  1.1349 +
  1.1350 +    }
  1.1351 +}
  1.1352 +
  1.1353 +PtnElem*
  1.1354 +PatternMap::getHeader(UChar baseChar) {
  1.1355 +    PtnElem* curElem;
  1.1356 +
  1.1357 +    if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
  1.1358 +         curElem = boot[baseChar-CAP_A];
  1.1359 +    }
  1.1360 +    else {
  1.1361 +        if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) {
  1.1362 +            curElem = boot[26+baseChar-LOW_A];
  1.1363 +        }
  1.1364 +        else {
  1.1365 +            return NULL;
  1.1366 +        }
  1.1367 +    }
  1.1368 +    return curElem;
  1.1369 +}
  1.1370 +
  1.1371 +PatternMap::~PatternMap() {
  1.1372 +   for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
  1.1373 +       if (boot[i]!=NULL ) {
  1.1374 +           delete boot[i];
  1.1375 +           boot[i]=NULL;
  1.1376 +       }
  1.1377 +   }
  1.1378 +}  // PatternMap destructor
  1.1379 +
  1.1380 +void
  1.1381 +PatternMap::add(const UnicodeString& basePattern,
  1.1382 +                const PtnSkeleton& skeleton,
  1.1383 +                const UnicodeString& value,// mapped pattern value
  1.1384 +                UBool skeletonWasSpecified,
  1.1385 +                UErrorCode &status) {
  1.1386 +    UChar baseChar = basePattern.charAt(0);
  1.1387 +    PtnElem *curElem, *baseElem;
  1.1388 +    status = U_ZERO_ERROR;
  1.1389 +
  1.1390 +    // the baseChar must be A-Z or a-z
  1.1391 +    if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) {
  1.1392 +        baseElem = boot[baseChar-CAP_A];
  1.1393 +    }
  1.1394 +    else {
  1.1395 +        if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) {
  1.1396 +            baseElem = boot[26+baseChar-LOW_A];
  1.1397 +         }
  1.1398 +         else {
  1.1399 +             status = U_ILLEGAL_CHARACTER;
  1.1400 +             return;
  1.1401 +         }
  1.1402 +    }
  1.1403 +
  1.1404 +    if (baseElem == NULL) {
  1.1405 +        if ((curElem = new PtnElem(basePattern, value)) == NULL ) {
  1.1406 +            // out of memory
  1.1407 +            status = U_MEMORY_ALLOCATION_ERROR;
  1.1408 +            return;
  1.1409 +        }
  1.1410 +        if (baseChar >= LOW_A) {
  1.1411 +            boot[26 + (baseChar-LOW_A)] = curElem;
  1.1412 +        }
  1.1413 +        else {
  1.1414 +            boot[baseChar-CAP_A] = curElem;
  1.1415 +        }
  1.1416 +        curElem->skeleton = new PtnSkeleton(skeleton);
  1.1417 +        curElem->skeletonWasSpecified = skeletonWasSpecified;
  1.1418 +    }
  1.1419 +    if ( baseElem != NULL ) {
  1.1420 +        curElem = getDuplicateElem(basePattern, skeleton, baseElem);
  1.1421 +
  1.1422 +        if (curElem == NULL) {
  1.1423 +            // add new element to the list.
  1.1424 +            curElem = baseElem;
  1.1425 +            while( curElem -> next != NULL )
  1.1426 +            {
  1.1427 +                curElem = curElem->next;
  1.1428 +            }
  1.1429 +            if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) {
  1.1430 +                // out of memory
  1.1431 +                status = U_MEMORY_ALLOCATION_ERROR;
  1.1432 +                return;
  1.1433 +            }
  1.1434 +            curElem=curElem->next;
  1.1435 +            curElem->skeleton = new PtnSkeleton(skeleton);
  1.1436 +            curElem->skeletonWasSpecified = skeletonWasSpecified;
  1.1437 +        }
  1.1438 +        else {
  1.1439 +            // Pattern exists in the list already.
  1.1440 +            if ( !isDupAllowed ) {
  1.1441 +                return;
  1.1442 +            }
  1.1443 +            // Overwrite the value.
  1.1444 +            curElem->pattern = value;
  1.1445 +            // It was a bug that we were not doing the following previously,
  1.1446 +            // though that bug hid other problems by making things partly work.
  1.1447 +            curElem->skeletonWasSpecified = skeletonWasSpecified;
  1.1448 +        }
  1.1449 +    }
  1.1450 +}  // PatternMap::add
  1.1451 +
  1.1452 +// Find the pattern from the given basePattern string.
  1.1453 +const UnicodeString *
  1.1454 +PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for
  1.1455 +   PtnElem *curElem;
  1.1456 +
  1.1457 +   if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
  1.1458 +       return NULL;  // no match
  1.1459 +   }
  1.1460 +
  1.1461 +   do  {
  1.1462 +       if ( basePattern.compare(curElem->basePattern)==0 ) {
  1.1463 +          skeletonWasSpecified = curElem->skeletonWasSpecified;
  1.1464 +          return &(curElem->pattern);
  1.1465 +       }
  1.1466 +       curElem=curElem->next;
  1.1467 +   }while (curElem != NULL);
  1.1468 +
  1.1469 +   return NULL;
  1.1470 +}  // PatternMap::getFromBasePattern
  1.1471 +
  1.1472 +
  1.1473 +// Find the pattern from the given skeleton.
  1.1474 +// At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
  1.1475 +// the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
  1.1476 +// and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
  1.1477 +// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
  1.1478 +// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
  1.1479 +const UnicodeString *
  1.1480 +PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for
  1.1481 +   PtnElem *curElem;
  1.1482 +
  1.1483 +   if (specifiedSkeletonPtr) {
  1.1484 +       *specifiedSkeletonPtr = NULL;
  1.1485 +   }
  1.1486 +
  1.1487 +   // find boot entry
  1.1488 +   UChar baseChar='\0';
  1.1489 +   for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1490 +       if (skeleton.baseOriginal[i].length() !=0 ) {
  1.1491 +           baseChar = skeleton.baseOriginal[i].charAt(0);
  1.1492 +           break;
  1.1493 +       }
  1.1494 +   }
  1.1495 +
  1.1496 +   if ((curElem=getHeader(baseChar))==NULL) {
  1.1497 +       return NULL;  // no match
  1.1498 +   }
  1.1499 +
  1.1500 +   do  {
  1.1501 +       int32_t i=0;
  1.1502 +       if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
  1.1503 +           for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1504 +               if (curElem->skeleton->original[i].compare(skeleton.original[i]) != 0 )
  1.1505 +               {
  1.1506 +                   break;
  1.1507 +               }
  1.1508 +           }
  1.1509 +       } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
  1.1510 +           for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1511 +               if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 )
  1.1512 +               {
  1.1513 +                   break;
  1.1514 +               }
  1.1515 +           }
  1.1516 +       }
  1.1517 +       if (i == UDATPG_FIELD_COUNT) {
  1.1518 +           if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) {
  1.1519 +               *specifiedSkeletonPtr = curElem->skeleton;
  1.1520 +           }
  1.1521 +           return &(curElem->pattern);
  1.1522 +       }
  1.1523 +       curElem=curElem->next;
  1.1524 +   }while (curElem != NULL);
  1.1525 +
  1.1526 +   return NULL;
  1.1527 +}
  1.1528 +
  1.1529 +UBool
  1.1530 +PatternMap::equals(const PatternMap& other) {
  1.1531 +    if ( this==&other ) {
  1.1532 +        return TRUE;
  1.1533 +    }
  1.1534 +    for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
  1.1535 +        if ( boot[bootIndex]==other.boot[bootIndex] ) {
  1.1536 +            continue;
  1.1537 +        }
  1.1538 +        if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) {
  1.1539 +            return FALSE;
  1.1540 +        }
  1.1541 +        PtnElem *otherElem = other.boot[bootIndex];
  1.1542 +        PtnElem *myElem = boot[bootIndex];
  1.1543 +        while ((otherElem!=NULL) || (myElem!=NULL)) {
  1.1544 +            if ( myElem == otherElem ) {
  1.1545 +                break;
  1.1546 +            }
  1.1547 +            if ((otherElem==NULL) || (myElem==NULL)) {
  1.1548 +                return FALSE;
  1.1549 +            }
  1.1550 +            if ( (myElem->basePattern != otherElem->basePattern) ||
  1.1551 +                 (myElem->pattern != otherElem->pattern) ) {
  1.1552 +                return FALSE;
  1.1553 +            }
  1.1554 +            if ((myElem->skeleton!=otherElem->skeleton)&&
  1.1555 +                !myElem->skeleton->equals(*(otherElem->skeleton))) {
  1.1556 +                return FALSE;
  1.1557 +            }
  1.1558 +            myElem = myElem->next;
  1.1559 +            otherElem=otherElem->next;
  1.1560 +        }
  1.1561 +    }
  1.1562 +    return TRUE;
  1.1563 +}
  1.1564 +
  1.1565 +// find any key existing in the mapping table already.
  1.1566 +// return TRUE if there is an existing key, otherwise return FALSE.
  1.1567 +PtnElem*
  1.1568 +PatternMap::getDuplicateElem(
  1.1569 +            const UnicodeString &basePattern,
  1.1570 +            const PtnSkeleton &skeleton,
  1.1571 +            PtnElem *baseElem)  {
  1.1572 +   PtnElem *curElem;
  1.1573 +
  1.1574 +   if ( baseElem == (PtnElem *)NULL )  {
  1.1575 +         return (PtnElem*)NULL;
  1.1576 +   }
  1.1577 +   else {
  1.1578 +         curElem = baseElem;
  1.1579 +   }
  1.1580 +   do {
  1.1581 +     if ( basePattern.compare(curElem->basePattern)==0 ) {
  1.1582 +        UBool isEqual=TRUE;
  1.1583 +        for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1584 +            if (curElem->skeleton->type[i] != skeleton.type[i] ) {
  1.1585 +                isEqual=FALSE;
  1.1586 +                break;
  1.1587 +            }
  1.1588 +        }
  1.1589 +        if (isEqual) {
  1.1590 +            return curElem;
  1.1591 +        }
  1.1592 +     }
  1.1593 +     curElem = curElem->next;
  1.1594 +   } while( curElem != (PtnElem *)NULL );
  1.1595 +
  1.1596 +   // end of the list
  1.1597 +   return (PtnElem*)NULL;
  1.1598 +
  1.1599 +}  // PatternMap::getDuplicateElem
  1.1600 +
  1.1601 +DateTimeMatcher::DateTimeMatcher(void) {
  1.1602 +}
  1.1603 +
  1.1604 +DateTimeMatcher::~DateTimeMatcher() {}
  1.1605 +
  1.1606 +DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) {
  1.1607 +    copyFrom(other.skeleton);
  1.1608 +}
  1.1609 +
  1.1610 +
  1.1611 +void
  1.1612 +DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) {
  1.1613 +    PtnSkeleton localSkeleton;
  1.1614 +    return set(pattern, fp, localSkeleton);
  1.1615 +}
  1.1616 +
  1.1617 +void
  1.1618 +DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) {
  1.1619 +    int32_t i;
  1.1620 +    for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1621 +        skeletonResult.type[i]=NONE;
  1.1622 +    }
  1.1623 +    fp->set(pattern);
  1.1624 +    for (i=0; i < fp->itemNumber; i++) {
  1.1625 +        UnicodeString field = fp->items[i];
  1.1626 +        if ( field.charAt(0) == LOW_A ) {
  1.1627 +            continue;  // skip 'a'
  1.1628 +        }
  1.1629 +
  1.1630 +        if ( fp->isQuoteLiteral(field) ) {
  1.1631 +            UnicodeString quoteLiteral;
  1.1632 +            fp->getQuoteLiteral(quoteLiteral, &i);
  1.1633 +            continue;
  1.1634 +        }
  1.1635 +        int32_t canonicalIndex = fp->getCanonicalIndex(field);
  1.1636 +        if (canonicalIndex < 0 ) {
  1.1637 +            continue;
  1.1638 +        }
  1.1639 +        const dtTypeElem *row = &dtTypes[canonicalIndex];
  1.1640 +        int32_t typeValue = row->field;
  1.1641 +        skeletonResult.original[typeValue]=field;
  1.1642 +        UChar repeatChar = row->patternChar;
  1.1643 +        int32_t repeatCount = row->minLen; // #7930 removes cap at 3
  1.1644 +        while (repeatCount-- > 0) {
  1.1645 +            skeletonResult.baseOriginal[typeValue] += repeatChar;
  1.1646 +        }
  1.1647 +        int16_t subTypeValue = row->type;
  1.1648 +        if ( row->type > 0) {
  1.1649 +            subTypeValue += field.length();
  1.1650 +        }
  1.1651 +        skeletonResult.type[typeValue] = subTypeValue;
  1.1652 +    }
  1.1653 +    copyFrom(skeletonResult);
  1.1654 +}
  1.1655 +
  1.1656 +void
  1.1657 +DateTimeMatcher::getBasePattern(UnicodeString &result ) {
  1.1658 +    result.remove(); // Reset the result first.
  1.1659 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
  1.1660 +        if (skeleton.baseOriginal[i].length()!=0) {
  1.1661 +            result += skeleton.baseOriginal[i];
  1.1662 +        }
  1.1663 +    }
  1.1664 +}
  1.1665 +
  1.1666 +UnicodeString
  1.1667 +DateTimeMatcher::getPattern() {
  1.1668 +    UnicodeString result;
  1.1669 +
  1.1670 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
  1.1671 +        if (skeleton.original[i].length()!=0) {
  1.1672 +            result += skeleton.original[i];
  1.1673 +        }
  1.1674 +    }
  1.1675 +    return result;
  1.1676 +}
  1.1677 +
  1.1678 +int32_t
  1.1679 +DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) {
  1.1680 +    int32_t result=0;
  1.1681 +    distanceInfo.clear();
  1.1682 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
  1.1683 +        int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
  1.1684 +        int32_t otherType = other.skeleton.type[i];
  1.1685 +        if (myType==otherType) {
  1.1686 +            continue;
  1.1687 +        }
  1.1688 +        if (myType==0) {// and other is not
  1.1689 +            result += EXTRA_FIELD;
  1.1690 +            distanceInfo.addExtra(i);
  1.1691 +        }
  1.1692 +        else {
  1.1693 +            if (otherType==0) {
  1.1694 +                result += MISSING_FIELD;
  1.1695 +                distanceInfo.addMissing(i);
  1.1696 +            }
  1.1697 +            else {
  1.1698 +                result += abs(myType - otherType);
  1.1699 +            }
  1.1700 +        }
  1.1701 +
  1.1702 +    }
  1.1703 +    return result;
  1.1704 +}
  1.1705 +
  1.1706 +void
  1.1707 +DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) {
  1.1708 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1709 +        this->skeleton.type[i]=newSkeleton.type[i];
  1.1710 +        this->skeleton.original[i]=newSkeleton.original[i];
  1.1711 +        this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i];
  1.1712 +    }
  1.1713 +}
  1.1714 +
  1.1715 +void
  1.1716 +DateTimeMatcher::copyFrom() {
  1.1717 +    // same as clear
  1.1718 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1719 +        this->skeleton.type[i]=0;
  1.1720 +        this->skeleton.original[i].remove();
  1.1721 +        this->skeleton.baseOriginal[i].remove();
  1.1722 +    }
  1.1723 +}
  1.1724 +
  1.1725 +UBool
  1.1726 +DateTimeMatcher::equals(const DateTimeMatcher* other) const {
  1.1727 +    if (other==NULL) {
  1.1728 +        return FALSE;
  1.1729 +    }
  1.1730 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1731 +        if (this->skeleton.original[i]!=other->skeleton.original[i] ) {
  1.1732 +            return FALSE;
  1.1733 +        }
  1.1734 +    }
  1.1735 +    return TRUE;
  1.1736 +}
  1.1737 +
  1.1738 +int32_t
  1.1739 +DateTimeMatcher::getFieldMask() {
  1.1740 +    int32_t result=0;
  1.1741 +
  1.1742 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.1743 +        if (skeleton.type[i]!=0) {
  1.1744 +            result |= (1<<i);
  1.1745 +        }
  1.1746 +    }
  1.1747 +    return result;
  1.1748 +}
  1.1749 +
  1.1750 +PtnSkeleton*
  1.1751 +DateTimeMatcher::getSkeletonPtr() {
  1.1752 +    return &skeleton;
  1.1753 +}
  1.1754 +
  1.1755 +FormatParser::FormatParser () {
  1.1756 +    status = START;
  1.1757 +    itemNumber=0;
  1.1758 +}
  1.1759 +
  1.1760 +
  1.1761 +FormatParser::~FormatParser () {
  1.1762 +}
  1.1763 +
  1.1764 +
  1.1765 +// Find the next token with the starting position and length
  1.1766 +// Note: the startPos may
  1.1767 +FormatParser::TokenStatus
  1.1768 +FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
  1.1769 +    int32_t  curLoc = startPos;
  1.1770 +    if ( curLoc >= pattern.length()) {
  1.1771 +        return DONE;
  1.1772 +    }
  1.1773 +    // check the current char is between A-Z or a-z
  1.1774 +    do {
  1.1775 +        UChar c=pattern.charAt(curLoc);
  1.1776 +        if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) {
  1.1777 +           curLoc++;
  1.1778 +        }
  1.1779 +        else {
  1.1780 +               startPos = curLoc;
  1.1781 +               *len=1;
  1.1782 +               return ADD_TOKEN;
  1.1783 +        }
  1.1784 +
  1.1785 +        if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) {
  1.1786 +            break;  // not the same token
  1.1787 +        }
  1.1788 +    } while(curLoc <= pattern.length());
  1.1789 +    *len = curLoc-startPos;
  1.1790 +    return ADD_TOKEN;
  1.1791 +}
  1.1792 +
  1.1793 +void
  1.1794 +FormatParser::set(const UnicodeString& pattern) {
  1.1795 +    int32_t startPos=0;
  1.1796 +    TokenStatus result=START;
  1.1797 +    int32_t len=0;
  1.1798 +    itemNumber =0;
  1.1799 +
  1.1800 +    do {
  1.1801 +        result = setTokens( pattern, startPos, &len );
  1.1802 +        if ( result == ADD_TOKEN )
  1.1803 +        {
  1.1804 +            items[itemNumber++] = UnicodeString(pattern, startPos, len );
  1.1805 +            startPos += len;
  1.1806 +        }
  1.1807 +        else {
  1.1808 +            break;
  1.1809 +        }
  1.1810 +    } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN);
  1.1811 +}
  1.1812 +
  1.1813 +int32_t
  1.1814 +FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) {
  1.1815 +    int32_t len = s.length();
  1.1816 +    if (len == 0) {
  1.1817 +        return -1;
  1.1818 +    }
  1.1819 +    UChar ch = s.charAt(0);
  1.1820 +
  1.1821 +    // Verify that all are the same character.
  1.1822 +    for (int32_t l = 1; l < len; l++) {
  1.1823 +        if (ch != s.charAt(l)) {
  1.1824 +            return -1;
  1.1825 +        }
  1.1826 +    }
  1.1827 +    int32_t i = 0;
  1.1828 +    int32_t bestRow = -1;
  1.1829 +    while (dtTypes[i].patternChar != '\0') {
  1.1830 +        if ( dtTypes[i].patternChar != ch ) {
  1.1831 +            ++i;
  1.1832 +            continue;
  1.1833 +        }
  1.1834 +        bestRow = i;
  1.1835 +        if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) {
  1.1836 +            return i;
  1.1837 +        }
  1.1838 +        if (dtTypes[i+1].minLen <= len) {
  1.1839 +            ++i;
  1.1840 +            continue;
  1.1841 +        }
  1.1842 +        return i;
  1.1843 +    }
  1.1844 +    return strict ? -1 : bestRow;
  1.1845 +}
  1.1846 +
  1.1847 +UBool
  1.1848 +FormatParser::isQuoteLiteral(const UnicodeString& s) const {
  1.1849 +    return (UBool)(s.charAt(0)==SINGLE_QUOTE);
  1.1850 +}
  1.1851 +
  1.1852 +// This function aussumes the current itemIndex points to the quote literal.
  1.1853 +// Please call isQuoteLiteral prior to this function.
  1.1854 +void
  1.1855 +FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
  1.1856 +    int32_t i=*itemIndex;
  1.1857 +
  1.1858 +    quote.remove();
  1.1859 +    if (items[i].charAt(0)==SINGLE_QUOTE) {
  1.1860 +        quote += items[i];
  1.1861 +        ++i;
  1.1862 +    }
  1.1863 +    while ( i < itemNumber ) {
  1.1864 +        if ( items[i].charAt(0)==SINGLE_QUOTE ) {
  1.1865 +            if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) {
  1.1866 +                // two single quotes e.g. 'o''clock'
  1.1867 +                quote += items[i++];
  1.1868 +                quote += items[i++];
  1.1869 +                continue;
  1.1870 +            }
  1.1871 +            else {
  1.1872 +                quote += items[i];
  1.1873 +                break;
  1.1874 +            }
  1.1875 +        }
  1.1876 +        else {
  1.1877 +            quote += items[i];
  1.1878 +        }
  1.1879 +        ++i;
  1.1880 +    }
  1.1881 +    *itemIndex=i;
  1.1882 +}
  1.1883 +
  1.1884 +UBool
  1.1885 +FormatParser::isPatternSeparator(UnicodeString& field) {
  1.1886 +    for (int32_t i=0; i<field.length(); ++i ) {
  1.1887 +        UChar c= field.charAt(i);
  1.1888 +        if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
  1.1889 +             (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) {
  1.1890 +            continue;
  1.1891 +        }
  1.1892 +        else {
  1.1893 +            return FALSE;
  1.1894 +        }
  1.1895 +    }
  1.1896 +    return TRUE;
  1.1897 +}
  1.1898 +
  1.1899 +DistanceInfo::~DistanceInfo() {}
  1.1900 +
  1.1901 +void
  1.1902 +DistanceInfo::setTo(DistanceInfo &other) {
  1.1903 +    missingFieldMask = other.missingFieldMask;
  1.1904 +    extraFieldMask= other.extraFieldMask;
  1.1905 +}
  1.1906 +
  1.1907 +PatternMapIterator::PatternMapIterator() {
  1.1908 +    bootIndex = 0;
  1.1909 +    nodePtr = NULL;
  1.1910 +    patternMap=NULL;
  1.1911 +    matcher= new DateTimeMatcher();
  1.1912 +}
  1.1913 +
  1.1914 +
  1.1915 +PatternMapIterator::~PatternMapIterator() {
  1.1916 +    delete matcher;
  1.1917 +}
  1.1918 +
  1.1919 +void
  1.1920 +PatternMapIterator::set(PatternMap& newPatternMap) {
  1.1921 +    this->patternMap=&newPatternMap;
  1.1922 +}
  1.1923 +
  1.1924 +PtnSkeleton*
  1.1925 +PatternMapIterator::getSkeleton() {
  1.1926 +    if ( nodePtr == NULL ) {
  1.1927 +        return NULL;
  1.1928 +    }
  1.1929 +    else {
  1.1930 +        return nodePtr->skeleton;
  1.1931 +    }
  1.1932 +}
  1.1933 +
  1.1934 +UBool
  1.1935 +PatternMapIterator::hasNext() {
  1.1936 +    int32_t headIndex=bootIndex;
  1.1937 +    PtnElem *curPtr=nodePtr;
  1.1938 +
  1.1939 +    if (patternMap==NULL) {
  1.1940 +        return FALSE;
  1.1941 +    }
  1.1942 +    while ( headIndex < MAX_PATTERN_ENTRIES ) {
  1.1943 +        if ( curPtr != NULL ) {
  1.1944 +            if ( curPtr->next != NULL ) {
  1.1945 +                return TRUE;
  1.1946 +            }
  1.1947 +            else {
  1.1948 +                headIndex++;
  1.1949 +                curPtr=NULL;
  1.1950 +                continue;
  1.1951 +            }
  1.1952 +        }
  1.1953 +        else {
  1.1954 +            if ( patternMap->boot[headIndex] != NULL ) {
  1.1955 +                return TRUE;
  1.1956 +            }
  1.1957 +            else {
  1.1958 +                headIndex++;
  1.1959 +                continue;
  1.1960 +            }
  1.1961 +        }
  1.1962 +
  1.1963 +    }
  1.1964 +    return FALSE;
  1.1965 +}
  1.1966 +
  1.1967 +DateTimeMatcher&
  1.1968 +PatternMapIterator::next() {
  1.1969 +    while ( bootIndex < MAX_PATTERN_ENTRIES ) {
  1.1970 +        if ( nodePtr != NULL ) {
  1.1971 +            if ( nodePtr->next != NULL ) {
  1.1972 +                nodePtr = nodePtr->next;
  1.1973 +                break;
  1.1974 +            }
  1.1975 +            else {
  1.1976 +                bootIndex++;
  1.1977 +                nodePtr=NULL;
  1.1978 +                continue;
  1.1979 +            }
  1.1980 +        }
  1.1981 +        else {
  1.1982 +            if ( patternMap->boot[bootIndex] != NULL ) {
  1.1983 +                nodePtr = patternMap->boot[bootIndex];
  1.1984 +                break;
  1.1985 +            }
  1.1986 +            else {
  1.1987 +                bootIndex++;
  1.1988 +                continue;
  1.1989 +            }
  1.1990 +        }
  1.1991 +    }
  1.1992 +    if (nodePtr!=NULL) {
  1.1993 +        matcher->copyFrom(*nodePtr->skeleton);
  1.1994 +    }
  1.1995 +    else {
  1.1996 +        matcher->copyFrom();
  1.1997 +    }
  1.1998 +    return *matcher;
  1.1999 +}
  1.2000 +
  1.2001 +PtnSkeleton::PtnSkeleton() {
  1.2002 +}
  1.2003 +
  1.2004 +
  1.2005 +PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) {
  1.2006 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.2007 +        this->type[i]=other.type[i];
  1.2008 +        this->original[i]=other.original[i];
  1.2009 +        this->baseOriginal[i]=other.baseOriginal[i];
  1.2010 +    }
  1.2011 +}
  1.2012 +
  1.2013 +UBool
  1.2014 +PtnSkeleton::equals(const PtnSkeleton& other)  {
  1.2015 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.2016 +        if ( (type[i]!= other.type[i]) ||
  1.2017 +             (original[i]!=other.original[i]) ||
  1.2018 +             (baseOriginal[i]!=other.baseOriginal[i]) ) {
  1.2019 +            return FALSE;
  1.2020 +        }
  1.2021 +    }
  1.2022 +    return TRUE;
  1.2023 +}
  1.2024 +
  1.2025 +UnicodeString
  1.2026 +PtnSkeleton::getSkeleton() {
  1.2027 +    UnicodeString result;
  1.2028 +
  1.2029 +    for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
  1.2030 +        if (original[i].length()!=0) {
  1.2031 +            result += original[i];
  1.2032 +        }
  1.2033 +    }
  1.2034 +    return result;
  1.2035 +}
  1.2036 +
  1.2037 +UnicodeString
  1.2038 +PtnSkeleton::getBaseSkeleton() {
  1.2039 +    UnicodeString result;
  1.2040 +
  1.2041 +    for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
  1.2042 +        if (baseOriginal[i].length()!=0) {
  1.2043 +            result += baseOriginal[i];
  1.2044 +        }
  1.2045 +    }
  1.2046 +    return result;
  1.2047 +}
  1.2048 +
  1.2049 +PtnSkeleton::~PtnSkeleton() {
  1.2050 +}
  1.2051 +
  1.2052 +PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
  1.2053 +basePattern(basePat),
  1.2054 +skeleton(NULL),
  1.2055 +pattern(pat),
  1.2056 +next(NULL)
  1.2057 +{
  1.2058 +}
  1.2059 +
  1.2060 +PtnElem::~PtnElem() {
  1.2061 +
  1.2062 +    if (next!=NULL) {
  1.2063 +        delete next;
  1.2064 +    }
  1.2065 +    delete skeleton;
  1.2066 +}
  1.2067 +
  1.2068 +DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) {
  1.2069 +    PtnElem  *curElem;
  1.2070 +    PtnSkeleton *curSkeleton;
  1.2071 +    UnicodeString s;
  1.2072 +    int32_t bootIndex;
  1.2073 +
  1.2074 +    pos=0;
  1.2075 +    fSkeletons = new UVector(status);
  1.2076 +    if (U_FAILURE(status)) {
  1.2077 +        delete fSkeletons;
  1.2078 +        return;
  1.2079 +    }
  1.2080 +    for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
  1.2081 +        curElem = patternMap.boot[bootIndex];
  1.2082 +        while (curElem!=NULL) {
  1.2083 +            switch(type) {
  1.2084 +                case DT_BASESKELETON:
  1.2085 +                    s=curElem->basePattern;
  1.2086 +                    break;
  1.2087 +                case DT_PATTERN:
  1.2088 +                    s=curElem->pattern;
  1.2089 +                    break;
  1.2090 +                case DT_SKELETON:
  1.2091 +                    curSkeleton=curElem->skeleton;
  1.2092 +                    s=curSkeleton->getSkeleton();
  1.2093 +                    break;
  1.2094 +            }
  1.2095 +            if ( !isCanonicalItem(s) ) {
  1.2096 +                fSkeletons->addElement(new UnicodeString(s), status);
  1.2097 +                if (U_FAILURE(status)) {
  1.2098 +                    delete fSkeletons;
  1.2099 +                    fSkeletons = NULL;
  1.2100 +                    return;
  1.2101 +                }
  1.2102 +            }
  1.2103 +            curElem = curElem->next;
  1.2104 +        }
  1.2105 +    }
  1.2106 +    if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) {
  1.2107 +        status = U_BUFFER_OVERFLOW_ERROR;
  1.2108 +    }
  1.2109 +}
  1.2110 +
  1.2111 +const UnicodeString*
  1.2112 +DTSkeletonEnumeration::snext(UErrorCode& status) {
  1.2113 +    if (U_SUCCESS(status) && pos < fSkeletons->size()) {
  1.2114 +        return (const UnicodeString*)fSkeletons->elementAt(pos++);
  1.2115 +    }
  1.2116 +    return NULL;
  1.2117 +}
  1.2118 +
  1.2119 +void
  1.2120 +DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
  1.2121 +    pos=0;
  1.2122 +}
  1.2123 +
  1.2124 +int32_t
  1.2125 +DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
  1.2126 +   return (fSkeletons==NULL) ? 0 : fSkeletons->size();
  1.2127 +}
  1.2128 +
  1.2129 +UBool
  1.2130 +DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
  1.2131 +    if ( item.length() != 1 ) {
  1.2132 +        return FALSE;
  1.2133 +    }
  1.2134 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.2135 +        if (item.charAt(0)==Canonical_Items[i]) {
  1.2136 +            return TRUE;
  1.2137 +        }
  1.2138 +    }
  1.2139 +    return FALSE;
  1.2140 +}
  1.2141 +
  1.2142 +DTSkeletonEnumeration::~DTSkeletonEnumeration() {
  1.2143 +    UnicodeString *s;
  1.2144 +    for (int32_t i=0; i<fSkeletons->size(); ++i) {
  1.2145 +        if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) {
  1.2146 +            delete s;
  1.2147 +        }
  1.2148 +    }
  1.2149 +    delete fSkeletons;
  1.2150 +}
  1.2151 +
  1.2152 +DTRedundantEnumeration::DTRedundantEnumeration() {
  1.2153 +    pos=0;
  1.2154 +    fPatterns = NULL;
  1.2155 +}
  1.2156 +
  1.2157 +void
  1.2158 +DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
  1.2159 +    if (U_FAILURE(status)) return;
  1.2160 +    if (fPatterns == NULL)  {
  1.2161 +        fPatterns = new UVector(status);
  1.2162 +        if (U_FAILURE(status)) {
  1.2163 +            delete fPatterns;
  1.2164 +            fPatterns = NULL;
  1.2165 +            return;
  1.2166 +       }
  1.2167 +    }
  1.2168 +    fPatterns->addElement(new UnicodeString(pattern), status);
  1.2169 +    if (U_FAILURE(status)) {
  1.2170 +        delete fPatterns;
  1.2171 +        fPatterns = NULL;
  1.2172 +        return;
  1.2173 +    }
  1.2174 +}
  1.2175 +
  1.2176 +const UnicodeString*
  1.2177 +DTRedundantEnumeration::snext(UErrorCode& status) {
  1.2178 +    if (U_SUCCESS(status) && pos < fPatterns->size()) {
  1.2179 +        return (const UnicodeString*)fPatterns->elementAt(pos++);
  1.2180 +    }
  1.2181 +    return NULL;
  1.2182 +}
  1.2183 +
  1.2184 +void
  1.2185 +DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
  1.2186 +    pos=0;
  1.2187 +}
  1.2188 +
  1.2189 +int32_t
  1.2190 +DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
  1.2191 +       return (fPatterns==NULL) ? 0 : fPatterns->size();
  1.2192 +}
  1.2193 +
  1.2194 +UBool
  1.2195 +DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
  1.2196 +    if ( item.length() != 1 ) {
  1.2197 +        return FALSE;
  1.2198 +    }
  1.2199 +    for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
  1.2200 +        if (item.charAt(0)==Canonical_Items[i]) {
  1.2201 +            return TRUE;
  1.2202 +        }
  1.2203 +    }
  1.2204 +    return FALSE;
  1.2205 +}
  1.2206 +
  1.2207 +DTRedundantEnumeration::~DTRedundantEnumeration() {
  1.2208 +    UnicodeString *s;
  1.2209 +    for (int32_t i=0; i<fPatterns->size(); ++i) {
  1.2210 +        if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) {
  1.2211 +            delete s;
  1.2212 +        }
  1.2213 +    }
  1.2214 +    delete fPatterns;
  1.2215 +}
  1.2216 +
  1.2217 +U_NAMESPACE_END
  1.2218 +
  1.2219 +
  1.2220 +#endif /* #if !UCONFIG_NO_FORMATTING */
  1.2221 +
  1.2222 +//eof

mercurial