intl/icu/source/i18n/dtitvinf.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*******************************************************************************
michael@0 2 * Copyright (C) 2008-2012, International Business Machines Corporation and
michael@0 3 * others. All Rights Reserved.
michael@0 4 *******************************************************************************
michael@0 5 *
michael@0 6 * File DTITVINF.CPP
michael@0 7 *
michael@0 8 *******************************************************************************
michael@0 9 */
michael@0 10
michael@0 11 #include "unicode/dtitvinf.h"
michael@0 12
michael@0 13
michael@0 14 #if !UCONFIG_NO_FORMATTING
michael@0 15
michael@0 16 //TODO: define it in compiler time
michael@0 17 //#define DTITVINF_DEBUG 1
michael@0 18
michael@0 19
michael@0 20 #ifdef DTITVINF_DEBUG
michael@0 21 #include <iostream>
michael@0 22 #endif
michael@0 23
michael@0 24 #include "cstring.h"
michael@0 25 #include "unicode/msgfmt.h"
michael@0 26 #include "unicode/uloc.h"
michael@0 27 #include "unicode/ures.h"
michael@0 28 #include "dtitv_impl.h"
michael@0 29 #include "hash.h"
michael@0 30 #include "gregoimp.h"
michael@0 31 #include "uresimp.h"
michael@0 32 #include "hash.h"
michael@0 33 #include "gregoimp.h"
michael@0 34 #include "uresimp.h"
michael@0 35
michael@0 36
michael@0 37 U_NAMESPACE_BEGIN
michael@0 38
michael@0 39
michael@0 40 #ifdef DTITVINF_DEBUG
michael@0 41 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
michael@0 42 #endif
michael@0 43
michael@0 44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
michael@0 45
michael@0 46 static const char gCalendarTag[]="calendar";
michael@0 47 static const char gGregorianTag[]="gregorian";
michael@0 48 static const char gIntervalDateTimePatternTag[]="intervalFormats";
michael@0 49 static const char gFallbackPatternTag[]="fallback";
michael@0 50
michael@0 51 // {0}
michael@0 52 static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
michael@0 53 // {1}
michael@0 54 static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
michael@0 55
michael@0 56 // default fall-back
michael@0 57 static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
michael@0 58
michael@0 59
michael@0 60
michael@0 61 DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
michael@0 62 : fFallbackIntervalPattern(gDefaultFallbackPattern),
michael@0 63 fFirstDateInPtnIsLaterDate(false),
michael@0 64 fIntervalPatterns(NULL)
michael@0 65 {
michael@0 66 fIntervalPatterns = initHash(status);
michael@0 67 }
michael@0 68
michael@0 69
michael@0 70
michael@0 71 DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
michael@0 72 : fFallbackIntervalPattern(gDefaultFallbackPattern),
michael@0 73 fFirstDateInPtnIsLaterDate(false),
michael@0 74 fIntervalPatterns(NULL)
michael@0 75 {
michael@0 76 initializeData(locale, status);
michael@0 77 }
michael@0 78
michael@0 79
michael@0 80
michael@0 81 void
michael@0 82 DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
michael@0 83 UCalendarDateFields lrgDiffCalUnit,
michael@0 84 const UnicodeString& intervalPattern,
michael@0 85 UErrorCode& status) {
michael@0 86
michael@0 87 if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
michael@0 88 setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
michael@0 89 setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
michael@0 90 } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
michael@0 91 lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
michael@0 92 setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
michael@0 93 } else {
michael@0 94 setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98
michael@0 99 void
michael@0 100 DateIntervalInfo::setFallbackIntervalPattern(
michael@0 101 const UnicodeString& fallbackPattern,
michael@0 102 UErrorCode& status) {
michael@0 103 if ( U_FAILURE(status) ) {
michael@0 104 return;
michael@0 105 }
michael@0 106 int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
michael@0 107 sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
michael@0 108 int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
michael@0 109 sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
michael@0 110 if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
michael@0 111 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 112 return;
michael@0 113 }
michael@0 114 if ( firstPatternIndex > secondPatternIndex ) {
michael@0 115 fFirstDateInPtnIsLaterDate = true;
michael@0 116 }
michael@0 117 fFallbackIntervalPattern = fallbackPattern;
michael@0 118 }
michael@0 119
michael@0 120
michael@0 121
michael@0 122 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
michael@0 123 : UObject(dtitvinf),
michael@0 124 fIntervalPatterns(NULL)
michael@0 125 {
michael@0 126 *this = dtitvinf;
michael@0 127 }
michael@0 128
michael@0 129
michael@0 130
michael@0 131 DateIntervalInfo&
michael@0 132 DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
michael@0 133 if ( this == &dtitvinf ) {
michael@0 134 return *this;
michael@0 135 }
michael@0 136
michael@0 137 UErrorCode status = U_ZERO_ERROR;
michael@0 138 deleteHash(fIntervalPatterns);
michael@0 139 fIntervalPatterns = initHash(status);
michael@0 140 copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
michael@0 141 if ( U_FAILURE(status) ) {
michael@0 142 return *this;
michael@0 143 }
michael@0 144
michael@0 145 fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
michael@0 146 fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
michael@0 147 return *this;
michael@0 148 }
michael@0 149
michael@0 150
michael@0 151 DateIntervalInfo*
michael@0 152 DateIntervalInfo::clone() const {
michael@0 153 return new DateIntervalInfo(*this);
michael@0 154 }
michael@0 155
michael@0 156
michael@0 157 DateIntervalInfo::~DateIntervalInfo() {
michael@0 158 deleteHash(fIntervalPatterns);
michael@0 159 fIntervalPatterns = NULL;
michael@0 160 }
michael@0 161
michael@0 162
michael@0 163 UBool
michael@0 164 DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
michael@0 165 UBool equal = (
michael@0 166 fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
michael@0 167 fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
michael@0 168
michael@0 169 if ( equal == TRUE ) {
michael@0 170 equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
michael@0 171 }
michael@0 172
michael@0 173 return equal;
michael@0 174 }
michael@0 175
michael@0 176
michael@0 177 UnicodeString&
michael@0 178 DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
michael@0 179 UCalendarDateFields field,
michael@0 180 UnicodeString& result,
michael@0 181 UErrorCode& status) const {
michael@0 182 if ( U_FAILURE(status) ) {
michael@0 183 return result;
michael@0 184 }
michael@0 185
michael@0 186 const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
michael@0 187 if ( patternsOfOneSkeleton != NULL ) {
michael@0 188 IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
michael@0 189 if ( U_FAILURE(status) ) {
michael@0 190 return result;
michael@0 191 }
michael@0 192 const UnicodeString& intervalPattern = patternsOfOneSkeleton[index];
michael@0 193 if ( !intervalPattern.isEmpty() ) {
michael@0 194 result = intervalPattern;
michael@0 195 }
michael@0 196 }
michael@0 197 return result;
michael@0 198 }
michael@0 199
michael@0 200
michael@0 201 UBool
michael@0 202 DateIntervalInfo::getDefaultOrder() const {
michael@0 203 return fFirstDateInPtnIsLaterDate;
michael@0 204 }
michael@0 205
michael@0 206
michael@0 207 UnicodeString&
michael@0 208 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
michael@0 209 result = fFallbackIntervalPattern;
michael@0 210 return result;
michael@0 211 }
michael@0 212
michael@0 213 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
michael@0 214
michael@0 215 void
michael@0 216 DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
michael@0 217 {
michael@0 218 fIntervalPatterns = initHash(err);
michael@0 219 if ( U_FAILURE(err) ) {
michael@0 220 return;
michael@0 221 }
michael@0 222 const char *locName = locale.getName();
michael@0 223 char parentLocale[ULOC_FULLNAME_CAPACITY];
michael@0 224 uprv_strcpy(parentLocale, locName);
michael@0 225 UErrorCode status = U_ZERO_ERROR;
michael@0 226 Hashtable skeletonSet(FALSE, status);
michael@0 227 if ( U_FAILURE(status) ) {
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 // determine calendar type
michael@0 232 const char * calendarTypeToUse = gGregorianTag; // initial default
michael@0 233 char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
michael@0 234 char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
michael@0 235 // obtain a locale that always has the calendar key value that should be used
michael@0 236 (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
michael@0 237 "calendar", "calendar", locName, NULL, FALSE, &status);
michael@0 238 localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
michael@0 239 // now get the calendar key value from that locale
michael@0 240 int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status);
michael@0 241 if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
michael@0 242 calendarTypeToUse = calendarType;
michael@0 243 }
michael@0 244 status = U_ZERO_ERROR;
michael@0 245
michael@0 246 do {
michael@0 247 UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
michael@0 248 rb = ures_open(NULL, parentLocale, &status);
michael@0 249 if ( U_FAILURE(status) ) {
michael@0 250 break;
michael@0 251 }
michael@0 252 calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
michael@0 253 calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
michael@0 254 itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
michael@0 255 gIntervalDateTimePatternTag, NULL, &status);
michael@0 256
michael@0 257 if ( U_SUCCESS(status) ) {
michael@0 258 // look for fallback first, since it establishes the default order
michael@0 259 const UChar* resStr;
michael@0 260 int32_t resStrLen = 0;
michael@0 261 resStr = ures_getStringByKeyWithFallback(itvDtPtnResource,
michael@0 262 gFallbackPatternTag,
michael@0 263 &resStrLen, &status);
michael@0 264 if ( U_SUCCESS(status) ) {
michael@0 265 UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
michael@0 266 setFallbackIntervalPattern(pattern, status);
michael@0 267 }
michael@0 268
michael@0 269 int32_t size = ures_getSize(itvDtPtnResource);
michael@0 270 int32_t index;
michael@0 271 for ( index = 0; index < size; ++index ) {
michael@0 272 LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index,
michael@0 273 NULL, &status));
michael@0 274 if ( U_SUCCESS(status) ) {
michael@0 275 const char* skeleton = ures_getKey(oneRes.getAlias());
michael@0 276 if (skeleton == NULL) {
michael@0 277 continue;
michael@0 278 }
michael@0 279 UnicodeString skeletonUniStr(skeleton, -1, US_INV);
michael@0 280 if ( skeletonSet.geti(skeletonUniStr) == 1 ) {
michael@0 281 continue;
michael@0 282 }
michael@0 283 skeletonSet.puti(skeletonUniStr, 1, status);
michael@0 284 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
michael@0 285 continue; // fallback
michael@0 286 }
michael@0 287
michael@0 288 LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
michael@0 289 itvDtPtnResource, skeleton, NULL, &status));
michael@0 290
michael@0 291 if ( U_FAILURE(status) ) {
michael@0 292 break;
michael@0 293 }
michael@0 294 if ( intervalPatterns == NULL ) {
michael@0 295 continue;
michael@0 296 }
michael@0 297
michael@0 298 const char* key;
michael@0 299 int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
michael@0 300 int32_t ptnIndex;
michael@0 301 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
michael@0 302 UnicodeString pattern =
michael@0 303 ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
michael@0 304 if ( U_FAILURE(status) ) {
michael@0 305 break;
michael@0 306 }
michael@0 307
michael@0 308 UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
michael@0 309 if ( !uprv_strcmp(key, "y") ) {
michael@0 310 calendarField = UCAL_YEAR;
michael@0 311 } else if ( !uprv_strcmp(key, "M") ) {
michael@0 312 calendarField = UCAL_MONTH;
michael@0 313 } else if ( !uprv_strcmp(key, "d") ) {
michael@0 314 calendarField = UCAL_DATE;
michael@0 315 } else if ( !uprv_strcmp(key, "a") ) {
michael@0 316 calendarField = UCAL_AM_PM;
michael@0 317 } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
michael@0 318 calendarField = UCAL_HOUR;
michael@0 319 } else if ( !uprv_strcmp(key, "m") ) {
michael@0 320 calendarField = UCAL_MINUTE;
michael@0 321 }
michael@0 322 if ( calendarField != UCAL_FIELD_COUNT ) {
michael@0 323 setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327 }
michael@0 328 }
michael@0 329 ures_close(itvDtPtnResource);
michael@0 330 ures_close(calTypeBundle);
michael@0 331 ures_close(calBundle);
michael@0 332
michael@0 333 status = U_ZERO_ERROR;
michael@0 334 // Find the name of the appropriate parent locale (from %%Parent if present, else
michael@0 335 // uloc_getParent on the actual locale name)
michael@0 336 // (It would be nice to have a ures function that did this...)
michael@0 337 int32_t locNameLen;
michael@0 338 const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status);
michael@0 339 if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
michael@0 340 u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
michael@0 341 } else {
michael@0 342 status = U_ZERO_ERROR;
michael@0 343 // Get the actual name of the current locale being used
michael@0 344 const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status);
michael@0 345 if ( U_FAILURE(status) ) {
michael@0 346 curLocaleName = parentLocale;
michael@0 347 status = U_ZERO_ERROR;
michael@0 348 }
michael@0 349 uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status);
michael@0 350 if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
michael@0 351 parentLocale[0] = 0; // just fallback to root, will cause us to stop
michael@0 352 status = U_ZERO_ERROR;
michael@0 353 }
michael@0 354 }
michael@0 355 // Now we can close the current locale bundle
michael@0 356 ures_close(rb);
michael@0 357 // If the new current locale is root, then stop
michael@0 358 // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up
michael@0 359 // to root to find additional data for non-root locales)
michael@0 360 } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 );
michael@0 361 }
michael@0 362
michael@0 363
michael@0 364
michael@0 365 void
michael@0 366 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
michael@0 367 UCalendarDateFields lrgDiffCalUnit,
michael@0 368 const UnicodeString& intervalPattern,
michael@0 369 UErrorCode& status) {
michael@0 370 IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
michael@0 371 if ( U_FAILURE(status) ) {
michael@0 372 return;
michael@0 373 }
michael@0 374 UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
michael@0 375 UBool emptyHash = false;
michael@0 376 if ( patternsOfOneSkeleton == NULL ) {
michael@0 377 patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
michael@0 378 emptyHash = true;
michael@0 379 }
michael@0 380
michael@0 381 patternsOfOneSkeleton[index] = intervalPattern;
michael@0 382 if ( emptyHash == TRUE ) {
michael@0 383 fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
michael@0 384 }
michael@0 385 }
michael@0 386
michael@0 387
michael@0 388
michael@0 389 void
michael@0 390 DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
michael@0 391 int32_t* skeletonFieldWidth) {
michael@0 392 const int8_t PATTERN_CHAR_BASE = 0x41;
michael@0 393 int32_t i;
michael@0 394 for ( i = 0; i < skeleton.length(); ++i ) {
michael@0 395 // it is an ASCII char in skeleton
michael@0 396 int8_t ch = (int8_t)skeleton.charAt(i);
michael@0 397 ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
michael@0 398 }
michael@0 399 }
michael@0 400
michael@0 401
michael@0 402
michael@0 403 UBool
michael@0 404 DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
michael@0 405 char patternLetter) {
michael@0 406 if ( patternLetter == 'M' ) {
michael@0 407 if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
michael@0 408 (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
michael@0 409 return true;
michael@0 410 }
michael@0 411 }
michael@0 412 return false;
michael@0 413 }
michael@0 414
michael@0 415
michael@0 416
michael@0 417 const UnicodeString*
michael@0 418 DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
michael@0 419 int8_t& bestMatchDistanceInfo) const {
michael@0 420 #ifdef DTITVINF_DEBUG
michael@0 421 char result[1000];
michael@0 422 char result_1[1000];
michael@0 423 char mesg[2000];
michael@0 424 skeleton.extract(0, skeleton.length(), result, "UTF-8");
michael@0 425 sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
michael@0 426 PRINTMESG(mesg)
michael@0 427 #endif
michael@0 428
michael@0 429
michael@0 430 int32_t inputSkeletonFieldWidth[] =
michael@0 431 {
michael@0 432 // A B C D E F G H I J K L M N O
michael@0 433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 434 // P Q R S T U V W X Y Z
michael@0 435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 436 // a b c d e f g h i j k l m n o
michael@0 437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 438 // p q r s t u v w x y z
michael@0 439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 440 };
michael@0 441
michael@0 442 int32_t skeletonFieldWidth[] =
michael@0 443 {
michael@0 444 // A B C D E F G H I J K L M N O
michael@0 445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 446 // P Q R S T U V W X Y Z
michael@0 447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 448 // a b c d e f g h i j k l m n o
michael@0 449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 450 // p q r s t u v w x y z
michael@0 451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 452 };
michael@0 453
michael@0 454 const int32_t DIFFERENT_FIELD = 0x1000;
michael@0 455 const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
michael@0 456 const int32_t BASE = 0x41;
michael@0 457 const UChar CHAR_V = 0x0076;
michael@0 458 const UChar CHAR_Z = 0x007A;
michael@0 459
michael@0 460 // hack for 'v' and 'z'.
michael@0 461 // resource bundle only have time skeletons ending with 'v',
michael@0 462 // but not for time skeletons ending with 'z'.
michael@0 463 UBool replaceZWithV = false;
michael@0 464 const UnicodeString* inputSkeleton = &skeleton;
michael@0 465 UnicodeString copySkeleton;
michael@0 466 if ( skeleton.indexOf(CHAR_Z) != -1 ) {
michael@0 467 copySkeleton = skeleton;
michael@0 468 copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
michael@0 469 inputSkeleton = &copySkeleton;
michael@0 470 replaceZWithV = true;
michael@0 471 }
michael@0 472
michael@0 473 parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
michael@0 474 int32_t bestDistance = MAX_POSITIVE_INT;
michael@0 475 const UnicodeString* bestSkeleton = NULL;
michael@0 476
michael@0 477 // 0 means exact the same skeletons;
michael@0 478 // 1 means having the same field, but with different length,
michael@0 479 // 2 means only z/v differs
michael@0 480 // -1 means having different field.
michael@0 481 bestMatchDistanceInfo = 0;
michael@0 482 int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
michael@0 483
michael@0 484 int32_t pos = -1;
michael@0 485 const UHashElement* elem = NULL;
michael@0 486 while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
michael@0 487 const UHashTok keyTok = elem->key;
michael@0 488 UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
michael@0 489 #ifdef DTITVINF_DEBUG
michael@0 490 skeleton->extract(0, skeleton->length(), result, "UTF-8");
michael@0 491 sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
michael@0 492 PRINTMESG(mesg)
michael@0 493 #endif
michael@0 494
michael@0 495 // clear skeleton field width
michael@0 496 int8_t i;
michael@0 497 for ( i = 0; i < fieldLength; ++i ) {
michael@0 498 skeletonFieldWidth[i] = 0;
michael@0 499 }
michael@0 500 parseSkeleton(*skeleton, skeletonFieldWidth);
michael@0 501 // calculate distance
michael@0 502 int32_t distance = 0;
michael@0 503 int8_t fieldDifference = 1;
michael@0 504 for ( i = 0; i < fieldLength; ++i ) {
michael@0 505 int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
michael@0 506 int32_t fieldWidth = skeletonFieldWidth[i];
michael@0 507 if ( inputFieldWidth == fieldWidth ) {
michael@0 508 continue;
michael@0 509 }
michael@0 510 if ( inputFieldWidth == 0 ) {
michael@0 511 fieldDifference = -1;
michael@0 512 distance += DIFFERENT_FIELD;
michael@0 513 } else if ( fieldWidth == 0 ) {
michael@0 514 fieldDifference = -1;
michael@0 515 distance += DIFFERENT_FIELD;
michael@0 516 } else if (stringNumeric(inputFieldWidth, fieldWidth,
michael@0 517 (char)(i+BASE) ) ) {
michael@0 518 distance += STRING_NUMERIC_DIFFERENCE;
michael@0 519 } else {
michael@0 520 distance += (inputFieldWidth > fieldWidth) ?
michael@0 521 (inputFieldWidth - fieldWidth) :
michael@0 522 (fieldWidth - inputFieldWidth);
michael@0 523 }
michael@0 524 }
michael@0 525 if ( distance < bestDistance ) {
michael@0 526 bestSkeleton = skeleton;
michael@0 527 bestDistance = distance;
michael@0 528 bestMatchDistanceInfo = fieldDifference;
michael@0 529 }
michael@0 530 if ( distance == 0 ) {
michael@0 531 bestMatchDistanceInfo = 0;
michael@0 532 break;
michael@0 533 }
michael@0 534 }
michael@0 535 if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
michael@0 536 bestMatchDistanceInfo = 2;
michael@0 537 }
michael@0 538 return bestSkeleton;
michael@0 539 }
michael@0 540
michael@0 541
michael@0 542
michael@0 543 DateIntervalInfo::IntervalPatternIndex
michael@0 544 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
michael@0 545 UErrorCode& status) {
michael@0 546 if ( U_FAILURE(status) ) {
michael@0 547 return kIPI_MAX_INDEX;
michael@0 548 }
michael@0 549 IntervalPatternIndex index = kIPI_MAX_INDEX;
michael@0 550 switch ( field ) {
michael@0 551 case UCAL_ERA:
michael@0 552 index = kIPI_ERA;
michael@0 553 break;
michael@0 554 case UCAL_YEAR:
michael@0 555 index = kIPI_YEAR;
michael@0 556 break;
michael@0 557 case UCAL_MONTH:
michael@0 558 index = kIPI_MONTH;
michael@0 559 break;
michael@0 560 case UCAL_DATE:
michael@0 561 case UCAL_DAY_OF_WEEK:
michael@0 562 //case UCAL_DAY_OF_MONTH:
michael@0 563 index = kIPI_DATE;
michael@0 564 break;
michael@0 565 case UCAL_AM_PM:
michael@0 566 index = kIPI_AM_PM;
michael@0 567 break;
michael@0 568 case UCAL_HOUR:
michael@0 569 case UCAL_HOUR_OF_DAY:
michael@0 570 index = kIPI_HOUR;
michael@0 571 break;
michael@0 572 case UCAL_MINUTE:
michael@0 573 index = kIPI_MINUTE;
michael@0 574 break;
michael@0 575 default:
michael@0 576 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 577 }
michael@0 578 return index;
michael@0 579 }
michael@0 580
michael@0 581
michael@0 582
michael@0 583 void
michael@0 584 DateIntervalInfo::deleteHash(Hashtable* hTable)
michael@0 585 {
michael@0 586 if ( hTable == NULL ) {
michael@0 587 return;
michael@0 588 }
michael@0 589 int32_t pos = -1;
michael@0 590 const UHashElement* element = NULL;
michael@0 591 while ( (element = hTable->nextElement(pos)) != NULL ) {
michael@0 592 const UHashTok valueTok = element->value;
michael@0 593 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
michael@0 594 delete[] value;
michael@0 595 }
michael@0 596 delete fIntervalPatterns;
michael@0 597 }
michael@0 598
michael@0 599
michael@0 600 U_CDECL_BEGIN
michael@0 601
michael@0 602 /**
michael@0 603 * set hash table value comparator
michael@0 604 *
michael@0 605 * @param val1 one value in comparison
michael@0 606 * @param val2 the other value in comparison
michael@0 607 * @return TRUE if 2 values are the same, FALSE otherwise
michael@0 608 */
michael@0 609 static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
michael@0 610
michael@0 611 static UBool
michael@0 612 U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
michael@0 613 const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
michael@0 614 const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
michael@0 615 UBool ret = TRUE;
michael@0 616 int8_t i;
michael@0 617 for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
michael@0 618 ret = (pattern1[i] == pattern2[i]);
michael@0 619 }
michael@0 620 return ret;
michael@0 621 }
michael@0 622
michael@0 623 U_CDECL_END
michael@0 624
michael@0 625
michael@0 626 Hashtable*
michael@0 627 DateIntervalInfo::initHash(UErrorCode& status) {
michael@0 628 if ( U_FAILURE(status) ) {
michael@0 629 return NULL;
michael@0 630 }
michael@0 631 Hashtable* hTable;
michael@0 632 if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
michael@0 633 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 634 return NULL;
michael@0 635 }
michael@0 636 if ( U_FAILURE(status) ) {
michael@0 637 delete hTable;
michael@0 638 return NULL;
michael@0 639 }
michael@0 640 hTable->setValueComparator(dtitvinfHashTableValueComparator);
michael@0 641 return hTable;
michael@0 642 }
michael@0 643
michael@0 644
michael@0 645 void
michael@0 646 DateIntervalInfo::copyHash(const Hashtable* source,
michael@0 647 Hashtable* target,
michael@0 648 UErrorCode& status) {
michael@0 649 if ( U_FAILURE(status) ) {
michael@0 650 return;
michael@0 651 }
michael@0 652 int32_t pos = -1;
michael@0 653 const UHashElement* element = NULL;
michael@0 654 if ( source ) {
michael@0 655 while ( (element = source->nextElement(pos)) != NULL ) {
michael@0 656 const UHashTok keyTok = element->key;
michael@0 657 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 658 const UHashTok valueTok = element->value;
michael@0 659 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
michael@0 660 UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
michael@0 661 int8_t i;
michael@0 662 for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
michael@0 663 copy[i] = value[i];
michael@0 664 }
michael@0 665 target->put(UnicodeString(*key), copy, status);
michael@0 666 if ( U_FAILURE(status) ) {
michael@0 667 return;
michael@0 668 }
michael@0 669 }
michael@0 670 }
michael@0 671 }
michael@0 672
michael@0 673
michael@0 674 U_NAMESPACE_END
michael@0 675
michael@0 676 #endif

mercurial