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 40int 41wcscoll_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 243int 244wcscoll(const wchar_t *ws1, const wchar_t *ws2) 245{ 246 return wcscoll_l(ws1, ws2, __current_locale()); 247} 248