]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/ustrcase.c
ICU-3.13.tar.gz
[apple/icu.git] / icuSources / common / ustrcase.c
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2001-2003, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: ustrcase.c
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2002feb20
14 * created by: Markus W. Scherer
15 *
16 * Implementation file for string casing C API functions.
17 * Uses functions from uchar.c for basic functionality that requires access
18 * to the Unicode Character Database (uprops.dat).
19 */
20
21 #include "unicode/utypes.h"
22 #include "unicode/ustring.h"
23 #include "unicode/ubrk.h"
24 #include "cmemory.h"
25 #include "unormimp.h"
26 #include "ustr_imp.h"
27
28 /* string casing ------------------------------------------------------------ */
29
30 #if !UCONFIG_NO_BREAK_ITERATION
31
32 /*
33 * Internal titlecasing function,
34 * using u_internalStrToLower() and u_internalToTitle().
35 *
36 * Must get titleIter!=NULL.
37 */
38 U_CFUNC int32_t
39 u_internalStrToTitle(UChar *dest, int32_t destCapacity,
40 const UChar *src, int32_t srcLength,
41 UBreakIterator *titleIter,
42 const char *locale,
43 UErrorCode *pErrorCode) {
44 UCharIterator iter;
45 UChar32 c;
46 int32_t prev, index, destIndex, length;
47 UBool isFirstIndex;
48
49 /* set up local variables */
50 uiter_setString(&iter, src, srcLength);
51 destIndex=0;
52 prev=0;
53 isFirstIndex=TRUE;
54
55 /* titlecasing loop */
56 while(prev<srcLength) {
57 /* find next index where to titlecase */
58 if(isFirstIndex) {
59 isFirstIndex=FALSE;
60 index=ubrk_first(titleIter);
61 } else {
62 index=ubrk_next(titleIter);
63 }
64 if(index==UBRK_DONE || index>srcLength) {
65 index=srcLength;
66 }
67
68 /* lowercase [prev..index[ */
69 if(prev<index) {
70 if(destIndex<destCapacity) {
71 length=u_internalStrToLower(dest+destIndex, destCapacity-destIndex,
72 src, srcLength,
73 prev, index,
74 locale,
75 pErrorCode);
76 } else {
77 length=u_internalStrToLower(NULL, 0,
78 src, srcLength,
79 prev, index,
80 locale,
81 pErrorCode);
82 }
83 destIndex+=length;
84 }
85
86 if(index>=srcLength) {
87 break;
88 }
89
90 /* titlecase the character at the found index */
91 UTF_NEXT_CHAR(src, index, srcLength, c);
92 iter.move(&iter, index, UITER_ZERO);
93 if(destIndex<destCapacity) {
94 length=u_internalToTitle(c, &iter,
95 dest+destIndex, destCapacity-destIndex,
96 locale);
97 } else {
98 length=u_internalToTitle(c, &iter, NULL, 0, locale);
99 }
100 if(length<0) {
101 length=-length;
102 }
103 destIndex+=length;
104
105 prev=index;
106 }
107
108 return destIndex;
109 }
110
111 #endif
112
113 /*
114 * Implement argument checking and buffer handling
115 * for string case mapping as a common function.
116 */
117 enum {
118 TO_LOWER,
119 TO_UPPER,
120 TO_TITLE,
121 FOLD_CASE
122 };
123
124 static int32_t
125 u_strCaseMap(UChar *dest, int32_t destCapacity,
126 const UChar *src, int32_t srcLength,
127 UBreakIterator *titleIter,
128 const char *locale,
129 uint32_t options,
130 int32_t toWhichCase,
131 UErrorCode *pErrorCode) {
132 UChar buffer[300];
133 UChar *temp;
134 int32_t destLength;
135 UBool ownTitleIter;
136
137 /* check argument values */
138 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
139 return 0;
140 }
141 if( destCapacity<0 ||
142 (dest==NULL && destCapacity>0) ||
143 src==NULL ||
144 srcLength<-1
145 ) {
146 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
147 return 0;
148 }
149
150 /* get the string length */
151 if(srcLength==-1) {
152 srcLength=u_strlen(src);
153 }
154
155 /* check for overlapping source and destination */
156 if( dest!=NULL &&
157 ((src>=dest && src<(dest+destCapacity)) ||
158 (dest>=src && dest<(src+srcLength)))
159 ) {
160 /* overlap: provide a temporary destination buffer and later copy the result */
161 if(destCapacity<=(sizeof(buffer)/U_SIZEOF_UCHAR)) {
162 /* the stack buffer is large enough */
163 temp=buffer;
164 } else {
165 /* allocate a buffer */
166 temp=(UChar *)uprv_malloc(destCapacity*U_SIZEOF_UCHAR);
167 if(temp==NULL) {
168 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
169 return 0;
170 }
171 }
172 } else {
173 temp=dest;
174 }
175
176 ownTitleIter=FALSE;
177 destLength=0;
178
179 if(toWhichCase==TO_LOWER) {
180 destLength=u_internalStrToLower(temp, destCapacity,
181 src, srcLength,
182 0, srcLength,
183 locale, pErrorCode);
184 } else if(toWhichCase==TO_UPPER) {
185 destLength=u_internalStrToUpper(temp, destCapacity, src, srcLength,
186 locale, pErrorCode);
187 #if !UCONFIG_NO_BREAK_ITERATION
188 } else if(toWhichCase==TO_TITLE) {
189 if(titleIter==NULL) {
190 titleIter=ubrk_open(UBRK_WORD, locale,
191 src, srcLength,
192 pErrorCode);
193 ownTitleIter=(UBool)U_SUCCESS(*pErrorCode);
194 }
195 if(U_SUCCESS(*pErrorCode)) {
196 destLength=u_internalStrToTitle(temp, destCapacity, src, srcLength,
197 titleIter, locale, pErrorCode);
198 }
199 #endif
200 } else {
201 destLength=u_internalStrFoldCase(temp, destCapacity, src, srcLength,
202 options, pErrorCode);
203 }
204 if(temp!=dest) {
205 /* copy the result string to the destination buffer */
206 if(destLength>0) {
207 int32_t copyLength= destLength<=destCapacity ? destLength : destCapacity;
208 if(copyLength>0) {
209 uprv_memmove(dest, temp, copyLength*U_SIZEOF_UCHAR);
210 }
211 }
212 if(temp!=buffer) {
213 uprv_free(temp);
214 }
215 }
216
217 #if !UCONFIG_NO_BREAK_ITERATION
218 if(ownTitleIter) {
219 ubrk_close(titleIter);
220 }
221 #endif
222
223 return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
224 }
225
226 U_CAPI int32_t U_EXPORT2
227 u_strToLower(UChar *dest, int32_t destCapacity,
228 const UChar *src, int32_t srcLength,
229 const char *locale,
230 UErrorCode *pErrorCode) {
231 return u_strCaseMap(dest, destCapacity,
232 src, srcLength,
233 NULL, locale, 0,
234 TO_LOWER, pErrorCode);
235 }
236
237 U_CAPI int32_t U_EXPORT2
238 u_strToUpper(UChar *dest, int32_t destCapacity,
239 const UChar *src, int32_t srcLength,
240 const char *locale,
241 UErrorCode *pErrorCode) {
242 return u_strCaseMap(dest, destCapacity,
243 src, srcLength,
244 NULL, locale, 0,
245 TO_UPPER, pErrorCode);
246 }
247
248 U_CAPI int32_t U_EXPORT2
249 u_strToTitle(UChar *dest, int32_t destCapacity,
250 const UChar *src, int32_t srcLength,
251 UBreakIterator *titleIter,
252 const char *locale,
253 UErrorCode *pErrorCode) {
254 return u_strCaseMap(dest, destCapacity,
255 src, srcLength,
256 titleIter, locale, 0,
257 TO_TITLE, pErrorCode);
258 }
259
260 U_CAPI int32_t U_EXPORT2
261 u_strFoldCase(UChar *dest, int32_t destCapacity,
262 const UChar *src, int32_t srcLength,
263 uint32_t options,
264 UErrorCode *pErrorCode) {
265 return u_strCaseMap(dest, destCapacity,
266 src, srcLength,
267 NULL, NULL, options,
268 FOLD_CASE, pErrorCode);
269 }
270
271 /* case-insensitive string comparisons */
272
273 U_CAPI int32_t U_EXPORT2
274 u_strCaseCompare(const UChar *s1, int32_t length1,
275 const UChar *s2, int32_t length2,
276 uint32_t options,
277 UErrorCode *pErrorCode) {
278 /* argument checking */
279 if(pErrorCode==0 || U_FAILURE(*pErrorCode)) {
280 return 0;
281 }
282 if(s1==NULL || length1<-1 || s2==NULL || length2<-1) {
283 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
284 return 0;
285 }
286 return unorm_cmpEquivFold(s1, length1, s2, length2,
287 options|U_COMPARE_IGNORE_CASE,
288 pErrorCode);
289 }
290
291 U_CAPI int32_t U_EXPORT2
292 u_strcasecmp(const UChar *s1, const UChar *s2, uint32_t options) {
293 UErrorCode errorCode=U_ZERO_ERROR;
294 return unorm_cmpEquivFold(s1, -1, s2, -1,
295 options|U_COMPARE_IGNORE_CASE,
296 &errorCode);
297 }
298
299 U_CAPI int32_t U_EXPORT2
300 u_memcasecmp(const UChar *s1, const UChar *s2, int32_t length, uint32_t options) {
301 UErrorCode errorCode=U_ZERO_ERROR;
302 return unorm_cmpEquivFold(s1, length, s2, length,
303 options|U_COMPARE_IGNORE_CASE,
304 &errorCode);
305 }
306
307 U_CAPI int32_t U_EXPORT2
308 u_strncasecmp(const UChar *s1, const UChar *s2, int32_t n, uint32_t options) {
309 UErrorCode errorCode=U_ZERO_ERROR;
310 return unorm_cmpEquivFold(s1, n, s2, n,
311 options|(U_COMPARE_IGNORE_CASE|_STRNCMP_STYLE),
312 &errorCode);
313 }