/ string / FreeBSD / wcscoll.c
wcscoll.c
  1  /*-
  2   * Copyright (c) 2002 Tim J. Robbins
  3   * All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   *
 14   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 15   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 17   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 18   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 19   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 20   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 21   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 22   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 23   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 24   * SUCH DAMAGE.
 25   */
 26  
 27  #include <sys/cdefs.h>
 28  __FBSDID("$FreeBSD: src/lib/libc/string/wcscoll.c,v 1.3 2004/04/07 09:47:56 tjr Exp $");
 29  
 30  #include "xlocale_private.h"
 31  
 32  #include <errno.h>
 33  #include <stdlib.h>
 34  #include <string.h>
 35  #include <wchar.h>
 36  #include "collate.h"
 37  
 38  #define NOTFORWARD	(DIRECTIVE_BACKWARD | DIRECTIVE_POSITION)
 39  
 40  int
 41  wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc)
 42  {
 43  	int sverrno;
 44  	int len, len2, prim, prim2, sec, sec2, ret, ret2;
 45  	const wchar_t *t, *t2;
 46  	wchar_t *tt = NULL, *tt2 = NULL;
 47  	wchar_t *tr = NULL, *tr2 = NULL;
 48  	struct __collate_st_info *info;
 49  
 50  	NORMALIZE_LOCALE(loc);
 51  	if (loc->__collate_load_error)
 52  		/*
 53  		 * Locale has no special collating order or could not be
 54  		 * loaded, do a fast binary comparison.
 55  		 */
 56  		return (wcscmp(ws1, ws2));
 57  
 58  	info = &loc->__lc_collate->__info;
 59  	len = len2 = 1;
 60  	ret = ret2 = 0;
 61  
 62  	if ((info->directive[0] & NOTFORWARD) ||
 63  	    (info->directive[1] & NOTFORWARD) ||
 64  	    (!(info->flags && COLLATE_SUBST_DUP) &&
 65  	    (info->subst_count[0] > 0 || info->subst_count[1] > 0))) {
 66  		int direc, pass;
 67  		for(pass = 0; pass < info->directive_count; pass++) {
 68  			direc = info->directive[pass];
 69  			if (pass == 0 || !(info->flags & COLLATE_SUBST_DUP)) {
 70  				free(tt);
 71  				tt = __collate_substitute(ws1, pass, loc);
 72  				free(tt2);
 73  				tt2 = tt ? __collate_substitute(ws2, pass, loc) : NULL;
 74  			}
 75  			if (direc & DIRECTIVE_BACKWARD) {
 76  				wchar_t *bp, *fp, c;
 77  				tr = __collate_wcsdup(tt ? tt : ws1);
 78  				bp = tr;
 79  				fp = tr + wcslen(tr) - 1;
 80  				while(bp < fp) {
 81  					c = *bp;
 82  					*bp++ = *fp;
 83  					*fp-- = c;
 84  				}
 85  				tr2 = __collate_wcsdup(tt2 ? tt2 : ws2);
 86  				bp = tr2;
 87  				fp = tr2 + wcslen(tr2) - 1;
 88  				while(bp < fp) {
 89  					c = *bp;
 90  					*bp++ = *fp;
 91  					*fp-- = c;
 92  				}
 93  				t = (const wchar_t *)tr;
 94  				t2 = (const wchar_t *)tr2;
 95  			} else if (tt) {
 96  				t = (const wchar_t *)tt;
 97  				t2 = (const wchar_t *)tt2;
 98  			} else {
 99  				t = (const wchar_t *)ws1;
100  				t2 = (const wchar_t *)ws2;
101  			}
102  			if(direc & DIRECTIVE_POSITION) {
103  				while(*t && *t2) {
104  					prim = prim2 = 0;
105  					__collate_lookup_which(t, &len, &prim, pass, loc);
106  					if (prim <= 0) {
107  						if (prim < 0) {
108  							errno = EINVAL;
109  							ret = -1;
110  							goto end;
111  						}
112  						prim = COLLATE_MAX_PRIORITY;
113  					}
114  					__collate_lookup_which(t2, &len2, &prim2, pass, loc);
115  					if (prim2 <= 0) {
116  						if (prim2 < 0) {
117  							errno = EINVAL;
118  							ret = -1;
119  							goto end;
120  						}
121  						prim2 = COLLATE_MAX_PRIORITY;
122  					}
123  					if(prim != prim2) {
124  						ret = prim - prim2;
125  						goto end;
126  					}
127  					t += len;
128  					t2 += len2;
129  				}
130  			} else {
131  				while(*t && *t2) {
132  					prim = prim2 = 0;
133  					while(*t) {
134  						__collate_lookup_which(t, &len, &prim, pass, loc);
135  						if(prim > 0)
136  							break;
137  						if (prim < 0) {
138  							errno = EINVAL;
139  							ret = -1;
140  							goto end;
141  						}
142  						t += len;
143  					}
144  					while(*t2) {
145  						__collate_lookup_which(t2, &len2, &prim2, pass, loc);
146  						if(prim2 > 0)
147  							break;
148  						if (prim2 < 0) {
149  							errno = EINVAL;
150  							ret = -1;
151  							goto end;
152  						}
153  						t2 += len2;
154  					}
155  					if(!prim || !prim2)
156  						break;
157  					if(prim != prim2) {
158  						ret = prim - prim2;
159  						goto end;
160  					}
161  					t += len;
162  					t2 += len2;
163  				}
164  			}
165  			if(!*t) {
166  				if(*t2) {
167  					ret = -(int)*t2;
168  					goto end;
169  				}
170  			} else {
171  				ret = *t;
172  				goto end;
173  			}
174  		}
175  		ret = 0;
176  		goto end;
177  	}
178  
179  	/* optimized common case: order_start forward;forward and duplicate
180  	 * (or no) substitute tables */
181  	tt = __collate_substitute(ws1, 0, loc);
182  	if (tt == NULL) {
183  		tt2 = NULL;
184  		t = (const wchar_t *)ws1;
185  		t2 = (const wchar_t *)ws2;
186  	} else {
187  		tt2 = __collate_substitute(ws2, 0, loc);
188  		t = (const wchar_t *)tt;
189  		t2 = (const wchar_t *)tt2;
190  	}
191  	while(*t && *t2) {
192  		prim = prim2 = 0;
193  		while(*t) {
194  			__collate_lookup_l(t, &len, &prim, &sec, loc);
195  			if (prim > 0)
196  				break;
197  			if (prim < 0) {
198  				errno = EINVAL;
199  				ret = -1;
200  				goto end;
201  			}
202  			t += len;
203  		}
204  		while(*t2) {
205  			__collate_lookup_l(t2, &len2, &prim2, &sec2, loc);
206  			if (prim2 > 0)
207  				break;
208  			if (prim2 < 0) {
209  				errno = EINVAL;
210  				ret = -1;
211  				goto end;
212  			}
213  			t2 += len2;
214  		}
215  		if(!prim || !prim2)
216  			break;
217  		if(prim != prim2) {
218  			ret = prim - prim2;
219  			goto end;
220  		}
221  		if(!ret2)
222  			ret2 = sec - sec2;
223  		t += len;
224  		t2 += len2;
225  	}
226  	if(!*t && *t2)
227  		ret = -(int)*t2;
228  	else if(*t && !*t2)
229  		ret = *t;
230  	else if(!*t && !*t2)
231  		ret = ret2;
232    end:
233  	sverrno = errno;
234  	free(tt);
235  	free(tt2);
236  	free(tr);
237  	free(tr2);
238  	errno = sverrno;
239  
240  	return ret;
241  }
242  
243  int
244  wcscoll(const wchar_t *ws1, const wchar_t *ws2)
245  {
246  	return wcscoll_l(ws1, ws2, __current_locale());
247  }