michael@0: /******************************************************************************* michael@0: * Copyright (C) 2008-2012, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ******************************************************************************* michael@0: * michael@0: * File DTITVINF.CPP michael@0: * michael@0: ******************************************************************************* michael@0: */ michael@0: michael@0: #include "unicode/dtitvinf.h" michael@0: michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: //TODO: define it in compiler time michael@0: //#define DTITVINF_DEBUG 1 michael@0: michael@0: michael@0: #ifdef DTITVINF_DEBUG michael@0: #include michael@0: #endif michael@0: michael@0: #include "cstring.h" michael@0: #include "unicode/msgfmt.h" michael@0: #include "unicode/uloc.h" michael@0: #include "unicode/ures.h" michael@0: #include "dtitv_impl.h" michael@0: #include "hash.h" michael@0: #include "gregoimp.h" michael@0: #include "uresimp.h" michael@0: #include "hash.h" michael@0: #include "gregoimp.h" michael@0: #include "uresimp.h" michael@0: michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: michael@0: #ifdef DTITVINF_DEBUG michael@0: #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; } michael@0: #endif michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo) michael@0: michael@0: static const char gCalendarTag[]="calendar"; michael@0: static const char gGregorianTag[]="gregorian"; michael@0: static const char gIntervalDateTimePatternTag[]="intervalFormats"; michael@0: static const char gFallbackPatternTag[]="fallback"; michael@0: michael@0: // {0} michael@0: static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET}; michael@0: // {1} michael@0: static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET}; michael@0: michael@0: // default fall-back michael@0: 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: michael@0: michael@0: michael@0: DateIntervalInfo::DateIntervalInfo(UErrorCode& status) michael@0: : fFallbackIntervalPattern(gDefaultFallbackPattern), michael@0: fFirstDateInPtnIsLaterDate(false), michael@0: fIntervalPatterns(NULL) michael@0: { michael@0: fIntervalPatterns = initHash(status); michael@0: } michael@0: michael@0: michael@0: michael@0: DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status) michael@0: : fFallbackIntervalPattern(gDefaultFallbackPattern), michael@0: fFirstDateInPtnIsLaterDate(false), michael@0: fIntervalPatterns(NULL) michael@0: { michael@0: initializeData(locale, status); michael@0: } michael@0: michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton, michael@0: UCalendarDateFields lrgDiffCalUnit, michael@0: const UnicodeString& intervalPattern, michael@0: UErrorCode& status) { michael@0: michael@0: if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) { michael@0: setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status); michael@0: setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status); michael@0: } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH || michael@0: lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) { michael@0: setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status); michael@0: } else { michael@0: setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status); michael@0: } michael@0: } michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::setFallbackIntervalPattern( michael@0: const UnicodeString& fallbackPattern, michael@0: UErrorCode& status) { michael@0: if ( U_FAILURE(status) ) { michael@0: return; michael@0: } michael@0: int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, michael@0: sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0); michael@0: int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, michael@0: sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0); michael@0: if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return; michael@0: } michael@0: if ( firstPatternIndex > secondPatternIndex ) { michael@0: fFirstDateInPtnIsLaterDate = true; michael@0: } michael@0: fFallbackIntervalPattern = fallbackPattern; michael@0: } michael@0: michael@0: michael@0: michael@0: DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) michael@0: : UObject(dtitvinf), michael@0: fIntervalPatterns(NULL) michael@0: { michael@0: *this = dtitvinf; michael@0: } michael@0: michael@0: michael@0: michael@0: DateIntervalInfo& michael@0: DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) { michael@0: if ( this == &dtitvinf ) { michael@0: return *this; michael@0: } michael@0: michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: deleteHash(fIntervalPatterns); michael@0: fIntervalPatterns = initHash(status); michael@0: copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status); michael@0: if ( U_FAILURE(status) ) { michael@0: return *this; michael@0: } michael@0: michael@0: fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern; michael@0: fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate; michael@0: return *this; michael@0: } michael@0: michael@0: michael@0: DateIntervalInfo* michael@0: DateIntervalInfo::clone() const { michael@0: return new DateIntervalInfo(*this); michael@0: } michael@0: michael@0: michael@0: DateIntervalInfo::~DateIntervalInfo() { michael@0: deleteHash(fIntervalPatterns); michael@0: fIntervalPatterns = NULL; michael@0: } michael@0: michael@0: michael@0: UBool michael@0: DateIntervalInfo::operator==(const DateIntervalInfo& other) const { michael@0: UBool equal = ( michael@0: fFallbackIntervalPattern == other.fFallbackIntervalPattern && michael@0: fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate ); michael@0: michael@0: if ( equal == TRUE ) { michael@0: equal = fIntervalPatterns->equals(*(other.fIntervalPatterns)); michael@0: } michael@0: michael@0: return equal; michael@0: } michael@0: michael@0: michael@0: UnicodeString& michael@0: DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton, michael@0: UCalendarDateFields field, michael@0: UnicodeString& result, michael@0: UErrorCode& status) const { michael@0: if ( U_FAILURE(status) ) { michael@0: return result; michael@0: } michael@0: michael@0: const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton); michael@0: if ( patternsOfOneSkeleton != NULL ) { michael@0: IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status); michael@0: if ( U_FAILURE(status) ) { michael@0: return result; michael@0: } michael@0: const UnicodeString& intervalPattern = patternsOfOneSkeleton[index]; michael@0: if ( !intervalPattern.isEmpty() ) { michael@0: result = intervalPattern; michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: michael@0: UBool michael@0: DateIntervalInfo::getDefaultOrder() const { michael@0: return fFirstDateInPtnIsLaterDate; michael@0: } michael@0: michael@0: michael@0: UnicodeString& michael@0: DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const { michael@0: result = fFallbackIntervalPattern; michael@0: return result; michael@0: } michael@0: michael@0: #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) michael@0: michael@0: void michael@0: DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err) michael@0: { michael@0: fIntervalPatterns = initHash(err); michael@0: if ( U_FAILURE(err) ) { michael@0: return; michael@0: } michael@0: const char *locName = locale.getName(); michael@0: char parentLocale[ULOC_FULLNAME_CAPACITY]; michael@0: uprv_strcpy(parentLocale, locName); michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: Hashtable skeletonSet(FALSE, status); michael@0: if ( U_FAILURE(status) ) { michael@0: return; michael@0: } michael@0: michael@0: // determine calendar type michael@0: const char * calendarTypeToUse = gGregorianTag; // initial default michael@0: char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well michael@0: char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; michael@0: // obtain a locale that always has the calendar key value that should be used michael@0: (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL, michael@0: "calendar", "calendar", locName, NULL, FALSE, &status); michael@0: localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination michael@0: // now get the calendar key value from that locale michael@0: int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status); michael@0: if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { michael@0: calendarTypeToUse = calendarType; michael@0: } michael@0: status = U_ZERO_ERROR; michael@0: michael@0: do { michael@0: UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource; michael@0: rb = ures_open(NULL, parentLocale, &status); michael@0: if ( U_FAILURE(status) ) { michael@0: break; michael@0: } michael@0: calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); michael@0: calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); michael@0: itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, michael@0: gIntervalDateTimePatternTag, NULL, &status); michael@0: michael@0: if ( U_SUCCESS(status) ) { michael@0: // look for fallback first, since it establishes the default order michael@0: const UChar* resStr; michael@0: int32_t resStrLen = 0; michael@0: resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, michael@0: gFallbackPatternTag, michael@0: &resStrLen, &status); michael@0: if ( U_SUCCESS(status) ) { michael@0: UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen); michael@0: setFallbackIntervalPattern(pattern, status); michael@0: } michael@0: michael@0: int32_t size = ures_getSize(itvDtPtnResource); michael@0: int32_t index; michael@0: for ( index = 0; index < size; ++index ) { michael@0: LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index, michael@0: NULL, &status)); michael@0: if ( U_SUCCESS(status) ) { michael@0: const char* skeleton = ures_getKey(oneRes.getAlias()); michael@0: if (skeleton == NULL) { michael@0: continue; michael@0: } michael@0: UnicodeString skeletonUniStr(skeleton, -1, US_INV); michael@0: if ( skeletonSet.geti(skeletonUniStr) == 1 ) { michael@0: continue; michael@0: } michael@0: skeletonSet.puti(skeletonUniStr, 1, status); michael@0: if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { michael@0: continue; // fallback michael@0: } michael@0: michael@0: LocalUResourceBundlePointer intervalPatterns(ures_getByKey( michael@0: itvDtPtnResource, skeleton, NULL, &status)); michael@0: michael@0: if ( U_FAILURE(status) ) { michael@0: break; michael@0: } michael@0: if ( intervalPatterns == NULL ) { michael@0: continue; michael@0: } michael@0: michael@0: const char* key; michael@0: int32_t ptnNum = ures_getSize(intervalPatterns.getAlias()); michael@0: int32_t ptnIndex; michael@0: for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { michael@0: UnicodeString pattern = michael@0: ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status); michael@0: if ( U_FAILURE(status) ) { michael@0: break; michael@0: } michael@0: michael@0: UCalendarDateFields calendarField = UCAL_FIELD_COUNT; michael@0: if ( !uprv_strcmp(key, "y") ) { michael@0: calendarField = UCAL_YEAR; michael@0: } else if ( !uprv_strcmp(key, "M") ) { michael@0: calendarField = UCAL_MONTH; michael@0: } else if ( !uprv_strcmp(key, "d") ) { michael@0: calendarField = UCAL_DATE; michael@0: } else if ( !uprv_strcmp(key, "a") ) { michael@0: calendarField = UCAL_AM_PM; michael@0: } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { michael@0: calendarField = UCAL_HOUR; michael@0: } else if ( !uprv_strcmp(key, "m") ) { michael@0: calendarField = UCAL_MINUTE; michael@0: } michael@0: if ( calendarField != UCAL_FIELD_COUNT ) { michael@0: setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: ures_close(itvDtPtnResource); michael@0: ures_close(calTypeBundle); michael@0: ures_close(calBundle); michael@0: michael@0: status = U_ZERO_ERROR; michael@0: // Find the name of the appropriate parent locale (from %%Parent if present, else michael@0: // uloc_getParent on the actual locale name) michael@0: // (It would be nice to have a ures function that did this...) michael@0: int32_t locNameLen; michael@0: const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status); michael@0: if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) { michael@0: u_UCharsToChars(parentUName, parentLocale, locNameLen + 1); michael@0: } else { michael@0: status = U_ZERO_ERROR; michael@0: // Get the actual name of the current locale being used michael@0: const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status); michael@0: if ( U_FAILURE(status) ) { michael@0: curLocaleName = parentLocale; michael@0: status = U_ZERO_ERROR; michael@0: } michael@0: uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status); michael@0: if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { michael@0: parentLocale[0] = 0; // just fallback to root, will cause us to stop michael@0: status = U_ZERO_ERROR; michael@0: } michael@0: } michael@0: // Now we can close the current locale bundle michael@0: ures_close(rb); michael@0: // If the new current locale is root, then stop michael@0: // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up michael@0: // to root to find additional data for non-root locales) michael@0: } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 ); michael@0: } michael@0: michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton, michael@0: UCalendarDateFields lrgDiffCalUnit, michael@0: const UnicodeString& intervalPattern, michael@0: UErrorCode& status) { michael@0: IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status); michael@0: if ( U_FAILURE(status) ) { michael@0: return; michael@0: } michael@0: UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton)); michael@0: UBool emptyHash = false; michael@0: if ( patternsOfOneSkeleton == NULL ) { michael@0: patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX]; michael@0: emptyHash = true; michael@0: } michael@0: michael@0: patternsOfOneSkeleton[index] = intervalPattern; michael@0: if ( emptyHash == TRUE ) { michael@0: fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status); michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton, michael@0: int32_t* skeletonFieldWidth) { michael@0: const int8_t PATTERN_CHAR_BASE = 0x41; michael@0: int32_t i; michael@0: for ( i = 0; i < skeleton.length(); ++i ) { michael@0: // it is an ASCII char in skeleton michael@0: int8_t ch = (int8_t)skeleton.charAt(i); michael@0: ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE]; michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: UBool michael@0: DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, michael@0: char patternLetter) { michael@0: if ( patternLetter == 'M' ) { michael@0: if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || michael@0: (fieldWidth > 2 && anotherFieldWidth <= 2 )) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: michael@0: michael@0: const UnicodeString* michael@0: DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, michael@0: int8_t& bestMatchDistanceInfo) const { michael@0: #ifdef DTITVINF_DEBUG michael@0: char result[1000]; michael@0: char result_1[1000]; michael@0: char mesg[2000]; michael@0: skeleton.extract(0, skeleton.length(), result, "UTF-8"); michael@0: sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result); michael@0: PRINTMESG(mesg) michael@0: #endif michael@0: michael@0: michael@0: int32_t inputSkeletonFieldWidth[] = michael@0: { michael@0: // A B C D E F G H I J K L M N O michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // P Q R S T U V W X Y Z michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // a b c d e f g h i j k l m n o michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // p q r s t u v w x y z michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 michael@0: }; michael@0: michael@0: int32_t skeletonFieldWidth[] = michael@0: { michael@0: // A B C D E F G H I J K L M N O michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // P Q R S T U V W X Y Z michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // a b c d e f g h i j k l m n o michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, michael@0: // p q r s t u v w x y z michael@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 michael@0: }; michael@0: michael@0: const int32_t DIFFERENT_FIELD = 0x1000; michael@0: const int32_t STRING_NUMERIC_DIFFERENCE = 0x100; michael@0: const int32_t BASE = 0x41; michael@0: const UChar CHAR_V = 0x0076; michael@0: const UChar CHAR_Z = 0x007A; michael@0: michael@0: // hack for 'v' and 'z'. michael@0: // resource bundle only have time skeletons ending with 'v', michael@0: // but not for time skeletons ending with 'z'. michael@0: UBool replaceZWithV = false; michael@0: const UnicodeString* inputSkeleton = &skeleton; michael@0: UnicodeString copySkeleton; michael@0: if ( skeleton.indexOf(CHAR_Z) != -1 ) { michael@0: copySkeleton = skeleton; michael@0: copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V)); michael@0: inputSkeleton = ©Skeleton; michael@0: replaceZWithV = true; michael@0: } michael@0: michael@0: parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth); michael@0: int32_t bestDistance = MAX_POSITIVE_INT; michael@0: const UnicodeString* bestSkeleton = NULL; michael@0: michael@0: // 0 means exact the same skeletons; michael@0: // 1 means having the same field, but with different length, michael@0: // 2 means only z/v differs michael@0: // -1 means having different field. michael@0: bestMatchDistanceInfo = 0; michael@0: int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]); michael@0: michael@0: int32_t pos = -1; michael@0: const UHashElement* elem = NULL; michael@0: while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) { michael@0: const UHashTok keyTok = elem->key; michael@0: UnicodeString* skeleton = (UnicodeString*)keyTok.pointer; michael@0: #ifdef DTITVINF_DEBUG michael@0: skeleton->extract(0, skeleton->length(), result, "UTF-8"); michael@0: sprintf(mesg, "available skeletons: skeleton: %s; \n", result); michael@0: PRINTMESG(mesg) michael@0: #endif michael@0: michael@0: // clear skeleton field width michael@0: int8_t i; michael@0: for ( i = 0; i < fieldLength; ++i ) { michael@0: skeletonFieldWidth[i] = 0; michael@0: } michael@0: parseSkeleton(*skeleton, skeletonFieldWidth); michael@0: // calculate distance michael@0: int32_t distance = 0; michael@0: int8_t fieldDifference = 1; michael@0: for ( i = 0; i < fieldLength; ++i ) { michael@0: int32_t inputFieldWidth = inputSkeletonFieldWidth[i]; michael@0: int32_t fieldWidth = skeletonFieldWidth[i]; michael@0: if ( inputFieldWidth == fieldWidth ) { michael@0: continue; michael@0: } michael@0: if ( inputFieldWidth == 0 ) { michael@0: fieldDifference = -1; michael@0: distance += DIFFERENT_FIELD; michael@0: } else if ( fieldWidth == 0 ) { michael@0: fieldDifference = -1; michael@0: distance += DIFFERENT_FIELD; michael@0: } else if (stringNumeric(inputFieldWidth, fieldWidth, michael@0: (char)(i+BASE) ) ) { michael@0: distance += STRING_NUMERIC_DIFFERENCE; michael@0: } else { michael@0: distance += (inputFieldWidth > fieldWidth) ? michael@0: (inputFieldWidth - fieldWidth) : michael@0: (fieldWidth - inputFieldWidth); michael@0: } michael@0: } michael@0: if ( distance < bestDistance ) { michael@0: bestSkeleton = skeleton; michael@0: bestDistance = distance; michael@0: bestMatchDistanceInfo = fieldDifference; michael@0: } michael@0: if ( distance == 0 ) { michael@0: bestMatchDistanceInfo = 0; michael@0: break; michael@0: } michael@0: } michael@0: if ( replaceZWithV && bestMatchDistanceInfo != -1 ) { michael@0: bestMatchDistanceInfo = 2; michael@0: } michael@0: return bestSkeleton; michael@0: } michael@0: michael@0: michael@0: michael@0: DateIntervalInfo::IntervalPatternIndex michael@0: DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, michael@0: UErrorCode& status) { michael@0: if ( U_FAILURE(status) ) { michael@0: return kIPI_MAX_INDEX; michael@0: } michael@0: IntervalPatternIndex index = kIPI_MAX_INDEX; michael@0: switch ( field ) { michael@0: case UCAL_ERA: michael@0: index = kIPI_ERA; michael@0: break; michael@0: case UCAL_YEAR: michael@0: index = kIPI_YEAR; michael@0: break; michael@0: case UCAL_MONTH: michael@0: index = kIPI_MONTH; michael@0: break; michael@0: case UCAL_DATE: michael@0: case UCAL_DAY_OF_WEEK: michael@0: //case UCAL_DAY_OF_MONTH: michael@0: index = kIPI_DATE; michael@0: break; michael@0: case UCAL_AM_PM: michael@0: index = kIPI_AM_PM; michael@0: break; michael@0: case UCAL_HOUR: michael@0: case UCAL_HOUR_OF_DAY: michael@0: index = kIPI_HOUR; michael@0: break; michael@0: case UCAL_MINUTE: michael@0: index = kIPI_MINUTE; michael@0: break; michael@0: default: michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: } michael@0: return index; michael@0: } michael@0: michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::deleteHash(Hashtable* hTable) michael@0: { michael@0: if ( hTable == NULL ) { michael@0: return; michael@0: } michael@0: int32_t pos = -1; michael@0: const UHashElement* element = NULL; michael@0: while ( (element = hTable->nextElement(pos)) != NULL ) { michael@0: const UHashTok valueTok = element->value; michael@0: const UnicodeString* value = (UnicodeString*)valueTok.pointer; michael@0: delete[] value; michael@0: } michael@0: delete fIntervalPatterns; michael@0: } michael@0: michael@0: michael@0: U_CDECL_BEGIN michael@0: michael@0: /** michael@0: * set hash table value comparator michael@0: * michael@0: * @param val1 one value in comparison michael@0: * @param val2 the other value in comparison michael@0: * @return TRUE if 2 values are the same, FALSE otherwise michael@0: */ michael@0: static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); michael@0: michael@0: static UBool michael@0: U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { michael@0: const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; michael@0: const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; michael@0: UBool ret = TRUE; michael@0: int8_t i; michael@0: for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { michael@0: ret = (pattern1[i] == pattern2[i]); michael@0: } michael@0: return ret; michael@0: } michael@0: michael@0: U_CDECL_END michael@0: michael@0: michael@0: Hashtable* michael@0: DateIntervalInfo::initHash(UErrorCode& status) { michael@0: if ( U_FAILURE(status) ) { michael@0: return NULL; michael@0: } michael@0: Hashtable* hTable; michael@0: if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: if ( U_FAILURE(status) ) { michael@0: delete hTable; michael@0: return NULL; michael@0: } michael@0: hTable->setValueComparator(dtitvinfHashTableValueComparator); michael@0: return hTable; michael@0: } michael@0: michael@0: michael@0: void michael@0: DateIntervalInfo::copyHash(const Hashtable* source, michael@0: Hashtable* target, michael@0: UErrorCode& status) { michael@0: if ( U_FAILURE(status) ) { michael@0: return; michael@0: } michael@0: int32_t pos = -1; michael@0: const UHashElement* element = NULL; michael@0: if ( source ) { michael@0: while ( (element = source->nextElement(pos)) != NULL ) { michael@0: const UHashTok keyTok = element->key; michael@0: const UnicodeString* key = (UnicodeString*)keyTok.pointer; michael@0: const UHashTok valueTok = element->value; michael@0: const UnicodeString* value = (UnicodeString*)valueTok.pointer; michael@0: UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX]; michael@0: int8_t i; michael@0: for ( i = 0; i < kIPI_MAX_INDEX; ++i ) { michael@0: copy[i] = value[i]; michael@0: } michael@0: target->put(UnicodeString(*key), copy, status); michael@0: if ( U_FAILURE(status) ) { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif