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