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