2 *******************************************************************************
4 * Copyright (C) 2001-2015, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: ustrcase.cpp
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/brkiter.h"
23 #include "unicode/ustring.h"
24 #include "unicode/ucasemap.h"
25 #include "unicode/ubrk.h"
26 #include "unicode/utf.h"
27 #include "unicode/utf16.h"
35 /* string casing ------------------------------------------------------------ */
37 /* Appends a full case mapping result, see UCASE_MAX_STRING_LENGTH. */
39 appendResult(UChar
*dest
, int32_t destIndex
, int32_t destCapacity
,
40 int32_t result
, const UChar
*s
) {
44 /* decode the result */
46 /* (not) original code point */
49 } else if(result
<=UCASE_MAX_STRING_LENGTH
) {
57 if(destIndex
<destCapacity
) {
58 /* append the result */
62 U16_APPEND(dest
, destIndex
, destCapacity
, c
, isError
);
64 /* overflow, nothing written */
65 destIndex
+=U16_LENGTH(c
);
69 if((destIndex
+length
)<=destCapacity
) {
71 dest
[destIndex
++]=*s
++;
82 destIndex
+=U16_LENGTH(c
);
90 static UChar32 U_CALLCONV
91 utf16_caseContextIterator(void *context
, int8_t dir
) {
92 UCaseContext
*csc
=(UCaseContext
*)context
;
96 /* reset for backward iteration */
97 csc
->index
=csc
->cpStart
;
100 /* reset for forward iteration */
101 csc
->index
=csc
->cpLimit
;
104 /* continue current iteration direction */
109 if(csc
->start
<csc
->index
) {
110 U16_PREV((const UChar
*)csc
->p
, csc
->start
, csc
->index
, c
);
114 if(csc
->index
<csc
->limit
) {
115 U16_NEXT((const UChar
*)csc
->p
, csc
->index
, csc
->limit
, c
);
123 * Case-maps [srcStart..srcLimit[ but takes
124 * context [0..srcLength[ into account.
127 _caseMap(const UCaseMap
*csm
, UCaseMapFull
*map
,
128 UChar
*dest
, int32_t destCapacity
,
129 const UChar
*src
, UCaseContext
*csc
,
130 int32_t srcStart
, int32_t srcLimit
,
131 UErrorCode
*pErrorCode
) {
134 int32_t srcIndex
, destIndex
;
137 locCache
=csm
->locCache
;
139 /* case mapping loop */
142 while(srcIndex
<srcLimit
) {
143 csc
->cpStart
=srcIndex
;
144 U16_NEXT(src
, srcIndex
, srcLimit
, c
);
145 csc
->cpLimit
=srcIndex
;
146 c
=map(csm
->csp
, c
, utf16_caseContextIterator
, csc
, &s
, csm
->locale
, &locCache
);
147 if((destIndex
<destCapacity
) && (c
<0 ? (c2
=~c
)<=0xffff : UCASE_MAX_STRING_LENGTH
<c
&& (c2
=c
)<=0xffff)) {
148 /* fast path version of appendResult() for BMP results */
149 dest
[destIndex
++]=(UChar
)c2
;
151 destIndex
=appendResult(dest
, destIndex
, destCapacity
, c
, s
);
155 if(destIndex
>destCapacity
) {
156 *pErrorCode
=U_BUFFER_OVERFLOW_ERROR
;
161 #if !UCONFIG_NO_BREAK_ITERATION
163 U_CFUNC
int32_t U_CALLCONV
164 ustrcase_internalToTitle(const UCaseMap
*csm
,
165 UChar
*dest
, int32_t destCapacity
,
166 const UChar
*src
, int32_t srcLength
,
167 UErrorCode
*pErrorCode
) {
170 int32_t prev
, titleStart
, titleLimit
, idx
, destIndex
, length
;
173 if(U_FAILURE(*pErrorCode
)) {
177 // Use the C++ abstract base class to minimize dependencies.
178 // TODO: Change UCaseMap.iter to store a BreakIterator directly.
179 BreakIterator
*bi
=reinterpret_cast<BreakIterator
*>(csm
->iter
);
181 /* set up local variables */
182 int32_t locCache
=csm
->locCache
;
183 UCaseContext csc
=UCASECONTEXT_INITIALIZER
;
190 /* titlecasing loop */
191 while(prev
<srcLength
) {
192 /* find next index where to titlecase */
199 if(idx
==UBRK_DONE
|| idx
>srcLength
) {
204 * Unicode 4 & 5 section 3.13 Default Case Operations:
206 * R3 toTitlecase(X): Find the word boundaries based on Unicode Standard Annex
207 * #29, "Text Boundaries." Between each pair of word boundaries, find the first
208 * cased character F. If F exists, map F to default_title(F); then map each
209 * subsequent character C to default_lower(C).
211 * In this implementation, segment [prev..index[ into 3 parts:
212 * a) uncased characters (copy as-is) [prev..titleStart[
213 * b) first case letter (titlecase) [titleStart..titleLimit[
214 * c) subsequent characters (lowercase) [titleLimit..index[
217 /* find and copy uncased characters [prev..titleStart[ */
218 titleStart
=titleLimit
=prev
;
219 U16_NEXT(src
, titleLimit
, idx
, c
);
220 if((csm
->options
&U_TITLECASE_NO_BREAK_ADJUSTMENT
)==0 && UCASE_NONE
==ucase_getType(csm
->csp
, c
)) {
221 /* Adjust the titlecasing index (titleStart) to the next cased character. */
223 titleStart
=titleLimit
;
224 if(titleLimit
==idx
) {
226 * only uncased characters in [prev..index[
227 * stop with titleStart==titleLimit==index
231 U16_NEXT(src
, titleLimit
, idx
, c
);
232 if(UCASE_NONE
!=ucase_getType(csm
->csp
, c
)) {
233 break; /* cased letter at [titleStart..titleLimit[ */
236 length
=titleStart
-prev
;
238 if((destIndex
+length
)<=destCapacity
) {
239 uprv_memcpy(dest
+destIndex
, src
+prev
, length
*U_SIZEOF_UCHAR
);
245 if(titleStart
<titleLimit
) {
246 /* titlecase c which is from [titleStart..titleLimit[ */
247 csc
.cpStart
=titleStart
;
248 csc
.cpLimit
=titleLimit
;
249 c
=ucase_toFullTitle(csm
->csp
, c
, utf16_caseContextIterator
, &csc
, &s
, csm
->locale
, &locCache
);
250 destIndex
=appendResult(dest
, destIndex
, destCapacity
, c
, s
);
252 /* Special case Dutch IJ titlecasing */
253 if ( titleStart
+1 < idx
&&
254 ucase_getCaseLocale(csm
->locale
,&locCache
) == UCASE_LOC_DUTCH
&&
255 ( src
[titleStart
] == (UChar32
) 0x0049 || src
[titleStart
] == (UChar32
) 0x0069 ) &&
256 ( src
[titleStart
+1] == (UChar32
) 0x004A || src
[titleStart
+1] == (UChar32
) 0x006A )) {
258 destIndex
=appendResult(dest
, destIndex
, destCapacity
, c
, s
);
262 /* lowercase [titleLimit..index[ */
264 if((csm
->options
&U_TITLECASE_NO_LOWERCASE
)==0) {
265 /* Normal operation: Lowercase the rest of the word. */
268 csm
, ucase_toFullLower
,
269 dest
+destIndex
, destCapacity
-destIndex
,
274 /* Optionally just copy the rest of the word unchanged. */
275 length
=idx
-titleLimit
;
276 if((destIndex
+length
)<=destCapacity
) {
277 uprv_memcpy(dest
+destIndex
, src
+titleLimit
, length
*U_SIZEOF_UCHAR
);
288 if(destIndex
>destCapacity
) {
289 *pErrorCode
=U_BUFFER_OVERFLOW_ERROR
;
294 #endif // !UCONFIG_NO_BREAK_ITERATION
296 /* functions available in the common library (for unistr_case.cpp) */
298 U_CFUNC
int32_t U_CALLCONV
299 ustrcase_internalToLower(const UCaseMap
*csm
,
300 UChar
*dest
, int32_t destCapacity
,
301 const UChar
*src
, int32_t srcLength
,
302 UErrorCode
*pErrorCode
) {
303 UCaseContext csc
=UCASECONTEXT_INITIALIZER
;
307 csm
, ucase_toFullLower
,
309 src
, &csc
, 0, srcLength
,
313 U_CFUNC
int32_t U_CALLCONV
314 ustrcase_internalToUpper(const UCaseMap
*csm
,
315 UChar
*dest
, int32_t destCapacity
,
316 const UChar
*src
, int32_t srcLength
,
317 UErrorCode
*pErrorCode
) {
318 UCaseContext csc
=UCASECONTEXT_INITIALIZER
;
322 csm
, ucase_toFullUpper
,
324 src
, &csc
, 0, srcLength
,
329 ustr_foldCase(const UCaseProps
*csp
,
330 UChar
*dest
, int32_t destCapacity
,
331 const UChar
*src
, int32_t srcLength
,
333 UErrorCode
*pErrorCode
) {
334 int32_t srcIndex
, destIndex
;
339 /* case mapping loop */
340 srcIndex
=destIndex
=0;
341 while(srcIndex
<srcLength
) {
342 U16_NEXT(src
, srcIndex
, srcLength
, c
);
343 c
=ucase_toFullFolding(csp
, c
, &s
, options
);
344 if((destIndex
<destCapacity
) && (c
<0 ? (c2
=~c
)<=0xffff : UCASE_MAX_STRING_LENGTH
<c
&& (c2
=c
)<=0xffff)) {
345 /* fast path version of appendResult() for BMP results */
346 dest
[destIndex
++]=(UChar
)c2
;
348 destIndex
=appendResult(dest
, destIndex
, destCapacity
, c
, s
);
352 if(destIndex
>destCapacity
) {
353 *pErrorCode
=U_BUFFER_OVERFLOW_ERROR
;
358 U_CFUNC
int32_t U_CALLCONV
359 ustrcase_internalFold(const UCaseMap
*csm
,
360 UChar
*dest
, int32_t destCapacity
,
361 const UChar
*src
, int32_t srcLength
,
362 UErrorCode
*pErrorCode
) {
363 return ustr_foldCase(csm
->csp
, dest
, destCapacity
, src
, srcLength
, csm
->options
, pErrorCode
);
367 ustrcase_map(const UCaseMap
*csm
,
368 UChar
*dest
, int32_t destCapacity
,
369 const UChar
*src
, int32_t srcLength
,
370 UStringCaseMapper
*stringCaseMapper
,
371 UErrorCode
*pErrorCode
) {
377 /* check argument values */
378 if(U_FAILURE(*pErrorCode
)) {
381 if( destCapacity
<0 ||
382 (dest
==NULL
&& destCapacity
>0) ||
386 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
390 /* get the string length */
392 srcLength
=u_strlen(src
);
395 /* check for overlapping source and destination */
397 ((src
>=dest
&& src
<(dest
+destCapacity
)) ||
398 (dest
>=src
&& dest
<(src
+srcLength
)))
400 /* overlap: provide a temporary destination buffer and later copy the result */
401 if(destCapacity
<=UPRV_LENGTHOF(buffer
)) {
402 /* the stack buffer is large enough */
405 /* allocate a buffer */
406 temp
=(UChar
*)uprv_malloc(destCapacity
*U_SIZEOF_UCHAR
);
408 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
416 destLength
=stringCaseMapper(csm
, temp
, destCapacity
, src
, srcLength
, pErrorCode
);
418 /* copy the result string to the destination buffer */
420 int32_t copyLength
= destLength
<=destCapacity
? destLength
: destCapacity
;
422 uprv_memmove(dest
, temp
, copyLength
*U_SIZEOF_UCHAR
);
430 return u_terminateUChars(dest
, destCapacity
, destLength
, pErrorCode
);
433 /* public API functions */
435 U_CAPI
int32_t U_EXPORT2
436 u_strFoldCase(UChar
*dest
, int32_t destCapacity
,
437 const UChar
*src
, int32_t srcLength
,
439 UErrorCode
*pErrorCode
) {
440 UCaseMap csm
=UCASEMAP_INITIALIZER
;
441 csm
.csp
=ucase_getSingleton();
447 ustrcase_internalFold
, pErrorCode
);
450 /* case-insensitive string comparisons -------------------------------------- */
453 * This function is a copy of unorm_cmpEquivFold() minus the parts for
454 * canonical equivalence.
455 * Keep the functions in sync, and see there for how this works.
456 * The duplication is for modularization:
457 * It makes caseless (but not canonical caseless) matches independent of
458 * the normalization code.
461 /* stack element for previous-level source/decomposition pointers */
462 struct CmpEquivLevel
{
463 const UChar
*start
, *s
, *limit
;
465 typedef struct CmpEquivLevel CmpEquivLevel
;
468 * Internal implementation code comparing string with case fold.
469 * This function is called from u_strcmpFold() and u_caseInsensitivePrefixMatch().
471 * @param s1 input string 1
472 * @param length1 length of string 1, or -1 (NULL terminated)
473 * @param s2 input string 2
474 * @param length2 length of string 2, or -1 (NULL terminated)
475 * @param options compare options
476 * @param matchLen1 (output) length of partial prefix match in s1
477 * @param matchLen2 (output) length of partial prefix match in s2
478 * @param pErrorCode receives error status
479 * @return The result of comparison
481 static int32_t _cmpFold(
482 const UChar
*s1
, int32_t length1
,
483 const UChar
*s2
, int32_t length2
,
485 int32_t *matchLen1
, int32_t *matchLen2
,
486 UErrorCode
*pErrorCode
) {
489 const UCaseProps
*csp
;
491 /* current-level start/limit - s1/s2 as current */
492 const UChar
*start1
, *start2
, *limit1
, *limit2
;
494 /* points to the original start address */
495 const UChar
*org1
, *org2
;
497 /* points to the end of match + 1 */
498 const UChar
*m1
, *m2
;
500 /* case folding variables */
504 /* stacks of previous-level start/current/limit */
505 CmpEquivLevel stack1
[2], stack2
[2];
507 /* case folding buffers, only use current-level start/limit */
508 UChar fold1
[UCASE_MAX_STRING_LENGTH
+1], fold2
[UCASE_MAX_STRING_LENGTH
+1];
510 /* track which is the current level per string */
511 int32_t level1
, level2
;
513 /* current code units, and code points for lookups */
514 UChar32 c1
, c2
, cp1
, cp2
;
516 /* no argument error checking because this itself is not an API */
519 * assume that at least the option U_COMPARE_IGNORE_CASE is set
520 * otherwise this function would have to behave exactly as uprv_strCompare()
522 csp
=ucase_getSingleton();
523 if(U_FAILURE(*pErrorCode
)) {
529 U_ASSERT(matchLen2
!=NULL
);
551 /* comparison loop */
554 * here a code unit value of -1 means "get another code unit"
555 * below it will mean "this source is finished"
559 /* get next code unit from string 1, post-increment */
561 if(s1
==limit1
|| ((c1
=*s1
)==0 && (limit1
==NULL
|| (options
&_STRNCMP_STYLE
)))) {
571 /* reached end of level buffer, pop one level */
574 start1
=stack1
[level1
].start
; /*Not uninitialized*/
575 } while(start1
==NULL
);
576 s1
=stack1
[level1
].s
; /*Not uninitialized*/
577 limit1
=stack1
[level1
].limit
; /*Not uninitialized*/
582 /* get next code unit from string 2, post-increment */
584 if(s2
==limit2
|| ((c2
=*s2
)==0 && (limit2
==NULL
|| (options
&_STRNCMP_STYLE
)))) {
594 /* reached end of level buffer, pop one level */
597 start2
=stack2
[level2
].start
; /*Not uninitialized*/
598 } while(start2
==NULL
);
599 s2
=stack2
[level2
].s
; /*Not uninitialized*/
600 limit2
=stack2
[level2
].limit
; /*Not uninitialized*/
606 * either variable c1, c2 is -1 only if the corresponding string is finished
609 const UChar
*next1
, *next2
;
612 cmpRes
=0; /* c1==c2==-1 indicating end of strings */
617 * Note: Move the match positions in both strings at the same time
618 * only when corresponding code point(s) in the original strings
619 * are fully consumed. For example, when comparing s1="Fust" and
620 * s2="Fu\u00dfball", s2[2] is folded into "ss", and s1[2] matches
621 * the first code point in the case-folded data. But the second "s"
622 * has no matching code point in s1, so this implementation returns
623 * 2 as the prefix match length ("Fu").
628 } else if(s1
==limit1
) {
629 /* Note: This implementation only use a single level of stack.
630 * If this code needs to be changed to use multiple levels
631 * of stacks, the code above should check if the current
632 * code is at the end of all stacks.
636 /* is s1 at the end of the current stack? */
643 } else if(s2
==limit2
) {
646 /* is s2 at the end of the current stack? */
654 c1
=c2
=-1; /* make us fetch new code units */
657 cmpRes
=-1; /* string 1 ends before string 2 */
660 cmpRes
=1; /* string 2 ends before string 1 */
663 /* c1!=c2 && c1>=0 && c2>=0 */
665 /* get complete code points for c1, c2 for lookups if either is a surrogate */
667 if(U_IS_SURROGATE(c1
)) {
670 if(U_IS_SURROGATE_LEAD(c1
)) {
671 if(s1
!=limit1
&& U16_IS_TRAIL(c
=*s1
)) {
672 /* advance ++s1; only below if cp1 decomposes/case-folds */
673 cp1
=U16_GET_SUPPLEMENTARY(c1
, c
);
675 } else /* isTrail(c1) */ {
676 if(start1
<=(s1
-2) && U16_IS_LEAD(c
=*(s1
-2))) {
677 cp1
=U16_GET_SUPPLEMENTARY(c
, c1
);
683 if(U_IS_SURROGATE(c2
)) {
686 if(U_IS_SURROGATE_LEAD(c2
)) {
687 if(s2
!=limit2
&& U16_IS_TRAIL(c
=*s2
)) {
688 /* advance ++s2; only below if cp2 decomposes/case-folds */
689 cp2
=U16_GET_SUPPLEMENTARY(c2
, c
);
691 } else /* isTrail(c2) */ {
692 if(start2
<=(s2
-2) && U16_IS_LEAD(c
=*(s2
-2))) {
693 cp2
=U16_GET_SUPPLEMENTARY(c
, c2
);
699 * go down one level for each string
700 * continue with the main loop as soon as there is a real change
704 (length
=ucase_toFullFolding(csp
, (UChar32
)cp1
, &p
, options
))>=0
706 /* cp1 case-folds to the code point "length" or to p[length] */
707 if(U_IS_SURROGATE(c1
)) {
708 if(U_IS_SURROGATE_LEAD(c1
)) {
709 /* advance beyond source surrogate pair if it case-folds */
711 } else /* isTrail(c1) */ {
713 * we got a supplementary code point when hitting its trail surrogate,
714 * therefore the lead surrogate must have been the same as in the other string;
715 * compare this decomposition with the lead surrogate in the other string
716 * remember that this simulates bulk text replacement:
717 * the decomposition would replace the entire code point
725 /* push current level pointers */
726 stack1
[0].start
=start1
;
728 stack1
[0].limit
=limit1
;
731 /* copy the folding result to fold1[] */
732 if(length
<=UCASE_MAX_STRING_LENGTH
) {
733 u_memcpy(fold1
, p
, length
);
736 U16_APPEND_UNSAFE(fold1
, i
, length
);
740 /* set next level pointers to case folding */
744 /* get ready to read from decomposition, continue with loop */
750 (length
=ucase_toFullFolding(csp
, (UChar32
)cp2
, &p
, options
))>=0
752 /* cp2 case-folds to the code point "length" or to p[length] */
753 if(U_IS_SURROGATE(c2
)) {
754 if(U_IS_SURROGATE_LEAD(c2
)) {
755 /* advance beyond source surrogate pair if it case-folds */
757 } else /* isTrail(c2) */ {
759 * we got a supplementary code point when hitting its trail surrogate,
760 * therefore the lead surrogate must have been the same as in the other string;
761 * compare this decomposition with the lead surrogate in the other string
762 * remember that this simulates bulk text replacement:
763 * the decomposition would replace the entire code point
771 /* push current level pointers */
772 stack2
[0].start
=start2
;
774 stack2
[0].limit
=limit2
;
777 /* copy the folding result to fold2[] */
778 if(length
<=UCASE_MAX_STRING_LENGTH
) {
779 u_memcpy(fold2
, p
, length
);
782 U16_APPEND_UNSAFE(fold2
, i
, length
);
786 /* set next level pointers to case folding */
790 /* get ready to read from decomposition, continue with loop */
796 * no decomposition/case folding, max level for both sides:
797 * return difference result
799 * code point order comparison must not just return cp1-cp2
800 * because when single surrogates are present then the surrogate pairs
801 * that formed cp1 and cp2 may be from different string indexes
803 * example: { d800 d800 dc01 } vs. { d800 dc00 }, compare at second code units
804 * c1=d800 cp1=10001 c2=dc00 cp2=10000
805 * cp1-cp2>0 but c1-c2<0 and in fact in UTF-32 it is { d800 10001 } < { 10000 }
807 * therefore, use same fix-up as in ustring.c/uprv_strCompare()
808 * except: uprv_strCompare() fetches c=*s while this functions fetches c=*s++
809 * so we have slightly different pointer/start/limit comparisons here
812 if(c1
>=0xd800 && c2
>=0xd800 && (options
&U_COMPARE_CODE_POINT_ORDER
)) {
813 /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
815 (c1
<=0xdbff && s1
!=limit1
&& U16_IS_TRAIL(*s1
)) ||
816 (U16_IS_TRAIL(c1
) && start1
!=(s1
-1) && U16_IS_LEAD(*(s1
-2)))
818 /* part of a surrogate pair, leave >=d800 */
820 /* BMP code point - may be surrogate code point - make <d800 */
825 (c2
<=0xdbff && s2
!=limit2
&& U16_IS_TRAIL(*s2
)) ||
826 (U16_IS_TRAIL(c2
) && start2
!=(s2
-1) && U16_IS_LEAD(*(s2
-2)))
828 /* part of a surrogate pair, leave >=d800 */
830 /* BMP code point - may be surrogate code point - make <d800 */
846 /* internal function */
848 u_strcmpFold(const UChar
*s1
, int32_t length1
,
849 const UChar
*s2
, int32_t length2
,
851 UErrorCode
*pErrorCode
) {
852 return _cmpFold(s1
, length1
, s2
, length2
, options
, NULL
, NULL
, pErrorCode
);
855 /* public API functions */
857 U_CAPI
int32_t U_EXPORT2
858 u_strCaseCompare(const UChar
*s1
, int32_t length1
,
859 const UChar
*s2
, int32_t length2
,
861 UErrorCode
*pErrorCode
) {
862 /* argument checking */
863 if(pErrorCode
==0 || U_FAILURE(*pErrorCode
)) {
866 if(s1
==NULL
|| length1
<-1 || s2
==NULL
|| length2
<-1) {
867 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
870 return u_strcmpFold(s1
, length1
, s2
, length2
,
871 options
|U_COMPARE_IGNORE_CASE
,
875 U_CAPI
int32_t U_EXPORT2
876 u_strcasecmp(const UChar
*s1
, const UChar
*s2
, uint32_t options
) {
877 UErrorCode errorCode
=U_ZERO_ERROR
;
878 return u_strcmpFold(s1
, -1, s2
, -1,
879 options
|U_COMPARE_IGNORE_CASE
,
883 U_CAPI
int32_t U_EXPORT2
884 u_memcasecmp(const UChar
*s1
, const UChar
*s2
, int32_t length
, uint32_t options
) {
885 UErrorCode errorCode
=U_ZERO_ERROR
;
886 return u_strcmpFold(s1
, length
, s2
, length
,
887 options
|U_COMPARE_IGNORE_CASE
,
891 U_CAPI
int32_t U_EXPORT2
892 u_strncasecmp(const UChar
*s1
, const UChar
*s2
, int32_t n
, uint32_t options
) {
893 UErrorCode errorCode
=U_ZERO_ERROR
;
894 return u_strcmpFold(s1
, n
, s2
, n
,
895 options
|(U_COMPARE_IGNORE_CASE
|_STRNCMP_STYLE
),
899 /* internal API - detect length of shared prefix */
901 u_caseInsensitivePrefixMatch(const UChar
*s1
, int32_t length1
,
902 const UChar
*s2
, int32_t length2
,
904 int32_t *matchLen1
, int32_t *matchLen2
,
905 UErrorCode
*pErrorCode
) {
906 _cmpFold(s1
, length1
, s2
, length2
, options
,
907 matchLen1
, matchLen2
, pErrorCode
);