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: * Author: Alan Liu michael@0: * Created: November 11 2002 michael@0: * Since: ICU 2.4 michael@0: ********************************************************************** michael@0: */ michael@0: #include "utypeinfo.h" // for 'typeid' to work michael@0: michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/strenum.h" michael@0: #include "unicode/putil.h" michael@0: #include "uenumimp.h" michael@0: #include "ustrenum.h" michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: #include "uassert.h" michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: // StringEnumeration implementation ---------------------------------------- *** michael@0: michael@0: StringEnumeration::StringEnumeration() michael@0: : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) { michael@0: } michael@0: michael@0: StringEnumeration::~StringEnumeration() { michael@0: if (chars != NULL && chars != charsBuffer) { michael@0: uprv_free(chars); michael@0: } michael@0: } michael@0: michael@0: // StringEnumeration base class clone() default implementation, does not clone michael@0: StringEnumeration * michael@0: StringEnumeration::clone() const { michael@0: return NULL; michael@0: } michael@0: michael@0: const char * michael@0: StringEnumeration::next(int32_t *resultLength, UErrorCode &status) { michael@0: const UnicodeString *s=snext(status); michael@0: if(U_SUCCESS(status) && s!=NULL) { michael@0: unistr=*s; michael@0: ensureCharsCapacity(unistr.length()+1, status); michael@0: if(U_SUCCESS(status)) { michael@0: if(resultLength!=NULL) { michael@0: *resultLength=unistr.length(); michael@0: } michael@0: unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV); michael@0: return chars; michael@0: } michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: const UChar * michael@0: StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) { michael@0: const UnicodeString *s=snext(status); michael@0: if(U_SUCCESS(status) && s!=NULL) { michael@0: unistr=*s; michael@0: if(resultLength!=NULL) { michael@0: *resultLength=unistr.length(); michael@0: } michael@0: return unistr.getTerminatedBuffer(); michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: const UnicodeString * michael@0: StringEnumeration::snext(UErrorCode &status) { michael@0: int32_t length; michael@0: const char *s=next(&length, status); michael@0: return setChars(s, length, status); michael@0: } michael@0: michael@0: void michael@0: StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) { michael@0: if(U_SUCCESS(status) && capacity>charsCapacity) { michael@0: if(capacity<(charsCapacity+charsCapacity/2)) { michael@0: // avoid allocation thrashing michael@0: capacity=charsCapacity+charsCapacity/2; michael@0: } michael@0: if(chars!=charsBuffer) { michael@0: uprv_free(chars); michael@0: } michael@0: chars=(char *)uprv_malloc(capacity); michael@0: if(chars==NULL) { michael@0: chars=charsBuffer; michael@0: charsCapacity=sizeof(charsBuffer); michael@0: status=U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: charsCapacity=capacity; michael@0: } michael@0: } michael@0: } michael@0: michael@0: UnicodeString * michael@0: StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) { michael@0: if(U_SUCCESS(status) && s!=NULL) { michael@0: if(length<0) { michael@0: length=(int32_t)uprv_strlen(s); michael@0: } michael@0: michael@0: UChar *buffer=unistr.getBuffer(length+1); michael@0: if(buffer!=NULL) { michael@0: u_charsToUChars(s, buffer, length); michael@0: buffer[length]=0; michael@0: unistr.releaseBuffer(length); michael@0: return &unistr; michael@0: } else { michael@0: status=U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: UBool michael@0: StringEnumeration::operator==(const StringEnumeration& that)const { michael@0: return typeid(*this) == typeid(that); michael@0: } michael@0: michael@0: UBool michael@0: StringEnumeration::operator!=(const StringEnumeration& that)const { michael@0: return !operator==(that); michael@0: } michael@0: michael@0: // UStringEnumeration implementation --------------------------------------- *** michael@0: michael@0: UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) : michael@0: uenum(_uenum) { michael@0: U_ASSERT(_uenum != 0); michael@0: } michael@0: michael@0: UStringEnumeration::~UStringEnumeration() { michael@0: uenum_close(uenum); michael@0: } michael@0: michael@0: int32_t UStringEnumeration::count(UErrorCode& status) const { michael@0: return uenum_count(uenum, &status); michael@0: } michael@0: michael@0: const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) { michael@0: return uenum_next(uenum, resultLength, &status); michael@0: } michael@0: michael@0: const UnicodeString* UStringEnumeration::snext(UErrorCode& status) { michael@0: int32_t length; michael@0: const UChar* str = uenum_unext(uenum, &length, &status); michael@0: if (str == 0 || U_FAILURE(status)) { michael@0: return 0; michael@0: } michael@0: return &unistr.setTo(str, length); michael@0: } michael@0: michael@0: void UStringEnumeration::reset(UErrorCode& status) { michael@0: uenum_reset(uenum, &status); michael@0: } michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration) michael@0: U_NAMESPACE_END michael@0: michael@0: // C wrapper --------------------------------------------------------------- *** michael@0: michael@0: #define THIS(en) ((icu::StringEnumeration*)(en->context)) michael@0: michael@0: U_CDECL_BEGIN michael@0: michael@0: /** michael@0: * Wrapper API to make StringEnumeration look like UEnumeration. michael@0: */ michael@0: static void U_CALLCONV michael@0: ustrenum_close(UEnumeration* en) { michael@0: delete THIS(en); michael@0: uprv_free(en); michael@0: } michael@0: michael@0: /** michael@0: * Wrapper API to make StringEnumeration look like UEnumeration. michael@0: */ michael@0: static int32_t U_CALLCONV michael@0: ustrenum_count(UEnumeration* en, michael@0: UErrorCode* ec) michael@0: { michael@0: return THIS(en)->count(*ec); michael@0: } michael@0: michael@0: /** michael@0: * Wrapper API to make StringEnumeration look like UEnumeration. michael@0: */ michael@0: static const UChar* U_CALLCONV michael@0: ustrenum_unext(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* ec) michael@0: { michael@0: return THIS(en)->unext(resultLength, *ec); michael@0: } michael@0: michael@0: /** michael@0: * Wrapper API to make StringEnumeration look like UEnumeration. michael@0: */ michael@0: static const char* U_CALLCONV michael@0: ustrenum_next(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* ec) michael@0: { michael@0: return THIS(en)->next(resultLength, *ec); michael@0: } michael@0: michael@0: /** michael@0: * Wrapper API to make StringEnumeration look like UEnumeration. michael@0: */ michael@0: static void U_CALLCONV michael@0: ustrenum_reset(UEnumeration* en, michael@0: UErrorCode* ec) michael@0: { michael@0: THIS(en)->reset(*ec); michael@0: } michael@0: michael@0: /** michael@0: * Pseudo-vtable for UEnumeration wrapper around StringEnumeration. michael@0: * The StringEnumeration pointer will be stored in 'context'. michael@0: */ michael@0: static const UEnumeration USTRENUM_VT = { michael@0: NULL, michael@0: NULL, // store StringEnumeration pointer here michael@0: ustrenum_close, michael@0: ustrenum_count, michael@0: ustrenum_unext, michael@0: ustrenum_next, michael@0: ustrenum_reset michael@0: }; michael@0: michael@0: U_CDECL_END michael@0: michael@0: /** michael@0: * Given a StringEnumeration, wrap it in a UEnumeration. The michael@0: * StringEnumeration is adopted; after this call, the caller must not michael@0: * delete it (regardless of error status). michael@0: */ michael@0: U_CAPI UEnumeration* U_EXPORT2 michael@0: uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) { michael@0: UEnumeration* result = NULL; michael@0: if (U_SUCCESS(*ec) && adopted != NULL) { michael@0: result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration)); michael@0: if (result == NULL) { michael@0: *ec = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT)); michael@0: result->context = adopted; michael@0: } michael@0: } michael@0: if (result == NULL) { michael@0: delete adopted; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: // C wrapper --------------------------------------------------------------- *** michael@0: michael@0: U_CDECL_BEGIN michael@0: michael@0: typedef struct UCharStringEnumeration { michael@0: UEnumeration uenum; michael@0: int32_t index, count; michael@0: } UCharStringEnumeration; michael@0: michael@0: static void U_CALLCONV michael@0: ucharstrenum_close(UEnumeration* en) { michael@0: uprv_free(en); michael@0: } michael@0: michael@0: static int32_t U_CALLCONV michael@0: ucharstrenum_count(UEnumeration* en, michael@0: UErrorCode* /*ec*/) { michael@0: return ((UCharStringEnumeration*)en)->count; michael@0: } michael@0: michael@0: static const UChar* U_CALLCONV michael@0: ucharstrenum_unext(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* /*ec*/) { michael@0: UCharStringEnumeration *e = (UCharStringEnumeration*) en; michael@0: if (e->index >= e->count) { michael@0: return NULL; michael@0: } michael@0: const UChar* result = ((const UChar**)e->uenum.context)[e->index++]; michael@0: if (resultLength) { michael@0: *resultLength = (int32_t)u_strlen(result); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: michael@0: static const char* U_CALLCONV michael@0: ucharstrenum_next(UEnumeration* en, michael@0: int32_t* resultLength, michael@0: UErrorCode* /*ec*/) { michael@0: UCharStringEnumeration *e = (UCharStringEnumeration*) en; michael@0: if (e->index >= e->count) { michael@0: return NULL; michael@0: } michael@0: const char* result = ((const char**)e->uenum.context)[e->index++]; michael@0: if (resultLength) { michael@0: *resultLength = (int32_t)uprv_strlen(result); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: static void U_CALLCONV michael@0: ucharstrenum_reset(UEnumeration* en, michael@0: UErrorCode* /*ec*/) { michael@0: ((UCharStringEnumeration*)en)->index = 0; michael@0: } michael@0: michael@0: static const UEnumeration UCHARSTRENUM_VT = { michael@0: NULL, michael@0: NULL, // store StringEnumeration pointer here michael@0: ucharstrenum_close, michael@0: ucharstrenum_count, michael@0: uenum_unextDefault, michael@0: ucharstrenum_next, michael@0: ucharstrenum_reset michael@0: }; michael@0: michael@0: static const UEnumeration UCHARSTRENUM_U_VT = { michael@0: NULL, michael@0: NULL, // store StringEnumeration pointer here michael@0: ucharstrenum_close, michael@0: ucharstrenum_count, michael@0: ucharstrenum_unext, michael@0: uenum_nextDefault, michael@0: ucharstrenum_reset michael@0: }; michael@0: michael@0: U_CDECL_END michael@0: michael@0: U_CAPI UEnumeration* U_EXPORT2 michael@0: uenum_openCharStringsEnumeration(const char* const strings[], int32_t count, michael@0: UErrorCode* ec) { michael@0: UCharStringEnumeration* result = NULL; michael@0: if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { michael@0: result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); michael@0: if (result == NULL) { michael@0: *ec = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: U_ASSERT((char*)result==(char*)(&result->uenum)); michael@0: uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT)); michael@0: result->uenum.context = (void*)strings; michael@0: result->index = 0; michael@0: result->count = count; michael@0: } michael@0: } michael@0: return (UEnumeration*) result; michael@0: } michael@0: michael@0: U_CAPI UEnumeration* U_EXPORT2 michael@0: uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count, michael@0: UErrorCode* ec) { michael@0: UCharStringEnumeration* result = NULL; michael@0: if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { michael@0: result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); michael@0: if (result == NULL) { michael@0: *ec = U_MEMORY_ALLOCATION_ERROR; michael@0: } else { michael@0: U_ASSERT((char*)result==(char*)(&result->uenum)); michael@0: uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT)); michael@0: result->uenum.context = (void*)strings; michael@0: result->index = 0; michael@0: result->count = count; michael@0: } michael@0: } michael@0: return (UEnumeration*) result; michael@0: } michael@0: michael@0: michael@0: // end C Wrapper