On Sat, Mar 09, 2013 at 02:45:00PM +0100, Stefan Sperling wrote:
I'd like to concentrate on collation. To properly review your diff,
I need to understand what needs to be added to OpenBSD' locale implementation.
I hope the attached patch helps.
Instead, you should consider OpenBSD's code as your starting point.
And add to that _only_ what needs to be done to support collation.
Not so easy, because the implementation of collations that I know is
the one of FreeBSD (by the way mklocale and the ctype catalogues come from
NetBSD, as well as part of the libc implementation --both from citrus).
In future would be nice to implement collation in UTF-8 complete, but at
least here something for single-byte encondings and UTF-8 translatable
to ISO8859-1.
By the way to support UTF-8 translatable to ISO8859-1 I changed the
functions in collate.c with respect to the implementation of FreeBSD.
I don't have a FreeBSD at hand, but I guess it doesn't support
collations in locales like es_CO.UTF-8, while the attached
implementation does.
Adding new functions like strxfrm_l() etc. just doesn't make sense to me.
You shouldn't need to add any new functions. We already have strcoll()
and strxfrm(). Those are interfaces from C89, so they're a bit dated.
But they should be good enough for getting some basic collation support
going. We can talk about adding support for newer interfaces later, but
those should not matter for the initial implementation.
Those functions were removed (but I left the credit of the
implementations that I used).
You have other unrelated changes in there, such as shuffling of MLINKS lists.
Those add noise to the diff and make it harder to review.
Other changes I sent in separate emails (including man pages for
wcscoll and wcsxfrm).
If there is interest in xlocale support after this or after having
other kind of collation support in OpenBSD, please let me know. I
also want to advance in other LC_* implementations.
Best regards.
--
Dios, gracias por tu amor infinito.
--
Vladimir Támara Patiño. http://vtamara.pasosdeJesus.org/
http://www.pasosdejesus.org/dominio_publico_colombia.html
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/Makefile.inc
src/lib/libc/locale/Makefile.inc
--- src53orig/lib/libc/locale/Makefile.inc Sat Mar 9 11:16:47 2013
+++ src/lib/libc/locale/Makefile.inc Tue Mar 19 05:52:30 2013
@@ -9,7 +9,7 @@
wcstombs.c wctob.c wctomb.c wcstof.c wcstod.c wcstold.c wcstol.c \
wcstoul.c wcstoll.c wcstoull.c wcstoimax.c wcstoumax.c \
setrunelocale.c runeglue.c rune.c runetable.c ___runetype_mb.c \
- _wctrans.c wcsxfrm.c
+ _wctrans.c wcsxfrm.c collate.c
MAN+= nl_langinfo.3 setlocale.3 iswalnum.3 towlower.3 \
btowc.3 mblen.3 mbrlen.3 mbrtowc.3 mbsinit.3 mbsrtowcs.3 \
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/collate.c
src/lib/libc/locale/collate.c
--- src53orig/lib/libc/locale/collate.c Wed Dec 31 19:00:00 1969
+++ src/lib/libc/locale/collate.c Mon Mar 18 07:24:12 2013
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <[email protected]>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/**
+ * Public domain according to Colombian Legislation.
+ * http://www.pasosdejesus.org/dominio_publico_colombia.html
+ * 2013. [email protected].
+ */
+
+
+#include <sys/cdefs.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "rune.h"
+#include "runetype.h"
+#include "collate.h"
+
+#define TABLE_SIZE 100
+#define COLLATE_VERSION "1.1\n"
+
+/*
+ * To avoid modifying the original (single-threaded) code too much, we'll just
+ * define the old globals as fields inside the table.
+ *
+ * We also modify the collation table test functions to search the thread-local
+ * table first and the global table second.
+ */
+#define __collate_substitute_table (*__collate_substitute_table_ptr)
+#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
+
+#define __collate_substitute_nontrivial
(table->__collate_substitute_nontrivial)
+#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
+#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
+#define __collate_chain_pri_table (table->__collate_chain_pri_table)
+int __collate_load_error;
+
+
+struct xlocale_collate __xlocale_global_collate = {
+ 1, 0
+};
+
+struct xlocale_collate __xlocale_C_collate = {
+ 1, 0
+};
+
+void __collate_err(int ex, const char *f);
+
+int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
+
+static void
+destruct_collate(void *t)
+{
+ struct xlocale_collate *table = t;
+ if (__collate_chain_pri_table) {
+ free(__collate_chain_pri_table);
+ }
+ free(t);
+}
+
+void *
+__collate_load(const char *encoding)
+{
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ return &__xlocale_C_collate;
+ }
+ struct xlocale_collate *table =
+ calloc(sizeof(struct xlocale_collate), 1);
+ //table->header.header.destructor = destruct_collate;
+ // FIXME: Make sure that _LDP_CACHE is never returned. We should be
doing
+ // the caching outside of this section
+ if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
+ /* xlocale_release(table); */
+ free(table);
+ return NULL;
+ }
+
+ return table;
+}
+
+/**
+ * Load the collation tables for the specified encoding into the global table.
+ */
+int
+__collate_load_tables(const char *encoding)
+{
+ int ret = __collate_load_tables_l(encoding, &__xlocale_global_collate);
+ __collate_load_error = __xlocale_global_collate.__collate_load_error;
+ return ret;
+}
+
+int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
+{
+ FILE *fp;
+ int i, saverr, chains;
+ uint32_t u32;
+ char strbuf[STR_LEN], buf[PATH_MAX];
+ void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
+
+ /* 'encoding' must be already checked. */
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ table->__collate_load_error = 1;
+ return (_LDP_CACHE);
+ }
+
+ /* '_PATH_LOCALE' must be already set & checked. */
+ /* Range checking not needed, encoding has fixed size */
+ (void)strlcpy(buf, _PATH_LOCALE, PATH_MAX);
+ (void)strlcat(buf, "/", PATH_MAX);
+ (void)strlcat(buf, encoding, PATH_MAX);
+ (void)strlcat(buf, "/LC_COLLATE", PATH_MAX);
+ if ((fp = fopen(buf, "re")) == NULL)
+ return (_LDP_ERROR);
+
+ if (fread(strbuf, sizeof(strbuf), 1, fp) != 1) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ chains = -1;
+ if (strcmp(strbuf, COLLATE_VERSION) == 0)
+ chains = 0;
+ else if (strcmp(strbuf, COLLATE_VERSION1_2) == 0)
+ chains = 1;
+ if (chains < 0) {
+ (void)fclose(fp);
+ errno = EFTYPE;
+ return (_LDP_ERROR);
+ }
+ if (chains) {
+ if (fread(&u32, sizeof(u32), 1, fp) != 1) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((chains = (int)ntohl(u32)) < 1) {
+ (void)fclose(fp);
+ errno = EFTYPE;
+ return (_LDP_ERROR);
+ }
+ } else
+ chains = TABLE_SIZE;
+
+ if ((TMP_substitute_table =
+ malloc(sizeof(__collate_substitute_table))) == NULL) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((TMP_char_pri_table =
+ malloc(sizeof(__collate_char_pri_table))) == NULL) {
+ saverr = errno;
+ free(TMP_substitute_table);
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((TMP_chain_pri_table =
+ malloc(sizeof(*__collate_chain_pri_table) * chains)) == NULL) {
+ saverr = errno;
+ free(TMP_substitute_table);
+ free(TMP_char_pri_table);
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+
+#define FREAD(a, b, c, d) \
+{ \
+ if (fread(a, b, c, d) != c) { \
+ saverr = errno; \
+ free(TMP_substitute_table); \
+ free(TMP_char_pri_table); \
+ free(TMP_chain_pri_table); \
+ (void)fclose(d); \
+ errno = saverr; \
+ return (_LDP_ERROR); \
+ } \
+}
+
+ FREAD(TMP_substitute_table, sizeof(__collate_substitute_table), 1, fp);
+ FREAD(TMP_char_pri_table, sizeof(__collate_char_pri_table), 1, fp);
+ FREAD(TMP_chain_pri_table,
+ sizeof(*__collate_chain_pri_table), chains, fp);
+ (void)fclose(fp);
+
+ if (__collate_substitute_table_ptr != NULL)
+ free(__collate_substitute_table_ptr);
+ __collate_substitute_table_ptr = TMP_substitute_table;
+ if (__collate_char_pri_table_ptr != NULL)
+ free(__collate_char_pri_table_ptr);
+ __collate_char_pri_table_ptr = TMP_char_pri_table;
+ for (i = 0; i < UCHAR_MAX + 1; i++) {
+ __collate_char_pri_table[i].prim =
+ ntohl(__collate_char_pri_table[i].prim);
+ __collate_char_pri_table[i].sec =
+ ntohl(__collate_char_pri_table[i].sec);
+ }
+ if (__collate_chain_pri_table != NULL)
+ free(__collate_chain_pri_table);
+ __collate_chain_pri_table = TMP_chain_pri_table;
+ for (i = 0; i < chains; i++) {
+ __collate_chain_pri_table[i].prim =
+ ntohl(__collate_chain_pri_table[i].prim);
+ __collate_chain_pri_table[i].sec =
+ ntohl(__collate_chain_pri_table[i].sec);
+ }
+ __collate_substitute_nontrivial = 0;
+ for (i = 0; i < UCHAR_MAX + 1; i++) {
+ if (__collate_substitute_table[i][0] != i ||
+ __collate_substitute_table[i][1] != 0) {
+ __collate_substitute_nontrivial = 1;
+ break;
+ }
+ }
+ table->__collate_load_error = 0;
+
+ return (_LDP_LOADED);
+}
+
+/** The following functions in FreeBSD received char *, in OpenBSD to
+ * be able to have initial support for UTF-8 we changed to wchar_t
+ */
+
+size_t
+strlcpy_wc(wchar_t *d, u_char *s, size_t sd) {
+ if (d == NULL || s == NULL || sd == 0) {
+ return 0;
+ }
+ int t = 0;
+ while (*s != '\0' && sd > 0) {
+ *d = (wchar_t)*s;
+ s++;
+ sd--;
+ t++;
+ }
+ return t;
+}
+
+wchar_t *
+__collate_strdup_w(wchar_t *s)
+{
+ wchar_t *t = wcsdup(s);
+
+ if (t == NULL)
+ __collate_err(EX_OSERR, __func__);
+ return (t);
+}
+
+
+wchar_t *
+__collate_substitute_w(struct xlocale_collate *table, const wchar_t *s)
+{
+ int dest_len, len, nlen;
+ int delta = wcslen(s);
+ wchar_t *dest_str = NULL;
+
+ if (s == NULL || *s == L'\0')
+ return (__collate_strdup_w(L""));
+ delta += delta / 8;
+ dest_str = malloc((dest_len = delta)*sizeof(wchar_t));
+ if (dest_str == NULL)
+ __collate_err(EX_OSERR, __func__);
+ len = nlen = 0;
+ while (*s != L'\0') {
+ nlen = len + strlen(__collate_substitute_table[(u_char)*s]);
+ if (dest_len <= nlen) {
+ size_t size = (dest_len = nlen + delta)*sizeof(wchar_t);
+ dest_str = (wchar_t *)realloc(dest_str, size);
+ if (dest_str == NULL) {
+ free(dest_str);
+ __collate_err(EX_OSERR, __func__);
+ }
+ }
+ (void)strlcpy_wc(dest_str + len,
+ __collate_substitute_table[(u_char)*s++],
+ dest_len - len);
+ len = nlen;
+ }
+ dest_str[len] = L'\0';
+ return (dest_str);
+}
+
+
+void
+__collate_lookup_w(struct xlocale_collate *table, const wchar_t *t, int *len,
int *prim, int *sec)
+{
+ struct __collate_st_chain_pri *p2;
+
+ *len = 1;
+ *prim = *sec = 0;
+ for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) {
+ if (*t == (wchar_t)p2->str[0] &&
+ strncmp_wc((wchar_t *)t, p2->str, strlen(p2->str)) == 0) {
+ *len = strlen(p2->str);
+ *prim = p2->prim;
+ *sec = p2->sec;
+ return;
+ }
+ }
+ *prim = __collate_char_pri_table[(u_char)*t].prim;
+ *sec = __collate_char_pri_table[(u_char)*t].sec;
+}
+
+void
+__collate_err(int ex, const char *f)
+{
+ const char *s;
+ int serrno = errno;
+
+ //s = _getprogname();
+ s = "Program";
+ write(STDERR_FILENO, s, strlen(s));
+ write(STDERR_FILENO, ": ", 2);
+ s = f;
+ write(STDERR_FILENO, s, strlen(s));
+ write(STDERR_FILENO, ": ", 2);
+ s = strerror(serrno);
+ write(STDERR_FILENO, s, strlen(s));
+ write(STDERR_FILENO, "\n", 1);
+ exit(ex);
+}
+
+
+
+//#define COLLATE_DEBUG
+#ifdef COLLATE_DEBUG
+void
+__collate_print_tables(struct xlocale_collate *table)
+{
+ int i;
+ struct __collate_st_chain_pri *p2;
+ if (table == NULL) {
+ table = &__xlocale_global_collate;
+ }
+
+ printf("Substitute table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ if (i != *__collate_substitute_table[i])
+ printf("\t'%c' --> \"%s\"\n", i,
+ __collate_substitute_table[i]);
+ printf("Chain priority table:\n");
+ for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++)
+ printf("\t\"%s\" : %d %d\n", p2->str, p2->prim, p2->sec);
+ printf("Char priority table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
+ __collate_char_pri_table[i].sec);
+}
+#endif
+
+int
+strncmp_wc(wchar_t *ws, char *cs, size_t l)
+{
+ if (ws == NULL || cs == NULL || l == 0) {
+ return -1;
+ }
+ while (*ws != 0 && *cs != 0 && l > 0 && *ws == (wchar_t)*cs) {
+ ws++;
+ cs++;
+ l--;
+ }
+ return *ws - *cs;
+}
+
+
+/** Duplicate a mb string as wc string,
+ *
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/769-BSI.html
+ * In future, when xlocale, will receive locale_t as 2nd parameter
+ * */
+wchar_t *__dup_as_wcs_l(const char *s)
+{
+ int numc = mbstowcs(NULL, s, 0) + 1;
+ if (numc == 0 || numc > ULONG_MAX / sizeof(wchar_t)
+ || numc == (size_t)-1) {
+ errno = EINVAL;
+ return NULL;
+ }
+ wchar_t *ws = (wchar_t *)malloc(numc * sizeof(wchar_t) );
+ if (ws == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mbstowcs(ws, s, numc);
+
+ return ws;
+}
+
+
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/collate.h
src/lib/libc/locale/collate.h
--- src53orig/lib/libc/locale/collate.h Wed Dec 31 19:00:00 1969
+++ src/lib/libc/locale/collate.h Tue Mar 19 05:51:03 2013
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <[email protected]>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/locale/collate.h,v 1.17 2012/11/17 01:49:29 svnexp
Exp $
+ */
+/*-
+ * Copyright (c) 2000, 2001 Alexey Zelkin <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From lib/libc/locale/ldpart.h of FreeBSD
+ */
+
+#ifndef _COLLATE_H_
+#define _COLLATE_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <wchar.h>
+
+#define STR_LEN 10
+#define COLLATE_VERSION1_2 "1.2\n"
+
+struct __collate_st_char_pri {
+ int prim, sec;
+};
+struct __collate_st_chain_pri {
+ u_char str[STR_LEN];
+ int prim, sec;
+};
+
+//#define __collate_substitute_table (*__collate_substitute_table_ptr)
+//#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
+
+struct xlocale_collate {
+ int __collate_load_error;
+ int __collate_substitute_nontrivial;
+
+ u_char (*__collate_substitute_table_ptr)[UCHAR_MAX + 1][STR_LEN];
+ struct __collate_st_char_pri (*__collate_char_pri_table_ptr)[UCHAR_MAX
+ 1];
+ struct __collate_st_chain_pri *__collate_chain_pri_table;
+};
+
+
+__BEGIN_DECLS
+
+// Current LC_COLLATE
+struct xlocale_collate __xlocale_global_collate;
+
+/** In OpenBSD using wchar_t, while the original from FreeBSD was char * */
+wchar_t *__collate_substitute_w(struct xlocale_collate *table, const wchar_t
*s);
+void __collate_lookup_w(struct xlocale_collate *table, const wchar_t *t, int
*len, int *prim, int *sec);
+int __collate_load_tables(const char *);
+int __collate_range_cmp(struct xlocale_collate *, int, int);
+#ifdef COLLATE_DEBUG
+void __collate_print_tables(void);
+#endif
+int strncmp_wc(wchar_t *ws, char *cs, size_t l);
+wchar_t *__dup_as_wcs_l(const char *s);
+__END_DECLS
+
+#define _LDP_LOADED 0
+#define _LDP_ERROR (-1)
+#define _LDP_CACHE 1
+
+
+#endif /* !_COLLATE_H_ */
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/setlocale.c
src/lib/libc/locale/setlocale.c
--- src53orig/lib/libc/locale/setlocale.c Tue May 24 07:21:15 2011
+++ src/lib/libc/locale/setlocale.c Mon Mar 18 06:15:06 2013
@@ -42,6 +42,7 @@
#include "rune.h"
#include "rune_local.h"
+#include "collate.h"
/*
* Category names for getenv()
*/
@@ -200,7 +201,12 @@
__install_currentrunelocale_ctype();
break;
case LC_MESSAGES:
+ break;
case LC_COLLATE:
+ if (__collate_load_tables("C")) {
+ return;
+ }
+ break;
case LC_MONETARY:
case LC_NUMERIC:
case LC_TIME:
@@ -236,9 +242,13 @@
return -1;
__install_currentrunelocale_ctype();
break;
-
case LC_MESSAGES:
+ break;
case LC_COLLATE:
+ if (__collate_load_tables(locname)) {
+ return -1;
+ }
+ break;
case LC_MONETARY:
case LC_NUMERIC:
case LC_TIME:
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/wcscoll.c
src/lib/libc/locale/wcscoll.c
--- src53orig/lib/libc/locale/wcscoll.c Sat Feb 9 14:26:52 2013
+++ src/lib/libc/locale/wcscoll.c Mon Mar 18 06:16:15 2013
@@ -1,6 +1,5 @@
/* $OpenBSD: wcscoll.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
/* $NetBSD: wcscoll.c,v 1.1 2003/03/02 22:18:16 tshiozak Exp $ */
-
/*-
* Copyright (c)2003 Citrus Project,
* All rights reserved.
@@ -26,16 +25,97 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Adapted from lib/libc/string/wcscoll.c of FreeBSD
+ */
-#include <assert.h>
#include <wchar.h>
+#include "collate.h"
+
/*
- * Compare strings with using collating information.
+ * Compare strings using collating information.
*/
int
wcscoll(const wchar_t *s1, const wchar_t *s2)
{
- /* XXX: LC_COLLATE should be implemented. */
- return (wcscmp(s1, s2));
+ int len1, len2, ret, ret2;
+ wint_t prim1, prim2, sec1, sec2;
+ const wchar_t *t1, *t2;
+ wchar_t *tt1, *tt2;
+ struct xlocale_collate *table =
+ (struct xlocale_collate *)&__xlocale_global_collate;
+
+ if (table->__collate_load_error)
+ return wcscmp(s1, s2);
+
+ len1 = len2 = 1;
+ ret = ret2 = 0;
+ if (table->__collate_substitute_nontrivial) {
+ t1 = tt1 = __collate_substitute_w(table, s1);
+ t2 = tt2 = __collate_substitute_w(table, s2);
+ } else {
+ tt1 = tt2 = NULL;
+ t1 = s1;
+ t2 = s2;
+ }
+ while(*t1 && *t2) {
+ prim1 = prim2 = 0;
+ while(*t1 && !prim1) {
+ __collate_lookup_w(table, t1, &len1, &prim1, &sec1);
+ t1 += len1;
+ }
+ while(*t2 && !prim2) {
+ __collate_lookup_w(table, t2, &len2, &prim2, &sec2);
+ t2 += len2;
+ }
+ if(!prim1 || !prim2)
+ break;
+ if(prim1 != prim2) {
+ ret = prim1 - prim2;
+ goto end;
+ }
+ if(!ret2)
+ ret2 = sec1 - sec2;
+ }
+ if(!*t1 && *t2)
+ ret = -(int)((u_char)*t2);
+ else if(*t1 && !*t2)
+ ret = (u_char)*t1;
+ else if(!*t1 && !*t2)
+ ret = ret2;
+ end:
+ free(tt1);
+ free(tt2);
+
+ return ret;
}
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/locale/wcsxfrm.c
src/lib/libc/locale/wcsxfrm.c
--- src53orig/lib/libc/locale/wcsxfrm.c Sat Feb 9 14:26:52 2013
+++ src/lib/libc/locale/wcsxfrm.c Mon Mar 18 06:08:54 2013
@@ -30,13 +30,91 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <[email protected]>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * Adapted from lib/libc/string/wcsxfrm.c of FreeBSD
+ */
+
+
+#include <sys/cdefs.h>
+#include <stdlib.h>
+#include <string.h>
#include <wchar.h>
+#include "collate.h"
-size_t
-wcsxfrm(wchar_t *dest, const wchar_t *src, size_t n)
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
{
- if (n == 0)
- return wcslen(src);
- return wcslcpy(dest, src, n);
+ wint_t prim, sec;
+ int l;
+ size_t slen;
+ wchar_t *s, *ss;
+ struct xlocale_collate *table =
+ (struct xlocale_collate *)&__xlocale_global_collate;
+
+ if (!*src) {
+ if (len > 0 && dest != NULL)
+ *dest = '\0';
+ return 0;
+ }
+
+ if (table->__collate_load_error)
+ return wcslcpy(dest, src, len);
+
+ slen = 0;
+ prim = sec = 0;
+ ss = s = __collate_substitute_w(table, src);
+ while (*s != L'\0') {
+ while (*s != L'\0' && !prim) {
+ __collate_lookup_w(table, s, &l, &prim, &sec);
+ s += l;
+ }
+ if (prim) {
+ if (len > 1) {
+ if (dest != NULL) {
+ *dest++ = prim;
+ }
+ len--;
+ }
+ slen++;
+ prim = 0;
+ }
+ }
+ free(ss);
+ if (len > 0 && dest != NULL) {
+ *dest = '\0';
+ }
+
+ return slen;
}
+
+
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/string/strcoll.3
src/lib/libc/string/strcoll.3
--- src53orig/lib/libc/string/strcoll.3 Mon Jul 25 17:03:20 2011
+++ src/lib/libc/string/strcoll.3 Mon Mar 18 06:24:34 2013
@@ -71,3 +71,7 @@
.Fn strcoll
function first appeared in
.Bx 4.3 Reno .
+.\" ----------------------------------------------------------------------
+.Sh BUGS
+The current implementation is enough only for single byte encodings and UTF-8
+translatable to ISO8859-1.
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/string/strcoll.c
src/lib/libc/string/strcoll.c
--- src53orig/lib/libc/string/strcoll.c Mon Aug 8 03:05:37 2005
+++ src/lib/libc/string/strcoll.c Mon Mar 18 07:25:12 2013
@@ -30,15 +30,40 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/**
+ * Public domain according to Colombian Legislation.
+ * http://www.pasosdejesus.org/dominio_publico_colombia.html
+ * 2013. [email protected].
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
+#include "../locale/collate.h"
+
+
/*
* Compare strings according to LC_COLLATE category of current locale.
*/
int
strcoll(const char *s1, const char *s2)
{
- /* LC_COLLATE is unimplemented, hence always "C" */
- return (strcmp(s1, s2));
+ int r = 0;
+ wchar_t *ws1 = NULL;
+ wchar_t *ws2 = NULL;
+
+ ws1 = __dup_as_wcs_l(s1);
+ if (ws1 != NULL) {
+ ws2 = __dup_as_wcs_l(s2);
+ if (ws2 != NULL) {
+ r = wcscoll(ws1, ws2);
+ free(ws2);
+ }
+ free(ws1);
+ }
+ return r;
}
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/string/strxfrm.3
src/lib/libc/string/strxfrm.3
--- src53orig/lib/libc/string/strxfrm.3 Mon Jul 25 17:03:20 2011
+++ src/lib/libc/string/strxfrm.3 Fri Mar 22 06:08:11 2013
@@ -72,8 +72,7 @@
.Fn strxfrm
function first appeared in
.Bx 4.3 Reno .
+.\" ----------------------------------------------------------------------
.Sh BUGS
-Since locales are not fully implemented on
-.Ox ,
-.Fn strxfrm
-just returns a copy of the original string.
+The current implementation is enough only for single byte encodings and UTF-8
+translatable to ISO8859-1.
diff -ruN -x obj -x CVS -x *~ src53orig/lib/libc/string/strxfrm.c
src/lib/libc/string/strxfrm.c
--- src53orig/lib/libc/string/strxfrm.c Mon Aug 8 03:05:37 2005
+++ src/lib/libc/string/strxfrm.c Fri Mar 22 06:14:29 2013
@@ -30,8 +30,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/**
+ * Public domain according to Colombian Legislation.
+ * http://www.pasosdejesus.org/dominio_publico_colombia.html
+ * 2013. [email protected].
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include "../locale/collate.h"
/*
* Transform src, storing the result in dst, such that
@@ -41,11 +50,34 @@
size_t
strxfrm(char *dst, const char *src, size_t n)
{
+ size_t r = 0;
+ wchar_t *ws = NULL;
+ wchar_t *wd = NULL;
- /*
- * Since locales are unimplemented, this is just a copy.
- */
- if (n == 0)
- return (strlen(src));
- return (strlcpy(dst, src, n));
+ ws = __dup_as_wcs_l(src);
+ if (ws != NULL) {
+ if (n > 0 && dst != NULL) {
+ if (n > ULONG_MAX / sizeof(wchar_t)) {
+ errno = EINVAL;
+ goto end;
+ }
+ wd = (wchar_t *)malloc(n * sizeof(wchar_t) );
+ if (wd == NULL) {
+ errno = ENOMEM;
+ goto end;
+ }
+ }
+ r = wcsxfrm(wd, ws, n);
+ if (n > 0 && dst != NULL) {
+ wcstombs(dst, wd, n);
+ }
+ }
+end:
+ if (ws != NULL) {
+ free(ws);
+ }
+ if (wd != NULL) {
+ free(wd);
+ }
+ return r;
}
diff -ruN -x obj -x CVS -x *~
src53orig/regress/lib/libc/locale/check_collate/Makefile
src53grcoll/regress/lib/libc/locale/check_collate/Makefile
--- src53orig/regress/lib/libc/locale/check_collate/Makefile Wed Dec 31
19:00:00 1969
+++ src53grcoll/regress/lib/libc/locale/check_collate/Makefile Tue Mar 19
07:49:37 2013
@@ -0,0 +1,11 @@
+
+NOMAN=
+PROG=check_collate
+
+CFLAGS=-g
+
+
+run-regress-check_collate: ${PROG}
+ ./${PROG} >/dev/null
+
+.include <bsd.regress.mk>
diff -ruN -x obj -x CVS -x *~
src53orig/regress/lib/libc/locale/check_collate/check_collate.c
src53grcoll/regress/lib/libc/locale/check_collate/check_collate.c
--- src53orig/regress/lib/libc/locale/check_collate/check_collate.c Wed Dec
31 19:00:00 1969
+++ src53grcoll/regress/lib/libc/locale/check_collate/check_collate.c Wed Mar
20 16:55:53 2013
@@ -0,0 +1,249 @@
+/**
+ * Public domain according to Colombian Legislation.
+ * http://www.pasosdejesus.org/dominio_publico_colombia.html
+ * 2013. [email protected].
+ */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+int bad;
+
+#define p(t) printf("%s:\t ",#t); \
+ if (t) { \
+ printf("\x1b[38;5;2mOK\x1b[0m\n"); \
+ } else { \
+ bad++; \
+ printf("\x1b[38;5;1mERROR\x1b[0m\n"); \
+ }
+
+void test_esCO88591()
+{
+ char *nl = setlocale(LC_ALL, "es_CO.ISO8859-1");
+ printf("locale %s\n", nl);
+ p(strcoll("\xe9", "f") < 0); // \xe9 is e with acute accent in LATIN1
+ p(strcoll("b", "\xe9") < 0);
+}
+
+
+void test_posix()
+{
+ char *nl = setlocale(LC_ALL, "C");
+ printf("locale %s\n", nl);
+ p(strcoll("\xe9", "f") > 0);
+ p(strcoll("b", "\xe9") < 0);
+ p(strcoll("", "\xe9") < 0);
+ p(strcoll("a", "") > 0);
+ p(strcoll("", "") == 0);
+}
+
+void test_esCOUTF8()
+{
+ char *nl = setlocale(LC_ALL, "es_CO.UTF-8");
+ printf("locale %s\n", nl);
+ p(strcoll("é", "f") < 0);
+ p(strcoll("b", "é") < 0);
+
+ wchar_t wcsb[1000];
+ mbstowcs(wcsb, "b", 1000);
+ wchar_t wcse[1000];
+ mbstowcs(wcse, "é", 1000);
+ p(wcscoll(wcsb, wcse) < 0);
+ mbstowcs(wcsb, "b", 1000);
+ mbstowcs(wcse, "é", 1000);
+ p(wcscoll(wcsb, wcse) < 0);
+ p(wcscoll(L"b", L"é") < 0);
+ p(strcoll("á", "e") < 0);
+ p(strcoll("ama", "ana") < 0);
+ p(strcoll("á", "e") < 0);
+ p(wcscoll(L"b", L"é") < 0);
+ p(wcscoll(L"á", L"e") < 0);
+ p(wcscoll(L"á", L"e") < 0);
+ /* Order in spanish*/
+ p(wcscoll(L" ", L"á") < 0);
+ p(wcscoll(L"á", L"b") < 0);
+ p(wcscoll(L"d", L"é") < 0);
+ p(wcscoll(L"é", L"f") < 0);
+ p(wcscoll(L"h", L"í") < 0);
+ p(wcscoll(L"í", L"j") < 0);
+ p(wcscoll(L"n", L"ñ") < 0);
+ p(wcscoll(L"ñ", L"o") < 0);
+ p(wcscoll(L"ñ", L"ó") < 0);
+ p(wcscoll(L"ó", L"p") < 0);
+ p(wcscoll(L"t", L"ú") < 0);
+ p(wcscoll(L"t", L"ü") < 0);
+ p(wcscoll(L"ú", L"v") < 0);
+ p(wcscoll(L"ü", L"v") < 0);
+ p(wcscoll(L"Á", L"B") < 0);
+ p(wcscoll(L"D", L"É") < 0);
+ p(wcscoll(L"É", L"F") < 0);
+ p(wcscoll(L"H", L"Í") < 0);
+ p(wcscoll(L"Í", L"J") < 0);
+ p(wcscoll(L"N", L"Ñ") < 0);
+ p(wcscoll(L"Ñ", L"O") < 0);
+ p(wcscoll(L"Ñ", L"Ó") < 0);
+ p(wcscoll(L"Ó", L"P") < 0);
+ p(wcscoll(L"T", L"Ú") < 0);
+ p(wcscoll(L"T", L"Ü") < 0);
+ p(wcscoll(L"Ú", L"V") < 0);
+ p(wcscoll(L"Ü", L"V") < 0);
+ p(wcscoll(L"", L"Á") < 0);
+ p(wcscoll(L"á", L"") > 0);
+ p(wcscoll(L"áá", L"á") > 0);
+
+ wchar_t wa[10], wb[10], we[10], wf[10], wn[10], wegne[10],
+ wo[10];
+
+ p(wcsxfrm(wo, L"oro", 1000) > 0);
+ printf("oro wo='%ls'\n", wo);
+ p(wcsxfrm(wa, L"", 1000) >= 0);
+ printf("wa='%ls'\n", wa);
+ p(wcsxfrm(wa, L"á", 1000) > 0);
+ printf("wa='%ls'\n", wa);
+ p(wcsxfrm(wb, L"b", 1000) > 0);
+ printf("wb='%ls'\n", wb);
+ p(wcscmp(wa, wb) < 0);
+ p(wcsxfrm(we, L"é", 1000) > 0);
+ printf("we='%ls'\n", we);
+ p(wcscmp(wb, we) < 0);
+ p(wcsxfrm(wf, L"f", 1000) > 0);
+ printf("wf='%ls'\n", wf);
+ p(wcscmp(wb, wf) < 0);
+ p(wcscmp(we, wf) < 0);
+ p(wcsxfrm(wn, L"n", 1000) > 0);
+ printf("wn='%ls'\n", wn);
+ p(wcsxfrm(wegne, L"ñ", 1000) > 0);
+ printf("wegne='%ls'\n", wegne);
+ p(wcsxfrm(wo, L"o", 1000) > 0);
+ printf("o wo='%ls'\n", wo);
+ p(wcsxfrm(wo, L"oso", 1000) > 0);
+ printf("oso wo='%ls'\n", wo);
+ p(wcscmp(wn, wegne) < 0);
+ p(wcscmp(wegne, wo) < 0);
+
+ char a[1000], b[1000], e[1000], f[1000];
+ size_t sr = 0;
+ p((sr = strxfrm(NULL, "equis", 0)) == 5);
+ p(strxfrm(NULL, "", 1000) == 0);
+ p(strxfrm(a, "", 1000) == 0 && a[0] == '\0');
+ p(strxfrm(a, "á", 1000) > 0);
+ p(strxfrm(b, "b", 1000) > 0);
+ p(strcmp(a, b) < 0);
+ p(strxfrm(e, "é", 1000) > 0);
+ printf("é e=%s\n", e);
+ p(strcmp(b, e) < 0);
+ p(strxfrm(f, "f", 1000) > 0);
+ p(strcmp(b, f) < 0);
+ p(strcmp(e, f) < 0);
+ p(strxfrm(e, "éa", 1000) > 0);
+ printf("e=%s\n", e);
+ p(strxfrm(f, "éb", 1000) > 0);
+ printf("f=%s\n", f);
+ p(strcmp(e, f) < 0);
+ p(strxfrm(f, "oso", 1000) > 0);
+ printf("oso f=%s\n", f);
+ p(strcmp(e, f) < 0);
+
+}
+
+void test_ruRUKOI8R()
+{
+ char *nl = setlocale(LC_ALL, "ru_RU.KOI8-R");
+ printf("locale %s\n", nl);
+ p(strcoll("\xc1", "\xc2") < 0); // a, б
+ p(strcoll("\xc2", "\xd7") < 0); // б, в
+ p(strcoll("\xd7", "\xc7") < 0); // в, г
+ p(strcoll("\xe1", "\xe2") < 0); // A, Б
+ p(strcoll("\xe2", "\xf7") < 0); // Б, В
+ p(strcoll("\xf7", "\xe7") < 0); // В, Г
+ p(strcoll("\xe7", "\xc1") < 0); // Г, a
+}
+
+void test_bgcp1251()
+{
+ char *nl = setlocale(LC_ALL, "bg_BG.CP1251");
+ printf("locale %s\n", nl);
+ p(strcoll("\xc0", "\xc1") < 0); // A, Б
+ p(strcoll("\xc0", "\xa8") < 0); // A, Ë
+}
+
+void test_csCZ88592()
+{
+ char *nl = setlocale(LC_ALL, "cs_CZ.ISO8859-2");
+ printf("locale %s\n", nl);
+ p(strcoll("\xea", "f") < 0); // é
+ p(strcoll("\xf0", "e") < 0); // đ
+}
+
+
+void test_elGR88597()
+{
+ char *nl = setlocale(LC_ALL, "el_GR.ISO8859-7");
+ printf("locale %s\n", nl);
+ p(strcoll("\xdc", "\xc0") < 0); // ά, ΐ
+}
+
+void test_hyAMARMSCII8()
+{
+ char *nl = setlocale(LC_ALL, "hy_AM.ARMSCII-8");
+ printf("locale %s\n", nl);
+ p(strcoll("\xa9", "A") < 0);
+}
+
+void test_kkKZPT154()
+{
+ char *nl = setlocale(LC_ALL, "kk_KZ.PT154");
+ printf("locale %s\n", nl);
+ p(strcoll("\xce", "\xa4") < 0);
+}
+
+void test_ltLT88594()
+{
+ char *nl = setlocale(LC_ALL, "lt_LT.ISO8859-4");
+ printf("locale %s\n", nl);
+ p(strcoll("\xc1", "B") < 0);
+}
+
+void test_ruRUCP866()
+{
+ char *nl = setlocale(LC_ALL, "ru_RU.CP866");
+ printf("locale %s\n", nl);
+ p(strcoll("\x80", "a") < 0);
+}
+
+void test_ruRU88595()
+{
+ char *nl = setlocale(LC_ALL, "ru_RU.ISO8859-5");
+ printf("locale %s\n", nl);
+ p(strcoll("\xb0", "a") < 0);
+}
+
+void test_trTR88599()
+{
+ char *nl = setlocale(LC_ALL, "tr_TR.ISO8859-9");
+ printf("locale %s\n", nl);
+ p(strcoll("\xe1", "b") < 0);
+}
+
+int main()
+{
+ test_esCO88591();
+ test_posix();
+ test_esCOUTF8();
+ test_ruRUKOI8R();
+ test_bgcp1251();
+ test_csCZ88592();
+ test_elGR88597();
+ test_hyAMARMSCII8();
+ test_kkKZPT154();
+ test_ltLT88594();
+ test_ruRUCP866();
+ test_ruRU88595();
+ test_trTR88599();
+
+ return bad != 0;
+}