1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/dtitvinf.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,676 @@ 1.4 +/******************************************************************************* 1.5 +* Copyright (C) 2008-2012, International Business Machines Corporation and 1.6 +* others. All Rights Reserved. 1.7 +******************************************************************************* 1.8 +* 1.9 +* File DTITVINF.CPP 1.10 +* 1.11 +******************************************************************************* 1.12 +*/ 1.13 + 1.14 +#include "unicode/dtitvinf.h" 1.15 + 1.16 + 1.17 +#if !UCONFIG_NO_FORMATTING 1.18 + 1.19 +//TODO: define it in compiler time 1.20 +//#define DTITVINF_DEBUG 1 1.21 + 1.22 + 1.23 +#ifdef DTITVINF_DEBUG 1.24 +#include <iostream> 1.25 +#endif 1.26 + 1.27 +#include "cstring.h" 1.28 +#include "unicode/msgfmt.h" 1.29 +#include "unicode/uloc.h" 1.30 +#include "unicode/ures.h" 1.31 +#include "dtitv_impl.h" 1.32 +#include "hash.h" 1.33 +#include "gregoimp.h" 1.34 +#include "uresimp.h" 1.35 +#include "hash.h" 1.36 +#include "gregoimp.h" 1.37 +#include "uresimp.h" 1.38 + 1.39 + 1.40 +U_NAMESPACE_BEGIN 1.41 + 1.42 + 1.43 +#ifdef DTITVINF_DEBUG 1.44 +#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; } 1.45 +#endif 1.46 + 1.47 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo) 1.48 + 1.49 +static const char gCalendarTag[]="calendar"; 1.50 +static const char gGregorianTag[]="gregorian"; 1.51 +static const char gIntervalDateTimePatternTag[]="intervalFormats"; 1.52 +static const char gFallbackPatternTag[]="fallback"; 1.53 + 1.54 +// {0} 1.55 +static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET}; 1.56 +// {1} 1.57 +static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET}; 1.58 + 1.59 +// default fall-back 1.60 +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}; 1.61 + 1.62 + 1.63 + 1.64 +DateIntervalInfo::DateIntervalInfo(UErrorCode& status) 1.65 +: fFallbackIntervalPattern(gDefaultFallbackPattern), 1.66 + fFirstDateInPtnIsLaterDate(false), 1.67 + fIntervalPatterns(NULL) 1.68 +{ 1.69 + fIntervalPatterns = initHash(status); 1.70 +} 1.71 + 1.72 + 1.73 + 1.74 +DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status) 1.75 +: fFallbackIntervalPattern(gDefaultFallbackPattern), 1.76 + fFirstDateInPtnIsLaterDate(false), 1.77 + fIntervalPatterns(NULL) 1.78 +{ 1.79 + initializeData(locale, status); 1.80 +} 1.81 + 1.82 + 1.83 + 1.84 +void 1.85 +DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton, 1.86 + UCalendarDateFields lrgDiffCalUnit, 1.87 + const UnicodeString& intervalPattern, 1.88 + UErrorCode& status) { 1.89 + 1.90 + if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) { 1.91 + setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status); 1.92 + setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status); 1.93 + } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH || 1.94 + lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) { 1.95 + setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status); 1.96 + } else { 1.97 + setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status); 1.98 + } 1.99 +} 1.100 + 1.101 + 1.102 +void 1.103 +DateIntervalInfo::setFallbackIntervalPattern( 1.104 + const UnicodeString& fallbackPattern, 1.105 + UErrorCode& status) { 1.106 + if ( U_FAILURE(status) ) { 1.107 + return; 1.108 + } 1.109 + int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, 1.110 + sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0); 1.111 + int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, 1.112 + sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0); 1.113 + if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) { 1.114 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.115 + return; 1.116 + } 1.117 + if ( firstPatternIndex > secondPatternIndex ) { 1.118 + fFirstDateInPtnIsLaterDate = true; 1.119 + } 1.120 + fFallbackIntervalPattern = fallbackPattern; 1.121 +} 1.122 + 1.123 + 1.124 + 1.125 +DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) 1.126 +: UObject(dtitvinf), 1.127 + fIntervalPatterns(NULL) 1.128 +{ 1.129 + *this = dtitvinf; 1.130 +} 1.131 + 1.132 + 1.133 + 1.134 +DateIntervalInfo& 1.135 +DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) { 1.136 + if ( this == &dtitvinf ) { 1.137 + return *this; 1.138 + } 1.139 + 1.140 + UErrorCode status = U_ZERO_ERROR; 1.141 + deleteHash(fIntervalPatterns); 1.142 + fIntervalPatterns = initHash(status); 1.143 + copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status); 1.144 + if ( U_FAILURE(status) ) { 1.145 + return *this; 1.146 + } 1.147 + 1.148 + fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern; 1.149 + fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate; 1.150 + return *this; 1.151 +} 1.152 + 1.153 + 1.154 +DateIntervalInfo* 1.155 +DateIntervalInfo::clone() const { 1.156 + return new DateIntervalInfo(*this); 1.157 +} 1.158 + 1.159 + 1.160 +DateIntervalInfo::~DateIntervalInfo() { 1.161 + deleteHash(fIntervalPatterns); 1.162 + fIntervalPatterns = NULL; 1.163 +} 1.164 + 1.165 + 1.166 +UBool 1.167 +DateIntervalInfo::operator==(const DateIntervalInfo& other) const { 1.168 + UBool equal = ( 1.169 + fFallbackIntervalPattern == other.fFallbackIntervalPattern && 1.170 + fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate ); 1.171 + 1.172 + if ( equal == TRUE ) { 1.173 + equal = fIntervalPatterns->equals(*(other.fIntervalPatterns)); 1.174 + } 1.175 + 1.176 + return equal; 1.177 +} 1.178 + 1.179 + 1.180 +UnicodeString& 1.181 +DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton, 1.182 + UCalendarDateFields field, 1.183 + UnicodeString& result, 1.184 + UErrorCode& status) const { 1.185 + if ( U_FAILURE(status) ) { 1.186 + return result; 1.187 + } 1.188 + 1.189 + const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton); 1.190 + if ( patternsOfOneSkeleton != NULL ) { 1.191 + IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status); 1.192 + if ( U_FAILURE(status) ) { 1.193 + return result; 1.194 + } 1.195 + const UnicodeString& intervalPattern = patternsOfOneSkeleton[index]; 1.196 + if ( !intervalPattern.isEmpty() ) { 1.197 + result = intervalPattern; 1.198 + } 1.199 + } 1.200 + return result; 1.201 +} 1.202 + 1.203 + 1.204 +UBool 1.205 +DateIntervalInfo::getDefaultOrder() const { 1.206 + return fFirstDateInPtnIsLaterDate; 1.207 +} 1.208 + 1.209 + 1.210 +UnicodeString& 1.211 +DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const { 1.212 + result = fFallbackIntervalPattern; 1.213 + return result; 1.214 +} 1.215 + 1.216 +#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) 1.217 + 1.218 +void 1.219 +DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err) 1.220 +{ 1.221 + fIntervalPatterns = initHash(err); 1.222 + if ( U_FAILURE(err) ) { 1.223 + return; 1.224 + } 1.225 + const char *locName = locale.getName(); 1.226 + char parentLocale[ULOC_FULLNAME_CAPACITY]; 1.227 + uprv_strcpy(parentLocale, locName); 1.228 + UErrorCode status = U_ZERO_ERROR; 1.229 + Hashtable skeletonSet(FALSE, status); 1.230 + if ( U_FAILURE(status) ) { 1.231 + return; 1.232 + } 1.233 + 1.234 + // determine calendar type 1.235 + const char * calendarTypeToUse = gGregorianTag; // initial default 1.236 + char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well 1.237 + char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; 1.238 + // obtain a locale that always has the calendar key value that should be used 1.239 + (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL, 1.240 + "calendar", "calendar", locName, NULL, FALSE, &status); 1.241 + localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination 1.242 + // now get the calendar key value from that locale 1.243 + int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status); 1.244 + if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { 1.245 + calendarTypeToUse = calendarType; 1.246 + } 1.247 + status = U_ZERO_ERROR; 1.248 + 1.249 + do { 1.250 + UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource; 1.251 + rb = ures_open(NULL, parentLocale, &status); 1.252 + if ( U_FAILURE(status) ) { 1.253 + break; 1.254 + } 1.255 + calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); 1.256 + calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); 1.257 + itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, 1.258 + gIntervalDateTimePatternTag, NULL, &status); 1.259 + 1.260 + if ( U_SUCCESS(status) ) { 1.261 + // look for fallback first, since it establishes the default order 1.262 + const UChar* resStr; 1.263 + int32_t resStrLen = 0; 1.264 + resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, 1.265 + gFallbackPatternTag, 1.266 + &resStrLen, &status); 1.267 + if ( U_SUCCESS(status) ) { 1.268 + UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen); 1.269 + setFallbackIntervalPattern(pattern, status); 1.270 + } 1.271 + 1.272 + int32_t size = ures_getSize(itvDtPtnResource); 1.273 + int32_t index; 1.274 + for ( index = 0; index < size; ++index ) { 1.275 + LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index, 1.276 + NULL, &status)); 1.277 + if ( U_SUCCESS(status) ) { 1.278 + const char* skeleton = ures_getKey(oneRes.getAlias()); 1.279 + if (skeleton == NULL) { 1.280 + continue; 1.281 + } 1.282 + UnicodeString skeletonUniStr(skeleton, -1, US_INV); 1.283 + if ( skeletonSet.geti(skeletonUniStr) == 1 ) { 1.284 + continue; 1.285 + } 1.286 + skeletonSet.puti(skeletonUniStr, 1, status); 1.287 + if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { 1.288 + continue; // fallback 1.289 + } 1.290 + 1.291 + LocalUResourceBundlePointer intervalPatterns(ures_getByKey( 1.292 + itvDtPtnResource, skeleton, NULL, &status)); 1.293 + 1.294 + if ( U_FAILURE(status) ) { 1.295 + break; 1.296 + } 1.297 + if ( intervalPatterns == NULL ) { 1.298 + continue; 1.299 + } 1.300 + 1.301 + const char* key; 1.302 + int32_t ptnNum = ures_getSize(intervalPatterns.getAlias()); 1.303 + int32_t ptnIndex; 1.304 + for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { 1.305 + UnicodeString pattern = 1.306 + ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status); 1.307 + if ( U_FAILURE(status) ) { 1.308 + break; 1.309 + } 1.310 + 1.311 + UCalendarDateFields calendarField = UCAL_FIELD_COUNT; 1.312 + if ( !uprv_strcmp(key, "y") ) { 1.313 + calendarField = UCAL_YEAR; 1.314 + } else if ( !uprv_strcmp(key, "M") ) { 1.315 + calendarField = UCAL_MONTH; 1.316 + } else if ( !uprv_strcmp(key, "d") ) { 1.317 + calendarField = UCAL_DATE; 1.318 + } else if ( !uprv_strcmp(key, "a") ) { 1.319 + calendarField = UCAL_AM_PM; 1.320 + } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { 1.321 + calendarField = UCAL_HOUR; 1.322 + } else if ( !uprv_strcmp(key, "m") ) { 1.323 + calendarField = UCAL_MINUTE; 1.324 + } 1.325 + if ( calendarField != UCAL_FIELD_COUNT ) { 1.326 + setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status); 1.327 + } 1.328 + } 1.329 + } 1.330 + } 1.331 + } 1.332 + ures_close(itvDtPtnResource); 1.333 + ures_close(calTypeBundle); 1.334 + ures_close(calBundle); 1.335 + 1.336 + status = U_ZERO_ERROR; 1.337 + // Find the name of the appropriate parent locale (from %%Parent if present, else 1.338 + // uloc_getParent on the actual locale name) 1.339 + // (It would be nice to have a ures function that did this...) 1.340 + int32_t locNameLen; 1.341 + const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status); 1.342 + if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) { 1.343 + u_UCharsToChars(parentUName, parentLocale, locNameLen + 1); 1.344 + } else { 1.345 + status = U_ZERO_ERROR; 1.346 + // Get the actual name of the current locale being used 1.347 + const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status); 1.348 + if ( U_FAILURE(status) ) { 1.349 + curLocaleName = parentLocale; 1.350 + status = U_ZERO_ERROR; 1.351 + } 1.352 + uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status); 1.353 + if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { 1.354 + parentLocale[0] = 0; // just fallback to root, will cause us to stop 1.355 + status = U_ZERO_ERROR; 1.356 + } 1.357 + } 1.358 + // Now we can close the current locale bundle 1.359 + ures_close(rb); 1.360 + // If the new current locale is root, then stop 1.361 + // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up 1.362 + // to root to find additional data for non-root locales) 1.363 + } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 ); 1.364 +} 1.365 + 1.366 + 1.367 + 1.368 +void 1.369 +DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton, 1.370 + UCalendarDateFields lrgDiffCalUnit, 1.371 + const UnicodeString& intervalPattern, 1.372 + UErrorCode& status) { 1.373 + IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status); 1.374 + if ( U_FAILURE(status) ) { 1.375 + return; 1.376 + } 1.377 + UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton)); 1.378 + UBool emptyHash = false; 1.379 + if ( patternsOfOneSkeleton == NULL ) { 1.380 + patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX]; 1.381 + emptyHash = true; 1.382 + } 1.383 + 1.384 + patternsOfOneSkeleton[index] = intervalPattern; 1.385 + if ( emptyHash == TRUE ) { 1.386 + fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status); 1.387 + } 1.388 +} 1.389 + 1.390 + 1.391 + 1.392 +void 1.393 +DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton, 1.394 + int32_t* skeletonFieldWidth) { 1.395 + const int8_t PATTERN_CHAR_BASE = 0x41; 1.396 + int32_t i; 1.397 + for ( i = 0; i < skeleton.length(); ++i ) { 1.398 + // it is an ASCII char in skeleton 1.399 + int8_t ch = (int8_t)skeleton.charAt(i); 1.400 + ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE]; 1.401 + } 1.402 +} 1.403 + 1.404 + 1.405 + 1.406 +UBool 1.407 +DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, 1.408 + char patternLetter) { 1.409 + if ( patternLetter == 'M' ) { 1.410 + if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || 1.411 + (fieldWidth > 2 && anotherFieldWidth <= 2 )) { 1.412 + return true; 1.413 + } 1.414 + } 1.415 + return false; 1.416 +} 1.417 + 1.418 + 1.419 + 1.420 +const UnicodeString* 1.421 +DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, 1.422 + int8_t& bestMatchDistanceInfo) const { 1.423 +#ifdef DTITVINF_DEBUG 1.424 + char result[1000]; 1.425 + char result_1[1000]; 1.426 + char mesg[2000]; 1.427 + skeleton.extract(0, skeleton.length(), result, "UTF-8"); 1.428 + sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result); 1.429 + PRINTMESG(mesg) 1.430 +#endif 1.431 + 1.432 + 1.433 + int32_t inputSkeletonFieldWidth[] = 1.434 + { 1.435 + // A B C D E F G H I J K L M N O 1.436 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.437 + // P Q R S T U V W X Y Z 1.438 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.439 + // a b c d e f g h i j k l m n o 1.440 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.441 + // p q r s t u v w x y z 1.442 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1.443 + }; 1.444 + 1.445 + int32_t skeletonFieldWidth[] = 1.446 + { 1.447 + // A B C D E F G H I J K L M N O 1.448 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.449 + // P Q R S T U V W X Y Z 1.450 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.451 + // a b c d e f g h i j k l m n o 1.452 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.453 + // p q r s t u v w x y z 1.454 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1.455 + }; 1.456 + 1.457 + const int32_t DIFFERENT_FIELD = 0x1000; 1.458 + const int32_t STRING_NUMERIC_DIFFERENCE = 0x100; 1.459 + const int32_t BASE = 0x41; 1.460 + const UChar CHAR_V = 0x0076; 1.461 + const UChar CHAR_Z = 0x007A; 1.462 + 1.463 + // hack for 'v' and 'z'. 1.464 + // resource bundle only have time skeletons ending with 'v', 1.465 + // but not for time skeletons ending with 'z'. 1.466 + UBool replaceZWithV = false; 1.467 + const UnicodeString* inputSkeleton = &skeleton; 1.468 + UnicodeString copySkeleton; 1.469 + if ( skeleton.indexOf(CHAR_Z) != -1 ) { 1.470 + copySkeleton = skeleton; 1.471 + copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V)); 1.472 + inputSkeleton = ©Skeleton; 1.473 + replaceZWithV = true; 1.474 + } 1.475 + 1.476 + parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth); 1.477 + int32_t bestDistance = MAX_POSITIVE_INT; 1.478 + const UnicodeString* bestSkeleton = NULL; 1.479 + 1.480 + // 0 means exact the same skeletons; 1.481 + // 1 means having the same field, but with different length, 1.482 + // 2 means only z/v differs 1.483 + // -1 means having different field. 1.484 + bestMatchDistanceInfo = 0; 1.485 + int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]); 1.486 + 1.487 + int32_t pos = -1; 1.488 + const UHashElement* elem = NULL; 1.489 + while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) { 1.490 + const UHashTok keyTok = elem->key; 1.491 + UnicodeString* skeleton = (UnicodeString*)keyTok.pointer; 1.492 +#ifdef DTITVINF_DEBUG 1.493 + skeleton->extract(0, skeleton->length(), result, "UTF-8"); 1.494 + sprintf(mesg, "available skeletons: skeleton: %s; \n", result); 1.495 + PRINTMESG(mesg) 1.496 +#endif 1.497 + 1.498 + // clear skeleton field width 1.499 + int8_t i; 1.500 + for ( i = 0; i < fieldLength; ++i ) { 1.501 + skeletonFieldWidth[i] = 0; 1.502 + } 1.503 + parseSkeleton(*skeleton, skeletonFieldWidth); 1.504 + // calculate distance 1.505 + int32_t distance = 0; 1.506 + int8_t fieldDifference = 1; 1.507 + for ( i = 0; i < fieldLength; ++i ) { 1.508 + int32_t inputFieldWidth = inputSkeletonFieldWidth[i]; 1.509 + int32_t fieldWidth = skeletonFieldWidth[i]; 1.510 + if ( inputFieldWidth == fieldWidth ) { 1.511 + continue; 1.512 + } 1.513 + if ( inputFieldWidth == 0 ) { 1.514 + fieldDifference = -1; 1.515 + distance += DIFFERENT_FIELD; 1.516 + } else if ( fieldWidth == 0 ) { 1.517 + fieldDifference = -1; 1.518 + distance += DIFFERENT_FIELD; 1.519 + } else if (stringNumeric(inputFieldWidth, fieldWidth, 1.520 + (char)(i+BASE) ) ) { 1.521 + distance += STRING_NUMERIC_DIFFERENCE; 1.522 + } else { 1.523 + distance += (inputFieldWidth > fieldWidth) ? 1.524 + (inputFieldWidth - fieldWidth) : 1.525 + (fieldWidth - inputFieldWidth); 1.526 + } 1.527 + } 1.528 + if ( distance < bestDistance ) { 1.529 + bestSkeleton = skeleton; 1.530 + bestDistance = distance; 1.531 + bestMatchDistanceInfo = fieldDifference; 1.532 + } 1.533 + if ( distance == 0 ) { 1.534 + bestMatchDistanceInfo = 0; 1.535 + break; 1.536 + } 1.537 + } 1.538 + if ( replaceZWithV && bestMatchDistanceInfo != -1 ) { 1.539 + bestMatchDistanceInfo = 2; 1.540 + } 1.541 + return bestSkeleton; 1.542 +} 1.543 + 1.544 + 1.545 + 1.546 +DateIntervalInfo::IntervalPatternIndex 1.547 +DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, 1.548 + UErrorCode& status) { 1.549 + if ( U_FAILURE(status) ) { 1.550 + return kIPI_MAX_INDEX; 1.551 + } 1.552 + IntervalPatternIndex index = kIPI_MAX_INDEX; 1.553 + switch ( field ) { 1.554 + case UCAL_ERA: 1.555 + index = kIPI_ERA; 1.556 + break; 1.557 + case UCAL_YEAR: 1.558 + index = kIPI_YEAR; 1.559 + break; 1.560 + case UCAL_MONTH: 1.561 + index = kIPI_MONTH; 1.562 + break; 1.563 + case UCAL_DATE: 1.564 + case UCAL_DAY_OF_WEEK: 1.565 + //case UCAL_DAY_OF_MONTH: 1.566 + index = kIPI_DATE; 1.567 + break; 1.568 + case UCAL_AM_PM: 1.569 + index = kIPI_AM_PM; 1.570 + break; 1.571 + case UCAL_HOUR: 1.572 + case UCAL_HOUR_OF_DAY: 1.573 + index = kIPI_HOUR; 1.574 + break; 1.575 + case UCAL_MINUTE: 1.576 + index = kIPI_MINUTE; 1.577 + break; 1.578 + default: 1.579 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.580 + } 1.581 + return index; 1.582 +} 1.583 + 1.584 + 1.585 + 1.586 +void 1.587 +DateIntervalInfo::deleteHash(Hashtable* hTable) 1.588 +{ 1.589 + if ( hTable == NULL ) { 1.590 + return; 1.591 + } 1.592 + int32_t pos = -1; 1.593 + const UHashElement* element = NULL; 1.594 + while ( (element = hTable->nextElement(pos)) != NULL ) { 1.595 + const UHashTok valueTok = element->value; 1.596 + const UnicodeString* value = (UnicodeString*)valueTok.pointer; 1.597 + delete[] value; 1.598 + } 1.599 + delete fIntervalPatterns; 1.600 +} 1.601 + 1.602 + 1.603 +U_CDECL_BEGIN 1.604 + 1.605 +/** 1.606 + * set hash table value comparator 1.607 + * 1.608 + * @param val1 one value in comparison 1.609 + * @param val2 the other value in comparison 1.610 + * @return TRUE if 2 values are the same, FALSE otherwise 1.611 + */ 1.612 +static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); 1.613 + 1.614 +static UBool 1.615 +U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { 1.616 + const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; 1.617 + const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; 1.618 + UBool ret = TRUE; 1.619 + int8_t i; 1.620 + for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { 1.621 + ret = (pattern1[i] == pattern2[i]); 1.622 + } 1.623 + return ret; 1.624 +} 1.625 + 1.626 +U_CDECL_END 1.627 + 1.628 + 1.629 +Hashtable* 1.630 +DateIntervalInfo::initHash(UErrorCode& status) { 1.631 + if ( U_FAILURE(status) ) { 1.632 + return NULL; 1.633 + } 1.634 + Hashtable* hTable; 1.635 + if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { 1.636 + status = U_MEMORY_ALLOCATION_ERROR; 1.637 + return NULL; 1.638 + } 1.639 + if ( U_FAILURE(status) ) { 1.640 + delete hTable; 1.641 + return NULL; 1.642 + } 1.643 + hTable->setValueComparator(dtitvinfHashTableValueComparator); 1.644 + return hTable; 1.645 +} 1.646 + 1.647 + 1.648 +void 1.649 +DateIntervalInfo::copyHash(const Hashtable* source, 1.650 + Hashtable* target, 1.651 + UErrorCode& status) { 1.652 + if ( U_FAILURE(status) ) { 1.653 + return; 1.654 + } 1.655 + int32_t pos = -1; 1.656 + const UHashElement* element = NULL; 1.657 + if ( source ) { 1.658 + while ( (element = source->nextElement(pos)) != NULL ) { 1.659 + const UHashTok keyTok = element->key; 1.660 + const UnicodeString* key = (UnicodeString*)keyTok.pointer; 1.661 + const UHashTok valueTok = element->value; 1.662 + const UnicodeString* value = (UnicodeString*)valueTok.pointer; 1.663 + UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX]; 1.664 + int8_t i; 1.665 + for ( i = 0; i < kIPI_MAX_INDEX; ++i ) { 1.666 + copy[i] = value[i]; 1.667 + } 1.668 + target->put(UnicodeString(*key), copy, status); 1.669 + if ( U_FAILURE(status) ) { 1.670 + return; 1.671 + } 1.672 + } 1.673 + } 1.674 +} 1.675 + 1.676 + 1.677 +U_NAMESPACE_END 1.678 + 1.679 +#endif