]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucstr.c
b19a0fcde46239989b21d0ab0998b31e5dfc1946
[openldap] / libraries / liblunicode / ucstr.c
1 #include "portable.h"
2
3 #include <ldap_pvt_uc.h>
4 #include <ac/ctype.h>
5
6 int ucstrncmp(
7         const ldap_unicode_t *u1,
8         const ldap_unicode_t *u2,
9         ber_len_t n )
10 {
11         for(; 0 < n; ++u1, ++u2, --n ) {
12                 if( *u1 != *u2 ) {
13                         return *u1 < *u2 ? -1 : +1;
14                 }
15                 if ( *u1 == 0 ) {
16                         return 0;
17                 }
18         }
19         return 0;
20 }
21
22 int ucstrncasecmp(
23         const ldap_unicode_t *u1,
24         const ldap_unicode_t *u2,
25         ber_len_t n )
26 {
27         for(; 0 < n; ++u1, ++u2, --n ) {
28                 ldap_unicode_t uu1 = uctoupper( *u1 );
29                 ldap_unicode_t uu2 = uctoupper( *u2 );
30
31                 if( uu1 != uu2 ) {
32                         return uu1 < uu2 ? -1 : +1;
33                 }
34                 if ( uu1 == 0 ) {
35                         return 0;
36                 }
37         }
38         return 0;
39 }
40
41 ldap_unicode_t * ucstrnchr(
42         const ldap_unicode_t *u,
43         ber_len_t n,
44         ldap_unicode_t c )
45 {
46         for(; 0 < n; ++u, --n ) {
47                 if( *u == c ) {
48                         return (ldap_unicode_t *) u;
49                 }
50         }
51
52         return NULL;
53 }
54
55 ldap_unicode_t * ucstrncasechr(
56         const ldap_unicode_t *u,
57         ber_len_t n,
58         ldap_unicode_t c )
59 {
60         c = uctoupper( c );
61         for(; 0 < n; ++u, --n ) {
62                 if( uctoupper( *u ) == c ) {
63                         return (ldap_unicode_t *) u;
64                 }
65         }
66
67         return NULL;
68 }
69
70 void ucstr2upper(
71         ldap_unicode_t *u,
72         ber_len_t n )
73 {
74         for(; 0 < n; ++u, --n ) {
75                 *u = uctoupper( *u );
76         }
77 }
78
79 char * UTF8normalize(
80         const char *s,
81         char casefold )
82 {
83         int i, j, len, clen, outpos, ucsoutlen, outsize, last;
84         char *out;
85         unsigned long *ucs, *p, *ucsout;
86
87         static unsigned char mask[] = {
88                 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
89
90         if ( s == NULL ) {
91                 return NULL;
92         }
93         
94         len = strlen( s );
95
96         if ( len == 0 ) {
97                 out = (char *) malloc( 1 );
98                 *out = '\0';
99                 return out;
100         }
101         
102         outsize = len + 7;
103         out = (char *) malloc( outsize );
104         if ( out == NULL ) {
105                 return NULL;
106         }
107
108         outpos = 0;
109
110         /* finish off everything up to character before first non-ascii */
111         if ( LDAP_UTF8_ISASCII( s ) ) {
112                 for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) {
113                         out[outpos++] = casefold ? TOUPPER( s[i-1] ) : s[i-1];
114                 }
115                 if ( i == len ) {
116                         out[outpos++] = casefold ? TOUPPER( s[len - 1] ) : s[len - 1];
117                         out[outpos] = '\0';
118                         return out;
119                 }
120         } else {
121                 i = 0;
122         }
123
124         p = ucs = (long *) malloc( len * sizeof(*ucs) );
125         if ( ucs == NULL ) {
126                 free(out);
127                 return NULL;
128         }
129
130         /* convert character before first non-ascii to ucs-4 */
131         if ( i > 0 ) {
132                 *p = casefold ? TOUPPER( s[i - 1] ) : s[i - 1];
133                 p++;
134         }
135
136         /* s[i] is now first non-ascii character */
137         for (;;) {
138                 /* s[i] is non-ascii */
139                 /* convert everything up to next ascii to ucs-4 */
140                 while ( i < len ) {
141                         clen = LDAP_UTF8_CHARLEN( s + i );
142                         if ( clen == 0 ) {
143                                 free( ucs );
144                                 free( out );
145                                 return NULL;
146                         }
147                         if ( clen == 1 ) {
148                                 /* ascii */
149                                 break;
150                         }
151                         *p = s[i] & mask[clen];
152                         i++;
153                         for( j = 1; j < clen; j++ ) {
154                                 if ( (s[i] & 0xc0) != 0x80 ) {
155                                         free( ucs );
156                                         free( out );
157                                         return NULL;
158                                 }
159                                 *p <<= 6;
160                                 *p |= s[i] & 0x3f;
161                                 i++;
162                         }
163                         if ( casefold ) {
164                                 *p = uctoupper( *p );
165                         }
166                         p++;
167                 }
168                 /* normalize ucs of length p - ucs */
169                 uccanondecomp( ucs, p - ucs, &ucsout, &ucsoutlen );    
170                 ucsoutlen = uccanoncomp( ucsout, ucsoutlen );
171                 /* convert ucs to utf-8 and store in out */
172                 for ( j = 0; j < ucsoutlen; j++ ) {
173                         /* allocate more space if not enough room for
174                            6 bytes and terminator */
175                         if ( outsize - outpos < 7 ) {
176                                 outsize = ucsoutlen - j + outpos + 6;
177                                 out = (char *) realloc( out, outsize );
178                                 if ( out == NULL ) {
179                                         free( ucs );
180                                         return NULL;
181                                 }
182                         }
183                         outpos += ldap_ucs4_to_utf8( ucsout[j], &out[outpos] );
184                 }
185                 
186                 if ( i == len ) {
187                         break;
188                 }
189
190                 last = i;
191
192                 /* s[i] is ascii */
193                 /* finish off everything up to char before next non-ascii */
194                 for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) {
195                         out[outpos++] = casefold ? TOUPPER( s[i-1] ) : s[i-1];
196                 }
197                 if ( i == len ) {
198                         out[outpos++] = casefold ? TOUPPER( s[len - 1] ) : s[len - 1];
199                         break;
200                 }
201
202                 /* convert character before next non-ascii to ucs-4 */
203                 *ucs = casefold ? TOUPPER( s[i - 1] ) : s[i - 1];
204                 p = ucs + 1;
205         }               
206         free( ucs );
207         out[outpos] = '\0';
208         return out;
209 }