1716024cdSPeter Avalos /*- 2716024cdSPeter Avalos * Copyright (c) 2002 Tim J. Robbins 3716024cdSPeter Avalos * All rights reserved. 4716024cdSPeter Avalos * 5*0d5acd74SJohn Marino * Copyright (c) 2011 The FreeBSD Foundation 6*0d5acd74SJohn Marino * All rights reserved. 7*0d5acd74SJohn Marino * Portions of this software were developed by David Chisnall 8*0d5acd74SJohn Marino * under sponsorship from the FreeBSD Foundation. 9*0d5acd74SJohn Marino * 10716024cdSPeter Avalos * Redistribution and use in source and binary forms, with or without 11716024cdSPeter Avalos * modification, are permitted provided that the following conditions 12716024cdSPeter Avalos * are met: 13716024cdSPeter Avalos * 1. Redistributions of source code must retain the above copyright 14716024cdSPeter Avalos * notice, this list of conditions and the following disclaimer. 15716024cdSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 16716024cdSPeter Avalos * notice, this list of conditions and the following disclaimer in the 17716024cdSPeter Avalos * documentation and/or other materials provided with the distribution. 18716024cdSPeter Avalos * 19716024cdSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20716024cdSPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21716024cdSPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22716024cdSPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23716024cdSPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24716024cdSPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25716024cdSPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26716024cdSPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27716024cdSPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28716024cdSPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29716024cdSPeter Avalos * SUCH DAMAGE. 30716024cdSPeter Avalos * 31*0d5acd74SJohn Marino * $FreeBSD: head/lib/libc/string/wcscoll.c 227753 2011-11-20 14:45:42Z theraven $ 32716024cdSPeter Avalos */ 33716024cdSPeter Avalos 34716024cdSPeter Avalos #include <errno.h> 35716024cdSPeter Avalos #include <stdlib.h> 36716024cdSPeter Avalos #include <string.h> 37716024cdSPeter Avalos #include <wchar.h> 38716024cdSPeter Avalos #include "collate.h" 39716024cdSPeter Avalos 40716024cdSPeter Avalos static char *__mbsdup(const wchar_t *); 41716024cdSPeter Avalos 42716024cdSPeter Avalos /* 43716024cdSPeter Avalos * Placeholder implementation of wcscoll(). Attempts to use the single-byte 44716024cdSPeter Avalos * collation ordering where possible, and falls back on wcscmp() in locales 45716024cdSPeter Avalos * with extended character sets. 46716024cdSPeter Avalos */ 47716024cdSPeter Avalos int 48*0d5acd74SJohn Marino wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale) 49716024cdSPeter Avalos { 50716024cdSPeter Avalos char *mbs1, *mbs2; 51716024cdSPeter Avalos int diff, sverrno; 52*0d5acd74SJohn Marino FIX_LOCALE(locale); 53*0d5acd74SJohn Marino struct xlocale_collate *table = 54*0d5acd74SJohn Marino (struct xlocale_collate*)locale->components[XLC_COLLATE]; 55716024cdSPeter Avalos 56*0d5acd74SJohn Marino if (table->__collate_load_error || MB_CUR_MAX > 1) 57716024cdSPeter Avalos /* 58716024cdSPeter Avalos * Locale has no special collating order, could not be 59716024cdSPeter Avalos * loaded, or has an extended character set; do a fast binary 60716024cdSPeter Avalos * comparison. 61716024cdSPeter Avalos */ 62716024cdSPeter Avalos return (wcscmp(ws1, ws2)); 63716024cdSPeter Avalos 64716024cdSPeter Avalos if ((mbs1 = __mbsdup(ws1)) == NULL || (mbs2 = __mbsdup(ws2)) == NULL) { 65716024cdSPeter Avalos /* 66716024cdSPeter Avalos * Out of memory or illegal wide chars; fall back to wcscmp() 67716024cdSPeter Avalos * but leave errno indicating the error. Callers that don't 68716024cdSPeter Avalos * check for error will get a reasonable but often slightly 69716024cdSPeter Avalos * incorrect result. 70716024cdSPeter Avalos */ 71716024cdSPeter Avalos sverrno = errno; 72716024cdSPeter Avalos free(mbs1); 73716024cdSPeter Avalos errno = sverrno; 74716024cdSPeter Avalos return (wcscmp(ws1, ws2)); 75716024cdSPeter Avalos } 76716024cdSPeter Avalos 77*0d5acd74SJohn Marino diff = strcoll_l(mbs1, mbs2, locale); 78716024cdSPeter Avalos sverrno = errno; 79716024cdSPeter Avalos free(mbs1); 80716024cdSPeter Avalos free(mbs2); 81716024cdSPeter Avalos errno = sverrno; 82716024cdSPeter Avalos 83716024cdSPeter Avalos return (diff); 84716024cdSPeter Avalos } 85716024cdSPeter Avalos 86*0d5acd74SJohn Marino int 87*0d5acd74SJohn Marino wcscoll(const wchar_t *ws1, const wchar_t *ws2) 88*0d5acd74SJohn Marino { 89*0d5acd74SJohn Marino return wcscoll_l(ws1, ws2, __get_locale()); 90*0d5acd74SJohn Marino } 91*0d5acd74SJohn Marino 92716024cdSPeter Avalos static char * 93716024cdSPeter Avalos __mbsdup(const wchar_t *ws) 94716024cdSPeter Avalos { 95716024cdSPeter Avalos static const mbstate_t initial; 96716024cdSPeter Avalos mbstate_t st; 97716024cdSPeter Avalos const wchar_t *wcp; 98716024cdSPeter Avalos size_t len; 99716024cdSPeter Avalos char *mbs; 100716024cdSPeter Avalos 101716024cdSPeter Avalos wcp = ws; 102716024cdSPeter Avalos st = initial; 103716024cdSPeter Avalos if ((len = wcsrtombs(NULL, &wcp, 0, &st)) == (size_t)-1) 104716024cdSPeter Avalos return (NULL); 105716024cdSPeter Avalos if ((mbs = malloc(len + 1)) == NULL) 106716024cdSPeter Avalos return (NULL); 107716024cdSPeter Avalos st = initial; 108716024cdSPeter Avalos wcsrtombs(mbs, &ws, len + 1, &st); 109716024cdSPeter Avalos 110716024cdSPeter Avalos return (mbs); 111716024cdSPeter Avalos } 112