2 *******************************************************************************
4 * Copyright (C) 2001-2003, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: ustrcase.c
10 * tab size: 8 (not used)
13 * created on: 2002feb20
14 * created by: Markus W. Scherer
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).
21 #include "unicode/utypes.h"
22 #include "unicode/ustring.h"
23 #include "unicode/ubrk.h"
28 /* string casing ------------------------------------------------------------ */
30 #if !UCONFIG_NO_BREAK_ITERATION
33 * Internal titlecasing function,
34 * using u_internalStrToLower() and u_internalToTitle().
36 * Must get titleIter!=NULL.
39 u_internalStrToTitle(UChar
*dest
, int32_t destCapacity
,
40 const UChar
*src
, int32_t srcLength
,
41 UBreakIterator
*titleIter
,
43 UErrorCode
*pErrorCode
) {
46 int32_t prev
, index
, destIndex
, length
;
49 /* set up local variables */
50 uiter_setString(&iter
, src
, srcLength
);
55 /* titlecasing loop */
56 while(prev
<srcLength
) {
57 /* find next index where to titlecase */
60 index
=ubrk_first(titleIter
);
62 index
=ubrk_next(titleIter
);
64 if(index
==UBRK_DONE
|| index
>srcLength
) {
68 /* lowercase [prev..index[ */
70 if(destIndex
<destCapacity
) {
71 length
=u_internalStrToLower(dest
+destIndex
, destCapacity
-destIndex
,
77 length
=u_internalStrToLower(NULL
, 0,
86 if(index
>=srcLength
) {
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
,
98 length
=u_internalToTitle(c
, &iter
, NULL
, 0, locale
);
114 * Implement argument checking and buffer handling
115 * for string case mapping as a common function.
125 u_strCaseMap(UChar
*dest
, int32_t destCapacity
,
126 const UChar
*src
, int32_t srcLength
,
127 UBreakIterator
*titleIter
,
131 UErrorCode
*pErrorCode
) {
137 /* check argument values */
138 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
141 if( destCapacity
<0 ||
142 (dest
==NULL
&& destCapacity
>0) ||
146 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
150 /* get the string length */
152 srcLength
=u_strlen(src
);
155 /* check for overlapping source and destination */
157 ((src
>=dest
&& src
<(dest
+destCapacity
)) ||
158 (dest
>=src
&& dest
<(src
+srcLength
)))
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 */
165 /* allocate a buffer */
166 temp
=(UChar
*)uprv_malloc(destCapacity
*U_SIZEOF_UCHAR
);
168 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
179 if(toWhichCase
==TO_LOWER
) {
180 destLength
=u_internalStrToLower(temp
, destCapacity
,
184 } else if(toWhichCase
==TO_UPPER
) {
185 destLength
=u_internalStrToUpper(temp
, destCapacity
, src
, srcLength
,
187 #if !UCONFIG_NO_BREAK_ITERATION
188 } else if(toWhichCase
==TO_TITLE
) {
189 if(titleIter
==NULL
) {
190 titleIter
=ubrk_open(UBRK_WORD
, locale
,
193 ownTitleIter
=(UBool
)U_SUCCESS(*pErrorCode
);
195 if(U_SUCCESS(*pErrorCode
)) {
196 destLength
=u_internalStrToTitle(temp
, destCapacity
, src
, srcLength
,
197 titleIter
, locale
, pErrorCode
);
201 destLength
=u_internalStrFoldCase(temp
, destCapacity
, src
, srcLength
,
202 options
, pErrorCode
);
205 /* copy the result string to the destination buffer */
207 int32_t copyLength
= destLength
<=destCapacity
? destLength
: destCapacity
;
209 uprv_memmove(dest
, temp
, copyLength
*U_SIZEOF_UCHAR
);
217 #if !UCONFIG_NO_BREAK_ITERATION
219 ubrk_close(titleIter
);
223 return u_terminateUChars(dest
, destCapacity
, destLength
, pErrorCode
);
226 U_CAPI
int32_t U_EXPORT2
227 u_strToLower(UChar
*dest
, int32_t destCapacity
,
228 const UChar
*src
, int32_t srcLength
,
230 UErrorCode
*pErrorCode
) {
231 return u_strCaseMap(dest
, destCapacity
,
234 TO_LOWER
, pErrorCode
);
237 U_CAPI
int32_t U_EXPORT2
238 u_strToUpper(UChar
*dest
, int32_t destCapacity
,
239 const UChar
*src
, int32_t srcLength
,
241 UErrorCode
*pErrorCode
) {
242 return u_strCaseMap(dest
, destCapacity
,
245 TO_UPPER
, pErrorCode
);
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
,
253 UErrorCode
*pErrorCode
) {
254 return u_strCaseMap(dest
, destCapacity
,
256 titleIter
, locale
, 0,
257 TO_TITLE
, pErrorCode
);
260 U_CAPI
int32_t U_EXPORT2
261 u_strFoldCase(UChar
*dest
, int32_t destCapacity
,
262 const UChar
*src
, int32_t srcLength
,
264 UErrorCode
*pErrorCode
) {
265 return u_strCaseMap(dest
, destCapacity
,
268 FOLD_CASE
, pErrorCode
);
271 /* case-insensitive string comparisons */
273 U_CAPI
int32_t U_EXPORT2
274 u_strCaseCompare(const UChar
*s1
, int32_t length1
,
275 const UChar
*s2
, int32_t length2
,
277 UErrorCode
*pErrorCode
) {
278 /* argument checking */
279 if(pErrorCode
==0 || U_FAILURE(*pErrorCode
)) {
282 if(s1
==NULL
|| length1
<-1 || s2
==NULL
|| length2
<-1) {
283 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
286 return unorm_cmpEquivFold(s1
, length1
, s2
, length2
,
287 options
|U_COMPARE_IGNORE_CASE
,
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
,
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
,
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
),