]>
Commit | Line | Data |
---|---|---|
3d9156a7 | 1 | --- wcscoll.c.orig 2004-11-25 11:38:47.000000000 -0800 |
224c7076 A |
2 | +++ wcscoll.c 2005-04-11 15:44:35.000000000 -0700 |
3 | @@ -27,72 +27,222 @@ | |
3d9156a7 A |
4 | #include <sys/cdefs.h> |
5 | __FBSDID("$FreeBSD: src/lib/libc/string/wcscoll.c,v 1.3 2004/04/07 09:47:56 tjr Exp $"); | |
6 | ||
7 | +#include "xlocale_private.h" | |
8 | + | |
9 | #include <errno.h> | |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
12 | #include <wchar.h> | |
13 | #include "collate.h" | |
14 | ||
15 | -static char *__mbsdup(const wchar_t *); | |
224c7076 | 16 | +#define NOTFORWARD (DIRECTIVE_BACKWARD | DIRECTIVE_POSITION) |
3d9156a7 | 17 | |
224c7076 A |
18 | -/* |
19 | - * Placeholder implementation of wcscoll(). Attempts to use the single-byte | |
20 | - * collation ordering where possible, and falls back on wcscmp() in locales | |
21 | - * with extended character sets. | |
22 | - */ | |
3d9156a7 A |
23 | int |
24 | -wcscoll(const wchar_t *ws1, const wchar_t *ws2) | |
25 | +wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc) | |
26 | { | |
224c7076 A |
27 | - char *mbs1, *mbs2; |
28 | - int diff, sverrno; | |
29 | + int sverrno; | |
30 | + int len, len2, prim, prim2, sec, sec2, ret, ret2; | |
31 | + const wchar_t *t, *t2; | |
32 | + wchar_t *tt = NULL, *tt2 = NULL; | |
33 | + wchar_t *tr = NULL, *tr2 = NULL; | |
34 | + wchar_t w, w2; | |
35 | + struct __collate_st_info *info; | |
3d9156a7 A |
36 | |
37 | - if (__collate_load_error || MB_CUR_MAX > 1) | |
38 | + NORMALIZE_LOCALE(loc); | |
224c7076 | 39 | + if (loc->__collate_load_error) |
3d9156a7 | 40 | /* |
224c7076 A |
41 | - * Locale has no special collating order, could not be |
42 | - * loaded, or has an extended character set; do a fast binary | |
43 | - * comparison. | |
44 | + * Locale has no special collating order or could not be | |
45 | + * loaded, do a fast binary comparison. | |
3d9156a7 A |
46 | */ |
47 | return (wcscmp(ws1, ws2)); | |
48 | ||
49 | - if ((mbs1 = __mbsdup(ws1)) == NULL || (mbs2 = __mbsdup(ws2)) == NULL) { | |
224c7076 A |
50 | - /* |
51 | - * Out of memory or illegal wide chars; fall back to wcscmp() | |
52 | - * but leave errno indicating the error. Callers that don't | |
53 | - * check for error will get a reasonable but often slightly | |
54 | - * incorrect result. | |
55 | - */ | |
56 | - sverrno = errno; | |
57 | - free(mbs1); | |
58 | - errno = sverrno; | |
59 | - return (wcscmp(ws1, ws2)); | |
60 | + info = &loc->__lc_collate->__info; | |
61 | + len = len2 = 1; | |
62 | + ret = ret2 = 0; | |
63 | + | |
64 | + if ((info->directive[0] & NOTFORWARD) || | |
65 | + (info->directive[1] & NOTFORWARD) || | |
66 | + (!(info->flags && COLLATE_SUBST_DUP) && | |
67 | + (info->subst_count[0] > 0 || info->subst_count[1] > 0))) { | |
68 | + int direc, pass; | |
69 | + for(pass = 0; pass < info->directive_count; pass++) { | |
70 | + direc = info->directive[pass]; | |
71 | + if (pass == 0 || !(info->flags & COLLATE_SUBST_DUP)) { | |
72 | + free(tt); | |
73 | + tt = __collate_substitute(ws1, pass, loc); | |
74 | + free(tt2); | |
75 | + tt2 = tt ? __collate_substitute(ws2, pass, loc) : NULL; | |
76 | + } | |
77 | + if (direc & DIRECTIVE_BACKWARD) { | |
78 | + wchar_t *bp, *fp, c; | |
79 | + tr = __collate_wcsdup(tt ? tt : ws1); | |
80 | + bp = tr; | |
81 | + fp = tr + wcslen(tr) - 1; | |
82 | + while(bp < fp) { | |
83 | + c = *bp; | |
84 | + *bp++ = *fp; | |
85 | + *fp-- = c; | |
86 | + } | |
87 | + tr2 = __collate_wcsdup(tt2 ? tt2 : ws2); | |
88 | + bp = tr2; | |
89 | + fp = tr2 + wcslen(tr2) - 1; | |
90 | + while(bp < fp) { | |
91 | + c = *bp; | |
92 | + *bp++ = *fp; | |
93 | + *fp-- = c; | |
94 | + } | |
95 | + t = (const wchar_t *)tr; | |
96 | + t2 = (const wchar_t *)tr2; | |
97 | + } else if (tt) { | |
98 | + t = (const wchar_t *)tt; | |
99 | + t2 = (const wchar_t *)tt2; | |
100 | + } else { | |
101 | + t = (const wchar_t *)ws1; | |
102 | + t2 = (const wchar_t *)ws2; | |
103 | + } | |
104 | + if(direc & DIRECTIVE_POSITION) { | |
105 | + while(*t && *t2) { | |
106 | + prim = prim2 = 0; | |
107 | + __collate_lookup_which(t, &len, &prim, pass, loc); | |
108 | + if (prim <= 0) { | |
109 | + if (prim < 0) { | |
110 | + errno = EINVAL; | |
111 | + ret = -1; | |
112 | + goto end; | |
113 | + } | |
114 | + prim = COLLATE_MAX_PRIORITY; | |
115 | + } | |
116 | + __collate_lookup_which(t2, &len2, &prim2, pass, loc); | |
117 | + if (prim2 <= 0) { | |
118 | + if (prim2 < 0) { | |
119 | + errno = EINVAL; | |
120 | + ret = -1; | |
121 | + goto end; | |
122 | + } | |
123 | + prim2 = COLLATE_MAX_PRIORITY; | |
124 | + } | |
125 | + if(prim != prim2) { | |
126 | + ret = prim - prim2; | |
127 | + goto end; | |
128 | + } | |
129 | + t += len; | |
130 | + t2 += len2; | |
131 | + } | |
132 | + } else { | |
133 | + while(*t && *t2) { | |
134 | + prim = prim2 = 0; | |
135 | + while(*t) { | |
136 | + __collate_lookup_which(t, &len, &prim, pass, loc); | |
137 | + if(prim > 0) | |
138 | + break; | |
139 | + if (prim < 0) { | |
140 | + errno = EINVAL; | |
141 | + ret = -1; | |
142 | + goto end; | |
143 | + } | |
144 | + t += len; | |
145 | + } | |
146 | + while(*t2) { | |
147 | + __collate_lookup_which(t2, &len2, &prim2, pass, loc); | |
148 | + if(prim2 > 0) | |
149 | + break; | |
150 | + if (prim2 < 0) { | |
151 | + errno = EINVAL; | |
152 | + ret = -1; | |
153 | + goto end; | |
154 | + } | |
155 | + t2 += len2; | |
156 | + } | |
157 | + if(!prim || !prim2) | |
158 | + break; | |
159 | + if(prim != prim2) { | |
160 | + ret = prim - prim2; | |
161 | + goto end; | |
162 | + } | |
163 | + t += len; | |
164 | + t2 += len2; | |
165 | + } | |
166 | + } | |
167 | + if(!*t) { | |
168 | + if(*t2) { | |
169 | + ret = -(int)*t2; | |
170 | + goto end; | |
171 | + } | |
172 | + } else { | |
173 | + ret = *t; | |
174 | + goto end; | |
175 | + } | |
176 | + } | |
177 | + ret = 0; | |
178 | + goto end; | |
3d9156a7 A |
179 | } |
180 | ||
181 | - diff = strcoll(mbs1, mbs2); | |
224c7076 A |
182 | + /* optimized common case: order_start forward;forward and duplicate |
183 | + * (or no) substitute tables */ | |
184 | + tt = __collate_substitute(ws1, 0, loc); | |
185 | + if (tt == NULL) { | |
186 | + tt2 = NULL; | |
187 | + t = (const wchar_t *)ws1; | |
188 | + t2 = (const wchar_t *)ws2; | |
189 | + } else { | |
190 | + tt2 = __collate_substitute(ws2, 0, loc); | |
191 | + t = (const wchar_t *)tt; | |
192 | + t2 = (const wchar_t *)tt2; | |
193 | + } | |
194 | + while(*t && *t2) { | |
195 | + prim = prim2 = 0; | |
196 | + while(*t) { | |
197 | + __collate_lookup_l(t, &len, &prim, &sec, loc); | |
198 | + if (prim > 0) | |
199 | + break; | |
200 | + if (prim < 0) { | |
201 | + errno = EINVAL; | |
202 | + ret = -1; | |
203 | + goto end; | |
204 | + } | |
205 | + t += len; | |
206 | + } | |
207 | + while(*t2) { | |
208 | + __collate_lookup_l(t2, &len2, &prim2, &sec2, loc); | |
209 | + if (prim2 > 0) | |
210 | + break; | |
211 | + if (prim2 < 0) { | |
212 | + errno = EINVAL; | |
213 | + ret = -1; | |
214 | + goto end; | |
215 | + } | |
216 | + t2 += len2; | |
217 | + } | |
218 | + if(!prim || !prim2) | |
219 | + break; | |
220 | + if(prim != prim2) { | |
221 | + ret = prim - prim2; | |
222 | + goto end; | |
223 | + } | |
224 | + if(!ret2) | |
225 | + ret2 = sec - sec2; | |
226 | + t += len; | |
227 | + t2 += len2; | |
228 | + } | |
229 | + if(!*t && *t2) | |
230 | + ret = -(int)*t2; | |
231 | + else if(*t && !*t2) | |
232 | + ret = *t; | |
233 | + else if(!*t && !*t2) | |
234 | + ret = ret2; | |
235 | + end: | |
3d9156a7 | 236 | sverrno = errno; |
224c7076 A |
237 | - free(mbs1); |
238 | - free(mbs2); | |
239 | + free(tt); | |
240 | + free(tt2); | |
241 | + free(tr); | |
242 | + free(tr2); | |
243 | errno = sverrno; | |
244 | ||
245 | - return (diff); | |
246 | + return ret; | |
3d9156a7 A |
247 | } |
248 | ||
224c7076 A |
249 | -static char * |
250 | -__mbsdup(const wchar_t *ws) | |
3d9156a7 A |
251 | +int |
252 | +wcscoll(const wchar_t *ws1, const wchar_t *ws2) | |
3d9156a7 | 253 | { |
224c7076 A |
254 | - static const mbstate_t initial; |
255 | - mbstate_t st; | |
256 | - const wchar_t *wcp; | |
257 | - size_t len; | |
258 | - char *mbs; | |
259 | - | |
260 | - wcp = ws; | |
261 | - st = initial; | |
3d9156a7 | 262 | - if ((len = wcsrtombs(NULL, &wcp, 0, &st)) == (size_t)-1) |
224c7076 A |
263 | - return (NULL); |
264 | - if ((mbs = malloc(len + 1)) == NULL) | |
265 | - return (NULL); | |
266 | - st = initial; | |
3d9156a7 | 267 | - wcsrtombs(mbs, &ws, len + 1, &st); |
224c7076 A |
268 | - |
269 | - return (mbs); | |
270 | + return wcscoll_l(ws1, ws2, __current_locale()); | |
3d9156a7 | 271 | } |