]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/dtitvinf.cpp
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / dtitvinf.cpp
index 74f84882876d9757cd9de57c5171428cd11d7a7c..c0a6980e5567bcd1d41e6906f34accfe666afc36 100644 (file)
@@ -1,9 +1,11 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*******************************************************************************
-* Copyright (C) 2008-2015, International Business Machines Corporation and
+* Copyright (C) 2008-2016, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
-* File DTITVINF.CPP 
+* File DTITVINF.CPP
 *
 *******************************************************************************
 */
 //#define DTITVINF_DEBUG 1
 
 
-#ifdef DTITVINF_DEBUG 
+#ifdef DTITVINF_DEBUG
 #include <iostream>
 #endif
 
+#include "cmemory.h"
 #include "cstring.h"
 #include "unicode/msgfmt.h"
 #include "unicode/uloc.h"
 #include "unicode/ures.h"
 #include "dtitv_impl.h"
+#include "charstr.h"
 #include "hash.h"
 #include "gregoimp.h"
 #include "uresimp.h"
@@ -37,7 +41,7 @@
 U_NAMESPACE_BEGIN
 
 
-#ifdef DTITVINF_DEBUG 
+#ifdef DTITVINF_DEBUG
 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
 #endif
 
@@ -56,9 +60,7 @@ static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURL
 // default fall-back
 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};
 
-
-
-DateIntervalInfo::DateIntervalInfo(UErrorCode& status) 
+DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
 :   fFallbackIntervalPattern(gDefaultFallbackPattern),
     fFirstDateInPtnIsLaterDate(false),
     fIntervalPatterns(NULL)
@@ -83,7 +85,7 @@ DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
                                      UCalendarDateFields lrgDiffCalUnit,
                                      const UnicodeString& intervalPattern,
                                      UErrorCode& status) {
-    
+
     if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
         setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
         setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
@@ -103,15 +105,15 @@ DateIntervalInfo::setFallbackIntervalPattern(
     if ( U_FAILURE(status) ) {
         return;
     }
-    int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, 
-                        sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
-    int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, 
-                        sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
+    int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
+                        UPRV_LENGTHOF(gFirstPattern), 0);
+    int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
+                        UPRV_LENGTHOF(gSecondPattern), 0);
     if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return;
     }
-    if ( firstPatternIndex > secondPatternIndex ) { 
+    if ( firstPatternIndex > secondPatternIndex ) {
         fFirstDateInPtnIsLaterDate = true;
     }
     fFallbackIntervalPattern = fallbackPattern;
@@ -125,7 +127,7 @@ DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
 {
     *this = dtitvinf;
 }
-    
+
 
 
 DateIntervalInfo&
@@ -133,14 +135,14 @@ DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
     if ( this == &dtitvinf ) {
         return *this;
     }
-    
+
     UErrorCode status = U_ZERO_ERROR;
     deleteHash(fIntervalPatterns);
     fIntervalPatterns = initHash(status);
     copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
     if ( U_FAILURE(status) ) {
         return *this;
-    } 
+    }
 
     fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
     fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
@@ -162,7 +164,7 @@ DateIntervalInfo::~DateIntervalInfo() {
 
 UBool
 DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
-    UBool equal = ( 
+    UBool equal = (
       fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
       fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
 
@@ -182,7 +184,7 @@ DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
     if ( U_FAILURE(status) ) {
         return result;
     }
-   
+
     const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
     if ( patternsOfOneSkeleton != NULL ) {
         IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
@@ -212,158 +214,265 @@ DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
 
 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
 
-void 
-DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
+
+static const int32_t PATH_PREFIX_LENGTH = 17;
+static const UChar PATH_PREFIX[] = {SOLIDUS, CAP_L, CAP_O, CAP_C, CAP_A, CAP_L, CAP_E, SOLIDUS,
+                                    LOW_C, LOW_A, LOW_L, LOW_E, LOW_N, LOW_D, LOW_A, LOW_R, SOLIDUS};
+static const int32_t PATH_SUFFIX_LENGTH = 16;
+static const UChar PATH_SUFFIX[] = {SOLIDUS, LOW_I, LOW_N, LOW_T, LOW_E, LOW_R, LOW_V, LOW_A,
+                                    LOW_L, CAP_F, LOW_O, LOW_R, LOW_M, LOW_A, LOW_T, LOW_S};
+
+/**
+ * Sink for enumerating all of the date interval skeletons.
+ */
+struct DateIntervalInfo::DateIntervalSink : public ResourceSink {
+
+    // Output data
+    DateIntervalInfo &dateIntervalInfo;
+
+    // Next calendar type
+    UnicodeString nextCalendarType;
+
+    DateIntervalSink(DateIntervalInfo &diInfo, const char *currentCalendarType)
+            : dateIntervalInfo(diInfo), nextCalendarType(currentCalendarType, -1, US_INV) { }
+    virtual ~DateIntervalSink();
+
+    virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &errorCode) {
+        if (U_FAILURE(errorCode)) { return; }
+
+        // Iterate over all the calendar entries and only pick the 'intervalFormats' table.
+        ResourceTable dateIntervalData = value.getTable(errorCode);
+        if (U_FAILURE(errorCode)) { return; }
+        for (int32_t i = 0; dateIntervalData.getKeyAndValue(i, key, value); i++) {
+            if (uprv_strcmp(key, gIntervalDateTimePatternTag) != 0) {
+                continue;
+            }
+
+            // Handle aliases and tables. Ignore the rest.
+            if (value.getType() == URES_ALIAS) {
+                // Get the calendar type for the alias path.
+                const UnicodeString &aliasPath = value.getAliasUnicodeString(errorCode);
+                if (U_FAILURE(errorCode)) { return; }
+
+                nextCalendarType.remove();
+                getCalendarTypeFromPath(aliasPath, nextCalendarType, errorCode);
+
+                if (U_FAILURE(errorCode)) {
+                    resetNextCalendarType();
+                }
+                break;
+
+            } else if (value.getType() == URES_TABLE) {
+                // Iterate over all the skeletons in the 'intervalFormat' table.
+                ResourceTable skeletonData = value.getTable(errorCode);
+                if (U_FAILURE(errorCode)) { return; }
+                for (int32_t j = 0; skeletonData.getKeyAndValue(j, key, value); j++) {
+                    if (value.getType() == URES_TABLE) {
+                        // Process the skeleton
+                        processSkeletonTable(key, value, errorCode);
+                        if (U_FAILURE(errorCode)) { return; }
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * Processes the patterns for a skeleton table
+     */
+    void processSkeletonTable(const char *key, ResourceValue &value, UErrorCode &errorCode) {
+        if (U_FAILURE(errorCode)) { return; }
+
+        // Iterate over all the patterns in the current skeleton table
+        const char *currentSkeleton = key;
+        ResourceTable patternData = value.getTable(errorCode);
+        if (U_FAILURE(errorCode)) { return; }
+        for (int32_t k = 0; patternData.getKeyAndValue(k, key, value); k++) {
+            if (value.getType() == URES_STRING) {
+                // Process the key
+                UCalendarDateFields calendarField = validateAndProcessPatternLetter(key);
+
+                // If the calendar field has a valid value
+                if (calendarField < UCAL_FIELD_COUNT) {
+                    // Set the interval pattern
+                    setIntervalPatternIfAbsent(currentSkeleton, calendarField, value, errorCode);
+                    if (U_FAILURE(errorCode)) { return; }
+                }
+            }
+        }
+    }
+
+    /**
+     * Extracts the calendar type from the path.
+     */
+    static void getCalendarTypeFromPath(const UnicodeString &path, UnicodeString &calendarType,
+                                        UErrorCode &errorCode) {
+        if (U_FAILURE(errorCode)) { return; }
+
+        if (!path.startsWith(PATH_PREFIX, PATH_PREFIX_LENGTH) || !path.endsWith(PATH_SUFFIX, PATH_SUFFIX_LENGTH)) {
+            errorCode = U_INVALID_FORMAT_ERROR;
+            return;
+        }
+
+        path.extractBetween(PATH_PREFIX_LENGTH, path.length() - PATH_SUFFIX_LENGTH, calendarType);
+    }
+
+    /**
+     * Validates and processes the pattern letter
+     */
+    UCalendarDateFields validateAndProcessPatternLetter(const char *patternLetter) {
+        // Check that patternLetter is just one letter
+        char c0;
+        if ((c0 = patternLetter[0]) != 0 && patternLetter[1] == 0) {
+            // Check that the pattern letter is accepted
+            if (c0 == 'G') {
+                return UCAL_ERA;
+            } else if (c0 == 'y') {
+                return UCAL_YEAR;
+            } else if (c0 == 'M') {
+                return UCAL_MONTH;
+            } else if (c0 == 'd') {
+                return UCAL_DATE;
+            } else if (c0 == 'a') {
+                return UCAL_AM_PM;
+            } else if (c0 == 'h' || c0 == 'H') {
+                return UCAL_HOUR;
+            } else if (c0 == 'm') {
+                return UCAL_MINUTE;
+            }// TODO(ticket:12190): Why icu4c doesn't accept the calendar field "s" but icu4j does?
+        }
+        return UCAL_FIELD_COUNT;
+    }
+
+    /**
+     * Stores the interval pattern for the current skeleton in the internal data structure
+     * if it's not present.
+     */
+    void setIntervalPatternIfAbsent(const char *currentSkeleton, UCalendarDateFields lrgDiffCalUnit,
+                                    const ResourceValue &value, UErrorCode &errorCode) {
+        // Check if the pattern has already been stored on the data structure
+        IntervalPatternIndex index =
+            dateIntervalInfo.calendarFieldToIntervalIndex(lrgDiffCalUnit, errorCode);
+        if (U_FAILURE(errorCode)) { return; }
+
+        UnicodeString skeleton(currentSkeleton, -1, US_INV);
+        UnicodeString* patternsOfOneSkeleton =
+            (UnicodeString*)(dateIntervalInfo.fIntervalPatterns->get(skeleton));
+
+        if (patternsOfOneSkeleton == NULL || patternsOfOneSkeleton[index].isEmpty()) {
+            UnicodeString pattern = value.getUnicodeString(errorCode);
+            dateIntervalInfo.setIntervalPatternInternally(skeleton, lrgDiffCalUnit,
+                                                          pattern, errorCode);
+        }
+    }
+
+    const UnicodeString &getNextCalendarType() {
+        return nextCalendarType;
+    }
+
+    void resetNextCalendarType() {
+        nextCalendarType.setToBogus();
+    }
+};
+
+// Virtual destructors must be defined out of line.
+DateIntervalInfo::DateIntervalSink::~DateIntervalSink() {}
+
+
+
+void
+DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status)
 {
-  fIntervalPatterns = initHash(err);
-  if ( U_FAILURE(err) ) {
-      return;
-  }
-  const char *locName = locale.getName();
-  char parentLocale[ULOC_FULLNAME_CAPACITY];
-  uprv_strcpy(parentLocale, locName);
-  UErrorCode status = U_ZERO_ERROR;
-  Hashtable skeletonKeyPairs(FALSE, status);
-  if ( U_FAILURE(status) ) {
+    fIntervalPatterns = initHash(status);
+    if (U_FAILURE(status)) {
       return;
-  }
-
-  // determine calendar type
-  const char * calendarTypeToUse = gGregorianTag; // initial default
-  char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
-  char         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
-  // obtain a locale that always has the calendar key value that should be used
-  (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
+    }
+    const char *locName = locale.getName();
+
+    // Get the correct calendar type
+    const char * calendarTypeToUse = gGregorianTag; // initial default
+    char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
+    char         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+    // obtain a locale that always has the calendar key value that should be used
+    (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
                                      "calendar", "calendar", locName, NULL, FALSE, &status);
-  localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
-  // now get the calendar key value from that locale
-  int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status);
-  if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
-    calendarTypeToUse = calendarType;
-  }
-  status = U_ZERO_ERROR;
-  
-  do {
-    UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
-    rb = ures_open(NULL, parentLocale, &status);
-    if ( U_FAILURE(status) ) {
-        break;
+    localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
+    // now get the calendar key value from that locale
+    int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType,
+                                                   ULOC_KEYWORDS_CAPACITY, &status);
+    if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+        calendarTypeToUse = calendarType;
+    }
+    status = U_ZERO_ERROR;
+
+    // Instantiate the resource bundles
+    UResourceBundle *rb, *calBundle;
+    rb = ures_open(NULL, locName, &status);
+    if (U_FAILURE(status)) {
+        return;
     }
-    calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); 
-    calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
-    itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, 
-                         gIntervalDateTimePatternTag, NULL, &status);
+    calBundle = ures_getByKeyWithFallback(rb, gCalendarTag, NULL, &status);
 
-    if ( U_SUCCESS(status) ) {
-        // look for fallback first, since it establishes the default order
+
+    if (U_SUCCESS(status)) {
+        UResourceBundle *calTypeBundle, *itvDtPtnResource;
+
+        // Get the fallback pattern
         const UChar* resStr;
         int32_t resStrLen = 0;
-        resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, 
-                                             gFallbackPatternTag, 
-                                             &resStrLen, &status);
+        calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &status);
+        itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
+                                                     gIntervalDateTimePatternTag, NULL, &status);
+        resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
+                                                 &resStrLen, &status);
         if ( U_SUCCESS(status) ) {
             UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
             setFallbackIntervalPattern(pattern, status);
         }
+        ures_close(itvDtPtnResource);
+        ures_close(calTypeBundle);
 
-        int32_t size = ures_getSize(itvDtPtnResource);
-        int32_t index;
-        for ( index = 0; index < size; ++index ) {
-            LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index, 
-                                                     NULL, &status));
-            if ( U_SUCCESS(status) ) {
-                const char* skeleton = ures_getKey(oneRes.getAlias());
-                if (skeleton == NULL) {
-                    continue;
-                }
-                UnicodeString skeletonUniStr(skeleton, -1, US_INV);
-                if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
-                    continue;  // fallback
-                }
 
-                LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
-                                     itvDtPtnResource, skeleton, NULL, &status));
+        // Instantiate the sink
+        DateIntervalSink sink(*this, calendarTypeToUse);
+        const UnicodeString &calendarTypeToUseUString = sink.getNextCalendarType();
+
+        // Already loaded calendar types
+        Hashtable loadedCalendarTypes(FALSE, status);
 
-                if ( U_FAILURE(status) ) {
+        if (U_SUCCESS(status)) {
+            while (!calendarTypeToUseUString.isBogus()) {
+                // Set an error when a loop is detected
+                if (loadedCalendarTypes.geti(calendarTypeToUseUString) == 1) {
+                    status = U_INVALID_FORMAT_ERROR;
                     break;
                 }
-                if ( intervalPatterns == NULL ) {
-                    continue;
-                }
 
-                const char* key;
-                int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
-                int32_t ptnIndex;
-                for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
-                    UnicodeString pattern =
-                        ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
-                    if ( U_FAILURE(status) ) {
-                        break;
-                    }
-                    UnicodeString keyUniStr(key, -1, US_INV);
-                    UnicodeString skeletonKeyPair(skeletonUniStr + keyUniStr);
-                    if ( skeletonKeyPairs.geti(skeletonKeyPair) == 1 ) {
-                        continue;
-                    }
-                    skeletonKeyPairs.puti(skeletonKeyPair, 1, status);
-        
-                    UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
-                    if ( !uprv_strcmp(key, "y") ) {
-                        calendarField = UCAL_YEAR;
-                    } else if ( !uprv_strcmp(key, "M") ) {
-                        calendarField = UCAL_MONTH;
-                    } else if ( !uprv_strcmp(key, "d") ) {
-                        calendarField = UCAL_DATE;
-                    } else if ( !uprv_strcmp(key, "a") ) {
-                        calendarField = UCAL_AM_PM;
-                    } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
-                        calendarField = UCAL_HOUR;
-                    } else if ( !uprv_strcmp(key, "m") ) {
-                        calendarField = UCAL_MINUTE;
-                    }
-                    if ( calendarField != UCAL_FIELD_COUNT ) {
-                        setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
-                    }
-                }
+                // Register the calendar type to avoid loops
+                loadedCalendarTypes.puti(calendarTypeToUseUString, 1, status);
+                if (U_FAILURE(status)) { break; }
+
+                // Get the calendar string
+                CharString calTypeBuffer;
+                calTypeBuffer.appendInvariantChars(calendarTypeToUseUString, status);
+                if (U_FAILURE(status)) { break; }
+                const char *calType = calTypeBuffer.data();
+
+                // Reset the next calendar type to load.
+                sink.resetNextCalendarType();
+
+                // Get all resources for this calendar type
+                ures_getAllItemsWithFallback(calBundle, calType, sink, status);
             }
         }
     }
-    ures_close(itvDtPtnResource);
-    ures_close(calTypeBundle);
-    ures_close(calBundle);
 
-    status = U_ZERO_ERROR;
-    // Find the name of the appropriate parent locale (from %%Parent if present, else
-    // uloc_getParent on the actual locale name)
-    // (It would be nice to have a ures function that did this...)
-    int32_t locNameLen;
-    const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status);
-    if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
-        u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
-    } else {
-        status = U_ZERO_ERROR;
-        // Get the actual name of the current locale being used
-        const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status);
-        if ( U_FAILURE(status) ) {
-            curLocaleName = parentLocale;
-            status = U_ZERO_ERROR;
-        }
-        uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status);
-        if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
-            parentLocale[0] = 0; // just fallback to root, will cause us to stop
-            status = U_ZERO_ERROR;
-        }
-    }
-    // Now we can close the current locale bundle
+    // Close the opened resource bundles
+    ures_close(calBundle);
     ures_close(rb);
-    // If the new current locale is root, then stop
-    // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up
-    // to root to find additional data for non-root locales)
-  } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 );
 }
 
-
-
 void
 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
                                       UCalendarDateFields lrgDiffCalUnit,
@@ -379,7 +488,7 @@ DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
         patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
         emptyHash = true;
     }
-    
+
     patternsOfOneSkeleton[index] = intervalPattern;
     if ( emptyHash == TRUE ) {
         fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
@@ -388,21 +497,21 @@ DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
 
 
 
-void 
-DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton, 
+void
+DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
                                 int32_t* skeletonFieldWidth) {
     const int8_t PATTERN_CHAR_BASE = 0x41;
     int32_t i;
     for ( i = 0; i < skeleton.length(); ++i ) {
         // it is an ASCII char in skeleton
-        int8_t ch = (int8_t)skeleton.charAt(i);  
+        int8_t ch = (int8_t)skeleton.charAt(i);
         ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
     }
 }
 
 
 
-UBool 
+UBool
 DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
                                 char patternLetter) {
     if ( patternLetter == 'M' ) {
@@ -416,7 +525,7 @@ DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
 
 
 
-const UnicodeString* 
+const UnicodeString*
 DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
                                   int8_t& bestMatchDistanceInfo) const {
 #ifdef DTITVINF_DEBUG
@@ -463,7 +572,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
     // resource bundle only have time skeletons ending with 'v',
     // but not for time skeletons ending with 'z'.
     UBool replaceZWithV = false;
-    const UnicodeString* inputSkeleton = &skeleton; 
+    const UnicodeString* inputSkeleton = &skeleton;
     UnicodeString copySkeleton;
     if ( skeleton.indexOf(CHAR_Z) != -1 ) {
         copySkeleton = skeleton;
@@ -481,13 +590,13 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
     // 2 means only z/v differs
     // -1 means having different field.
     bestMatchDistanceInfo = 0;
-    int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
+    int8_t fieldLength = UPRV_LENGTHOF(skeletonFieldWidth);
 
     int32_t pos = UHASH_FIRST;
     const UHashElement* elem = NULL;
     while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
         const UHashTok keyTok = elem->key;
-        UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
+        UnicodeString* newSkeleton = (UnicodeString*)keyTok.pointer;
 #ifdef DTITVINF_DEBUG
     skeleton->extract(0,  skeleton->length(), result, "UTF-8");
     sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
@@ -497,9 +606,9 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
         // clear skeleton field width
         int8_t i;
         for ( i = 0; i < fieldLength; ++i ) {
-            skeletonFieldWidth[i] = 0;    
+            skeletonFieldWidth[i] = 0;
         }
-        parseSkeleton(*skeleton, skeletonFieldWidth);
+        parseSkeleton(*newSkeleton, skeletonFieldWidth);
         // calculate distance
         int32_t distance = 0;
         int8_t fieldDifference = 1;
@@ -515,17 +624,17 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
             } else if ( fieldWidth == 0 ) {
                 fieldDifference = -1;
                 distance += DIFFERENT_FIELD;
-            } else if (stringNumeric(inputFieldWidth, fieldWidth, 
+            } else if (stringNumeric(inputFieldWidth, fieldWidth,
                                      (char)(i+BASE) ) ) {
                 distance += STRING_NUMERIC_DIFFERENCE;
             } else {
-                distance += (inputFieldWidth > fieldWidth) ? 
-                            (inputFieldWidth - fieldWidth) : 
+                distance += (inputFieldWidth > fieldWidth) ?
+                            (inputFieldWidth - fieldWidth) :
                             (fieldWidth - inputFieldWidth);
             }
         }
         if ( distance < bestDistance ) {
-            bestSkeleton = skeleton;
+            bestSkeleton = newSkeleton;
             bestDistance = distance;
             bestMatchDistanceInfo = fieldDifference;
         }
@@ -543,7 +652,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
 
 
 DateIntervalInfo::IntervalPatternIndex
-DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, 
+DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
                                                UErrorCode& status) {
     if ( U_FAILURE(status) ) {
         return kIPI_MAX_INDEX;
@@ -586,7 +695,7 @@ DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
 
 
 void
-DateIntervalInfo::deleteHash(Hashtable* hTable) 
+DateIntervalInfo::deleteHash(Hashtable* hTable)
 {
     if ( hTable == NULL ) {
         return;
@@ -602,7 +711,7 @@ DateIntervalInfo::deleteHash(Hashtable* hTable)
 }
 
 
-U_CDECL_BEGIN 
+U_CDECL_BEGIN
 
 /**
  * set hash table value comparator
@@ -613,7 +722,7 @@ U_CDECL_BEGIN
  */
 static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
 
-static UBool 
+static UBool
 U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
     const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
     const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
@@ -639,7 +748,7 @@ DateIntervalInfo::initHash(UErrorCode& status) {
         return NULL;
     }
     if ( U_FAILURE(status) ) {
-        delete hTable; 
+        delete hTable;
         return NULL;
     }
     hTable->setValueComparator(dtitvinfHashTableValueComparator);