diff --git a/icu4c/source/i18n/dtitv_impl.h b/icu4c/source/i18n/dtitv_impl.h index 027bc5e6adb..153e0cd4b90 100644 --- a/icu4c/source/i18n/dtitv_impl.h +++ b/icu4c/source/i18n/dtitv_impl.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2007-2008,2014, International Business Machines Corporation and +* Copyright (C) 2007-2016, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * @@ -30,6 +30,7 @@ #define RIGHT_CURLY_BRACKET ((UChar)0x007D) #define SPACE ((UChar)0x0020) #define EN_DASH ((UChar)0x2013) +#define SOLIDUS ((UChar)0x002F) #define DIGIT_ZERO ((UChar)0x0030) #define DIGIT_ONE ((UChar)0x0031) diff --git a/icu4c/source/i18n/dtitvinf.cpp b/icu4c/source/i18n/dtitvinf.cpp index bf0b2612629..4553159e6c5 100644 --- a/icu4c/source/i18n/dtitvinf.cpp +++ b/icu4c/source/i18n/dtitvinf.cpp @@ -3,7 +3,7 @@ * others. All Rights Reserved. ******************************************************************************* * -* File DTITVINF.CPP +* File DTITVINF.CPP * ******************************************************************************* */ @@ -17,7 +17,7 @@ //#define DTITVINF_DEBUG 1 -#ifdef DTITVINF_DEBUG +#ifdef DTITVINF_DEBUG #include #endif @@ -27,6 +27,7 @@ #include "unicode/uloc.h" #include "unicode/ures.h" #include "dtitv_impl.h" +#include "charstr.h" #include "hash.h" #include "gregoimp.h" #include "uresimp.h" @@ -38,7 +39,7 @@ U_NAMESPACE_BEGIN -#ifdef DTITVINF_DEBUG +#ifdef DTITVINF_DEBUG #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; } #endif @@ -57,9 +58,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) @@ -84,7 +83,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); @@ -104,15 +103,15 @@ DateIntervalInfo::setFallbackIntervalPattern( if ( U_FAILURE(status) ) { return; } - int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, + int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, UPRV_LENGTHOF(gFirstPattern), 0); - int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, + 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; @@ -126,7 +125,7 @@ DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) { *this = dtitvinf; } - + DateIntervalInfo& @@ -134,14 +133,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; @@ -163,7 +162,7 @@ DateIntervalInfo::~DateIntervalInfo() { UBool DateIntervalInfo::operator==(const DateIntervalInfo& other) const { - UBool equal = ( + UBool equal = ( fFallbackIntervalPattern == other.fFallbackIntervalPattern && fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate ); @@ -183,7 +182,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); @@ -213,158 +212,276 @@ 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) -{ - 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) ) { - 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, - "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; +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. + * Contains inner sink structs, each one corresponding to a type of resource table. + * The outer struct finds the dateInterval table or an alias. + */ +struct DateIntervalSink : public ResourceTableSink { + + /** + * Sink to handle each skeleton table. + */ + struct SkeletonSink : public ResourceTableSink { + SkeletonSink(DateIntervalSink &sink) : outer(sink) {} + virtual ~SkeletonSink(); + + virtual ResourceTableSink *getOrCreateTableSink( + const char *key, int32_t, UErrorCode &errorCode) { + if (U_SUCCESS(errorCode)) { + outer.currentSkeleton = key; + return &outer.patternSink; + } + return NULL; + } + + DateIntervalSink &outer; + } skeletonSink; + + /** + * Sink to store the date interval pattern for each skeleton pattern character. + */ + struct PatternSink : public ResourceTableSink { + PatternSink(DateIntervalSink &sink) : outer(sink) {} + virtual ~PatternSink(); + + virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) { + if (U_FAILURE(errorCode)) { return; } + + // 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(calendarField, value, errorCode); + } else { + errorCode = U_INVALID_FORMAT_ERROR; + } + } + + 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 == '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(UCalendarDateFields lrgDiffCalUnit, + const ResourceValue &value, UErrorCode &errorCode) { + // Check if the pattern has already been stored on the data structure + DateIntervalInfo::IntervalPatternIndex index = + outer.dateIntervalInfo.calendarFieldToIntervalIndex(lrgDiffCalUnit, errorCode); + if (U_FAILURE(errorCode)) { return; } + + UnicodeString skeleton(outer.currentSkeleton, -1, US_INV); + UnicodeString* patternsOfOneSkeleton = + (UnicodeString*)(outer.dateIntervalInfo.fIntervalPatterns->get(skeleton)); + + if (patternsOfOneSkeleton == NULL || patternsOfOneSkeleton[index].isEmpty()) { + UnicodeString pattern = value.getUnicodeString(errorCode); + outer.dateIntervalInfo.setIntervalPatternInternally(skeleton, lrgDiffCalUnit, + pattern, errorCode); + } + } + + DateIntervalSink &outer; + } patternSink; + + + DateIntervalSink(DateIntervalInfo &diInfo, const char *currentCalendarType) + : skeletonSink(*this), patternSink(*this), dateIntervalInfo(diInfo), + nextCalendarType(currentCalendarType, -1, US_INV), currentSkeleton(NULL) { } + virtual ~DateIntervalSink(); + + virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) { + // Check if it's an alias of intervalFormats + if (U_FAILURE(errorCode) || value.getType() != URES_ALIAS + || uprv_strcmp(key, gIntervalDateTimePatternTag) != 0) { + return; + } + + // 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(); + } } - calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); - calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); - itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, - gIntervalDateTimePatternTag, NULL, &status); - if ( U_SUCCESS(status) ) { - // look for fallback first, since it establishes the default order + virtual ResourceTableSink *getOrCreateTableSink( + const char *key, int32_t, UErrorCode &errorCode) { + // Check if it's the intervalFormat table + if (U_SUCCESS(errorCode) && uprv_strcmp(key, gIntervalDateTimePatternTag) == 0) { + return &skeletonSink; + } + return NULL; + } + + /** + * 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); + } + + const UnicodeString &getNextCalendarType() { + return nextCalendarType; + } + + void resetNextCalendarType() { + nextCalendarType.setToBogus(); + } + + + // Output data + DateIntervalInfo &dateIntervalInfo; + + // Next calendar type + UnicodeString nextCalendarType; + + // Current skeleton table being enumerated + const char *currentSkeleton; +}; + +// Virtual destructors must be defined out of line. +DateIntervalSink::SkeletonSink::~SkeletonSink() {} +DateIntervalSink::PatternSink::~PatternSink() {} +DateIntervalSink::~DateIntervalSink() {} + + + +void +DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status) +{ + fIntervalPatterns = initHash(status); + if (U_FAILURE(status)) { + return; + } + 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; + + // Instantiate the resource bundles + UResourceBundle *rb, *calBundle; + rb = ures_open(NULL, locName, &status); + if (U_FAILURE(status)) { + return; + } + calBundle = ures_getByKeyWithFallback(rb, gCalendarTag, NULL, &status); + + + 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(); - if ( U_FAILURE(status) ) { + // Already loaded calendar types + Hashtable loadedCalendarTypes(FALSE, 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_getAllTableItemsWithFallback(calBundle, calType, sink, status); } } } - ures_close(itvDtPtnResource); - ures_close(calTypeBundle); + + // Close the opened resource bundles 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 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, @@ -380,7 +497,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); @@ -389,21 +506,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' ) { @@ -417,7 +534,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 @@ -464,7 +581,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; @@ -498,7 +615,7 @@ 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); // calculate distance @@ -516,12 +633,12 @@ 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); } } @@ -544,7 +661,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; @@ -587,7 +704,7 @@ DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, void -DateIntervalInfo::deleteHash(Hashtable* hTable) +DateIntervalInfo::deleteHash(Hashtable* hTable) { if ( hTable == NULL ) { return; @@ -603,7 +720,7 @@ DateIntervalInfo::deleteHash(Hashtable* hTable) } -U_CDECL_BEGIN +U_CDECL_BEGIN /** * set hash table value comparator @@ -614,7 +731,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; @@ -640,7 +757,7 @@ DateIntervalInfo::initHash(UErrorCode& status) { return NULL; } if ( U_FAILURE(status) ) { - delete hTable; + delete hTable; return NULL; } hTable->setValueComparator(dtitvinfHashTableValueComparator); diff --git a/icu4c/source/i18n/unicode/dtitvinf.h b/icu4c/source/i18n/unicode/dtitvinf.h index 444356d3f83..2b23dfeaba5 100644 --- a/icu4c/source/i18n/unicode/dtitvinf.h +++ b/icu4c/source/i18n/unicode/dtitvinf.h @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 2008-2015, International Business Machines Corporation and + * Copyright (C) 2008-2016, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * @@ -49,22 +49,22 @@ U_NAMESPACE_BEGIN * to (date_interval_pattern). * *

- * A skeleton + * A skeleton *

    *
  1. - * only keeps the field pattern letter and ignores all other parts + * only keeps the field pattern letter and ignores all other parts * in a pattern, such as space, punctuations, and string literals. *
  2. - * hides the order of fields. + * hides the order of fields. *
  3. * might hide a field's pattern letter length. * - * For those non-digit calendar fields, the pattern letter length is - * important, such as MMM, MMMM, and MMMMM; EEE and EEEE, + * For those non-digit calendar fields, the pattern letter length is + * important, such as MMM, MMMM, and MMMMM; EEE and EEEE, * and the field's pattern letter length is honored. - * - * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy, - * the field pattern length is ignored and the best match, which is defined + * + * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy, + * the field pattern length is ignored and the best match, which is defined * in date time patterns, will be returned without honor the field pattern * letter length in skeleton. *
@@ -73,21 +73,21 @@ U_NAMESPACE_BEGIN * The calendar fields we support for interval formatting are: * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute. * Those calendar fields can be defined in the following order: - * year > month > date > am-pm > hour > minute - * + * year > month > date > am-pm > hour > minute + * * The largest different calendar fields between 2 calendars is the * first different calendar field in above order. * - * For example: the largest different calendar fields between "Jan 10, 2007" + * For example: the largest different calendar fields between "Jan 10, 2007" * and "Feb 20, 2008" is year. - * + * *

* There is a set of pre-defined static skeleton strings. * There are pre-defined interval patterns for those pre-defined skeletons * in locales' resource files. * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd", - * in en_US, if the largest different calendar field between date1 and date2 - * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy", + * in en_US, if the largest different calendar field between date1 and date2 + * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy", * such as "Jan 10, 2007 - Jan 10, 2008". * If the largest different calendar field between date1 and date2 is "month", * the date interval pattern is "MMM d - MMM d, yyyy", @@ -95,7 +95,7 @@ U_NAMESPACE_BEGIN * If the largest different calendar field between date1 and date2 is "day", * the date interval pattern is "MMM d-d, yyyy", such as "Jan 10-20, 2007". * - * For date skeleton, the interval patterns when year, or month, or date is + * For date skeleton, the interval patterns when year, or month, or date is * different are defined in resource files. * For time skeleton, the interval patterns when am/pm, or hour, or minute is * different are defined in resource files. @@ -108,43 +108,43 @@ U_NAMESPACE_BEGIN * We use fallback format for the default order for the locale. * For example, if the fallback format is "{0} - {1}", it means * the first date in the interval pattern for this locale is earlier date. - * If the fallback format is "{1} - {0}", it means the first date is the + * If the fallback format is "{1} - {0}", it means the first date is the * later date. * For a particular interval pattern, the default order can be overriden * by prefixing "latestFirst:" or "earliestFirst:" to the interval pattern. * For example, if the fallback format is "{0}-{1}", - * but for skeleton "yMMMd", the interval pattern when day is different is + * but for skeleton "yMMMd", the interval pattern when day is different is * "latestFirst:d-d MMM yy", it means by default, the first date in interval * pattern is the earlier date. But for skeleton "yMMMd", when day is different, * the first date in "d-d MMM yy" is the later date. - * + * *

- * The recommended way to create a DateIntervalFormat object is to pass in - * the locale. - * By using a Locale parameter, the DateIntervalFormat object is - * initialized with the pre-defined interval patterns for a given or + * The recommended way to create a DateIntervalFormat object is to pass in + * the locale. + * By using a Locale parameter, the DateIntervalFormat object is + * initialized with the pre-defined interval patterns for a given or * default locale. *

- * Users can also create DateIntervalFormat object + * Users can also create DateIntervalFormat object * by supplying their own interval patterns. * It provides flexibility for power users. * *

* After a DateIntervalInfo object is created, clients may modify * the interval patterns using setIntervalPattern function as so desired. - * Currently, users can only set interval patterns when the following - * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, + * Currently, users can only set interval patterns when the following + * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE. * Interval patterns when other calendar fields are different is not supported. *

- * DateIntervalInfo objects are cloneable. - * When clients obtain a DateIntervalInfo object, + * DateIntervalInfo objects are cloneable. + * When clients obtain a DateIntervalInfo object, * they can feel free to modify it as necessary. *

- * DateIntervalInfo are not expected to be subclassed. - * Data for a calendar is loaded out of resource bundles. + * DateIntervalInfo are not expected to be subclassed. + * Data for a calendar is loaded out of resource bundles. * Through ICU 4.4, date interval patterns are only supported in the Gregorian - * calendar; non-Gregorian calendars are supported from ICU 4.4.1. + * calendar; non-Gregorian calendars are supported from ICU 4.4.1. * @stable ICU 4.0 **/ @@ -156,8 +156,8 @@ public: * It does not initialize any interval patterns except * that it initialize default fall-back pattern as "{0} - {1}", * which can be reset by setFallbackIntervalPattern(). - * It should be followed by setFallbackIntervalPattern() and - * setIntervalPattern(), + * It should be followed by setFallbackIntervalPattern() and + * setIntervalPattern(), * and is recommended to be used only for power users who * wants to create their own interval patterns and use them to create * date interval formatter. @@ -168,7 +168,7 @@ public: #endif /* U_HIDE_INTERNAL_API */ - /** + /** * Construct DateIntervalInfo for the given locale, * @param locale the interval patterns are loaded from the appropriate calendar * data (specified calendar or default calendar) in this locale. @@ -226,7 +226,7 @@ public: - /** + /** * Provides a way for client to build interval patterns. * User could construct DateIntervalInfo by providing a list of skeletons * and their patterns. @@ -236,53 +236,53 @@ public: * UErrorCode status = U_ZERO_ERROR; * DateIntervalInfo dIntervalInfo = new DateIntervalInfo(); * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}"); - * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status); + * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status); * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status); * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status); * * - * Restriction: - * Currently, users can only set interval patterns when the following - * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, + * Restriction: + * Currently, users can only set interval patterns when the following + * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE. - * Interval patterns when other calendar fields are different are + * Interval patterns when other calendar fields are different are * not supported. * * @param skeleton the skeleton on which interval pattern based * @param lrgDiffCalUnit the largest different calendar unit. * @param intervalPattern the interval pattern on the largest different * calendar unit. - * For example, if lrgDiffCalUnit is + * For example, if lrgDiffCalUnit is * "year", the interval pattern for en_US when year * is different could be "'from' yyyy 'to' yyyy". * @param status output param set to success/failure code on exit * @stable ICU 4.0 */ - void setIntervalPattern(const UnicodeString& skeleton, - UCalendarDateFields lrgDiffCalUnit, + void setIntervalPattern(const UnicodeString& skeleton, + UCalendarDateFields lrgDiffCalUnit, const UnicodeString& intervalPattern, UErrorCode& status); /** - * Get the interval pattern given skeleton and + * Get the interval pattern given skeleton and * the largest different calendar field. * @param skeleton the skeleton * @param field the largest different calendar field * @param result output param to receive the pattern * @param status output param set to success/failure code on exit * @return a reference to 'result' - * @stable ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& getIntervalPattern(const UnicodeString& skeleton, UCalendarDateFields field, UnicodeString& result, - UErrorCode& status) const; + UErrorCode& status) const; /** * Get the fallback interval pattern. * @param result output param to receive the pattern * @return a reference to 'result' - * @stable ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const; @@ -298,7 +298,7 @@ public: * * @param fallbackPattern fall-back interval pattern. * @param status output param set to success/failure code on exit - * @stable ICU 4.0 + * @stable ICU 4.0 */ void setFallbackIntervalPattern(const UnicodeString& fallbackPattern, UErrorCode& status); @@ -308,7 +308,7 @@ public: or not. * return default date ordering in interval pattern. TRUE if the first date * in pattern is later date, FALSE otherwise. - * @stable ICU 4.0 + * @stable ICU 4.0 */ UBool getDefaultOrder() const; @@ -339,6 +339,8 @@ private: */ friend class DateIntervalFormat; + friend struct DateIntervalSink; + /** * Following is for saving the interval patterns. * We only support interval patterns on @@ -360,7 +362,7 @@ public: #ifndef U_HIDE_INTERNAL_API /** * Max index for stored interval patterns - * @internal ICU 4.4 + * @internal ICU 4.4 */ enum { kMaxIntervalPatternIndex = kIPI_MAX_INDEX @@ -369,7 +371,7 @@ public: private: - /** + /** * Initialize the DateIntervalInfo from locale * @param locale the given locale. * @param status output param set to success/failure code on exit @@ -390,10 +392,10 @@ private: void setIntervalPatternInternally(const UnicodeString& skeleton, UCalendarDateFields lrgDiffCalUnit, const UnicodeString& intervalPattern, - UErrorCode& status); + UErrorCode& status); - /**given an input skeleton, get the best match skeleton + /**given an input skeleton, get the best match skeleton * which has pre-defined interval pattern in resource file. * Also return the difference between the input skeleton * and the best match skeleton. @@ -404,7 +406,7 @@ private: * @param bestMatchDistanceInfo the difference between input skeleton * and best match skeleton. * 0, if there is exact match for input skeleton - * 1, if there is only field width difference between + * 1, if there is only field width difference between * the best match and the input skeleton * 2, the only field difference is 'v' and 'z' * -1, if there is calendar field difference between @@ -422,7 +424,7 @@ private: * @param skeleton skeleton to be parsed * @param skeletonFieldWidth parsed skeleton field width */ - static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton, + static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton, int32_t* skeletonFieldWidth); @@ -442,12 +444,12 @@ private: char patternLetter); - /** - * Convert calendar field to the interval pattern index in + /** + * Convert calendar field to the interval pattern index in * hash table. * - * Since we only support the following calendar fields: - * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK, + * Since we only support the following calendar fields: + * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK, * AM_PM, HOUR, HOUR_OF_DAY, and MINUTE, * We reserve only 4 interval patterns for a skeleton. * @@ -489,7 +491,7 @@ private: // data members - // fallback interval pattern + // fallback interval pattern UnicodeString fFallbackIntervalPattern; // default order UBool fFirstDateInPtnIsLaterDate;