Home | History | Annotate | Download | only in common
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 2002-2012, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *   file name:  uenum.c
     11 *   encoding:   UTF-8
     12 *   tab size:   8 (not used)
     13 *   indentation:2
     14 *
     15 *   created on: 2002jul08
     16 *   created by: Vladimir Weinstein
     17 */
     18 
     19 #include "unicode/putil.h"
     20 #include "uenumimp.h"
     21 #include "cmemory.h"
     22 
     23 /* Layout of the baseContext buffer. */
     24 typedef struct {
     25     int32_t len;  /* number of bytes available starting at 'data' */
     26     char    data; /* actual data starts here */
     27 } _UEnumBuffer;
     28 
     29 /* Extra bytes to allocate in the baseContext buffer. */
     30 static const int32_t PAD = 8;
     31 
     32 /* Return a pointer to the baseContext buffer, possibly allocating
     33    or reallocating it if at least 'capacity' bytes are not available. */
     34 static void* _getBuffer(UEnumeration* en, int32_t capacity) {
     35 
     36     if (en->baseContext != NULL) {
     37         if (((_UEnumBuffer*) en->baseContext)->len < capacity) {
     38             capacity += PAD;
     39             en->baseContext = uprv_realloc(en->baseContext,
     40                                            sizeof(int32_t) + capacity);
     41             if (en->baseContext == NULL) {
     42                 return NULL;
     43             }
     44             ((_UEnumBuffer*) en->baseContext)->len = capacity;
     45         }
     46     } else {
     47         capacity += PAD;
     48         en->baseContext = uprv_malloc(sizeof(int32_t) + capacity);
     49         if (en->baseContext == NULL) {
     50             return NULL;
     51         }
     52         ((_UEnumBuffer*) en->baseContext)->len = capacity;
     53     }
     54 
     55     return (void*) & ((_UEnumBuffer*) en->baseContext)->data;
     56 }
     57 
     58 U_CAPI void U_EXPORT2
     59 uenum_close(UEnumeration* en)
     60 {
     61     if (en) {
     62         if (en->close != NULL) {
     63             if (en->baseContext) {
     64                 uprv_free(en->baseContext);
     65             }
     66             en->close(en);
     67         } else { /* this seems dangerous, but we better kill the object */
     68             uprv_free(en);
     69         }
     70     }
     71 }
     72 
     73 U_CAPI int32_t U_EXPORT2
     74 uenum_count(UEnumeration* en, UErrorCode* status)
     75 {
     76     if (!en || U_FAILURE(*status)) {
     77         return -1;
     78     }
     79     if (en->count != NULL) {
     80         return en->count(en, status);
     81     } else {
     82         *status = U_UNSUPPORTED_ERROR;
     83         return -1;
     84     }
     85 }
     86 
     87 /* Don't call this directly. Only uenum_unext should be calling this. */
     88 U_CAPI const UChar* U_EXPORT2
     89 uenum_unextDefault(UEnumeration* en,
     90             int32_t* resultLength,
     91             UErrorCode* status)
     92 {
     93     UChar *ustr = NULL;
     94     int32_t len = 0;
     95     if (en->next != NULL) {
     96         const char *cstr = en->next(en, &len, status);
     97         if (cstr != NULL) {
     98             ustr = (UChar*) _getBuffer(en, (len+1) * sizeof(UChar));
     99             if (ustr == NULL) {
    100                 *status = U_MEMORY_ALLOCATION_ERROR;
    101             } else {
    102                 u_charsToUChars(cstr, ustr, len+1);
    103             }
    104         }
    105     } else {
    106         *status = U_UNSUPPORTED_ERROR;
    107     }
    108     if (resultLength) {
    109         *resultLength = len;
    110     }
    111     return ustr;
    112 }
    113 
    114 /* Don't call this directly. Only uenum_next should be calling this. */
    115 U_CAPI const char* U_EXPORT2
    116 uenum_nextDefault(UEnumeration* en,
    117             int32_t* resultLength,
    118             UErrorCode* status)
    119 {
    120     if (en->uNext != NULL) {
    121         char *tempCharVal;
    122         const UChar *tempUCharVal = en->uNext(en, resultLength, status);
    123         if (tempUCharVal == NULL) {
    124             return NULL;
    125         }
    126         tempCharVal = (char*)
    127             _getBuffer(en, (*resultLength+1) * sizeof(char));
    128         if (!tempCharVal) {
    129             *status = U_MEMORY_ALLOCATION_ERROR;
    130             return NULL;
    131         }
    132         u_UCharsToChars(tempUCharVal, tempCharVal, *resultLength + 1);
    133         return tempCharVal;
    134     } else {
    135         *status = U_UNSUPPORTED_ERROR;
    136         return NULL;
    137     }
    138 }
    139 
    140 U_CAPI const UChar* U_EXPORT2
    141 uenum_unext(UEnumeration* en,
    142             int32_t* resultLength,
    143             UErrorCode* status)
    144 {
    145     if (!en || U_FAILURE(*status)) {
    146         return NULL;
    147     }
    148     if (en->uNext != NULL) {
    149         return en->uNext(en, resultLength, status);
    150     } else {
    151         *status = U_UNSUPPORTED_ERROR;
    152         return NULL;
    153     }
    154 }
    155 
    156 U_CAPI const char* U_EXPORT2
    157 uenum_next(UEnumeration* en,
    158           int32_t* resultLength,
    159           UErrorCode* status)
    160 {
    161     if (!en || U_FAILURE(*status)) {
    162         return NULL;
    163     }
    164     if (en->next != NULL) {
    165         if (resultLength != NULL) {
    166             return en->next(en, resultLength, status);
    167         }
    168         else {
    169             int32_t dummyLength=0;
    170             return en->next(en, &dummyLength, status);
    171         }
    172     } else {
    173         *status = U_UNSUPPORTED_ERROR;
    174         return NULL;
    175     }
    176 }
    177 
    178 U_CAPI void U_EXPORT2
    179 uenum_reset(UEnumeration* en, UErrorCode* status)
    180 {
    181     if (!en || U_FAILURE(*status)) {
    182         return;
    183     }
    184     if (en->reset != NULL) {
    185         en->reset(en, status);
    186     } else {
    187         *status = U_UNSUPPORTED_ERROR;
    188     }
    189 }
    190