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