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