1 /* Compare UTF-8/UTF-16/UTF-32 strings using the collation rules of the current 2 locale. 3 Copyright (C) 2009-2021 Free Software Foundation, Inc. 4 Written by Bruno Haible <bruno@clisp.org>, 2009. 5 6 This file is free software. 7 It is dual-licensed under "the GNU LGPLv3+ or the GNU GPLv2+". 8 You can redistribute it and/or modify it under either 9 - the terms of the GNU Lesser General Public License as published 10 by the Free Software Foundation; either version 3, or (at your 11 option) any later version, or 12 - the terms of the GNU General Public License as published by the 13 Free Software Foundation; either version 2, or (at your option) 14 any later version, or 15 - the same dual license "the GNU LGPLv3+ or the GNU GPLv2+". 16 17 This file is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License and the GNU General Public License 21 for more details. 22 23 You should have received a copy of the GNU Lesser General Public 24 License and of the GNU General Public License along with this 25 program. If not, see <https://www.gnu.org/licenses/>. */ 26 27 int 28 FUNC (const UNIT *s1, const UNIT *s2) /* */ 29 { 30 /* When this function succeeds, it sets errno back to its original value. 31 When it fails, it sets errno, but also returns a meaningful return value, 32 for the sake of callers which ignore errno. */ 33 int final_errno = errno; 34 const char *encoding = locale_charset (); 35 char *sl1; 36 char *sl2; 37 int result; 38 39 /* Pass iconveh_error here, not iconveh_question_mark. Otherwise the 40 conversion to locale encoding can do transliteration or map some 41 characters to question marks, leading to results that depend on the 42 iconv() implementation and are not obvious. */ 43 sl1 = U_STRCONV_TO_ENCODING (s1, encoding, iconveh_error); 44 if (sl1 != NULL) 45 { 46 sl2 = U_STRCONV_TO_ENCODING (s2, encoding, iconveh_error); 47 if (sl2 != NULL) 48 { 49 /* Compare sl1 and sl2. */ 50 errno = 0; 51 result = strcoll (sl1, sl2); 52 if (errno == 0) 53 { 54 /* strcoll succeeded. */ 55 free (sl1); 56 free (sl2); 57 /* The conversion to locale encoding can drop Unicode TAG 58 characters. Therefore sl1 and sl2 may be equal when s1 59 and s2 were in fact different. Return a nonzero result 60 in this case. */ 61 if (result == 0) 62 result = U_STRCMP (s1, s2); 63 } 64 else 65 { 66 /* strcoll failed. */ 67 final_errno = errno; 68 free (sl1); 69 free (sl2); 70 result = U_STRCMP (s1, s2); 71 } 72 } 73 else 74 { 75 /* s1 could be converted to locale encoding, s2 not. */ 76 final_errno = errno; 77 free (sl1); 78 result = -1; 79 } 80 } 81 else 82 { 83 final_errno = errno; 84 sl2 = U_STRCONV_TO_ENCODING (s2, encoding, iconveh_error); 85 if (sl2 != NULL) 86 { 87 /* s2 could be converted to locale encoding, s1 not. */ 88 free (sl2); 89 result = 1; 90 } 91 else 92 { 93 /* Neither s1 nor s2 could be converted to locale encoding. */ 94 result = U_STRCMP (s1, s2); 95 } 96 } 97 98 errno = final_errno; 99 return result; 100 }