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