1 /* 2 * Copyright 2013 Garrett D'Amore <garrett@damore.org> 3 * Copyright 2017 Nexenta Systems, Inc. 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; 42 wchar_t *tr1 = NULL, *tr2 = NULL; 43 int direc, pass; 44 const struct lc_collate *lcc = loc->collate; 45 int ret = wcscmp(ws1, ws2); 46 47 if (lcc->lc_is_posix || ret == 0) 48 return (ret); 49 50 if (*ws1 == 0 && *ws2 != 0) 51 return (-1); 52 if (*ws1 != 0 && *ws2 == 0) 53 return (1); 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 const int32_t *st1 = NULL; 69 const int32_t *st2 = NULL; 70 const wchar_t *w1 = ws1; 71 const wchar_t *w2 = ws2; 72 73 /* special pass for UNDEFINED */ 74 if (pass == lcc->lc_directive_count) { 75 direc = DIRECTIVE_FORWARD; 76 } else { 77 direc = lcc->lc_directive[pass]; 78 } 79 80 if (direc & DIRECTIVE_BACKWARD) { 81 wchar_t *bp, *fp, c; 82 free(tr1); 83 if ((tr1 = wcsdup(w1)) == NULL) 84 goto end; 85 bp = tr1; 86 fp = tr1 + wcslen(tr1) - 1; 87 while (bp < fp) { 88 c = *bp; 89 *bp++ = *fp; 90 *fp-- = c; 91 } 92 free(tr2); 93 if ((tr2 = wcsdup(w2)) == NULL) 94 goto end; 95 bp = tr2; 96 fp = tr2 + wcslen(tr2) - 1; 97 while (bp < fp) { 98 c = *bp; 99 *bp++ = *fp; 100 *fp-- = c; 101 } 102 w1 = tr1; 103 w2 = tr2; 104 } 105 106 if (direc & DIRECTIVE_POSITION) { 107 int check1, check2; 108 while (*w1 && *w2) { 109 pri1 = pri2 = 0; 110 check1 = check2 = 1; 111 while ((pri1 == pri2) && (check1 || check2)) { 112 if (check1) { 113 _collate_lookup(lcc, w1, &len1, 114 &pri1, pass, &st1); 115 if (pri1 < 0) { 116 errno = EINVAL; 117 goto end; 118 } 119 if (!pri1) { 120 /*CSTYLED*/ 121 pri1 = COLLATE_MAX_PRIORITY; 122 st1 = NULL; 123 } 124 check1 = (st1 != NULL); 125 } 126 if (check2) { 127 _collate_lookup(lcc, w2, &len2, 128 &pri2, pass, &st2); 129 if (pri2 < 0) { 130 errno = EINVAL; 131 goto end; 132 } 133 if (!pri2) { 134 /*CSTYLED*/ 135 pri2 = COLLATE_MAX_PRIORITY; 136 st2 = NULL; 137 } 138 check2 = (st2 != NULL); 139 } 140 } 141 if (pri1 != pri2) { 142 ret = pri1 - pri2; 143 goto end; 144 } 145 w1 += len1; 146 w2 += len2; 147 } 148 if (!*w1) { 149 if (*w2) { 150 ret = -(int)*w2; 151 goto end; 152 } 153 } else { 154 ret = *w1; 155 goto end; 156 } 157 } else { 158 int vpri1 = 0, vpri2 = 0; 159 while (*w1 || *w2 || st1 || st2) { 160 pri1 = 1; 161 while (*w1 || st1) { 162 _collate_lookup(lcc, w1, &len1, &pri1, 163 pass, &st1); 164 w1 += len1; 165 if (pri1 > 0) { 166 vpri1++; 167 break; 168 } 169 if (pri1 < 0) { 170 errno = EINVAL; 171 goto end; 172 } 173 st1 = NULL; 174 } 175 pri2 = 1; 176 while (*w2 || st2) { 177 _collate_lookup(lcc, w2, &len2, &pri2, 178 pass, &st2); 179 w2 += len2; 180 if (pri2 > 0) { 181 vpri2++; 182 break; 183 } 184 if (pri2 < 0) { 185 errno = EINVAL; 186 goto end; 187 } 188 st2 = NULL; 189 } 190 if ((!pri1 || !pri2) && (vpri1 == vpri2)) 191 break; 192 if (pri1 != pri2) { 193 ret = pri1 - pri2; 194 goto end; 195 } 196 } 197 if (vpri1 && !vpri2) { 198 ret = 1; 199 goto end; 200 } 201 if (!vpri1 && vpri2) { 202 ret = -1; 203 goto end; 204 } 205 } 206 } 207 ret = 0; 208 209 end: 210 free(tr1); 211 free(tr2); 212 213 return (ret); 214 } 215 216 int 217 wcscoll(const wchar_t *ws1, const wchar_t *ws2) 218 { 219 return (wcscoll_l(ws1, ws2, uselocale(NULL))); 220 } 221