|
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 } |