Added UTF8bvnormcmp(), should replace UTF8normcmp()

This commit is contained in:
Stig Venaas 2002-02-20 15:51:10 +00:00
parent 2d1eb56725
commit 9e8f3053cb
2 changed files with 134 additions and 0 deletions

View File

@ -154,6 +154,11 @@ LDAP_LUNICODE_F(int) UTF8normcmp(
const char *,
unsigned );
LDAP_LUNICODE_F(int) UTF8bvnormcmp(
struct berval *,
struct berval *,
unsigned );
LDAP_END_DECL
#endif

View File

@ -498,3 +498,132 @@ int UTF8normcmp(
}
return l1 > l2 ? 1 : -1;
}
/* compare UTF8-strings, optionally ignore casing */
/* slow, should be optimized */
int UTF8bvnormcmp(
struct berval *bv1,
struct berval *bv2,
unsigned casefold )
{
int i, l1, l2, len, ulen, res;
char *s1, *s2, *done;
unsigned long *ucs, *ucsout1, *ucsout2;
if (bv1 == NULL) {
return bv2 == NULL ? 0 : -1;
} else if (bv2 == NULL) {
return 1;
}
l1 = bv1->bv_len;
l2 = bv2->bv_len;
len = (l1 < l2) ? l1 : l2;
if (len == 0) {
return l1 == 0 ? (l2 == 0 ? 0 : -1) : 1;
}
s1 = bv1->bv_val;
s2 = bv2->bv_val;
done = s1 + len;
while ( (s1 < done) && LDAP_UTF8_ISASCII(s1) && LDAP_UTF8_ISASCII(s2) ) {
if (casefold) {
char c1 = TOUPPER(*s1);
char c2 = TOUPPER(*s2);
res = c1 - c2;
} else {
res = *s1 - *s2;
}
s1++;
s2++;
if (res) {
/* done unless next character in s1 or s2 is non-ascii */
if (s1 < done) {
if (!LDAP_UTF8_ISASCII(s1) || !LDAP_UTF8_ISASCII(s2)) {
break;
}
} else if ((len < l1) && !LDAP_UTF8_ISASCII(s1) ||
(len < l2) && !LDAP_UTF8_ISASCII(s2)) {
break;
}
return res;
}
}
/* We have encountered non-ascii or strings equal up to len */
/* set i to number of iterations */
i = s1 - done + len;
/* passed through loop at least once? */
if (i > 0) {
if (!res && (s1 == done) &&
((len == l1) || LDAP_UTF8_ISASCII(s1)) &&
((len == l2) || LDAP_UTF8_ISASCII(s2))) {
/* all ascii and equal up to len */
return l1 - l2;
}
/* rewind one char, and do normalized compare from there */
s1--;
s2--;
l1 -= i - 1;
l2 -= i - 1;
}
/* FIXME: Should first check to see if strings are already in
* proper normalized form.
*/
ucs = (long *) malloc( ( l1 > l2 ? l1 : l2 ) * sizeof(*ucs) );
if ( ucs == NULL ) {
return l1 > l2 ? 1 : -1; /* what to do??? */
}
/*
* XXYYZ: we convert to ucs4 even though -llunicode
* expects ucs2 in an unsigned long
*/
/* convert and normalize 1st string */
for ( i = 0, ulen = 0; i < l1; i += len, ulen++ ) {
ucs[ulen] = ldap_x_utf8_to_ucs4( s1 + i );
if ( ucs[ulen] == LDAP_UCS4_INVALID ) {
free( ucs );
return -1; /* what to do??? */
}
len = LDAP_UTF8_CHARLEN( s1 + i );
}
uccanondecomp( ucs, ulen, &ucsout1, &l1 );
l1 = uccanoncomp( ucsout1, l1 );
/* convert and normalize 2nd string */
for ( i = 0, ulen = 0; i < l2; i += len, ulen++ ) {
ucs[ulen] = ldap_x_utf8_to_ucs4( s2 + i );
if ( ucs[ulen] == LDAP_UCS4_INVALID ) {
free( ucsout1 );
free( ucs );
return 1; /* what to do??? */
}
len = LDAP_UTF8_CHARLEN( s2 + i );
}
uccanondecomp( ucs, ulen, &ucsout2, &l2 );
l2 = uccanoncomp( ucsout2, l2 );
free( ucs );
res = casefold
? ucstrncasecmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 )
: ucstrncmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 );
free( ucsout1 );
free( ucsout2 );
if ( res != 0 ) {
return res;
}
if ( l1 == l2 ) {
return 0;
}
return l1 > l2 ? 1 : -1;
}