intl/icu/source/i18n/ucal.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 *******************************************************************************
     3 *   Copyright (C) 1996-2013, International Business Machines
     4 *   Corporation and others.  All Rights Reserved.
     5 *******************************************************************************
     6 */
     8 #include "utypeinfo.h"  // for 'typeid' to work
    10 #include "unicode/utypes.h"
    12 #if !UCONFIG_NO_FORMATTING
    14 #include "unicode/ucal.h"
    15 #include "unicode/uloc.h"
    16 #include "unicode/calendar.h"
    17 #include "unicode/timezone.h"
    18 #include "unicode/gregocal.h"
    19 #include "unicode/simpletz.h"
    20 #include "unicode/ustring.h"
    21 #include "unicode/strenum.h"
    22 #include "unicode/localpointer.h"
    23 #include "cmemory.h"
    24 #include "cstring.h"
    25 #include "ustrenum.h"
    26 #include "uenumimp.h"
    27 #include "ulist.h"
    29 U_NAMESPACE_USE
    31 static TimeZone*
    32 _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
    33     TimeZone* zone = NULL;
    34     if (ec!=NULL && U_SUCCESS(*ec)) {
    35         // Note that if zoneID is invalid, we get back GMT. This odd
    36         // behavior is by design and goes back to the JDK. The only
    37         // failure we will see is a memory allocation failure.
    38         int32_t l = (len<0 ? u_strlen(zoneID) : len);
    39         UnicodeString zoneStrID;
    40         zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
    41         zone = TimeZone::createTimeZone(zoneStrID);
    42         if (zone == NULL) {
    43             *ec = U_MEMORY_ALLOCATION_ERROR;
    44         }
    45     }
    46     return zone;
    47 }
    49 U_CAPI UEnumeration* U_EXPORT2
    50 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
    51                                 const int32_t* rawOffset, UErrorCode* ec) {
    52     return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
    53         zoneType, region, rawOffset, *ec), ec);
    54 }
    56 U_CAPI UEnumeration* U_EXPORT2
    57 ucal_openTimeZones(UErrorCode* ec) {
    58     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
    59 }
    61 U_CAPI UEnumeration* U_EXPORT2
    62 ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
    63     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
    64 }
    66 U_CAPI int32_t U_EXPORT2
    67 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
    68     int32_t len = 0;
    69     if (ec!=NULL && U_SUCCESS(*ec)) {
    70         TimeZone* zone = TimeZone::createDefault();
    71         if (zone == NULL) {
    72             *ec = U_MEMORY_ALLOCATION_ERROR;
    73         } else {
    74             UnicodeString id;
    75             zone->getID(id);
    76             delete zone;
    77             len = id.extract(result, resultCapacity, *ec);
    78         }
    79     }
    80     return len;
    81 }
    83 U_CAPI void U_EXPORT2
    84 ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
    85     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
    86     if (zone != NULL) {
    87         TimeZone::adoptDefault(zone);
    88     }
    89 }
    91 U_CAPI int32_t U_EXPORT2
    92 ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
    93     int32_t result = 0;
    94     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
    95     if (U_SUCCESS(*ec)) {
    96         SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
    97         if (stz != NULL) {
    98             result = stz->getDSTSavings();
    99         } else {
   100             // Since there is no getDSTSavings on TimeZone, we use a
   101             // heuristic: Starting with the current time, march
   102             // forwards for one year, looking for DST savings.
   103             // Stepping by weeks is sufficient.
   104             UDate d = Calendar::getNow();
   105             for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
   106                 int32_t raw, dst;
   107                 zone->getOffset(d, FALSE, raw, dst, *ec);
   108                 if (U_FAILURE(*ec)) {
   109                     break;
   110                 } else if (dst != 0) {
   111                     result = dst;
   112                     break;
   113                 }
   114             }
   115         }
   116     }
   117     delete zone;
   118     return result;
   119 }
   121 U_CAPI UDate  U_EXPORT2
   122 ucal_getNow()
   123 {
   125   return Calendar::getNow();
   126 }
   128 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
   130 U_CAPI UCalendar*  U_EXPORT2
   131 ucal_open(  const UChar*  zoneID,
   132             int32_t       len,
   133             const char*   locale,
   134             UCalendarType caltype,
   135             UErrorCode*   status)
   136 {
   138   if(U_FAILURE(*status)) return 0;
   140   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
   141       : _createTimeZone(zoneID, len, status);
   143   if (U_FAILURE(*status)) {
   144       return NULL;
   145   }
   147   if ( caltype == UCAL_GREGORIAN ) {
   148       char  localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
   149       if ( locale == NULL ) {
   150           locale = uloc_getDefault();
   151       }
   152       uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
   153       uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
   154       if (U_FAILURE(*status)) {
   155           return NULL;
   156       }
   157       return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
   158   }
   159   return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
   160 }
   162 U_CAPI void U_EXPORT2
   163 ucal_close(UCalendar *cal)
   164 {
   166   delete (Calendar*) cal;
   167 }
   169 U_CAPI UCalendar* U_EXPORT2 
   170 ucal_clone(const UCalendar* cal,
   171            UErrorCode*      status)
   172 {
   173   if(U_FAILURE(*status)) return 0;
   175   Calendar* res = ((Calendar*)cal)->clone();
   177   if(res == 0) {
   178     *status = U_MEMORY_ALLOCATION_ERROR;
   179     return 0;
   180   }
   182   return (UCalendar*) res;
   183 }
   185 U_CAPI void  U_EXPORT2
   186 ucal_setTimeZone(    UCalendar*      cal,
   187             const    UChar*            zoneID,
   188             int32_t        len,
   189             UErrorCode *status)
   190 {
   192   if(U_FAILURE(*status))
   193     return;
   195   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
   196       : _createTimeZone(zoneID, len, status);
   198   if (zone != NULL) {
   199       ((Calendar*)cal)->adoptTimeZone(zone);
   200   }
   201 }
   203 U_CAPI int32_t U_EXPORT2
   204 ucal_getTimeZoneID(const UCalendar *cal,
   205                    UChar *result,
   206                    int32_t resultLength,
   207                    UErrorCode *status)
   208 {
   209     if (U_FAILURE(*status)) {
   210         return 0;
   211     }
   212     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
   213     UnicodeString id;
   214     tz.getID(id);
   215     return id.extract(result, resultLength, *status);
   216 }
   218 U_CAPI int32_t U_EXPORT2
   219 ucal_getTimeZoneDisplayName(const     UCalendar*                 cal,
   220                     UCalendarDisplayNameType     type,
   221                     const char             *locale,
   222                     UChar*                  result,
   223                     int32_t                 resultLength,
   224                     UErrorCode*             status)
   225 {
   227     if(U_FAILURE(*status)) return -1;
   229     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
   230     UnicodeString id;
   231     if(!(result==NULL && resultLength==0)) {
   232         // NULL destination for pure preflighting: empty dummy string
   233         // otherwise, alias the destination buffer
   234         id.setTo(result, 0, resultLength);
   235     }
   237     switch(type) {
   238   case UCAL_STANDARD:
   239       tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
   240       break;
   242   case UCAL_SHORT_STANDARD:
   243       tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
   244       break;
   246   case UCAL_DST:
   247       tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
   248       break;
   250   case UCAL_SHORT_DST:
   251       tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
   252       break;
   253     }
   255     return id.extract(result, resultLength, *status);
   256 }
   258 U_CAPI UBool  U_EXPORT2
   259 ucal_inDaylightTime(    const    UCalendar*      cal, 
   260                     UErrorCode*     status )
   261 {
   263     if(U_FAILURE(*status)) return (UBool) -1;
   264     return ((Calendar*)cal)->inDaylightTime(*status);
   265 }
   267 U_CAPI void U_EXPORT2
   268 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
   269     if(U_FAILURE(*pErrorCode)) {
   270         return;
   271     }
   272     Calendar *cpp_cal = (Calendar *)cal;
   273     GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
   274     // Not if(gregocal == NULL) {
   275     // because we really want to work only with a GregorianCalendar, not with
   276     // its subclasses like BuddhistCalendar.
   277     if (cpp_cal == NULL) {
   278         // We normally don't check "this" pointers for NULL, but this here avoids
   279         // compiler-generated exception-throwing code in case cal == NULL.
   280         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   281         return;
   282     }
   283     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
   284         *pErrorCode = U_UNSUPPORTED_ERROR;
   285         return;
   286     }
   287     gregocal->setGregorianChange(date, *pErrorCode);
   288 }
   290 U_CAPI UDate U_EXPORT2
   291 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
   292     if(U_FAILURE(*pErrorCode)) {
   293         return (UDate)0;
   294     }
   295     const Calendar *cpp_cal = (const Calendar *)cal;
   296     const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
   297     // Not if(gregocal == NULL) {
   298     // see comments in ucal_setGregorianChange().
   299     if (cpp_cal == NULL) {
   300         // We normally don't check "this" pointers for NULL, but this here avoids
   301         // compiler-generated exception-throwing code in case cal == NULL.
   302         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   303         return (UDate)0;
   304     }
   305     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
   306         *pErrorCode = U_UNSUPPORTED_ERROR;
   307         return (UDate)0;
   308     }
   309     return gregocal->getGregorianChange();
   310 }
   312 U_CAPI int32_t U_EXPORT2
   313 ucal_getAttribute(    const    UCalendar*              cal,
   314                   UCalendarAttribute      attr)
   315 {
   317     switch(attr) {
   318   case UCAL_LENIENT:
   319       return ((Calendar*)cal)->isLenient();
   321   case UCAL_FIRST_DAY_OF_WEEK:
   322       return ((Calendar*)cal)->getFirstDayOfWeek();
   324   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
   325       return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
   327   case UCAL_REPEATED_WALL_TIME:
   328       return ((Calendar*)cal)->getRepeatedWallTimeOption();
   330   case UCAL_SKIPPED_WALL_TIME:
   331       return ((Calendar*)cal)->getSkippedWallTimeOption();
   333   default:
   334       break;
   335     }
   336     return -1;
   337 }
   339 U_CAPI void U_EXPORT2
   340 ucal_setAttribute(      UCalendar*              cal,
   341                   UCalendarAttribute      attr,
   342                   int32_t                 newValue)
   343 {
   345     switch(attr) {
   346   case UCAL_LENIENT:
   347       ((Calendar*)cal)->setLenient((UBool)newValue);
   348       break;
   350   case UCAL_FIRST_DAY_OF_WEEK:
   351       ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
   352       break;
   354   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
   355       ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
   356       break;
   358   case UCAL_REPEATED_WALL_TIME:
   359       ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue);
   360       break;
   362   case UCAL_SKIPPED_WALL_TIME:
   363       ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue);
   364       break;
   365     }
   366 }
   368 U_CAPI const char* U_EXPORT2
   369 ucal_getAvailable(int32_t index)
   370 {
   372     return uloc_getAvailable(index);
   373 }
   375 U_CAPI int32_t U_EXPORT2
   376 ucal_countAvailable()
   377 {
   379     return uloc_countAvailable();
   380 }
   382 U_CAPI UDate  U_EXPORT2
   383 ucal_getMillis(    const    UCalendar*      cal,
   384                UErrorCode*     status)
   385 {
   387     if(U_FAILURE(*status)) return (UDate) 0;
   389     return ((Calendar*)cal)->getTime(*status);
   390 }
   392 U_CAPI void  U_EXPORT2
   393 ucal_setMillis(        UCalendar*      cal,
   394                UDate           dateTime,
   395                UErrorCode*     status )
   396 {
   397     if(U_FAILURE(*status)) return;
   399     ((Calendar*)cal)->setTime(dateTime, *status);
   400 }
   402 // TBD: why does this take an UErrorCode?
   403 U_CAPI void  U_EXPORT2
   404 ucal_setDate(        UCalendar*        cal,
   405              int32_t            year,
   406              int32_t            month,
   407              int32_t            date,
   408              UErrorCode        *status)
   409 {
   411     if(U_FAILURE(*status)) return;
   413     ((Calendar*)cal)->set(year, month, date);
   414 }
   416 // TBD: why does this take an UErrorCode?
   417 U_CAPI void  U_EXPORT2
   418 ucal_setDateTime(    UCalendar*        cal,
   419                  int32_t            year,
   420                  int32_t            month,
   421                  int32_t            date,
   422                  int32_t            hour,
   423                  int32_t            minute,
   424                  int32_t            second,
   425                  UErrorCode        *status)
   426 {
   427     if(U_FAILURE(*status)) return;
   429     ((Calendar*)cal)->set(year, month, date, hour, minute, second);
   430 }
   432 U_CAPI UBool  U_EXPORT2
   433 ucal_equivalentTo(    const UCalendar*      cal1,
   434                   const UCalendar*      cal2)
   435 {
   437     return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
   438 }
   440 U_CAPI void  U_EXPORT2
   441 ucal_add(    UCalendar*                cal,
   442          UCalendarDateFields        field,
   443          int32_t                    amount,
   444          UErrorCode*                status)
   445 {
   447     if(U_FAILURE(*status)) return;
   449     ((Calendar*)cal)->add(field, amount, *status);
   450 }
   452 U_CAPI void  U_EXPORT2
   453 ucal_roll(        UCalendar*            cal,
   454           UCalendarDateFields field,
   455           int32_t                amount,
   456           UErrorCode*            status)
   457 {
   459     if(U_FAILURE(*status)) return;
   461     ((Calendar*)cal)->roll(field, amount, *status);
   462 }
   464 U_CAPI int32_t  U_EXPORT2
   465 ucal_get(    const    UCalendar*                cal,
   466          UCalendarDateFields        field,
   467          UErrorCode*                status )
   468 {
   470     if(U_FAILURE(*status)) return -1;
   472     return ((Calendar*)cal)->get(field, *status);
   473 }
   475 U_CAPI void  U_EXPORT2
   476 ucal_set(    UCalendar*                cal,
   477          UCalendarDateFields        field,
   478          int32_t                    value)
   479 {
   481     ((Calendar*)cal)->set(field, value);
   482 }
   484 U_CAPI UBool  U_EXPORT2
   485 ucal_isSet(    const    UCalendar*                cal,
   486            UCalendarDateFields        field)
   487 {
   489     return ((Calendar*)cal)->isSet(field);
   490 }
   492 U_CAPI void  U_EXPORT2
   493 ucal_clearField(    UCalendar*            cal,
   494                 UCalendarDateFields field)
   495 {
   497     ((Calendar*)cal)->clear(field);
   498 }
   500 U_CAPI void  U_EXPORT2
   501 ucal_clear(UCalendar* calendar)
   502 {
   504     ((Calendar*)calendar)->clear();
   505 }
   507 U_CAPI int32_t  U_EXPORT2
   508 ucal_getLimit(    const    UCalendar*              cal,
   509               UCalendarDateFields     field,
   510               UCalendarLimitType      type,
   511               UErrorCode        *status)
   512 {
   514     if(status==0 || U_FAILURE(*status)) {
   515         return -1;
   516     }
   518     switch(type) {
   519   case UCAL_MINIMUM:
   520       return ((Calendar*)cal)->getMinimum(field);
   522   case UCAL_MAXIMUM:
   523       return ((Calendar*)cal)->getMaximum(field);
   525   case UCAL_GREATEST_MINIMUM:
   526       return ((Calendar*)cal)->getGreatestMinimum(field);
   528   case UCAL_LEAST_MAXIMUM:
   529       return ((Calendar*)cal)->getLeastMaximum(field);
   531   case UCAL_ACTUAL_MINIMUM:
   532       return ((Calendar*)cal)->getActualMinimum(field,
   533           *status);
   535   case UCAL_ACTUAL_MAXIMUM:
   536       return ((Calendar*)cal)->getActualMaximum(field,
   537           *status);
   539   default:
   540       break;
   541     }
   542     return -1;
   543 }
   545 U_CAPI const char * U_EXPORT2
   546 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status) 
   547 {
   548     if (cal == NULL) {
   549         if (U_SUCCESS(*status)) {
   550             *status = U_ILLEGAL_ARGUMENT_ERROR;
   551         }
   552         return NULL;
   553     }
   554     return ((Calendar*)cal)->getLocaleID(type, *status);
   555 }
   557 U_CAPI const char * U_EXPORT2
   558 ucal_getTZDataVersion(UErrorCode* status)
   559 {
   560     return TimeZone::getTZDataVersion(*status);
   561 }
   563 U_CAPI int32_t U_EXPORT2
   564 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
   565                             UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
   566     if(status == 0 || U_FAILURE(*status)) {
   567         return 0;
   568     }
   569     if (isSystemID) {
   570         *isSystemID = FALSE;
   571     }
   572     if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
   573         *status = U_ILLEGAL_ARGUMENT_ERROR;
   574         return 0;
   575     }
   576     int32_t reslen = 0;
   577     UnicodeString canonical;
   578     UBool systemID = FALSE;
   579     TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
   580     if (U_SUCCESS(*status)) {
   581         if (isSystemID) {
   582             *isSystemID = systemID;
   583         }
   584         reslen = canonical.extract(result, resultCapacity, *status);
   585     }
   586     return reslen;
   587 }
   589 U_CAPI const char * U_EXPORT2
   590 ucal_getType(const UCalendar *cal, UErrorCode* status)
   591 {
   592     if (U_FAILURE(*status)) {
   593         return NULL;
   594     }
   595     return ((Calendar*)cal)->getType();
   596 }
   598 U_CAPI UCalendarWeekdayType U_EXPORT2
   599 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
   600 {
   601     if (U_FAILURE(*status)) {
   602         return UCAL_WEEKDAY;
   603     }
   604     return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
   605 }
   607 U_CAPI int32_t U_EXPORT2
   608 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
   609 {
   610     if (U_FAILURE(*status)) {
   611         return 0;
   612     }
   613     return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
   614 }
   616 U_CAPI UBool U_EXPORT2
   617 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
   618 {
   619     if (U_FAILURE(*status)) {
   620         return FALSE;
   621     }
   622     return ((Calendar*)cal)->isWeekend(date, *status);
   623 }
   625 U_CAPI int32_t  U_EXPORT2
   626 ucal_getFieldDifference(UCalendar* cal, UDate target,
   627                         UCalendarDateFields field,
   628                         UErrorCode* status )
   629 {
   630     if (U_FAILURE(*status)) {
   631         return 0;
   632     }
   633     return ((Calendar*)cal)->fieldDifference(target, field, *status);
   634 }
   637 static const UEnumeration defaultKeywordValues = {
   638     NULL,
   639     NULL,
   640     ulist_close_keyword_values_iterator,
   641     ulist_count_keyword_values,
   642     uenum_unextDefault,
   643     ulist_next_keyword_value, 
   644     ulist_reset_keyword_values_iterator
   645 };
   647 static const char * const CAL_TYPES[] = {
   648         "gregorian",
   649         "japanese",
   650         "buddhist",
   651         "roc",
   652         "persian",
   653         "islamic-civil",
   654         "islamic",
   655         "hebrew",
   656         "chinese",
   657         "indian",
   658         "coptic",
   659         "ethiopic",
   660         "ethiopic-amete-alem",
   661         "iso8601",
   662         "dangi",
   663         "islamic-umalqura",
   664         "islamic-tbla",
   665         "islamic-rgsa",
   666         NULL
   667 };
   669 U_CAPI UEnumeration* U_EXPORT2
   670 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
   671     // Resolve region
   672     char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
   673     int32_t prefRegionLength = 0;
   674     prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
   675     if (prefRegionLength == 0) {
   676         char loc[ULOC_FULLNAME_CAPACITY] = "";
   677         uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
   679         prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
   680     }
   682     // Read preferred calendar values from supplementalData calendarPreference
   683     UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
   684     ures_getByKey(rb, "calendarPreferenceData", rb, status);
   685     UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
   686     if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
   687         *status = U_ZERO_ERROR;
   688         order = ures_getByKey(rb, "001", NULL, status);
   689     }
   691     // Create a list of calendar type strings
   692     UList *values = NULL;
   693     if (U_SUCCESS(*status)) {
   694         values = ulist_createEmptyList(status);
   695         if (U_SUCCESS(*status)) {
   696             for (int i = 0; i < ures_getSize(order); i++) {
   697                 int32_t len;
   698                 const UChar *type = ures_getStringByIndex(order, i, &len, status);
   699                 char *caltype = (char*)uprv_malloc(len + 1);
   700                 if (caltype == NULL) {
   701                     *status = U_MEMORY_ALLOCATION_ERROR;
   702                     break;
   703                 }
   704                 u_UCharsToChars(type, caltype, len);
   705                 *(caltype + len) = 0;
   707                 ulist_addItemEndList(values, caltype, TRUE, status);
   708                 if (U_FAILURE(*status)) {
   709                     break;
   710                 }
   711             }
   713             if (U_SUCCESS(*status) && !commonlyUsed) {
   714                 // If not commonlyUsed, add other available values
   715                 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
   716                     if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
   717                         ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
   718                         if (U_FAILURE(*status)) {
   719                             break;
   720                         }
   721                     }
   722                 }
   723             }
   724             if (U_FAILURE(*status)) {
   725                 ulist_deleteList(values);
   726                 values = NULL;
   727             }
   728         }
   729     }
   731     ures_close(order);
   732     ures_close(rb);
   734     if (U_FAILURE(*status) || values == NULL) {
   735         return NULL;
   736     }
   738     // Create string enumeration
   739     UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
   740     if (en == NULL) {
   741         *status = U_MEMORY_ALLOCATION_ERROR;
   742         ulist_deleteList(values);
   743         return NULL;
   744     }
   745     ulist_resetList(values);
   746     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
   747     en->context = values;
   748     return en;
   749 }
   751 U_CAPI UBool U_EXPORT2 
   752 ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
   753                                UDate* transition, UErrorCode* status)
   754 {
   755     if (U_FAILURE(*status)) {
   756         return FALSE;
   757     }
   758     UDate base = ((Calendar*)cal)->getTime(*status);
   759     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
   760     const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
   761     if (btz != NULL && U_SUCCESS(*status)) {
   762         TimeZoneTransition tzt;
   763         UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
   764         UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
   765                         btz->getNextTransition(base, inclusive, tzt):
   766                         btz->getPreviousTransition(base, inclusive, tzt);
   767         if (result) {
   768             *transition = tzt.getTime();
   769             return TRUE;
   770         }
   771     }
   772     return FALSE;
   773 }
   775 #ifndef U_HIDE_DRAFT_API
   776 U_CAPI int32_t U_EXPORT2
   777 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) {
   778     if (U_FAILURE(*status)) {
   779         return 0;
   780     }
   782     int32_t resultLen = 0;
   783     UnicodeString resultWinID;
   785     TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status);
   786     if (U_SUCCESS(*status) && resultWinID.length() > 0) {
   787         resultLen = resultWinID.length();
   788         resultWinID.extract(winid, winidCapacity, *status);
   789     }
   791     return resultLen;
   792 }
   794 U_CAPI int32_t U_EXPORT2
   795 ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) {
   796     if (U_FAILURE(*status)) {
   797         return 0;
   798     }
   800     int32_t resultLen = 0;
   801     UnicodeString resultID;
   803     TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status);
   804     if (U_SUCCESS(*status) && resultID.length() > 0) {
   805         resultLen = resultID.length();
   806         resultID.extract(id, idCapacity, *status);
   807     }
   809     return resultLen;
   810 }
   812 #endif /* U_HIDE_DRAFT_API */
   814 #endif /* #if !UCONFIG_NO_FORMATTING */

mercurial