michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 2002-2012, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: uenum.c michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:2 michael@0: * michael@0: * created on: 2002jul08 michael@0: * created by: Vladimir Weinstein michael@0: */ michael@0: michael@0: #include "unicode/putil.h" michael@0: #include "uenumimp.h" michael@0: #include "cmemory.h" michael@0: michael@0: /* Layout of the baseContext buffer. */ michael@0: typedef struct { michael@0: int32_t len; /* number of bytes available starting at 'data' */ michael@0: char data; /* actual data starts here */ michael@0: } _UEnumBuffer; michael@0: michael@0: /* Extra bytes to allocate in the baseContext buffer. */ michael@0: static const int32_t PAD = 8; michael@0: michael@0: /* Return a pointer to the baseContext buffer, possibly allocating michael@0: or reallocating it if at least 'capacity' bytes are not available. */ michael@0: static void* _getBuffer(UEnumeration* en, int32_t capacity) { michael@0: michael@0: if (en->baseContext != NULL) { michael@0: if (((_UEnumBuffer*) en->baseContext)->len < capacity) { michael@0: capacity += PAD; michael@0: en->baseContext = uprv_realloc(en->baseContext, michael@0: sizeof(int32_t) + capacity); michael@0: if (en->baseContext == NULL) { michael@0: return NULL; michael@0: } michael@0: ((_UEnumBuffer*) en->baseContext)->len = capacity; michael@0: } michael@0: } else { michael@0: capacity += PAD; michael@0: en->baseContext = uprv_malloc(sizeof(int32_t) + capacity); michael@0: if (en->baseContext == NULL) { michael@0: return NULL; michael@0: } michael@0: ((_UEnumBuffer*) en->baseContext)->len = capacity; michael@0: } michael@0: michael@0: return (void*) & ((_UEnumBuffer*) en->baseContext)->data; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: uenum_close(UEnumeration* en) michael@0: { michael@0: if (en) { michael@0: if (en->close != NULL) { michael@0: if (en->baseContext) { michael@0: uprv_free(en->baseContext); michael@0: } michael@0: en->close(en); michael@0: } else { /* this seems dangerous, but we better kill the object */ michael@0: uprv_free(en); michael@0: } michael@0: } michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: uenum_count(UEnumeration* en, UErrorCode* status) michael@0: { michael@0: if (!en || U_FAILURE(*status)) { michael@0: return -1; michael@0: } michael@0: if (en->count != NULL) { michael@0: return en->count(en, status); michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: /* Don't call this directly. Only uenum_unext should be calling this. */ michael@0: U_CAPI const UChar* U_EXPORT2 michael@0: uenum_unextDefault(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* status) michael@0: { michael@0: UChar *ustr = NULL; michael@0: int32_t len = 0; michael@0: if (en->next != NULL) { michael@0: const char *cstr = en->next(en, &len, status); michael@0: if (cstr != NULL) { michael@0: ustr = (UChar*) _getBuffer(en, (len+1) * sizeof(UChar)); michael@0: if (ustr == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: u_charsToUChars(cstr, ustr, len+1); michael@0: } michael@0: } michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: if (resultLength) { michael@0: *resultLength = len; michael@0: } michael@0: return ustr; michael@0: } michael@0: michael@0: /* Don't call this directly. Only uenum_next should be calling this. */ michael@0: U_CAPI const char* U_EXPORT2 michael@0: uenum_nextDefault(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* status) michael@0: { michael@0: if (en->uNext != NULL) { michael@0: char *tempCharVal; michael@0: const UChar *tempUCharVal = en->uNext(en, resultLength, status); michael@0: if (tempUCharVal == NULL) { michael@0: return NULL; michael@0: } michael@0: tempCharVal = (char*) michael@0: _getBuffer(en, (*resultLength+1) * sizeof(char)); michael@0: if (!tempCharVal) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: u_UCharsToChars(tempUCharVal, tempCharVal, *resultLength + 1); michael@0: return tempCharVal; michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: U_CAPI const UChar* U_EXPORT2 michael@0: uenum_unext(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* status) michael@0: { michael@0: if (!en || U_FAILURE(*status)) { michael@0: return NULL; michael@0: } michael@0: if (en->uNext != NULL) { michael@0: return en->uNext(en, resultLength, status); michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: U_CAPI const char* U_EXPORT2 michael@0: uenum_next(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* status) michael@0: { michael@0: if (!en || U_FAILURE(*status)) { michael@0: return NULL; michael@0: } michael@0: if (en->next != NULL) { michael@0: if (resultLength != NULL) { michael@0: return en->next(en, resultLength, status); michael@0: } michael@0: else { michael@0: int32_t dummyLength=0; michael@0: return en->next(en, &dummyLength, status); michael@0: } michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: uenum_reset(UEnumeration* en, UErrorCode* status) michael@0: { michael@0: if (!en || U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: if (en->reset != NULL) { michael@0: en->reset(en, status); michael@0: } else { michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: }