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