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