Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 *   Copyright (C) 1996-2011, International Business Machines
      4 *   Corporation and others.  All Rights Reserved.
      5 *******************************************************************************
      6 */
      7 
      8 #include <typeinfo>  // for 'typeid' to work
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     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 "cmemory.h"
     23 #include "cstring.h"
     24 #include "ustrenum.h"
     25 #include "uenumimp.h"
     26 #include "ulist.h"
     27 
     28 U_NAMESPACE_USE
     29 
     30 static TimeZone*
     31 _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
     32     TimeZone* zone = NULL;
     33     if (ec!=NULL && U_SUCCESS(*ec)) {
     34         // Note that if zoneID is invalid, we get back GMT. This odd
     35         // behavior is by design and goes back to the JDK. The only
     36         // failure we will see is a memory allocation failure.
     37         int32_t l = (len<0 ? u_strlen(zoneID) : len);
     38         UnicodeString zoneStrID;
     39         zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
     40         zone = TimeZone::createTimeZone(zoneStrID);
     41         if (zone == NULL) {
     42             *ec = U_MEMORY_ALLOCATION_ERROR;
     43         }
     44     }
     45     return zone;
     46 }
     47 
     48 U_CAPI UEnumeration* U_EXPORT2
     49 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
     50                                 const int32_t* rawOffset, UErrorCode* ec) {
     51     return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
     52         zoneType, region, rawOffset, *ec), ec);
     53 }
     54 
     55 U_CAPI UEnumeration* U_EXPORT2
     56 ucal_openTimeZones(UErrorCode* ec) {
     57     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
     58 }
     59 
     60 U_CAPI UEnumeration* U_EXPORT2
     61 ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
     62     return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
     63 }
     64 
     65 U_CAPI int32_t U_EXPORT2
     66 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
     67     int32_t len = 0;
     68     if (ec!=NULL && U_SUCCESS(*ec)) {
     69         TimeZone* zone = TimeZone::createDefault();
     70         if (zone == NULL) {
     71             *ec = U_MEMORY_ALLOCATION_ERROR;
     72         } else {
     73             UnicodeString id;
     74             zone->getID(id);
     75             delete zone;
     76             len = id.extract(result, resultCapacity, *ec);
     77         }
     78     }
     79     return len;
     80 }
     81 
     82 U_CAPI void U_EXPORT2
     83 ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
     84     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
     85     if (zone != NULL) {
     86         TimeZone::adoptDefault(zone);
     87     }
     88 }
     89 
     90 U_CAPI int32_t U_EXPORT2
     91 ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
     92     int32_t result = 0;
     93     TimeZone* zone = _createTimeZone(zoneID, -1, ec);
     94     if (U_SUCCESS(*ec)) {
     95         SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
     96         if (stz != NULL) {
     97             result = stz->getDSTSavings();
     98         } else {
     99             // Since there is no getDSTSavings on TimeZone, we use a
    100             // heuristic: Starting with the current time, march
    101             // forwards for one year, looking for DST savings.
    102             // Stepping by weeks is sufficient.
    103             UDate d = Calendar::getNow();
    104             for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
    105                 int32_t raw, dst;
    106                 zone->getOffset(d, FALSE, raw, dst, *ec);
    107                 if (U_FAILURE(*ec)) {
    108                     break;
    109                 } else if (dst != 0) {
    110                     result = dst;
    111                     break;
    112                 }
    113             }
    114         }
    115     }
    116     delete zone;
    117     return result;
    118 }
    119 
    120 U_CAPI UDate  U_EXPORT2
    121 ucal_getNow()
    122 {
    123 
    124   return Calendar::getNow();
    125 }
    126 
    127 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
    128 
    129 U_CAPI UCalendar*  U_EXPORT2
    130 ucal_open(  const UChar*  zoneID,
    131             int32_t       len,
    132             const char*   locale,
    133             UCalendarType caltype,
    134             UErrorCode*   status)
    135 {
    136 
    137   if(U_FAILURE(*status)) return 0;
    138 
    139   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
    140       : _createTimeZone(zoneID, len, status);
    141 
    142   if (U_FAILURE(*status)) {
    143       return NULL;
    144   }
    145 
    146   if ( caltype == UCAL_GREGORIAN ) {
    147       char  localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
    148       if ( locale == NULL ) {
    149           locale = uloc_getDefault();
    150       }
    151       uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
    152       uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
    153       if (U_FAILURE(*status)) {
    154           return NULL;
    155       }
    156       return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
    157   }
    158   return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
    159 }
    160 
    161 U_CAPI void U_EXPORT2
    162 ucal_close(UCalendar *cal)
    163 {
    164 
    165   delete (Calendar*) cal;
    166 }
    167 
    168 U_CAPI UCalendar* U_EXPORT2
    169 ucal_clone(const UCalendar* cal,
    170            UErrorCode*      status)
    171 {
    172   if(U_FAILURE(*status)) return 0;
    173 
    174   Calendar* res = ((Calendar*)cal)->clone();
    175 
    176   if(res == 0) {
    177     *status = U_MEMORY_ALLOCATION_ERROR;
    178     return 0;
    179   }
    180 
    181   return (UCalendar*) res;
    182 }
    183 
    184 U_CAPI void  U_EXPORT2
    185 ucal_setTimeZone(    UCalendar*      cal,
    186             const    UChar*            zoneID,
    187             int32_t        len,
    188             UErrorCode *status)
    189 {
    190 
    191   if(U_FAILURE(*status))
    192     return;
    193 
    194   TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
    195       : _createTimeZone(zoneID, len, status);
    196 
    197   if (zone != NULL) {
    198       ((Calendar*)cal)->adoptTimeZone(zone);
    199   }
    200 }
    201 
    202 U_CAPI int32_t U_EXPORT2
    203 ucal_getTimeZoneDisplayName(const     UCalendar*                 cal,
    204                     UCalendarDisplayNameType     type,
    205                     const char             *locale,
    206                     UChar*                  result,
    207                     int32_t                 resultLength,
    208                     UErrorCode*             status)
    209 {
    210 
    211     if(U_FAILURE(*status)) return -1;
    212 
    213     const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
    214     UnicodeString id;
    215     if(!(result==NULL && resultLength==0)) {
    216         // NULL destination for pure preflighting: empty dummy string
    217         // otherwise, alias the destination buffer
    218         id.setTo(result, 0, resultLength);
    219     }
    220 
    221     switch(type) {
    222   case UCAL_STANDARD:
    223       tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
    224       break;
    225 
    226   case UCAL_SHORT_STANDARD:
    227       tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
    228       break;
    229 
    230   case UCAL_DST:
    231       tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
    232       break;
    233 
    234   case UCAL_SHORT_DST:
    235       tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
    236       break;
    237     }
    238 
    239     return id.extract(result, resultLength, *status);
    240 }
    241 
    242 U_CAPI UBool  U_EXPORT2
    243 ucal_inDaylightTime(    const    UCalendar*      cal,
    244                     UErrorCode*     status )
    245 {
    246 
    247     if(U_FAILURE(*status)) return (UBool) -1;
    248     return ((Calendar*)cal)->inDaylightTime(*status);
    249 }
    250 
    251 U_CAPI void U_EXPORT2
    252 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
    253     if(U_FAILURE(*pErrorCode)) {
    254         return;
    255     }
    256     Calendar *cpp_cal = (Calendar *)cal;
    257     GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
    258     // Not if(gregocal == NULL) {
    259     // because we really want to work only with a GregorianCalendar, not with
    260     // its subclasses like BuddhistCalendar.
    261     // BEGIN android-added.
    262     // See ICU ticket#9047.
    263     if (cpp_cal == NULL) {
    264         // We normally don't check "this" pointers for NULL, but this here avoids
    265         // compiler-generated exception-throwing code in case cal == NULL.
    266         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
    267         return;
    268     }
    269     // END android-added
    270     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
    271         *pErrorCode = U_UNSUPPORTED_ERROR;
    272         return;
    273     }
    274     gregocal->setGregorianChange(date, *pErrorCode);
    275 }
    276 
    277 U_CAPI UDate U_EXPORT2
    278 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
    279     if(U_FAILURE(*pErrorCode)) {
    280         return (UDate)0;
    281     }
    282     const Calendar *cpp_cal = (const Calendar *)cal;
    283     const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
    284     // Not if(gregocal == NULL) {
    285     // see comments in ucal_setGregorianChange().
    286     // BEGIN android-added.
    287     // See ICU ticket#9047.
    288     if (cpp_cal == NULL) {
    289         // We normally don't check "this" pointers for NULL, but this here avoids
    290         // compiler-generated exception-throwing code in case cal == NULL.
    291         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
    292         return (UDate)0;
    293     }
    294     // END android-added
    295     if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
    296         *pErrorCode = U_UNSUPPORTED_ERROR;
    297         return (UDate)0;
    298     }
    299     return gregocal->getGregorianChange();
    300 }
    301 
    302 U_CAPI int32_t U_EXPORT2
    303 ucal_getAttribute(    const    UCalendar*              cal,
    304                   UCalendarAttribute      attr)
    305 {
    306 
    307     switch(attr) {
    308   case UCAL_LENIENT:
    309       return ((Calendar*)cal)->isLenient();
    310 
    311   case UCAL_FIRST_DAY_OF_WEEK:
    312       return ((Calendar*)cal)->getFirstDayOfWeek();
    313 
    314   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
    315       return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
    316 
    317   default:
    318       break;
    319     }
    320     return -1;
    321 }
    322 
    323 U_CAPI void U_EXPORT2
    324 ucal_setAttribute(      UCalendar*              cal,
    325                   UCalendarAttribute      attr,
    326                   int32_t                 newValue)
    327 {
    328 
    329     switch(attr) {
    330   case UCAL_LENIENT:
    331       ((Calendar*)cal)->setLenient((UBool)newValue);
    332       break;
    333 
    334   case UCAL_FIRST_DAY_OF_WEEK:
    335       ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
    336       break;
    337 
    338   case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
    339       ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
    340       break;
    341     }
    342 }
    343 
    344 U_CAPI const char* U_EXPORT2
    345 ucal_getAvailable(int32_t index)
    346 {
    347 
    348     return uloc_getAvailable(index);
    349 }
    350 
    351 U_CAPI int32_t U_EXPORT2
    352 ucal_countAvailable()
    353 {
    354 
    355     return uloc_countAvailable();
    356 }
    357 
    358 U_CAPI UDate  U_EXPORT2
    359 ucal_getMillis(    const    UCalendar*      cal,
    360                UErrorCode*     status)
    361 {
    362 
    363     if(U_FAILURE(*status)) return (UDate) 0;
    364 
    365     return ((Calendar*)cal)->getTime(*status);
    366 }
    367 
    368 U_CAPI void  U_EXPORT2
    369 ucal_setMillis(        UCalendar*      cal,
    370                UDate           dateTime,
    371                UErrorCode*     status )
    372 {
    373     if(U_FAILURE(*status)) return;
    374 
    375     ((Calendar*)cal)->setTime(dateTime, *status);
    376 }
    377 
    378 // TBD: why does this take an UErrorCode?
    379 U_CAPI void  U_EXPORT2
    380 ucal_setDate(        UCalendar*        cal,
    381              int32_t            year,
    382              int32_t            month,
    383              int32_t            date,
    384              UErrorCode        *status)
    385 {
    386 
    387     if(U_FAILURE(*status)) return;
    388 
    389     ((Calendar*)cal)->set(year, month, date);
    390 }
    391 
    392 // TBD: why does this take an UErrorCode?
    393 U_CAPI void  U_EXPORT2
    394 ucal_setDateTime(    UCalendar*        cal,
    395                  int32_t            year,
    396                  int32_t            month,
    397                  int32_t            date,
    398                  int32_t            hour,
    399                  int32_t            minute,
    400                  int32_t            second,
    401                  UErrorCode        *status)
    402 {
    403     if(U_FAILURE(*status)) return;
    404 
    405     ((Calendar*)cal)->set(year, month, date, hour, minute, second);
    406 }
    407 
    408 U_CAPI UBool  U_EXPORT2
    409 ucal_equivalentTo(    const UCalendar*      cal1,
    410                   const UCalendar*      cal2)
    411 {
    412 
    413     return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
    414 }
    415 
    416 U_CAPI void  U_EXPORT2
    417 ucal_add(    UCalendar*                cal,
    418          UCalendarDateFields        field,
    419          int32_t                    amount,
    420          UErrorCode*                status)
    421 {
    422 
    423     if(U_FAILURE(*status)) return;
    424 
    425     ((Calendar*)cal)->add(field, amount, *status);
    426 }
    427 
    428 U_CAPI void  U_EXPORT2
    429 ucal_roll(        UCalendar*            cal,
    430           UCalendarDateFields field,
    431           int32_t                amount,
    432           UErrorCode*            status)
    433 {
    434 
    435     if(U_FAILURE(*status)) return;
    436 
    437     ((Calendar*)cal)->roll(field, amount, *status);
    438 }
    439 
    440 U_CAPI int32_t  U_EXPORT2
    441 ucal_get(    const    UCalendar*                cal,
    442          UCalendarDateFields        field,
    443          UErrorCode*                status )
    444 {
    445 
    446     if(U_FAILURE(*status)) return -1;
    447 
    448     return ((Calendar*)cal)->get(field, *status);
    449 }
    450 
    451 U_CAPI void  U_EXPORT2
    452 ucal_set(    UCalendar*                cal,
    453          UCalendarDateFields        field,
    454          int32_t                    value)
    455 {
    456 
    457     ((Calendar*)cal)->set(field, value);
    458 }
    459 
    460 U_CAPI UBool  U_EXPORT2
    461 ucal_isSet(    const    UCalendar*                cal,
    462            UCalendarDateFields        field)
    463 {
    464 
    465     return ((Calendar*)cal)->isSet(field);
    466 }
    467 
    468 U_CAPI void  U_EXPORT2
    469 ucal_clearField(    UCalendar*            cal,
    470                 UCalendarDateFields field)
    471 {
    472 
    473     ((Calendar*)cal)->clear(field);
    474 }
    475 
    476 U_CAPI void  U_EXPORT2
    477 ucal_clear(UCalendar* calendar)
    478 {
    479 
    480     ((Calendar*)calendar)->clear();
    481 }
    482 
    483 U_CAPI int32_t  U_EXPORT2
    484 ucal_getLimit(    const    UCalendar*              cal,
    485               UCalendarDateFields     field,
    486               UCalendarLimitType      type,
    487               UErrorCode        *status)
    488 {
    489 
    490     if(status==0 || U_FAILURE(*status)) {
    491         return -1;
    492     }
    493 
    494     switch(type) {
    495   case UCAL_MINIMUM:
    496       return ((Calendar*)cal)->getMinimum(field);
    497 
    498   case UCAL_MAXIMUM:
    499       return ((Calendar*)cal)->getMaximum(field);
    500 
    501   case UCAL_GREATEST_MINIMUM:
    502       return ((Calendar*)cal)->getGreatestMinimum(field);
    503 
    504   case UCAL_LEAST_MAXIMUM:
    505       return ((Calendar*)cal)->getLeastMaximum(field);
    506 
    507   case UCAL_ACTUAL_MINIMUM:
    508       return ((Calendar*)cal)->getActualMinimum(field,
    509           *status);
    510 
    511   case UCAL_ACTUAL_MAXIMUM:
    512       return ((Calendar*)cal)->getActualMaximum(field,
    513           *status);
    514 
    515   default:
    516       break;
    517     }
    518     return -1;
    519 }
    520 
    521 U_CAPI const char * U_EXPORT2
    522 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
    523 {
    524     if (cal == NULL) {
    525         if (U_SUCCESS(*status)) {
    526             *status = U_ILLEGAL_ARGUMENT_ERROR;
    527         }
    528         return NULL;
    529     }
    530     return ((Calendar*)cal)->getLocaleID(type, *status);
    531 }
    532 
    533 U_CAPI const char * U_EXPORT2
    534 ucal_getTZDataVersion(UErrorCode* status)
    535 {
    536     return TimeZone::getTZDataVersion(*status);
    537 }
    538 
    539 U_CAPI int32_t U_EXPORT2
    540 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
    541                             UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
    542     if(status == 0 || U_FAILURE(*status)) {
    543         return 0;
    544     }
    545     if (isSystemID) {
    546         *isSystemID = FALSE;
    547     }
    548     if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
    549         *status = U_ILLEGAL_ARGUMENT_ERROR;
    550         return 0;
    551     }
    552     int32_t reslen = 0;
    553     UnicodeString canonical;
    554     UBool systemID = FALSE;
    555     TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
    556     if (U_SUCCESS(*status)) {
    557         if (isSystemID) {
    558             *isSystemID = systemID;
    559         }
    560         reslen = canonical.extract(result, resultCapacity, *status);
    561     }
    562     return reslen;
    563 }
    564 
    565 U_CAPI const char * U_EXPORT2
    566 ucal_getType(const UCalendar *cal, UErrorCode* status)
    567 {
    568     if (U_FAILURE(*status)) {
    569         return NULL;
    570     }
    571     return ((Calendar*)cal)->getType();
    572 }
    573 
    574 U_CAPI UCalendarWeekdayType U_EXPORT2
    575 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
    576 {
    577     if (U_FAILURE(*status)) {
    578         return UCAL_WEEKDAY;
    579     }
    580     return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
    581 }
    582 
    583 U_CAPI int32_t U_EXPORT2
    584 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
    585 {
    586     if (U_FAILURE(*status)) {
    587         return 0;
    588     }
    589     return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
    590 }
    591 
    592 U_CAPI UBool U_EXPORT2
    593 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
    594 {
    595     if (U_FAILURE(*status)) {
    596         return FALSE;
    597     }
    598     return ((Calendar*)cal)->isWeekend(date, *status);
    599 }
    600 
    601 U_CAPI int32_t  U_EXPORT2
    602 ucal_getFieldDifference(UCalendar* cal, UDate target,
    603                         UCalendarDateFields field,
    604                         UErrorCode* status )
    605 {
    606     if (U_FAILURE(*status)) {
    607         return 0;
    608     }
    609     return ((Calendar*)cal)->fieldDifference(target, field, *status);
    610 }
    611 
    612 
    613 static const UEnumeration defaultKeywordValues = {
    614     NULL,
    615     NULL,
    616     ulist_close_keyword_values_iterator,
    617     ulist_count_keyword_values,
    618     uenum_unextDefault,
    619     ulist_next_keyword_value,
    620     ulist_reset_keyword_values_iterator
    621 };
    622 
    623 static const char * const CAL_TYPES[] = {
    624         "gregorian",
    625         "japanese",
    626         "buddhist",
    627         "roc",
    628         "persian",
    629         "islamic-civil",
    630         "islamic",
    631         "hebrew",
    632         "chinese",
    633         "indian",
    634         "coptic",
    635         "ethiopic",
    636         "ethiopic-amete-alem",
    637         NULL
    638 };
    639 
    640 U_CAPI UEnumeration* U_EXPORT2
    641 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
    642     // Resolve region
    643     char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
    644     int32_t prefRegionLength = 0;
    645     prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
    646     if (prefRegionLength == 0) {
    647         char loc[ULOC_FULLNAME_CAPACITY] = "";
    648         int32_t locLength = 0;
    649         locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
    650 
    651         prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
    652     }
    653 
    654     // Read preferred calendar values from supplementalData calendarPreference
    655     UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
    656     ures_getByKey(rb, "calendarPreferenceData", rb, status);
    657     UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
    658     if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
    659         *status = U_ZERO_ERROR;
    660         order = ures_getByKey(rb, "001", NULL, status);
    661     }
    662 
    663     // Create a list of calendar type strings
    664     UList *values = NULL;
    665     if (U_SUCCESS(*status)) {
    666         values = ulist_createEmptyList(status);
    667         if (U_SUCCESS(*status)) {
    668             for (int i = 0; i < ures_getSize(order); i++) {
    669                 int32_t len;
    670                 const UChar *type = ures_getStringByIndex(order, i, &len, status);
    671                 char *caltype = (char*)uprv_malloc(len + 1);
    672                 if (caltype == NULL) {
    673                     *status = U_MEMORY_ALLOCATION_ERROR;
    674                     break;
    675                 }
    676                 u_UCharsToChars(type, caltype, len);
    677                 *(caltype + len) = 0;
    678 
    679                 ulist_addItemEndList(values, caltype, TRUE, status);
    680                 if (U_FAILURE(*status)) {
    681                     break;
    682                 }
    683             }
    684 
    685             if (U_SUCCESS(*status) && !commonlyUsed) {
    686                 // If not commonlyUsed, add other available values
    687                 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
    688                     if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
    689                         ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
    690                         if (U_FAILURE(*status)) {
    691                             break;
    692                         }
    693                     }
    694                 }
    695             }
    696             if (U_FAILURE(*status)) {
    697                 ulist_deleteList(values);
    698                 values = NULL;
    699             }
    700         }
    701     }
    702 
    703     ures_close(order);
    704     ures_close(rb);
    705 
    706     if (U_FAILURE(*status) || values == NULL) {
    707         return NULL;
    708     }
    709 
    710     // Create string enumeration
    711     UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
    712     if (en == NULL) {
    713         *status = U_MEMORY_ALLOCATION_ERROR;
    714         ulist_deleteList(values);
    715         return NULL;
    716     }
    717     ulist_resetList(values);
    718     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
    719     en->context = values;
    720     return en;
    721 }
    722 
    723 #endif /* #if !UCONFIG_NO_FORMATTING */
    724