158f0484fSRodney W. Grimes /*- 2d915a14eSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3d915a14eSPedro F. Giffuni * 42a6abeebSBaptiste Daroussin * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 5a4d5d0cbSAndrey A. Chernov * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> 6a4d5d0cbSAndrey A. Chernov * at Electronni Visti IA, Kiev, Ukraine. 7a4d5d0cbSAndrey A. Chernov * All rights reserved. 858f0484fSRodney W. Grimes * 93c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation 10*5b5fa75aSEd Maste * 113c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall 123c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation. 133c87aa1dSDavid Chisnall * 1458f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 1558f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1658f0484fSRodney W. Grimes * are met: 1758f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1858f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1958f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 2058f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 2158f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 2258f0484fSRodney W. Grimes * 23a4d5d0cbSAndrey A. Chernov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 2458f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2558f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26a4d5d0cbSAndrey A. Chernov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 2758f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2858f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2958f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3058f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3158f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3258f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3358f0484fSRodney W. Grimes * SUCH DAMAGE. 3458f0484fSRodney W. Grimes */ 3558f0484fSRodney W. Grimes 36de5fe5d5SDavid E. O'Brien #include <sys/cdefs.h> 37de5fe5d5SDavid E. O'Brien __FBSDID("$FreeBSD$"); 385864b79cSDavid E. O'Brien 39a4d5d0cbSAndrey A. Chernov #include <stdlib.h> 4058f0484fSRodney W. Grimes #include <string.h> 412a6abeebSBaptiste Daroussin #include <errno.h> 422a6abeebSBaptiste Daroussin #include <wchar.h> 43a4d5d0cbSAndrey A. Chernov #include "collate.h" 4458f0484fSRodney W. Grimes 453c87aa1dSDavid Chisnall 462a6abeebSBaptiste Daroussin /* 47c71b5482SBaptiste Daroussin * In order to properly handle multibyte locales, its easiest to just 482a6abeebSBaptiste Daroussin * convert to wide characters and then use wcscoll. However if an 492a6abeebSBaptiste Daroussin * error occurs, we gracefully fall back to simple strcmp. Caller 502a6abeebSBaptiste Daroussin * should check errno. 512a6abeebSBaptiste Daroussin */ 5258f0484fSRodney W. Grimes int 530f701093SEitan Adler strcoll_l(const char *s, const char *s2, locale_t locale) 5458f0484fSRodney W. Grimes { 552a6abeebSBaptiste Daroussin int ret; 562a6abeebSBaptiste Daroussin wchar_t *t1 = NULL, *t2 = NULL; 572a6abeebSBaptiste Daroussin wchar_t *w1 = NULL, *w2 = NULL; 582a6abeebSBaptiste Daroussin const char *cs1, *cs2; 592a6abeebSBaptiste Daroussin mbstate_t mbs1; 602a6abeebSBaptiste Daroussin mbstate_t mbs2; 612a6abeebSBaptiste Daroussin size_t sz1, sz2; 622a6abeebSBaptiste Daroussin 632a6abeebSBaptiste Daroussin memset(&mbs1, 0, sizeof (mbstate_t)); 642a6abeebSBaptiste Daroussin memset(&mbs2, 0, sizeof (mbstate_t)); 652a6abeebSBaptiste Daroussin 662a6abeebSBaptiste Daroussin /* 672a6abeebSBaptiste Daroussin * The mbsrtowcs_l function can set the src pointer to null upon 682a6abeebSBaptiste Daroussin * failure, so it should act on a copy to avoid: 692a6abeebSBaptiste Daroussin * - sending null pointer to strcmp 702a6abeebSBaptiste Daroussin * - having strcoll/strcoll_l change *s or *s2 to null 712a6abeebSBaptiste Daroussin */ 722a6abeebSBaptiste Daroussin cs1 = s; 732a6abeebSBaptiste Daroussin cs2 = s2; 742a6abeebSBaptiste Daroussin 753c87aa1dSDavid Chisnall FIX_LOCALE(locale); 763c87aa1dSDavid Chisnall struct xlocale_collate *table = 773c87aa1dSDavid Chisnall (struct xlocale_collate*)locale->components[XLC_COLLATE]; 78a4d5d0cbSAndrey A. Chernov 793c87aa1dSDavid Chisnall if (table->__collate_load_error) 802a6abeebSBaptiste Daroussin goto error; 81a4d5d0cbSAndrey A. Chernov 822a6abeebSBaptiste Daroussin sz1 = strlen(s) + 1; 832a6abeebSBaptiste Daroussin sz2 = strlen(s2) + 1; 84a4d5d0cbSAndrey A. Chernov 852a6abeebSBaptiste Daroussin /* 862a6abeebSBaptiste Daroussin * Simple assumption: conversion to wide format is strictly 872a6abeebSBaptiste Daroussin * reducing, i.e. a single byte (or multibyte character) 882a6abeebSBaptiste Daroussin * cannot result in multiple wide characters. 892a6abeebSBaptiste Daroussin */ 902a6abeebSBaptiste Daroussin if ((t1 = malloc(sz1 * sizeof (wchar_t))) == NULL) 912a6abeebSBaptiste Daroussin goto error; 922a6abeebSBaptiste Daroussin w1 = t1; 932a6abeebSBaptiste Daroussin if ((t2 = malloc(sz2 * sizeof (wchar_t))) == NULL) 942a6abeebSBaptiste Daroussin goto error; 952a6abeebSBaptiste Daroussin w2 = t2; 962a6abeebSBaptiste Daroussin 972a6abeebSBaptiste Daroussin if ((mbsrtowcs_l(w1, &cs1, sz1, &mbs1, locale)) == (size_t)-1) 982a6abeebSBaptiste Daroussin goto error; 992a6abeebSBaptiste Daroussin 1002a6abeebSBaptiste Daroussin if ((mbsrtowcs_l(w2, &cs2, sz2, &mbs2, locale)) == (size_t)-1) 1012a6abeebSBaptiste Daroussin goto error; 1022a6abeebSBaptiste Daroussin 1032a6abeebSBaptiste Daroussin ret = wcscoll_l(w1, w2, locale); 1042a6abeebSBaptiste Daroussin free(t1); 1052a6abeebSBaptiste Daroussin free(t2); 1062a6abeebSBaptiste Daroussin 1072a6abeebSBaptiste Daroussin return (ret); 1082a6abeebSBaptiste Daroussin 1092a6abeebSBaptiste Daroussin error: 1102a6abeebSBaptiste Daroussin free(t1); 1112a6abeebSBaptiste Daroussin free(t2); 1122a6abeebSBaptiste Daroussin return (strcmp(s, s2)); 11358f0484fSRodney W. Grimes } 1143c87aa1dSDavid Chisnall 1153c87aa1dSDavid Chisnall int 1160f701093SEitan Adler strcoll(const char *s, const char *s2) 1173c87aa1dSDavid Chisnall { 1180f701093SEitan Adler return strcoll_l(s, s2, __get_locale()); 1193c87aa1dSDavid Chisnall } 1203c87aa1dSDavid Chisnall 121