intl/icu/source/i18n/dtitvinf.cpp

changeset 0
6474c204b198
     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 = &copySkeleton;
   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

mercurial