1 /* 2 * Copyright 2013 Garrett D'Amore <garrett@damore.org> 3 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 4 * Copyright (c) 2002 Tim J. Robbins 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "lint.h" 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <wchar.h> 34 #include <assert.h> 35 #include "collate.h" 36 #include "localeimpl.h" 37 38 int 39 wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc) 40 { 41 int len1, len2, pri1, pri2, ret; 42 wchar_t *tr1 = NULL, *tr2 = NULL; 43 int direc, pass; 44 const struct lc_collate *lcc = loc->collate; 45 46 if (lcc->lc_is_posix) 47 /* 48 * Locale has no special collating order or could not be 49 * loaded, do a fast binary comparison. 50 */ 51 return (wcscmp(ws1, ws2)); 52 53 ret = 0; 54 55 /* 56 * Once upon a time we had code to try to optimize this, but 57 * it turns out that you really can't make many assumptions 58 * safely. You absolutely have to run this pass by pass, 59 * because some passes will be ignored for a given character, 60 * while others will not. Simpler locales will benefit from 61 * having fewer passes, and most comparisions should resolve 62 * during the primary pass anyway. 63 * 64 * Note that we do one final extra pass at the end to pick 65 * up UNDEFINED elements. There is special handling for them. 66 */ 67 for (pass = 0; pass <= lcc->lc_directive_count; pass++) { 68 69 const int32_t *st1 = NULL; 70 const int32_t *st2 = NULL; 71 const wchar_t *w1 = ws1; 72 const wchar_t *w2 = ws2; 73 74 /* special pass for UNDEFINED */ 75 if (pass == lcc->lc_directive_count) { 76 direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED; 77 } else { 78 direc = lcc->lc_directive[pass]; 79 } 80 81 if (direc & DIRECTIVE_BACKWARD) { 82 wchar_t *bp, *fp, c; 83 if ((tr1 = wcsdup(w1)) == NULL) 84 goto fail; 85 bp = tr1; 86 fp = tr1 + wcslen(tr1) - 1; 87 while (bp < fp) { 88 c = *bp; 89 *bp++ = *fp; 90 *fp-- = c; 91 } 92 if ((tr2 = wcsdup(w2)) == NULL) 93 goto fail; 94 bp = tr2; 95 fp = tr2 + wcslen(tr2) - 1; 96 while (bp < fp) { 97 c = *bp; 98 *bp++ = *fp; 99 *fp-- = c; 100 } 101 w1 = tr1; 102 w2 = tr2; 103 } 104 105 if (direc & DIRECTIVE_POSITION) { 106 while ((*w1 || st1) && (*w2 || st2)) { 107 pri1 = pri2 = 0; 108 _collate_lookup(lcc, w1, &len1, &pri1, pass, 109 &st1); 110 if (pri1 <= 0) { 111 if (pri1 < 0) { 112 errno = EINVAL; 113 goto fail; 114 } 115 pri1 = COLLATE_MAX_PRIORITY; 116 } 117 _collate_lookup(lcc, w2, &len2, &pri2, pass, 118 &st2); 119 if (pri2 <= 0) { 120 if (pri2 < 0) { 121 errno = EINVAL; 122 goto fail; 123 } 124 pri2 = COLLATE_MAX_PRIORITY; 125 } 126 if (pri1 != pri2) { 127 ret = pri1 - pri2; 128 goto end; 129 } 130 w1 += len1; 131 w2 += len2; 132 } 133 } else { 134 while ((*w1 || st1) && (*w2 || st2)) { 135 pri1 = pri2 = 0; 136 while (*w1) { 137 _collate_lookup(lcc, w1, &len1, 138 &pri1, pass, &st1); 139 if (pri1 > 0) 140 break; 141 if (pri1 < 0) { 142 errno = EINVAL; 143 goto fail; 144 } 145 w1 += len1; 146 } 147 while (*w2) { 148 _collate_lookup(lcc, w2, &len2, 149 &pri2, pass, &st2); 150 if (pri2 > 0) 151 break; 152 if (pri2 < 0) { 153 errno = EINVAL; 154 goto fail; 155 } 156 w2 += len2; 157 } 158 if (!pri1 || !pri2) 159 break; 160 if (pri1 != pri2) { 161 ret = pri1 - pri2; 162 goto end; 163 } 164 w1 += len1; 165 w2 += len2; 166 } 167 } 168 if (!*w1) { 169 if (*w2) { 170 ret = -(int)*w2; 171 goto end; 172 } 173 } else { 174 ret = *w1; 175 goto end; 176 } 177 } 178 ret = 0; 179 180 end: 181 if (tr1) 182 free(tr1); 183 if (tr2) 184 free(tr2); 185 186 return (ret); 187 188 fail: 189 ret = wcscmp(ws1, ws2); 190 goto end; 191 } 192 193 194 int 195 wcscoll(const wchar_t *ws1, const wchar_t *ws2) 196 { 197 return (wcscoll_l(ws1, ws2, uselocale(NULL))); 198 } 199