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