summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/amd64/Makefile13
-rw-r--r--usr/src/lib/libc/i386/Makefile.com13
-rw-r--r--usr/src/lib/libc/port/i18n/isdigit.c148
-rw-r--r--usr/src/lib/libc/port/i18n/wscasecmp.c55
-rw-r--r--usr/src/lib/libc/port/locale/_ctype.h3
-rw-r--r--usr/src/lib/libc/port/locale/big5.c42
-rw-r--r--usr/src/lib/libc/port/locale/btowc.c13
-rw-r--r--usr/src/lib/libc/port/locale/collate.c218
-rw-r--r--usr/src/lib/libc/port/locale/collate.h35
-rw-r--r--usr/src/lib/libc/port/locale/collcmp.c11
-rw-r--r--usr/src/lib/libc/port/locale/euc.c187
-rw-r--r--usr/src/lib/libc/port/locale/fgetwc.c48
-rw-r--r--usr/src/lib/libc/port/locale/fnmatch.c58
-rw-r--r--usr/src/lib/libc/port/locale/fputwc.c3
-rw-r--r--usr/src/lib/libc/port/locale/gb18030.c45
-rw-r--r--usr/src/lib/libc/port/locale/gb2312.c43
-rw-r--r--usr/src/lib/libc/port/locale/gbk.c42
-rw-r--r--usr/src/lib/libc/port/locale/isdigit.c91
-rw-r--r--usr/src/lib/libc/port/locale/iswctype.c229
-rw-r--r--usr/src/lib/libc/port/locale/lctype.h66
-rw-r--r--usr/src/lib/libc/port/locale/ldpart.c23
-rw-r--r--usr/src/lib/libc/port/locale/ldpart.h3
-rw-r--r--usr/src/lib/libc/port/locale/lmessages.c56
-rw-r--r--usr/src/lib/libc/port/locale/lmessages.h6
-rw-r--r--usr/src/lib/libc/port/locale/lmonetary.c153
-rw-r--r--usr/src/lib/libc/port/locale/lmonetary.h5
-rw-r--r--usr/src/lib/libc/port/locale/lnumeric.c69
-rw-r--r--usr/src/lib/libc/port/locale/lnumeric.h6
-rw-r--r--usr/src/lib/libc/port/locale/localeconv.c47
-rw-r--r--usr/src/lib/libc/port/locale/localeimpl.c537
-rw-r--r--usr/src/lib/libc/port/locale/localeimpl.h107
-rw-r--r--usr/src/lib/libc/port/locale/mblen.c18
-rw-r--r--usr/src/lib/libc/port/locale/mblocal.h47
-rw-r--r--usr/src/lib/libc/port/locale/mbrlen.c14
-rw-r--r--usr/src/lib/libc/port/locale/mbrtowc.c16
-rw-r--r--usr/src/lib/libc/port/locale/mbsinit.c48
-rw-r--r--usr/src/lib/libc/port/locale/mbsnrtowcs.c23
-rw-r--r--usr/src/lib/libc/port/locale/mbsrtowcs.c18
-rw-r--r--usr/src/lib/libc/port/locale/mbstowcs.c15
-rw-r--r--usr/src/lib/libc/port/locale/mbtowc.c18
-rw-r--r--usr/src/lib/libc/port/locale/mskanji.c43
-rw-r--r--usr/src/lib/libc/port/locale/nextwctype.c32
-rw-r--r--usr/src/lib/libc/port/locale/nl_langinfo.c101
-rw-r--r--usr/src/lib/libc/port/locale/none.c72
-rw-r--r--usr/src/lib/libc/port/locale/regcomp.c15
-rw-r--r--usr/src/lib/libc/port/locale/rune.c73
-rw-r--r--usr/src/lib/libc/port/locale/runetype.c7
-rw-r--r--usr/src/lib/libc/port/locale/runetype.h6
-rw-r--r--usr/src/lib/libc/port/locale/setlocale.c336
-rw-r--r--usr/src/lib/libc/port/locale/setlocale.h4
-rw-r--r--usr/src/lib/libc/port/locale/setrunelocale.c274
-rw-r--r--usr/src/lib/libc/port/locale/strcasecmp.c (renamed from usr/src/lib/libc/port/i18n/strcasecmp.c)21
-rw-r--r--usr/src/lib/libc/port/locale/strcasestr.c (renamed from usr/src/lib/libc/port/i18n/strcasestr.c)14
-rw-r--r--usr/src/lib/libc/port/locale/strcoll.c25
-rw-r--r--usr/src/lib/libc/port/locale/strfmon.c199
-rw-r--r--usr/src/lib/libc/port/locale/strftime.c45
-rw-r--r--usr/src/lib/libc/port/locale/strncasecmp.c (renamed from usr/src/lib/libc/port/i18n/strncasecmp.c)20
-rw-r--r--usr/src/lib/libc/port/locale/strptime.c67
-rw-r--r--usr/src/lib/libc/port/locale/strxfrm.c17
-rw-r--r--usr/src/lib/libc/port/locale/table.c9
-rw-r--r--usr/src/lib/libc/port/locale/timelocal.c48
-rw-r--r--usr/src/lib/libc/port/locale/timelocal.h5
-rw-r--r--usr/src/lib/libc/port/locale/tolower.c22
-rw-r--r--usr/src/lib/libc/port/locale/towlower.c47
-rw-r--r--usr/src/lib/libc/port/locale/utf8.c34
-rw-r--r--usr/src/lib/libc/port/locale/wcrtomb.c16
-rw-r--r--usr/src/lib/libc/port/locale/wcscasecmp.c (renamed from usr/src/lib/libc/port/i18n/wsncasecmp.c)47
-rw-r--r--usr/src/lib/libc/port/locale/wcscoll.c36
-rw-r--r--usr/src/lib/libc/port/locale/wcsnrtombs.c26
-rw-r--r--usr/src/lib/libc/port/locale/wcsrtombs.c16
-rw-r--r--usr/src/lib/libc/port/locale/wcstombs.c14
-rw-r--r--usr/src/lib/libc/port/locale/wcswidth.c13
-rw-r--r--usr/src/lib/libc/port/locale/wcsxfrm.c17
-rw-r--r--usr/src/lib/libc/port/locale/wctob.c13
-rw-r--r--usr/src/lib/libc/port/locale/wctomb.c17
-rw-r--r--usr/src/lib/libc/port/locale/wctrans.c29
-rw-r--r--usr/src/lib/libc/port/locale/wctype.c17
-rw-r--r--usr/src/lib/libc/port/locale/wcwidth.c15
-rw-r--r--usr/src/lib/libc/port/mapfile-vers84
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com13
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com13
81 files changed, 2779 insertions, 1735 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index 873c2ded87..59d9a684e9 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -23,6 +23,7 @@
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -655,9 +656,6 @@ PORTI18N= \
getwchar.o \
putwchar.o \
putws.o \
- strcasecmp.o \
- strcasestr.o \
- strncasecmp.o \
strtows.o \
wcsnlen.o \
wcsstr.o \
@@ -670,7 +668,6 @@ PORTI18N= \
wmemcpy.o \
wmemmove.o \
wmemset.o \
- wscasecmp.o \
wscat.o \
wschr.o \
wscmp.o \
@@ -678,7 +675,6 @@ PORTI18N= \
wscspn.o \
wsdup.o \
wslen.o \
- wsncasecmp.o \
wsncat.o \
wsncmp.o \
wsncpy.o \
@@ -696,7 +692,6 @@ PORTI18N= \
gettext_gnu.o \
gettext_real.o \
gettext_util.o \
- isdigit.o \
plural_parser.o \
wdresolve.o \
_ctype.o \
@@ -724,12 +719,14 @@ PORTLOCALE= \
gb2312.o \
gbk.o \
getdate.o \
+ isdigit.o \
iswctype.o \
ldpart.o \
lmessages.o \
lnumeric.o \
lmonetary.o \
localeconv.o \
+ localeimpl.o \
mbftowc.o \
mblen.o \
mbrlen.o \
@@ -751,9 +748,12 @@ PORTLOCALE= \
runetype.o \
setlocale.o \
setrunelocale.o \
+ strcasecmp.o \
+ strcasestr.o \
strcoll.o \
strfmon.o \
strftime.o \
+ strncasecmp.o \
strptime.o \
strxfrm.o \
table.o \
@@ -763,6 +763,7 @@ PORTLOCALE= \
ungetwc.o \
utf8.o \
wcrtomb.o \
+ wcscasecmp.o \
wcscoll.o \
wcsftime.o \
wcsnrtombs.o \
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index b21f87a0d6..ca8e9b8970 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -22,6 +22,7 @@
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2013, Joyent, Inc. All rights reserved.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
#
# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Use is subject to license terms.
@@ -697,9 +698,6 @@ PORTI18N= \
getwchar.o \
putwchar.o \
putws.o \
- strcasecmp.o \
- strcasestr.o \
- strncasecmp.o \
strtows.o \
wcsnlen.o \
wcsstr.o \
@@ -712,7 +710,6 @@ PORTI18N= \
wmemcpy.o \
wmemmove.o \
wmemset.o \
- wscasecmp.o \
wscat.o \
wschr.o \
wscmp.o \
@@ -720,7 +717,6 @@ PORTI18N= \
wscspn.o \
wsdup.o \
wslen.o \
- wsncasecmp.o \
wsncat.o \
wsncmp.o \
wsncpy.o \
@@ -738,7 +734,6 @@ PORTI18N= \
gettext_gnu.o \
gettext_real.o \
gettext_util.o \
- isdigit.o \
plural_parser.o \
wdresolve.o \
_ctype.o \
@@ -766,12 +761,14 @@ PORTLOCALE= \
gb2312.o \
gbk.o \
getdate.o \
+ isdigit.o \
iswctype.o \
ldpart.o \
lmessages.o \
lnumeric.o \
lmonetary.o \
localeconv.o \
+ localeimpl.o \
mbftowc.o \
mblen.o \
mbrlen.o \
@@ -793,9 +790,12 @@ PORTLOCALE= \
runetype.o \
setlocale.o \
setrunelocale.o \
+ strcasecmp.o \
+ strcasestr.o \
strcoll.o \
strfmon.o \
strftime.o \
+ strncasecmp.o \
strptime.o \
strxfrm.o \
table.o \
@@ -805,6 +805,7 @@ PORTLOCALE= \
ungetwc.o \
utf8.o \
wcrtomb.o \
+ wcscasecmp.o \
wcscoll.o \
wcsftime.o \
wcsnrtombs.o \
diff --git a/usr/src/lib/libc/port/i18n/isdigit.c b/usr/src/lib/libc/port/i18n/isdigit.c
deleted file mode 100644
index 69f6f4bbdd..0000000000
--- a/usr/src/lib/libc/port/i18n/isdigit.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * This file contains the implementation of various functional forms
- * of the ctype tests, specifically the required by ISO C. These are defined
- * in the "C" (POSIX) locale.
- */
-
-#include "lint.h"
-#include <ctype.h>
-
-/*
- * We are supplying functional forms, so make sure to suppress any macros
- * we might have imported.
- */
-
-#ifdef isblank
-#undef isblank
-#endif
-
-int
-isblank(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISBLANK));
-}
-
-#ifdef isupper
-#undef isupper
-#endif
-
-int
-isupper(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISUPPER));
-}
-
-#ifdef islower
-#undef islower
-#endif
-
-int
-islower(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISLOWER));
-}
-
-#ifdef isdigit
-#undef isdigit
-#endif
-
-int
-isdigit(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISDIGIT));
-}
-
-#ifdef isxdigit
-#undef isxdigit
-#endif
-
-int
-isxdigit(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISXDIGIT));
-}
-
-#ifdef isalpha
-#undef isalpha
-#endif
-
-int
-isalpha(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISALPHA));
-}
-
-#ifdef isalnum
-#undef isalnum
-#endif
-
-int
-isalnum(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISALNUM));
-}
-
-#ifdef isspace
-#undef isspace
-#endif
-
-int
-isspace(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISSPACE));
-}
-
-#ifdef iscntrl
-#undef iscntrl
-#endif
-
-int
-iscntrl(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISCNTRL));
-}
-
-#ifdef isgraph
-#undef isgraph
-#endif
-
-int
-isgraph(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISGRAPH));
-}
-
-#ifdef ispunct
-#undef ispunct
-#endif
-
-int
-ispunct(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISPUNCT));
-}
-
-#ifdef isprint
-#undef isprint
-#endif
-
-int
-isprint(int c)
-{
- return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISPRINT));
-}
diff --git a/usr/src/lib/libc/port/i18n/wscasecmp.c b/usr/src/lib/libc/port/i18n/wscasecmp.c
deleted file mode 100644
index c8855ded41..0000000000
--- a/usr/src/lib/libc/port/i18n/wscasecmp.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * Compare strings ignoring case difference.
- * returns: s1>s2: >0 s1==s2: 0 s1<s2: <0
- * All letters are converted to the lowercase and compared.
- */
-
-#pragma weak _wscasecmp = wscasecmp
-
-#include "lint.h"
-#include <stdlib.h>
-#include <widec.h>
-#include "libc.h"
-
-int
-wcscasecmp(const wchar_t *s1, const wchar_t *s2)
-{
- if (s1 == s2)
- return (0);
-
- while (towlower(*s1) == towlower(*s2++))
- if (*s1++ == 0)
- return (0);
- return (towlower(*s1) - towlower(*(s2 - 1)));
-}
-
-int
-wscasecmp(const wchar_t *s1, const wchar_t *s2)
-{
- return (wcscasecmp(s1, s2));
-}
diff --git a/usr/src/lib/libc/port/locale/_ctype.h b/usr/src/lib/libc/port/locale/_ctype.h
index 34c3a49435..462b19f57c 100644
--- a/usr/src/lib/libc/port/locale/_ctype.h
+++ b/usr/src/lib/libc/port/locale/_ctype.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -79,6 +80,4 @@
#define _CTYPE_SWM 0xe0000000U /* Mask for screen width data */
#define _CTYPE_SWS 30 /* Bits to shift to get width */
-unsigned int ___runetype(int);
-
#endif /* !__CTYPE_H_ */
diff --git a/usr/src/lib/libc/port/locale/big5.c b/usr/src/lib/libc/port/locale/big5.c
index f13df7a6f2..2729ab0289 100644
--- a/usr/src/lib/libc/port/locale/big5.c
+++ b/usr/src/lib/libc/port/locale/big5.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
@@ -35,11 +36,11 @@
#include "lint.h"
#include <sys/types.h>
#include <errno.h>
-#include "runetype.h"
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -47,22 +48,27 @@ static size_t _BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD,
static int _BIG5_mbsinit(const mbstate_t *);
static size_t _BIG5_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+static size_t _BIG5_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _BIG5_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
typedef struct {
wchar_t ch;
} _BIG5State;
-int
-_BIG5_init(_RuneLocale *rl)
+void
+_BIG5_init(struct lc_ctype *lct)
{
-
- __mbrtowc = _BIG5_mbrtowc;
- __wcrtomb = _BIG5_wcrtomb;
- __mbsinit = _BIG5_mbsinit;
- _CurrentRuneLocale = rl;
- __ctype[520] = 2;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _BIG5_mbrtowc;
+ lct->lc_wcrtomb = _BIG5_wcrtomb;
+ lct->lc_mbsnrtowcs = _BIG5_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _BIG5_wcsnrtombs;
+ lct->lc_mbsinit = _BIG5_mbsinit;
+ lct->lc_max_mblen = 2;
+ lct->lc_is_ascii = 0;
}
static int
@@ -164,3 +170,17 @@ _BIG5_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
*s = wc & 0xff;
return (1);
}
+
+static size_t
+_BIG5_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _BIG5_mbrtowc));
+}
+
+static size_t
+_BIG5_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _BIG5_wcrtomb));
+}
diff --git a/usr/src/lib/libc/port/locale/btowc.c b/usr/src/lib/libc/port/locale/btowc.c
index d835f8da77..9401d9b030 100644
--- a/usr/src/lib/libc/port/locale/btowc.c
+++ b/usr/src/lib/libc/port/locale/btowc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002, 2003 Tim J. Robbins.
* All rights reserved.
@@ -28,10 +29,12 @@
#include "lint.h"
#include <stdio.h>
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
wint_t
-btowc(int c)
+btowc_l(int c, locale_t loc)
{
static const mbstate_t initial = { 0 };
mbstate_t mbs = initial;
@@ -46,7 +49,13 @@ btowc(int c)
* counts.
*/
cc = (char)c;
- if (__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ if (mbrtowc_l(&wc, &cc, 1, &mbs, loc) > 1)
return (WEOF);
return (wc);
}
+
+wint_t
+btowc(int c)
+{
+ return (btowc_l(c, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/collate.c b/usr/src/lib/libc/port/locale/collate.c
index 9064ca685f..75814a9a9f 100644
--- a/usr/src/lib/libc/port/locale/collate.c
+++ b/usr/src/lib/libc/port/locale/collate.c
@@ -1,5 +1,6 @@
/*
- * Copright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
@@ -44,7 +45,6 @@
#include "collate.h"
#include "setlocale.h"
-#include "ldpart.h"
/*
* See the comments in usr/src/cmd/localedef/collate.c for further
@@ -53,21 +53,21 @@
* handy (www.opengroup.org).
*/
-static collate_subst_t *subst_table[COLL_WEIGHTS_MAX];
-static collate_char_t *char_pri_table;
-static collate_large_t *large_pri_table;
-static collate_chain_t *chain_pri_table;
-static char *cache = NULL;
-static size_t cachesz;
-static char collate_encoding[ENCODING_LEN + 1];
+/*
+ * POSIX uses empty tables and falls down to strcmp.
+ */
+struct lc_collate lc_collate_posix = {
+ .lc_is_posix = 1,
+};
-/* Exposed externally to other parts of libc. */
-collate_info_t *_collate_info;
-int _collate_load_error = 1;
+struct locdata __posix_collate_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_collate_posix }
+};
-int
-_collate_load_tables(const char *encoding)
+struct locdata *
+__lc_collate_load(const char *locname)
{
int i, chains, z;
char buf[PATH_MAX];
@@ -76,49 +76,41 @@ _collate_load_tables(const char *encoding)
collate_info_t *info;
struct stat sbuf;
int fd;
-
- /* 'encoding' must be already checked. */
- if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
- _collate_load_error = 1;
- return (_LDP_CACHE);
- }
-
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (cache && (strncmp(encoding, collate_encoding, ENCODING_LEN) == 0)) {
- _collate_load_error = 0;
- return (_LDP_CACHE);
- }
+ struct locdata *ldata;
+ struct lc_collate *lcc;
/*
* Slurp the locale file into the cache.
*/
(void) snprintf(buf, sizeof (buf), "%s/%s/LC_COLLATE/LCL_DATA",
- _PathLocale, encoding);
+ _PathLocale, locname);
- if ((fd = open(buf, O_RDONLY)) < 0)
- return (_LDP_ERROR);
+ if ((fd = open(buf, O_RDONLY)) < 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
if (fstat(fd, &sbuf) < 0) {
(void) close(fd);
- return (_LDP_ERROR);
+ errno = EINVAL;
+ return (NULL);
}
if (sbuf.st_size < (COLLATE_STR_LEN + sizeof (info))) {
(void) close(fd);
errno = EINVAL;
- return (_LDP_ERROR);
+ return (NULL);
}
map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
(void) close(fd);
if ((TMP = map) == NULL) {
- return (_LDP_ERROR);
+ errno = EINVAL;
+ return (NULL);
}
if (strncmp(TMP, COLLATE_VERSION, COLLATE_STR_LEN) != 0) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
- return (_LDP_ERROR);
+ return (NULL);
}
TMP += COLLATE_STR_LEN;
@@ -130,72 +122,84 @@ _collate_load_tables(const char *encoding)
((chains = info->chain_count) < 0)) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
- return (_LDP_ERROR);
+ return (NULL);
}
i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
(sizeof (collate_chain_t) * chains) +
(sizeof (collate_large_t) * info->large_count);
- for (z = 0; z < (info->directive_count); z++) {
+ for (z = 0; z < info->directive_count; z++) {
i += sizeof (collate_subst_t) * info->subst_count[z];
}
if (i != (sbuf.st_size - (TMP - map))) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
- return (_LDP_ERROR);
+ return (NULL);
}
- char_pri_table = (void *)TMP;
+
+ if ((ldata = __locdata_alloc(locname, sizeof (*lcc))) == NULL) {
+ (void) munmap(map, sbuf.st_size);
+ return (NULL);
+ }
+ lcc = ldata->l_data[0];
+ ldata->l_map = map;
+ ldata->l_map_len = sbuf.st_size;
+
+ lcc->lc_info = info;
+ lcc->lc_directive_count = info->directive_count;
+ lcc->lc_large_count = info->large_count;
+
+ for (z = 0; z < COLL_WEIGHTS_MAX; z++) {
+ lcc->lc_directive[z] = info->directive[z];
+ lcc->lc_subst_count[z] = info->subst_count[z];
+ lcc->lc_pri_count[z] = info->pri_count[z];
+ lcc->lc_undef_pri[z] = info->undef_pri[z];
+ }
+
+ lcc->lc_char_table = (void *)TMP;
TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
- for (z = 0; z < info->directive_count; z++) {
- if (info->subst_count[z] > 0) {
- subst_table[z] = (void *)TMP;
- TMP += info->subst_count[z] * sizeof (collate_subst_t);
+ for (z = 0; z < lcc->lc_directive_count; z++) {
+ int count;
+ if ((count = lcc->lc_subst_count[z]) > 0) {
+ lcc->lc_subst_table[z] = (void *)TMP;
+ TMP += count * sizeof (collate_subst_t);
} else {
- subst_table[z] = NULL;
+ lcc->lc_subst_table[z] = NULL;
}
}
if (chains > 0) {
- chain_pri_table = (void *)TMP;
+ lcc->lc_chain_table = (void *)TMP;
TMP += chains * sizeof (collate_chain_t);
} else
- chain_pri_table = NULL;
- if (info->large_count > 0)
- large_pri_table = (void *)TMP;
+ lcc->lc_chain_table = NULL;
+ lcc->lc_chain_count = chains;
+ if (lcc->lc_large_count > 0)
+ lcc->lc_large_table = (void *)TMP;
else
- large_pri_table = NULL;
-
- (void) strlcpy(collate_encoding, encoding, ENCODING_LEN);
- _collate_info = info;
-
- if (cache)
- (void) munmap(cache, cachesz);
-
- cache = map;
- cachesz = sbuf.st_size;
- _collate_load_error = 0;
+ lcc->lc_large_table = NULL;
- return (_LDP_LOADED);
+ return (ldata);
}
-static int32_t *
-substsearch(const wchar_t key, int pass)
+static const int32_t *
+substsearch(const struct lc_collate *lcc, const wchar_t key, int pass)
{
- collate_subst_t *p;
- int n = _collate_info->subst_count[pass];
+ const collate_subst_t *p;
+ int n = lcc->lc_subst_count[pass];
if (n == 0)
return (NULL);
- if (pass >= _collate_info->directive_count)
+ if (pass >= lcc->lc_directive_count)
return (NULL);
if (!(key & COLLATE_SUBST_PRIORITY))
return (NULL);
- p = subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
+ p = lcc->lc_subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
assert(p->key == key);
return (p->pri);
}
@@ -206,7 +210,7 @@ substsearch(const wchar_t key, int pass)
*/
static collate_chain_t *
-chainsearch(const wchar_t *key, int *len)
+chainsearch(const struct lc_collate *lcc, const wchar_t *key, int *len)
{
int low;
int high;
@@ -214,12 +218,12 @@ chainsearch(const wchar_t *key, int *len)
collate_chain_t *p;
collate_chain_t *tab;
- if (_collate_info->chain_count == 0)
+ if (lcc->lc_info->chain_count == 0)
return (NULL);
low = 0;
- high = _collate_info->chain_count - 1;
- tab = chain_pri_table;
+ high = lcc->lc_info->chain_count - 1;
+ tab = lcc->lc_chain_table;
while (low <= high) {
next = (low + high) / 2;
@@ -242,15 +246,15 @@ chainsearch(const wchar_t *key, int *len)
}
static collate_large_t *
-largesearch(const wchar_t key)
+largesearch(const struct lc_collate *lcc, const wchar_t key)
{
int low = 0;
- int high = _collate_info->large_count - 1;
+ int high = lcc->lc_info->large_count - 1;
int next, compar;
collate_large_t *p;
- collate_large_t *tab = large_pri_table;
+ collate_large_t *tab = lcc->lc_large_table;
- if (_collate_info->large_count == 0)
+ if (lcc->lc_info->large_count == 0)
return (NULL);
while (low <= high) {
@@ -268,19 +272,19 @@ largesearch(const wchar_t key)
}
void
-_collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
+_collate_lookup(const struct lc_collate *lcc, const wchar_t *t,
+ int *len, int *pri, int which, const int **state)
{
collate_chain_t *p2;
collate_large_t *match;
- collate_info_t *info = _collate_info;
int p, l;
- int *sptr;
+ const int *sptr;
/*
* If this is the "last" pass for the UNDEFINED, then
* we just return the priority itself.
*/
- if (which >= info->directive_count) {
+ if (which >= lcc->lc_directive_count) {
*pri = *t;
*len = 1;
*state = NULL;
@@ -306,7 +310,7 @@ _collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
* Check for composites such as dipthongs that collate as a
* single element (aka chains or collating-elements).
*/
- if (((p2 = chainsearch(t, &l)) != NULL) &&
+ if (((p2 = chainsearch(lcc, t, &l)) != NULL) &&
((p = p2->pri[which]) >= 0)) {
*len = l;
@@ -318,10 +322,10 @@ _collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
* Character is a small (8-bit) character.
* We just look these up directly for speed.
*/
- *pri = char_pri_table[*t].pri[which];
+ *pri = lcc->lc_char_table[*t].pri[which];
- } else if ((info->large_count > 0) &&
- ((match = largesearch(*t)) != NULL)) {
+ } else if ((lcc->lc_info->large_count > 0) &&
+ ((match = largesearch(lcc, *t)) != NULL)) {
/*
* Character was found in the extended table.
@@ -332,11 +336,11 @@ _collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
/*
* Character lacks a specific definition.
*/
- if (info->directive[which] & DIRECTIVE_UNDEFINED) {
+ if (lcc->lc_directive[which] & DIRECTIVE_UNDEFINED) {
/* Mask off sign bit to prevent ordering confusion. */
*pri = (*t & COLLATE_MAX_PRIORITY);
} else {
- *pri = info->undef_pri[which];
+ *pri = lcc->lc_undef_pri[which];
}
/* No substitutions for undefined characters! */
return;
@@ -354,7 +358,7 @@ _collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
* to be substituted be unique for that level. The localedef
* code ensures this for us.
*/
- if ((sptr = substsearch(*pri, which)) != NULL) {
+ if ((sptr = substsearch(lcc, *pri, which)) != NULL) {
if ((*pri = *sptr) != 0) {
sptr++;
*state = *sptr ? sptr : NULL;
@@ -368,7 +372,8 @@ _collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
* NOT NULL terminate. That is left to the caller.
*/
size_t
-_collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
+_collate_wxfrm(const struct lc_collate *lcc, const wchar_t *src, wchar_t *xf,
+ size_t room)
{
int pri;
int len;
@@ -376,13 +381,14 @@ _collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
wchar_t *tr = NULL;
int direc;
int pass;
- int32_t *state;
+ const int32_t *state;
size_t want = 0;
size_t need = 0;
+ int ndir = lcc->lc_directive_count;
assert(src);
- for (pass = 0; pass <= _collate_info->directive_count; pass++) {
+ for (pass = 0; pass <= ndir; pass++) {
state = NULL;
@@ -396,10 +402,10 @@ _collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
}
/* special pass for undefined */
- if (pass == _collate_info->directive_count) {
+ if (pass == ndir) {
direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
} else {
- direc = _collate_info->directive[pass];
+ direc = lcc->lc_directive[pass];
}
t = src;
@@ -424,7 +430,8 @@ _collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
if (direc & DIRECTIVE_POSITION) {
while (*t || state) {
- _collate_lookup(t, &len, &pri, pass, &state);
+ _collate_lookup(lcc, t, &len, &pri, pass,
+ &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
@@ -442,7 +449,8 @@ _collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
}
} else {
while (*t || state) {
- _collate_lookup(t, &len, &pri, pass, &state);
+ _collate_lookup(lcc, t, &len, &pri, pass,
+ &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
@@ -497,10 +505,10 @@ fail:
#define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */
static int
-xfrm(unsigned char *p, int pri, int pass)
+xfrm(locale_t loc, unsigned char *p, int pri, int pass)
{
/* we use unsigned to ensure zero fill on right shift */
- uint32_t val = (uint32_t)_collate_info->pri_count[pass];
+ uint32_t val = (uint32_t)loc->collate->lc_pri_count[pass];
int nc = 0;
while (val) {
@@ -514,7 +522,7 @@ xfrm(unsigned char *p, int pri, int pass)
}
size_t
-_collate_sxfrm(const wchar_t *src, char *xf, size_t room)
+_collate_sxfrm(const wchar_t *src, char *xf, size_t room, locale_t loc)
{
int pri;
int len;
@@ -522,15 +530,17 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
wchar_t *tr = NULL;
int direc;
int pass;
- int32_t *state;
+ const int32_t *state;
size_t want = 0;
size_t need = 0;
int b;
uint8_t buf[XFRM_BYTES];
+ const struct lc_collate *lcc = loc->collate;
+ int ndir = lcc->lc_directive_count;
assert(src);
- for (pass = 0; pass <= _collate_info->directive_count; pass++) {
+ for (pass = 0; pass <= ndir; pass++) {
state = NULL;
@@ -544,10 +554,10 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
}
/* special pass for undefined */
- if (pass == _collate_info->directive_count) {
+ if (pass == ndir) {
direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
} else {
- direc = _collate_info->directive[pass];
+ direc = lcc->lc_directive[pass];
}
t = src;
@@ -573,7 +583,8 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
if (direc & DIRECTIVE_POSITION) {
while (*t || state) {
- _collate_lookup(t, &len, &pri, pass, &state);
+ _collate_lookup(lcc, t, &len, &pri, pass,
+ &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
@@ -583,7 +594,7 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
pri = COLLATE_MAX_PRIORITY;
}
- b = xfrm(buf, pri, pass);
+ b = xfrm(loc, buf, pri, pass);
want += b;
if (room) {
while (b) {
@@ -598,7 +609,8 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
}
} else {
while (*t || state) {
- _collate_lookup(t, &len, &pri, pass, &state);
+ _collate_lookup(lcc, t, &len, &pri, pass,
+ &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
@@ -608,7 +620,7 @@ _collate_sxfrm(const wchar_t *src, char *xf, size_t room)
continue;
}
- b = xfrm(buf, pri, pass);
+ b = xfrm(loc, buf, pri, pass);
want += b;
if (room) {
diff --git a/usr/src/lib/libc/port/locale/collate.h b/usr/src/lib/libc/port/locale/collate.h
index a175ce45bf..d3496be7cf 100644
--- a/usr/src/lib/libc/port/locale/collate.h
+++ b/usr/src/lib/libc/port/locale/collate.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systmes, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
@@ -31,6 +32,8 @@
#include <sys/types.h>
#include <limits.h>
+#include <locale.h>
+#include "localeimpl.h"
#define COLLATE_STR_LEN 24 /* should be 64-bit multiple */
#define COLLATE_VERSION "IllumosCollate2\n"
@@ -92,14 +95,30 @@ typedef struct collate_subst {
int32_t pri[COLLATE_STR_LEN];
} collate_subst_t;
-int _collate_load_tables(const char *);
-void _collate_lookup(const wchar_t *, int *, int *, int, int **);
-size_t _collate_wxfrm(const wchar_t *, wchar_t *, size_t);
-size_t _collate_sxfrm(const wchar_t *, char *, size_t);
-int _collate_range_cmp(wchar_t, wchar_t);
+struct lc_collate {
+ int lc_is_posix;
-extern int _collate_load_error;
-extern int _collate_substitute_nontrivial;
-extern collate_info_t *_collate_info;
+ uint8_t lc_directive_count;
+ uint8_t lc_directive[COLL_WEIGHTS_MAX];
+ int32_t lc_pri_count[COLL_WEIGHTS_MAX];
+ int32_t lc_flags;
+ int32_t lc_chain_count;
+ int32_t lc_large_count;
+ int32_t lc_subst_count[COLL_WEIGHTS_MAX];
+ int32_t lc_undef_pri[COLL_WEIGHTS_MAX];
+
+ collate_info_t *lc_info;
+ collate_char_t *lc_char_table;
+ collate_large_t *lc_large_table;
+ collate_chain_t *lc_chain_table;
+ collate_subst_t *lc_subst_table[COLL_WEIGHTS_MAX];
+};
+
+void _collate_lookup(const struct lc_collate *, const wchar_t *,
+ int *, int *, int, const int **);
+size_t _collate_wxfrm(const struct lc_collate *, const wchar_t *,
+ wchar_t *, size_t);
+size_t _collate_sxfrm(const wchar_t *, char *, size_t, locale_t);
+int _collate_range_cmp(wchar_t, wchar_t, locale_t);
#endif /* !_COLLATE_H_ */
diff --git a/usr/src/lib/libc/port/locale/collcmp.c b/usr/src/lib/libc/port/locale/collcmp.c
index 1b075f3c5f..b3ec74fd5e 100644
--- a/usr/src/lib/libc/port/locale/collcmp.c
+++ b/usr/src/lib/libc/port/locale/collcmp.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
@@ -30,15 +31,17 @@
#include "collate.h"
/*
- * Compare two characters using collate
+ * Compare two characters using collate - thread safe.
*/
int
-_collate_range_cmp(wchar_t c1, wchar_t c2)
+_collate_range_cmp(wchar_t c1, wchar_t c2, locale_t loc)
{
- static wchar_t s1[2], s2[2];
+ wchar_t s1[2], s2[2];
s1[0] = c1;
+ s1[1] = 0;
s2[0] = c2;
- return (wcscoll(s1, s2));
+ s2[1] = 0;
+ return (wcscoll_l(s1, s2, loc));
}
diff --git a/usr/src/lib/libc/port/locale/euc.c b/usr/src/lib/libc/port/locale/euc.c
index 03126946b7..36aad83ac2 100644
--- a/usr/src/lib/libc/port/locale/euc.c
+++ b/usr/src/lib/libc/port/locale/euc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
@@ -40,8 +41,8 @@
#include <wchar.h>
#include <sys/types.h>
#include <sys/euc.h>
-#include "runetype.h"
#include "mblocal.h"
+#include "lctype.h"
static size_t _EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -61,6 +62,7 @@ static size_t _EUC_KR_mbrtowc(wchar_t *_RESTRICT_KYWD,
static size_t _EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
size_t, mbstate_t *_RESTRICT_KYWD);
+
static size_t _EUC_CN_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
static size_t _EUC_JP_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
@@ -69,6 +71,33 @@ static size_t _EUC_KR_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
static size_t _EUC_TW_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+
+static size_t _EUC_CN_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_JP_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_KR_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_TW_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
+static size_t _EUC_CN_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_JP_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_KR_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
static int _EUC_mbsinit(const mbstate_t *);
typedef struct {
@@ -77,7 +106,7 @@ typedef struct {
int want;
} _EucState;
-static int
+int
_EUC_mbsinit(const mbstate_t *ps)
{
@@ -87,18 +116,17 @@ _EUC_mbsinit(const mbstate_t *ps)
/*
* EUC-CN uses CS0, CS1 and CS2 (4 bytes).
*/
-int
-_EUC_CN_init(_RuneLocale *rl)
+void
+_EUC_CN_init(struct lc_ctype *lct)
{
- __mbrtowc = _EUC_CN_mbrtowc;
- __wcrtomb = _EUC_CN_wcrtomb;
- __mbsinit = _EUC_mbsinit;
-
- _CurrentRuneLocale = rl;
-
- __ctype[520] = 4;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _EUC_CN_mbrtowc;
+ lct->lc_wcrtomb = _EUC_CN_wcrtomb;
+ lct->lc_mbsnrtowcs = _EUC_CN_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _EUC_CN_wcsnrtombs;
+ lct->lc_mbsinit = _EUC_mbsinit;
+
+ lct->lc_max_mblen = 4;
+ lct->lc_is_ascii = 0;
}
static size_t
@@ -109,27 +137,41 @@ _EUC_CN_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
}
static size_t
+_EUC_CN_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_CN_mbrtowc));
+}
+
+static size_t
_EUC_CN_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
mbstate_t *_RESTRICT_KYWD ps)
{
return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
}
+static size_t
+_EUC_CN_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_CN_wcrtomb));
+}
+
/*
* EUC-KR uses only CS0 and CS1.
*/
-int
-_EUC_KR_init(_RuneLocale *rl)
+void
+_EUC_KR_init(struct lc_ctype *lct)
{
- __mbrtowc = _EUC_KR_mbrtowc;
- __wcrtomb = _EUC_KR_wcrtomb;
- __mbsinit = _EUC_mbsinit;
-
- _CurrentRuneLocale = rl;
-
- __ctype[520] = 2;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _EUC_KR_mbrtowc;
+ lct->lc_wcrtomb = _EUC_KR_wcrtomb;
+ lct->lc_mbsnrtowcs = _EUC_KR_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _EUC_KR_wcsnrtombs;
+ lct->lc_mbsinit = _EUC_mbsinit;
+
+ lct->lc_max_mblen = 2;
+ lct->lc_is_ascii = 0;
}
static size_t
@@ -140,27 +182,41 @@ _EUC_KR_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
}
static size_t
+_EUC_KR_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_KR_mbrtowc));
+}
+
+static size_t
_EUC_KR_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
- mbstate_t *_RESTRICT_KYWD ps)
+ mbstate_t *_RESTRICT_KYWD ps)
{
return (_EUC_wcrtomb_impl(s, wc, ps, 0, 0, 0, 0));
}
+static size_t
+_EUC_KR_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_KR_wcrtomb));
+}
+
/*
* EUC-JP uses CS0, CS1, CS2, and CS3.
*/
-int
-_EUC_JP_init(_RuneLocale *rl)
+void
+_EUC_JP_init(struct lc_ctype *lct)
{
- __mbrtowc = _EUC_JP_mbrtowc;
- __wcrtomb = _EUC_JP_wcrtomb;
- __mbsinit = _EUC_mbsinit;
-
- _CurrentRuneLocale = rl;
-
- __ctype[520] = 3;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _EUC_JP_mbrtowc;
+ lct->lc_wcrtomb = _EUC_JP_wcrtomb;
+ lct->lc_mbsnrtowcs = _EUC_JP_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _EUC_JP_wcsnrtombs;
+ lct->lc_mbsinit = _EUC_mbsinit;
+
+ lct->lc_max_mblen = 3;
+ lct->lc_is_ascii = 0;
}
static size_t
@@ -171,51 +227,80 @@ _EUC_JP_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
}
static size_t
+_EUC_JP_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_JP_mbrtowc));
+}
+
+static size_t
_EUC_JP_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
mbstate_t *_RESTRICT_KYWD ps)
{
return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 2, SS3, 3));
}
+static size_t
+_EUC_JP_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_JP_wcrtomb));
+}
+
/*
* EUC-TW uses CS0, CS1, and CS2.
*/
-int
-_EUC_TW_init(_RuneLocale *rl)
+void
+_EUC_TW_init(struct lc_ctype *lct)
{
- __mbrtowc = _EUC_TW_mbrtowc;
- __wcrtomb = _EUC_TW_wcrtomb;
- __mbsinit = _EUC_mbsinit;
-
- _CurrentRuneLocale = rl;
-
- __ctype[520] = 4;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _EUC_TW_mbrtowc;
+ lct->lc_wcrtomb = _EUC_TW_wcrtomb;
+ lct->lc_mbsnrtowcs = _EUC_TW_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _EUC_TW_wcsnrtombs;
+ lct->lc_mbsinit = _EUC_mbsinit;
+
+ lct->lc_max_mblen = 4;
+ lct->lc_is_ascii = 0;
}
static size_t
_EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps)
{
return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
}
static size_t
+_EUC_TW_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_TW_mbrtowc));
+}
+
+static size_t
_EUC_TW_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
- mbstate_t *_RESTRICT_KYWD ps)
+ mbstate_t *_RESTRICT_KYWD ps)
{
return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
}
+static size_t
+_EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_TW_wcrtomb));
+}
+
/*
* Common EUC code.
*/
static size_t
_EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps,
- uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps,
+ uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
{
_EucState *es;
int i, want;
diff --git a/usr/src/lib/libc/port/locale/fgetwc.c b/usr/src/lib/libc/port/locale/fgetwc.c
index 6f86247132..282b65cebc 100644
--- a/usr/src/lib/libc/port/locale/fgetwc.c
+++ b/usr/src/lib/libc/port/locale/fgetwc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -35,22 +36,26 @@
#include <wchar.h>
#include "mblocal.h"
#include "stdiom.h"
+#include "localeimpl.h"
+#include "lctype.h"
/*
* Non-MT-safe version.
*/
wint_t
-_fgetwc_unlocked(FILE *fp)
+_fgetwc_unlocked_l(FILE *fp, locale_t loc)
{
wchar_t wc;
size_t nconv;
int c;
mbstate_t *statep;
+ const struct lc_ctype *lct;
if ((c = GETC(fp)) == EOF)
return (WEOF);
- if (MB_CUR_MAX == 1) {
+ lct = loc->ctype;
+ if (lct->lc_max_mblen == 1) {
/* Fast path for single-byte encodings. */
return ((wint_t)c);
}
@@ -61,7 +66,7 @@ _fgetwc_unlocked(FILE *fp)
}
do {
char x = (char)c;
- nconv = __mbrtowc(&wc, &x, 1, statep);
+ nconv = lct->lc_mbrtowc(&wc, &x, 1, statep);
if (nconv == (size_t)-1) {
break;
} else if (nconv == (size_t)-2) {
@@ -89,51 +94,64 @@ _fgetwc_unlocked(FILE *fp)
return (WEOF);
}
+wint_t
+_fgetwc_unlocked(FILE *fp)
+{
+ return (_fgetwc_unlocked_l(fp, uselocale(NULL)));
+}
+
/*
* MT safe version
*/
+#undef getwc
+#pragma weak getwc = fgetwc
wint_t
fgetwc(FILE *fp)
{
wint_t r;
rmutex_t *l;
+ locale_t loc = uselocale(NULL);
FLOCKFILE(l, fp);
- r = _fgetwc_unlocked(fp);
+ r = _fgetwc_unlocked_l(fp, loc);
FUNLOCKFILE(l);
return (r);
}
-#undef getwc
-wint_t
-getwc(FILE *fp)
-{
- return (getwc(fp));
-}
-
/*
* XPG5 version.
*/
+#undef __getwc_xpg5
+#pragma weak __getwc_xpg5 = __fgetwc_xpg5
wint_t
__fgetwc_xpg5(FILE *fp)
{
wint_t r;
rmutex_t *l;
+ locale_t loc = uselocale(NULL);
FLOCKFILE(l, fp);
if (GET_NO_MODE(fp))
_setorientation(fp, _WC_MODE);
- r = _fgetwc_unlocked(fp);
+ r = _fgetwc_unlocked_l(fp, loc);
FUNLOCKFILE(l);
return (r);
}
-#undef __getwc_xpg5
+#pragma weak getwc_l = fgetwc_l
wint_t
-__getwc_xpg5(FILE *fp)
+fgetwc_l(FILE *fp, locale_t loc)
{
- return (__fgetwc_xpg5(fp));
+ wint_t r;
+ rmutex_t *l;
+ FLOCKFILE(l, fp);
+ if (GET_NO_MODE(fp))
+ _setorientation(fp, _WC_MODE);
+ r = _fgetwc_unlocked_l(fp, loc);
+ FUNLOCKFILE(l);
+
+ return (r);
}
diff --git a/usr/src/lib/libc/port/locale/fnmatch.c b/usr/src/lib/libc/port/locale/fnmatch.c
index c218812bf2..ebea076036 100644
--- a/usr/src/lib/libc/port/locale/fnmatch.c
+++ b/usr/src/lib/libc/port/locale/fnmatch.c
@@ -31,6 +31,7 @@
*/
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -56,8 +57,9 @@
#include <limits.h>
#include <string.h>
#include <wchar.h>
+#include <xlocale.h>
#include <wctype.h>
-
+#include "localeimpl.h"
#include "collate.h"
#define EOS '\0'
@@ -66,23 +68,26 @@
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
-static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
+static int rangematch(const char *, wchar_t, int, char **, mbstate_t *,
+ locale_t);
static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
- mbstate_t);
+ mbstate_t, locale_t);
int
fnmatch(pattern, string, flags)
const char *pattern, *string;
int flags;
{
+ locale_t loc = uselocale(NULL);
static const mbstate_t initial = { 0 };
- return (fnmatch1(pattern, string, string, flags, initial, initial));
+ return (fnmatch1(pattern, string, string, flags, initial, initial,
+ loc));
}
static int
fnmatch1(const char *pattern, const char *string, const char *stringstart,
- int flags, mbstate_t patmbs, mbstate_t strmbs)
+ int flags, mbstate_t patmbs, mbstate_t strmbs, locale_t loc)
{
char *newp;
char c;
@@ -90,11 +95,11 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
size_t pclen, sclen;
for (;;) {
- pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
+ pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX, &patmbs, loc);
if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (FNM_NOMATCH);
pattern += pclen;
- sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs);
+ sclen = mbrtowc_l(&sc, string, MB_LEN_MAX, &strmbs, loc);
if (sclen == (size_t)-1 || sclen == (size_t)-2) {
sc = (unsigned char)*string;
sclen = 1;
@@ -145,10 +150,10 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
/* General case, use recursion. */
while (sc != EOS) {
if (!fnmatch1(pattern, string, stringstart,
- flags, patmbs, strmbs))
+ flags, patmbs, strmbs, loc))
return (0);
- sclen = mbrtowc(&sc, string, MB_LEN_MAX,
- &strmbs);
+ sclen = mbrtowc_l(&sc, string, MB_LEN_MAX,
+ &strmbs, loc);
if (sclen == (size_t)-1 ||
sclen == (size_t)-2) {
sc = (unsigned char)*string;
@@ -172,7 +177,7 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
return (FNM_NOMATCH);
switch (rangematch(pattern, sc, flags, &newp,
- &patmbs)) {
+ &patmbs, loc)) {
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
@@ -185,8 +190,8 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
- pclen = mbrtowc(&pc, pattern, MB_LEN_MAX,
- &patmbs);
+ pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX,
+ &patmbs, loc);
if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (FNM_NOMATCH);
if (pclen == 0)
@@ -200,7 +205,7 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
string += sclen;
else if ((flags & FNM_IGNORECASE) &&
- (towlower(pc) == towlower(sc)))
+ (towlower_l(pc, loc) == towlower_l(sc, loc)))
string += sclen;
else
return (FNM_NOMATCH);
@@ -212,12 +217,8 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
}
static int
-rangematch(pattern, test, flags, newp, patmbs)
- const char *pattern;
- wchar_t test;
- int flags;
- char **newp;
- mbstate_t *patmbs;
+rangematch(const char *pattern, wchar_t test, int flags, char **newp,
+ mbstate_t *patmbs, locale_t loc)
{
int negate, ok;
wchar_t c, c2;
@@ -235,7 +236,7 @@ rangematch(pattern, test, flags, newp, patmbs)
++pattern;
if (flags & FNM_IGNORECASE)
- test = towlower(test);
+ test = towlower_l(test, loc);
/*
* A right bracket shall lose its special meaning and represent
@@ -254,20 +255,21 @@ rangematch(pattern, test, flags, newp, patmbs)
return (RANGE_NOMATCH);
} else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
pattern++;
- pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
+ pclen = mbrtowc_l(&c, pattern, MB_LEN_MAX, patmbs, loc);
if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (RANGE_NOMATCH);
pattern += pclen;
if (flags & FNM_IGNORECASE)
- c = towlower(c);
+ c = towlower_l(c, loc);
if (*pattern == '-' && *(pattern + 1) != EOS &&
*(pattern + 1) != ']') {
if (*++pattern == '\\' && !(flags & FNM_NOESCAPE))
if (*pattern != EOS)
pattern++;
- pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs);
+ pclen = mbrtowc_l(&c2, pattern, MB_LEN_MAX, patmbs,
+ loc);
if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (RANGE_NOMATCH);
pattern += pclen;
@@ -275,12 +277,12 @@ rangematch(pattern, test, flags, newp, patmbs)
return (RANGE_ERROR);
if (flags & FNM_IGNORECASE)
- c2 = towlower(c2);
+ c2 = towlower_l(c2, loc);
- if (_collate_load_error ?
+ if (loc->collate->lc_is_posix ?
c <= test && test <= c2 :
- _collate_range_cmp(c, test) <= 0 &&
- _collate_range_cmp(test, c2) <= 0)
+ _collate_range_cmp(c, test, loc) <= 0 &&
+ _collate_range_cmp(test, c2, loc) <= 0)
ok = 1;
} else if (c == test)
ok = 1;
diff --git a/usr/src/lib/libc/port/locale/fputwc.c b/usr/src/lib/libc/port/locale/fputwc.c
index c02d7e251f..4c386adcdd 100644
--- a/usr/src/lib/libc/port/locale/fputwc.c
+++ b/usr/src/lib/libc/port/locale/fputwc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
@@ -72,8 +73,6 @@ __fputwc_impl(wchar_t wc, FILE *fp, int orient)
if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
/*
* Assume single-byte locale with no special encoding.
- * A more careful test would be to check
- * _CurrentRuneLocale->encoding.
*/
*buf = (unsigned char)wc;
len = 1;
diff --git a/usr/src/lib/libc/port/locale/gb18030.c b/usr/src/lib/libc/port/locale/gb18030.c
index eab6e332c2..232daade50 100644
--- a/usr/src/lib/libc/port/locale/gb18030.c
+++ b/usr/src/lib/libc/port/locale/gb18030.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
@@ -34,11 +35,11 @@
#include "lint.h"
#include <sys/types.h>
#include <errno.h>
-#include "runetype.h"
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD,
@@ -47,24 +48,30 @@ static size_t _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD,
static int _GB18030_mbsinit(const mbstate_t *);
static size_t _GB18030_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+static size_t _GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _GB18030_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
typedef struct {
int count;
uchar_t bytes[4];
} _GB18030State;
-int
-_GB18030_init(_RuneLocale *rl)
+void
+_GB18030_init(struct lc_ctype *lct)
{
- __mbrtowc = _GB18030_mbrtowc;
- __wcrtomb = _GB18030_wcrtomb;
- __mbsinit = _GB18030_mbsinit;
- _CurrentRuneLocale = rl;
- __ctype[520] = 4;
- charset_is_ascii = 0;
-
- return (0);
+ lct->lc_mbrtowc = _GB18030_mbrtowc;
+ lct->lc_wcrtomb = _GB18030_wcrtomb;
+ lct->lc_mbsinit = _GB18030_mbsinit;
+ lct->lc_mbsnrtowcs = _GB18030_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _GB18030_wcsnrtombs;
+ lct->lc_max_mblen = 4;
+ lct->lc_is_ascii = 0;
}
static int
@@ -221,3 +228,19 @@ ilseq:
errno = EILSEQ;
return ((size_t)-1);
}
+
+static size_t
+_GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+ mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB18030_mbrtowc));
+}
+
+static size_t
+_GB18030_wcsnrtombs(char *_RESTRICT_KYWD dst,
+ const wchar_t **_RESTRICT_KYWD src, size_t nwc, size_t len,
+ mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB18030_wcrtomb));
+}
diff --git a/usr/src/lib/libc/port/locale/gb2312.c b/usr/src/lib/libc/port/locale/gb2312.c
index 4658fe3944..a25af781b4 100644
--- a/usr/src/lib/libc/port/locale/gb2312.c
+++ b/usr/src/lib/libc/port/locale/gb2312.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
@@ -34,6 +35,7 @@
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -41,23 +43,30 @@ static size_t _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD,
static int _GB2312_mbsinit(const mbstate_t *);
static size_t _GB2312_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+static size_t _GB2312_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _GB2312_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
typedef struct {
int count;
uchar_t bytes[2];
} _GB2312State;
-int
-_GB2312_init(_RuneLocale *rl)
+void
+_GB2312_init(struct lc_ctype *lct)
{
- _CurrentRuneLocale = rl;
- __mbrtowc = _GB2312_mbrtowc;
- __wcrtomb = _GB2312_wcrtomb;
- __mbsinit = _GB2312_mbsinit;
- __ctype[520] = 2;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _GB2312_mbrtowc;
+ lct->lc_wcrtomb = _GB2312_wcrtomb;
+ lct->lc_mbsinit = _GB2312_mbsinit;
+ lct->lc_mbsnrtowcs = _GB2312_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _GB2312_wcsnrtombs;
+ lct->lc_max_mblen = 2;
+ lct->lc_is_ascii = 0;
}
static int
@@ -155,3 +164,19 @@ _GB2312_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
*s = wc & 0xff;
return (1);
}
+
+static size_t
+_GB2312_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+ mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB2312_mbrtowc));
+}
+
+static size_t
+_GB2312_wcsnrtombs(char *_RESTRICT_KYWD dst,
+ const wchar_t **_RESTRICT_KYWD src, size_t nwc, size_t len,
+ mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB2312_wcrtomb));
+}
diff --git a/usr/src/lib/libc/port/locale/gbk.c b/usr/src/lib/libc/port/locale/gbk.c
index 1d02c189a1..5c94b9954b 100644
--- a/usr/src/lib/libc/port/locale/gbk.c
+++ b/usr/src/lib/libc/port/locale/gbk.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
@@ -35,11 +36,11 @@
#include "lint.h"
#include <sys/types.h>
#include <errno.h>
-#include "runetype.h"
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _GBK_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -47,22 +48,27 @@ static size_t _GBK_mbrtowc(wchar_t *_RESTRICT_KYWD,
static int _GBK_mbsinit(const mbstate_t *);
static size_t _GBK_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+static size_t _GBK_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _GBK_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
typedef struct {
wchar_t ch;
} _GBKState;
-int
-_GBK_init(_RuneLocale *rl)
+void
+_GBK_init(struct lc_ctype *lct)
{
-
- __mbrtowc = _GBK_mbrtowc;
- __wcrtomb = _GBK_wcrtomb;
- __mbsinit = _GBK_mbsinit;
- _CurrentRuneLocale = rl;
- __ctype[520] = 2;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _GBK_mbrtowc;
+ lct->lc_wcrtomb = _GBK_wcrtomb;
+ lct->lc_mbsinit = _GBK_mbsinit;
+ lct->lc_mbsnrtowcs = _GBK_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _GBK_wcsnrtombs;
+ lct->lc_max_mblen = 2;
+ lct->lc_is_ascii = 0;
}
static int
@@ -164,3 +170,17 @@ _GBK_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
*s = wc & 0xff;
return (1);
}
+
+static size_t
+_GBK_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GBK_mbrtowc));
+}
+
+static size_t
+_GBK_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GBK_wcrtomb));
+}
diff --git a/usr/src/lib/libc/port/locale/isdigit.c b/usr/src/lib/libc/port/locale/isdigit.c
new file mode 100644
index 0000000000..c2cae89d93
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/isdigit.c
@@ -0,0 +1,91 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * This file contains the implementation of various functional forms
+ * of the ctype tests, specifically the required by ISO C. These are defined
+ * in the "C" (POSIX) locale.
+ */
+
+#include "lint.h"
+#include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "_ctype.h"
+#include "lctype.h"
+
+/*
+ * We are supplying functional forms, so make sure to suppress any macros
+ * we might have imported.
+ */
+
+/*
+ * Performance note: ASCII test is *much* faster, as we can avoid expensive
+ * function call overhead. This is the hot case, so we try to do that
+ * whenever possible. As far as we know, *every* encoding we support
+ * is a strict superset of ASCII. So we can make things faster by trying
+ * ASCII first, and only then falling to locale specific checks.
+ */
+
+static int
+isctype_l(int c, int mask, locale_t loc)
+{
+ return ((unsigned)c > 255 ? 0 : (loc->ctype->lc_ctype_mask[c] & mask));
+}
+
+#define ISTYPE_L(c, mask, loc) \
+ (isascii(c) ? (__ctype_mask[c] & (mask)) : isctype_l(c, mask, loc))
+
+#define ISTYPE(c, mask) ISTYPE_L(c, mask, uselocale(NULL))
+
+#define DEFN_ISTYPE(type, mask) \
+int \
+is##type##_l(int c, locale_t l) \
+{ \
+ return (ISTYPE_L(c, mask, l)); \
+} \
+ \
+int \
+is##type(int c) \
+{ \
+ return (ISTYPE(c, mask)); \
+}
+
+#undef isblank
+#undef isupper
+#undef islower
+#undef isdigit
+#undef isxdigit
+#undef isalpha
+#undef isalnum
+#undef isspace
+#undef iscntrl
+#undef isgraph
+#undef ispunct
+#undef isprint
+
+DEFN_ISTYPE(blank, _ISBLANK)
+DEFN_ISTYPE(upper, _ISUPPER)
+DEFN_ISTYPE(lower, _ISLOWER)
+DEFN_ISTYPE(digit, _ISDIGIT)
+DEFN_ISTYPE(xdigit, _ISXDIGIT)
+DEFN_ISTYPE(alpha, _ISALPHA)
+DEFN_ISTYPE(alnum, _ISALNUM)
+DEFN_ISTYPE(space, _ISSPACE)
+DEFN_ISTYPE(cntrl, _ISCNTRL)
+DEFN_ISTYPE(graph, _ISGRAPH)
+DEFN_ISTYPE(punct, _ISPUNCT)
+DEFN_ISTYPE(print, _ISPRINT)
diff --git a/usr/src/lib/libc/port/locale/iswctype.c b/usr/src/lib/libc/port/locale/iswctype.c
index c387a0cdae..1698113ace 100644
--- a/usr/src/lib/libc/port/locale/iswctype.c
+++ b/usr/src/lib/libc/port/locale/iswctype.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -38,178 +39,133 @@
#include "lint.h"
#include <wctype.h>
+#include <locale.h>
#include "runefile.h"
#include "runetype.h"
+#include "localeimpl.h"
#include "_ctype.h"
/*
- * We removed: iswascii, iswhexnumber, and iswnumber, as
- * these are not present on Solaris. Note that the standard requires
- * iswascii to be a macro, so it is defined in our headers.
+ * Note that the standard requires iswascii to be a macro, so it is defined
+ * in our headers.
*
- * We renamed (per Solaris) iswideogram, iswspecial, iswspecial to the
- * equivalent values without "w". We added a new isnumber, that looks
- * for non-ASCII numbers.
+ * We aliased (per Solaris) iswideogram, iswspecial, iswspecial to the
+ * equivalent values without "w". The Solaris specific function isenglish()
+ * is here, but does not get an isw* equivalent.
+ *
+ * Note that various code assumes that "numbers" (iswdigit, iswxdigit)
+ * only return true for characters in the portable set. While the assumption
+ * is not technically correct, it turns out that for all of our locales this
+ * is true. iswhexnumber is aliased to iswxdigit.
*/
static int
-__istype(wint_t c, unsigned int f)
+__istype_l(locale_t loc, wint_t c, unsigned int f)
{
unsigned int rt;
- /* Fast path for single byte locales */
if (c < 0 || c >= _CACHED_RUNES)
- rt = ___runetype(c);
+ rt = __runetype(loc->runelocale, c);
else
- rt = _CurrentRuneLocale->__runetype[c];
+ rt = loc->runelocale->__runetype[c];
return (rt & f);
}
static int
-__isctype(wint_t c, unsigned int f)
+__istype(wint_t c, unsigned int f)
{
- unsigned int rt;
+ return (__istype_l(uselocale(NULL), c, f));
+}
- /* Fast path for single byte locales */
- if (c < 0 || c >= _CACHED_RUNES)
- return (0);
- else
- rt = _CurrentRuneLocale->__runetype[c];
- return (rt & f);
+int
+iswctype_l(wint_t wc, wctype_t class, locale_t loc)
+{
+ if (iswascii(wc))
+ return (__ctype_mask[wc] & class);
+ return (__istype_l(loc, wc, class));
}
#undef iswctype
int
iswctype(wint_t wc, wctype_t class)
{
+ /*
+ * Note that we don't just call iswctype_l because we optimize for
+ * the iswascii() case, so that most of the time we have no need to
+ * call uselocale().
+ */
+ if (iswascii(wc))
+ return (__ctype_mask[wc] & class);
return (__istype(wc, class));
}
+/*
+ * This is a legacy version, baked into binaries.
+ */
#undef _iswctype
unsigned
_iswctype(wchar_t wc, int class)
{
+ if (iswascii(wc))
+ return (__ctype_mask[wc] & class);
return (__istype((wint_t)wc, (unsigned int)class));
}
-#undef iswalnum
-int
-iswalnum(wint_t wc)
-{
- return (__istype(wc, _CTYPE_A|_CTYPE_D));
-}
-
-#undef iswalpha
-int
-iswalpha(wint_t wc)
-{
- return (__istype(wc, _CTYPE_A));
-}
-
-#undef iswblank
-int
-iswblank(wint_t wc)
-{
- return (__istype(wc, _CTYPE_B));
-}
-
-#undef iswcntrl
-int
-iswcntrl(wint_t wc)
-{
- return (__istype(wc, _CTYPE_C));
-}
-
-#undef iswdigit
-int
-iswdigit(wint_t wc)
-{
- return (__isctype(wc, _CTYPE_D));
-}
-
-#undef iswgraph
-int
-iswgraph(wint_t wc)
-{
- return (__istype(wc, _CTYPE_G));
-}
+#define DEFN_ISWTYPE(type, mask) \
+int \
+isw##type##_l(wint_t wc, locale_t loc) \
+{ \
+ return (iswascii(wc) ? \
+ (__ctype_mask[wc] & (mask)) : \
+ __istype_l(loc, wc, mask)); \
+} \
+ \
+int \
+isw##type(wint_t wc) \
+{ \
+ return (iswascii(wc) ? \
+ (__ctype_mask[wc] & (mask)) : \
+ __istype(wc, mask)); \
+}
+
+/* kill off any macros */
+#undef iswalnum
+#undef iswalpha
+#undef iswblank
+
+DEFN_ISWTYPE(alnum, _CTYPE_A|_CTYPE_D)
+DEFN_ISWTYPE(alpha, _CTYPE_A)
+DEFN_ISWTYPE(blank, _CTYPE_B)
+DEFN_ISWTYPE(cntrl, _CTYPE_C)
+DEFN_ISWTYPE(digit, _CTYPE_D)
+DEFN_ISWTYPE(graph, _CTYPE_D)
+DEFN_ISWTYPE(lower, _CTYPE_L)
+DEFN_ISWTYPE(upper, _CTYPE_U)
+DEFN_ISWTYPE(print, _CTYPE_R)
+DEFN_ISWTYPE(punct, _CTYPE_P)
+DEFN_ISWTYPE(space, _CTYPE_S)
+DEFN_ISWTYPE(xdigit, _CTYPE_X)
+DEFN_ISWTYPE(ideogram, _CTYPE_I)
+DEFN_ISWTYPE(phonogram, _CTYPE_Q)
+DEFN_ISWTYPE(special, _CTYPE_T)
+DEFN_ISWTYPE(number, _CTYPE_N)
+
+
+#undef iswhexnumber
+#pragma weak iswhexnumber = iswxdigit
+#pragma weak iswhexnumber_l = iswxdigit_l
#undef isideogram
-int
-isideogram(wint_t wc)
-{
- return (__istype(wc, _CTYPE_I));
-}
-
-#undef iswlower
-int
-iswlower(wint_t wc)
-{
- return (__istype(wc, _CTYPE_L));
-}
+#pragma weak isideogram = iswideogram
#undef isphonogram
-int
-isphonogram(wint_t wc)
-{
- return (__istype(wc, _CTYPE_Q));
-}
-
-#undef iswprint
-int
-iswprint(wint_t wc)
-{
- return (__istype(wc, _CTYPE_R));
-}
-
-#undef iswpunct
-int
-iswpunct(wint_t wc)
-{
- return (__istype(wc, _CTYPE_P));
-}
-
-#undef iswspace
-int
-iswspace(wint_t wc)
-{
- return (__istype(wc, _CTYPE_S));
-}
-
-#undef iswupper
-int
-iswupper(wint_t wc)
-{
- return (__istype(wc, _CTYPE_U));
-}
-
-#undef iswxdigit
-int
-iswxdigit(wint_t wc)
-{
- return (__isctype(wc, _CTYPE_X));
-}
-
-#undef isenglish
-int
-isenglish(wint_t wc)
-{
- return (__istype(wc, _CTYPE_E));
-}
+#pragma weak isphonogram = iswphonogram
#undef isspecial
-int
-isspecial(wint_t wc)
-{
- return (__istype(wc, _CTYPE_T));
-}
+#pragma weak isspecial = iswspecial
#undef isnumber
-int
-isnumber(wint_t wc)
-{
- return (__istype(wc, _CTYPE_N));
-}
+#pragma weak isnumber = iswnumber
/*
* FreeBSD has iswrune() for use by external programs, and this is used by
@@ -228,6 +184,21 @@ __iswrune(wint_t wc)
* ctype values differently. We can't do that (ctype is baked into
* applications), but instead can just check if *any* bit is set in
* the ctype. Any bit being set indicates its a valid rune.
+ *
+ * NB: For ASCII all positions except NULL are runes.
*/
- return (__istype(wc, 0xffffffffU));
+ return (wc == 0 ? 0 : iswascii(wc) ? 1 : __istype(wc, 0xffffffffU));
+}
+
+/*
+ * isenglish is a Solaris legacy. No isw* equivalent. Note that this most
+ * likely doesn't work, as the locale data we have doesn't include it. It
+ * specifically is only valid for non-ASCII characters. We're not sure this
+ * is in actual use in the wild.
+ */
+#undef isenglish
+int
+isenglish(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_E));
}
diff --git a/usr/src/lib/libc/port/locale/lctype.h b/usr/src/lib/libc/port/locale/lctype.h
new file mode 100644
index 0000000000..25652da1d4
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/lctype.h
@@ -0,0 +1,66 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
+
+#ifndef _LCTYPE_H_
+#define _LCTYPE_H_
+
+#include <wchar.h>
+
+/* private LC_CTYPE related structures */
+
+/* encoding callbacks */
+struct lc_ctype {
+
+ size_t (*lc_mbrtowc)(wchar_t *_RESTRICT_KYWD,
+ const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+
+ int (*lc_mbsinit)(const mbstate_t *);
+
+ size_t (*lc_mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
+ size_t (*lc_wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
+ mbstate_t *_RESTRICT_KYWD);
+
+ size_t (*lc_wcsnrtombs)(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+
+ unsigned char lc_is_ascii;
+ unsigned char lc_max_mblen;
+
+ const int *lc_trans_upper;
+ const int *lc_trans_lower;
+ const unsigned *lc_ctype_mask;
+};
+
+/*
+ * Default implementation (C locale, i.e. ASCII).
+ */
+size_t __mbrtowc_ascii(wchar_t *_RESTRICT_KYWD,
+ const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+int __mbsinit_ascii(const mbstate_t *);
+size_t __mbsnrtowcs_ascii(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+ mbstate_t *_RESTRICT_KYWD);
+size_t __wcrtomb_ascii(char *_RESTRICT_KYWD, wchar_t,
+ mbstate_t *_RESTRICT_KYWD);
+size_t __wcsnrtombs_ascii(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD,
+ size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+
+
+#endif /* !_LCTYPE_H_ */
diff --git a/usr/src/lib/libc/port/locale/ldpart.c b/usr/src/lib/libc/port/locale/ldpart.c
index 6ae51a9423..e0dfc35c9b 100644
--- a/usr/src/lib/libc/port/locale/ldpart.c
+++ b/usr/src/lib/libc/port/locale/ldpart.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -37,13 +38,14 @@
#include <unistd.h>
#include <stdio.h>
+#include "libc.h"
#include "ldpart.h"
#include "setlocale.h"
static int split_lines(char *, const char *);
int
-__part_load_locale(const char *name, int *using_locale,
+__part_load_locale(const char *name,
char **locale_buf, const char *category_filename,
int locale_buf_size_max, int locale_buf_size_min,
const char **dst_localebuf)
@@ -55,20 +57,6 @@ __part_load_locale(const char *name, int *using_locale,
struct stat st;
size_t namesize, bufsize;
- /* 'name' must be already checked. */
- if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
- *using_locale = 0;
- return (_LDP_CACHE);
- }
-
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (*locale_buf != NULL && strcmp(name, *locale_buf) == 0) {
- *using_locale = 1;
- return (_LDP_CACHE);
- }
-
/*
* Slurp the locale file into the cache.
*/
@@ -88,7 +76,7 @@ __part_load_locale(const char *name, int *using_locale,
goto bad_locale;
}
bufsize = namesize + st.st_size;
- if ((lbuf = malloc(bufsize)) == NULL) {
+ if ((lbuf = libc_malloc(bufsize)) == NULL) {
errno = ENOMEM;
goto bad_locale;
}
@@ -117,14 +105,11 @@ __part_load_locale(const char *name, int *using_locale,
/*
* Record the successful parse in the cache.
*/
- if (*locale_buf != NULL)
- free(*locale_buf);
*locale_buf = lbuf;
for (p = *locale_buf, i = 0; i < num_lines; i++)
dst_localebuf[i] = (p += strlen(p) + 1);
for (i = num_lines; i < locale_buf_size_max; i++)
dst_localebuf[i] = NULL;
- *using_locale = 1;
return (_LDP_LOADED);
diff --git a/usr/src/lib/libc/port/locale/ldpart.h b/usr/src/lib/libc/port/locale/ldpart.h
index 040640237e..ba877de4b8 100644
--- a/usr/src/lib/libc/port/locale/ldpart.h
+++ b/usr/src/lib/libc/port/locale/ldpart.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
@@ -31,7 +32,7 @@
#define _LDP_ERROR (-1)
#define _LDP_CACHE 1
-int __part_load_locale(const char *, int *, char **, const char *,
+int __part_load_locale(const char *, char **, const char *,
int, int, const char **);
#endif /* !_LDPART_H_ */
diff --git a/usr/src/lib/libc/port/locale/lmessages.c b/usr/src/lib/libc/port/locale/lmessages.c
index 1cb83e0ac8..f15e143172 100644
--- a/usr/src/lib/libc/port/locale/lmessages.c
+++ b/usr/src/lib/libc/port/locale/lmessages.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -27,47 +28,54 @@
#include "lint.h"
#include <stddef.h>
+#include <errno.h>
#include "ldpart.h"
#include "lmessages.h"
+#include "localeimpl.h"
-#define LCMESSAGES_SIZE_FULL (sizeof (struct lc_messages_T) / sizeof (char *))
+#define LCMESSAGES_SIZE_FULL (sizeof (struct lc_messages) / sizeof (char *))
#define LCMESSAGES_SIZE_MIN \
- (offsetof(struct lc_messages_T, yesstr) / sizeof (char *))
+ (offsetof(struct lc_messages, yesstr) / sizeof (char *))
static char empty[] = "";
-static const struct lc_messages_T _C_messages_locale = {
+struct lc_messages lc_messages_posix = {
"^[yY]", /* yesexpr */
"^[nN]", /* noexpr */
"yes", /* yesstr */
"no" /* nostr */
};
-static struct lc_messages_T _messages_locale;
-static int _messages_using_locale;
-static char *_messages_locale_buf;
+struct locdata __posix_messages_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_messages_posix }
+};
-int
-__messages_load_locale(const char *name)
+struct locdata *
+__lc_messages_load(const char *name)
{
+ struct locdata *ldata;
+ struct lc_messages *lmsgs;
int ret;
- ret = __part_load_locale(name, &_messages_using_locale,
- &_messages_locale_buf, "LC_MESSAGES",
- LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
- (const char **)&_messages_locale);
- if (ret == _LDP_LOADED) {
- if (_messages_locale.yesstr == NULL)
- _messages_locale.yesstr = empty;
- if (_messages_locale.nostr == NULL)
- _messages_locale.nostr = empty;
+ if ((ldata = __locdata_alloc(name, sizeof (*lmsgs))) == NULL)
+ return (NULL);
+ lmsgs = ldata->l_data[0];
+
+ ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+ "LC_MESSAGES", LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
+ (const char **)lmsgs);
+
+ if (ret != _LDP_LOADED) {
+ __locdata_free(ldata);
+ errno = EINVAL;
+ return (NULL);
}
- return (ret);
-}
-struct lc_messages_T *
-__get_current_messages_locale(void)
-{
- return (_messages_using_locale ? &_messages_locale :
- (struct lc_messages_T *)&_C_messages_locale);
+ if (lmsgs->yesstr == NULL)
+ lmsgs->yesstr = empty;
+ if (lmsgs->nostr == NULL)
+ lmsgs->nostr = empty;
+
+ return (ldata);
}
diff --git a/usr/src/lib/libc/port/locale/lmessages.h b/usr/src/lib/libc/port/locale/lmessages.h
index e08198b810..a26bc224b9 100644
--- a/usr/src/lib/libc/port/locale/lmessages.h
+++ b/usr/src/lib/libc/port/locale/lmessages.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
@@ -27,14 +28,11 @@
#ifndef _LMESSAGES_H_
#define _LMESSAGES_H_
-struct lc_messages_T {
+struct lc_messages {
const char *yesexpr;
const char *noexpr;
const char *yesstr;
const char *nostr;
};
-struct lc_messages_T *__get_current_messages_locale(void);
-int __messages_load_locale(const char *);
-
#endif /* !_LMESSAGES_H_ */
diff --git a/usr/src/lib/libc/port/locale/lmonetary.c b/usr/src/lib/libc/port/locale/lmonetary.c
index 051a6b4d6c..623abc6281 100644
--- a/usr/src/lib/libc/port/locale/lmonetary.c
+++ b/usr/src/lib/libc/port/locale/lmonetary.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -29,20 +30,24 @@
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "libc.h"
#include "ldpart.h"
#include "lmonetary.h"
+#include "localeimpl.h"
-extern int __mlocale_changed;
extern const char *__fix_locale_grouping_str(const char *);
-#define LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary_T) / sizeof (char *))
+#define LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary) / sizeof (char *))
#define LCMONETARY_SIZE_MIN \
- (offsetof(struct lc_monetary_T, int_p_cs_precedes) / sizeof (char *))
+ (offsetof(struct lc_monetary, int_p_cs_precedes) / sizeof (char *))
static char empty[] = "";
static char numempty[] = { CHAR_MAX, '\0' };
-static const struct lc_monetary_T _C_monetary_locale = {
+struct lc_monetary lc_monetary_posix = {
empty, /* int_curr_symbol */
empty, /* currency_symbol */
empty, /* mon_decimal_point */
@@ -63,12 +68,14 @@ static const struct lc_monetary_T _C_monetary_locale = {
numempty, /* int_p_sep_by_space */
numempty, /* int_n_sep_by_space */
numempty, /* int_p_sign_posn */
- numempty /* int_n_sign_posn */
+ numempty, /* int_n_sign_posn */
+ empty /* crncystr */
};
-static struct lc_monetary_T _monetary_locale;
-static int _monetary_using_locale;
-static char *_monetary_locale_buf;
+struct locdata __posix_monetary_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_monetary_posix }
+};
static char
cnv(const char *str)
@@ -80,59 +87,93 @@ cnv(const char *str)
return ((char)i);
}
-int
-__monetary_load_locale(const char *name)
+struct locdata *
+__lc_monetary_load(const char *name)
{
int ret;
+ int clen;
+ struct lc_monetary *lmon;
+ struct locdata *ldata;
+
+ if ((ldata = __locdata_alloc(name, sizeof (*lmon))) == NULL) {
+ return (NULL);
+ }
+ lmon = ldata->l_data[0];
+
+ ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+ "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
+ (const char **)lmon);
+
+ if (ret != _LDP_LOADED) {
+ __locdata_free(ldata);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* special storage for currency string */
+ clen = strlen(lmon->currency_symbol) + 2;
+ ldata->l_data[2] = libc_malloc(clen);
+ lmon->crncystr = ldata->l_data[2];
- ret = __part_load_locale(name, &_monetary_using_locale,
- &_monetary_locale_buf, "LC_MONETARY",
- LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
- (const char **)&_monetary_locale);
- if (ret != _LDP_ERROR)
- __mlocale_changed = 1;
- if (ret == _LDP_LOADED) {
- _monetary_locale.mon_grouping =
- __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+ lmon->mon_grouping = __fix_locale_grouping_str(lmon->mon_grouping);
#define M_ASSIGN_CHAR(NAME) \
- (((char *)_monetary_locale.NAME)[0] = \
- cnv(_monetary_locale.NAME))
-
- M_ASSIGN_CHAR(int_frac_digits);
- M_ASSIGN_CHAR(frac_digits);
- M_ASSIGN_CHAR(p_cs_precedes);
- M_ASSIGN_CHAR(p_sep_by_space);
- M_ASSIGN_CHAR(n_cs_precedes);
- M_ASSIGN_CHAR(n_sep_by_space);
- M_ASSIGN_CHAR(p_sign_posn);
- M_ASSIGN_CHAR(n_sign_posn);
-
- /*
- * The six additional C99 international monetary formatting
- * parameters default to the national parameters when
- * reading FreeBSD LC_MONETARY data files.
- */
-#define M_ASSIGN_ICHAR(NAME) \
- if (_monetary_locale.int_##NAME == NULL) \
- _monetary_locale.int_##NAME = \
- _monetary_locale.NAME; \
- else \
- M_ASSIGN_CHAR(int_##NAME);
-
- M_ASSIGN_ICHAR(p_cs_precedes);
- M_ASSIGN_ICHAR(n_cs_precedes);
- M_ASSIGN_ICHAR(p_sep_by_space);
- M_ASSIGN_ICHAR(n_sep_by_space);
- M_ASSIGN_ICHAR(p_sign_posn);
- M_ASSIGN_ICHAR(n_sign_posn);
+ (((char *)lmon->NAME)[0] = cnv(lmon->NAME))
+
+ M_ASSIGN_CHAR(int_frac_digits);
+ M_ASSIGN_CHAR(frac_digits);
+ M_ASSIGN_CHAR(p_cs_precedes);
+ M_ASSIGN_CHAR(p_sep_by_space);
+ M_ASSIGN_CHAR(n_cs_precedes);
+ M_ASSIGN_CHAR(n_sep_by_space);
+ M_ASSIGN_CHAR(p_sign_posn);
+ M_ASSIGN_CHAR(n_sign_posn);
+
+ /*
+ * The six additional C99 international monetary formatting
+ * parameters default to the national parameters when
+ * reading FreeBSD LC_MONETARY data files.
+ */
+#define M_ASSIGN_ICHAR(NAME) \
+ if (lmon->int_##NAME == NULL) \
+ lmon->int_##NAME = lmon->NAME; \
+ else \
+ M_ASSIGN_CHAR(int_##NAME);
+
+ M_ASSIGN_ICHAR(p_cs_precedes);
+ M_ASSIGN_ICHAR(n_cs_precedes);
+ M_ASSIGN_ICHAR(p_sep_by_space);
+ M_ASSIGN_ICHAR(n_sep_by_space);
+ M_ASSIGN_ICHAR(p_sign_posn);
+ M_ASSIGN_ICHAR(n_sign_posn);
+
+ /*
+ * Now calculate the currency string (CRNCYSTR) for nl_langinfo.
+ * This is a legacy SUSv2 interface.
+ */
+ if ((lmon->p_cs_precedes[0] == lmon->n_cs_precedes[0]) &&
+ (lmon->currency_symbol[0] != '\0')) {
+ char sign = '\0';
+ switch (lmon->p_cs_precedes[0]) {
+ case 0:
+ sign = '-';
+ break;
+ case 1:
+ sign = '+';
+ break;
+ case CHAR_MAX:
+ /*
+ * Substitute currency string for radix character.
+ * To the best of my knowledge, no locale uses this.
+ */
+ if (strcmp(lmon->mon_decimal_point,
+ lmon->currency_symbol) == 0)
+ sign = '.';
+ break;
+ }
+ (void) snprintf(lmon->crncystr, clen, "%c%s", sign,
+ lmon->currency_symbol);
}
- return (ret);
-}
-struct lc_monetary_T *
-__get_current_monetary_locale(void)
-{
- return (_monetary_using_locale ? &_monetary_locale :
- (struct lc_monetary_T *)&_C_monetary_locale);
+ return (ldata);
}
diff --git a/usr/src/lib/libc/port/locale/lmonetary.h b/usr/src/lib/libc/port/locale/lmonetary.h
index ac7624fd30..5e97d64c10 100644
--- a/usr/src/lib/libc/port/locale/lmonetary.h
+++ b/usr/src/lib/libc/port/locale/lmonetary.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
@@ -27,7 +28,7 @@
#ifndef _LMONETARY_H_
#define _LMONETARY_H_
-struct lc_monetary_T {
+struct lc_monetary {
const char *int_curr_symbol;
const char *currency_symbol;
const char *mon_decimal_point;
@@ -49,9 +50,9 @@ struct lc_monetary_T {
const char *int_n_sep_by_space;
const char *int_p_sign_posn;
const char *int_n_sign_posn;
+ char *crncystr; /* nl_langinfo */
};
-struct lc_monetary_T *__get_current_monetary_locale(void);
int __monetary_load_locale(const char *);
#endif /* !_LMONETARY_H_ */
diff --git a/usr/src/lib/libc/port/locale/lnumeric.c b/usr/src/lib/libc/port/locale/lnumeric.c
index f887cf31ff..e5a1c08e9b 100644
--- a/usr/src/lib/libc/port/locale/lnumeric.c
+++ b/usr/src/lib/libc/port/locale/lnumeric.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore.
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -27,59 +28,57 @@
#include "lint.h"
#include <limits.h>
+#include <errno.h>
#include "ldpart.h"
#include "lnumeric.h"
-#include "../i18n/_locale.h"
+#include "localeimpl.h"
-extern int __nlocale_changed;
extern const char *__fix_locale_grouping_str(const char *);
-#define LCNUMERIC_SIZE (sizeof (struct lc_numeric_T) / sizeof (char *))
+#define LCNUMERIC_SIZE (sizeof (struct lc_numeric) / sizeof (char *))
static char numempty[] = { CHAR_MAX, '\0' };
-static const struct lc_numeric_T _C_numeric_locale = {
+struct lc_numeric lc_numeric_posix = {
".", /* decimal_point */
"", /* thousands_sep */
numempty /* grouping */
};
-static struct lc_numeric_T _numeric_locale;
-static int _numeric_using_locale;
-static char *_numeric_locale_buf;
+struct locdata __posix_numeric_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_numeric_posix }
+};
-int
-__numeric_load_locale(const char *name)
-{
- const struct lc_numeric_T *leg = &_C_numeric_locale;
+/*
+ * Return the locale's numeric locdata structure.
+ */
+struct locdata *
+__lc_numeric_load(const char *name)
+{
+ struct locdata *ldata;
+ struct lc_numeric *lnum;
int ret;
- ret = __part_load_locale(name, &_numeric_using_locale,
- &_numeric_locale_buf, "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE,
- (const char **)&_numeric_locale);
- if (ret == _LDP_ERROR)
- return (_LDP_ERROR);
+ if ((ldata = __locdata_alloc(name, sizeof (*lnum))) == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ lnum = ldata->l_data[0];
+
+ ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+ "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE, (const char **)lnum);
- __nlocale_changed = 1;
- if (ret == _LDP_LOADED) {
- /* Can't be empty according to C99 */
- if (*_numeric_locale.decimal_point == '\0')
- _numeric_locale.decimal_point =
- _C_numeric_locale.decimal_point;
- _numeric_locale.grouping =
- __fix_locale_grouping_str(_numeric_locale.grouping);
- leg = (const struct lc_numeric_T *)&_numeric_locale;
+ if (ret != _LDP_LOADED) {
+ __locdata_free(ldata);
+ return (NULL);
}
- /* This is Solaris legacy, required for ABI compatability */
- _numeric[0] = *leg->decimal_point;
- _numeric[1] = *leg->grouping;
- return (ret);
-}
-struct lc_numeric_T *
-__get_current_numeric_locale(void)
-{
- return (_numeric_using_locale ? &_numeric_locale :
- (struct lc_numeric_T *)&_C_numeric_locale);
+ /* Can't be empty according to C99 */
+ if (*lnum->decimal_point == '\0')
+ lnum->decimal_point = lc_numeric_posix.decimal_point;
+ lnum->grouping = __fix_locale_grouping_str(lnum->grouping);
+
+ return (ldata);
}
diff --git a/usr/src/lib/libc/port/locale/lnumeric.h b/usr/src/lib/libc/port/locale/lnumeric.h
index 74cac4dfa2..eda7fcb4cd 100644
--- a/usr/src/lib/libc/port/locale/lnumeric.h
+++ b/usr/src/lib/libc/port/locale/lnumeric.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
@@ -27,13 +28,10 @@
#ifndef _LNUMERIC_H_
#define _LNUMERIC_H_
-struct lc_numeric_T {
+struct lc_numeric {
const char *decimal_point;
const char *thousands_sep;
const char *grouping;
};
-struct lc_numeric_T *__get_current_numeric_locale(void);
-int __numeric_load_locale(const char *);
-
#endif /* !_LNUMERIC_H_ */
diff --git a/usr/src/lib/libc/port/locale/localeconv.c b/usr/src/lib/libc/port/locale/localeconv.c
index f2ad7f5559..0a36321870 100644
--- a/usr/src/lib/libc/port/locale/localeconv.c
+++ b/usr/src/lib/libc/port/locale/localeconv.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* Copyright (c) 1991, 1993
@@ -37,35 +38,37 @@
#include <locale.h>
#include "lmonetary.h"
#include "lnumeric.h"
+#include "localeimpl.h"
/*
- * The localeconv() function constructs a struct lconv from the current
- * monetary and numeric locales.
+ * Return the current locale conversion.
+ *
+ * Note that XPG7 specifically states that localeconv's return value may
+ * be invalidated if the application calls setlocale() or uselocale() within
+ * the same thread.
*
* Because localeconv() may be called many times (especially by library
* routines like printf() & strtod()), the approprate members of the
* lconv structure are computed only when the monetary or numeric
* locale has been changed.
*/
-int __mlocale_changed = 1;
-int __nlocale_changed = 1;
-
-/*
- * Return the current locale conversion.
- */
struct lconv *
localeconv(void)
{
- static struct lconv ret;
+ struct lconv *lconv;
+ locale_t loc;
+ struct lc_monetary *mptr;
+ struct lc_numeric *nptr;
+
+ loc = uselocale(NULL);
+ lconv = &loc->lconv;
- if (__mlocale_changed) {
- /* LC_MONETARY part */
- struct lc_monetary_T *mptr;
+ if (loc->loaded[LC_MONETARY] == 0) {
+ mptr = loc->locdata[LC_MONETARY]->l_data[0];
-#define M_ASSIGN_STR(NAME) (ret.NAME = (char *)mptr->NAME)
-#define M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0])
+#define M_ASSIGN_STR(NAME) (lconv->NAME = (char *)mptr->NAME)
+#define M_ASSIGN_CHAR(NAME) (lconv->NAME = mptr->NAME[0])
- mptr = __get_current_monetary_locale();
M_ASSIGN_STR(int_curr_symbol);
M_ASSIGN_STR(currency_symbol);
M_ASSIGN_STR(mon_decimal_point);
@@ -87,21 +90,19 @@ localeconv(void)
M_ASSIGN_CHAR(int_n_sep_by_space);
M_ASSIGN_CHAR(int_p_sign_posn);
M_ASSIGN_CHAR(int_n_sign_posn);
- __mlocale_changed = 0;
+ loc->loaded[LC_MONETARY] = 1;
}
- if (__nlocale_changed) {
- /* LC_NUMERIC part */
- struct lc_numeric_T *nptr;
+ if (loc->loaded[LC_NUMERIC] == 0) {
+ nptr = loc->locdata[LC_NUMERIC]->l_data[0];
-#define N_ASSIGN_STR(NAME) (ret.NAME = (char *)nptr->NAME)
+#define N_ASSIGN_STR(NAME) (lconv->NAME = (char *)nptr->NAME)
- nptr = __get_current_numeric_locale();
N_ASSIGN_STR(decimal_point);
N_ASSIGN_STR(thousands_sep);
N_ASSIGN_STR(grouping);
- __nlocale_changed = 0;
+ loc->loaded[LC_NUMERIC] = 1;
}
- return (&ret);
+ return (lconv);
}
diff --git a/usr/src/lib/libc/port/locale/localeimpl.c b/usr/src/lib/libc/port/locale/localeimpl.c
new file mode 100644
index 0000000000..a7be44a31b
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/localeimpl.c
@@ -0,0 +1,537 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * This file implements the 2008 newlocale and friends handling.
+ */
+
+#ifndef _LCONV_C99
+#define _LCONV_C99
+#endif
+
+#include "lint.h"
+#include <atomic.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include "libc.h"
+#include "mtlib.h"
+#include "tsd.h"
+#include "localeimpl.h"
+#include "lctype.h"
+
+/*
+ * Big Theory of Locales:
+ *
+ * (It is recommended that readers familiarize themselves with the POSIX
+ * 2008 (XPG Issue 7) specifications for locales, first.)
+ *
+ * Historically, we had a bunch of global variables that stored locale
+ * data. While this worked well, it limited applications to a single locale
+ * at a time. This doesn't work well in certain server applications.
+ *
+ * Issue 7, X/Open introduced the concept of a locale_t object, along with
+ * versions of functions that can take this object as a parameter, along
+ * with functions to clone and manipulate these locale objects. The new
+ * functions are named with a _l() suffix.
+ *
+ * Additionally uselocale() is introduced which can change the locale of
+ * of a single thread. However, setlocale() can still be used to change
+ * the global locale.
+ *
+ * In our implementation, we use libc's TSD to store the locale data that
+ * was previously global. We still have global data because some applications
+ * have had those global objects compiled into them. (Such applications will
+ * be unable to benefit from uselocale(), btw.) The legacy routines are
+ * reimplemented as wrappers that use the appropriate locale object by
+ * calling uselocale(). uselocale() when passed a NULL pointer returns the
+ * thread-specific locale object if one is present, or the global locale
+ * object otherwise. Note that once the TSD data is set, the only way
+ * to revert to the global locale is to pass the global locale LC_GLOBAL_LOCALE
+ * to uselocale().
+ *
+ * We are careful to minimize performance impact of multiple calls to
+ * uselocale() or setlocale() by using a cache of locale data whenever possible.
+ * As a consequence of this, applications that iterate over all possible
+ * locales will burn through a lot of virtual memory, but we find such
+ * applications rare. (locale -a might be an exception, but it is short lived.)
+ *
+ * Category data is never released (although enclosing locale objects might be),
+ * in order to guarantee thread-safety. Calling freelocale() on an object
+ * while it is in use by another thread is a programmer error (use-after-free)
+ * and we don't bother to note it further.
+ *
+ * Locale objects (global locales) established by setlocale() are also
+ * never freed (for MT safety), but we will save previous locale objects
+ * and reuse them when we can.
+ */
+
+typedef struct locdata *(*loadfn_t)(const char *);
+
+static const loadfn_t loaders[LC_ALL] = {
+ __lc_ctype_load,
+ __lc_numeric_load,
+ __lc_time_load,
+ __lc_collate_load,
+ __lc_monetary_load,
+ __lc_messages_load,
+};
+
+extern struct lc_monetary lc_monetary_posix;
+extern struct lc_numeric lc_numeric_posix;
+extern struct lc_messages lc_messages_posix;
+extern struct lc_time lc_time_posix;
+extern struct lc_ctype lc_ctype_posix;
+extern struct lc_collate lc_collate_posix;
+
+static struct locale posix_locale = {
+ /* locdata */
+ .locdata = {
+ &__posix_ctype_locdata,
+ &__posix_numeric_locdata,
+ &__posix_time_locdata,
+ &__posix_collate_locdata,
+ &__posix_monetary_locdata,
+ &__posix_messages_locdata,
+ },
+ .locname = "C",
+ .ctype = &lc_ctype_posix,
+ .numeric = &lc_numeric_posix,
+ .collate = &lc_collate_posix,
+ .monetary = &lc_monetary_posix,
+ .messages = &lc_messages_posix,
+ .time = &lc_time_posix,
+ .runelocale = &_DefaultRuneLocale,
+};
+
+locale_t ___global_locale = &posix_locale;
+
+locale_t
+__global_locale(void)
+{
+ return (___global_locale);
+}
+
+/*
+ * Category names for getenv() Note that this was modified
+ * for Solaris. See <iso/locale_iso.h>.
+ */
+#define NUM_CATS 7
+static char *categories[7] = {
+ "LC_CTYPE",
+ "LC_NUMERIC",
+ "LC_TIME",
+ "LC_COLLATE",
+ "LC_MONETARY",
+ "LC_MESSAGES",
+ "LC_ALL",
+};
+
+/*
+ * Prototypes.
+ */
+static const char *get_locale_env(int);
+static struct locdata *locdata_get(int, const const char *);
+static struct locdata *locdata_get_cache(int, const char *);
+static locale_t mklocname(locale_t);
+
+/*
+ * Some utility routines.
+ */
+
+struct locdata *
+__locdata_alloc(const char *name, size_t memsz)
+{
+ struct locdata *ldata;
+
+ if ((ldata = lmalloc(sizeof (*ldata))) == NULL) {
+ return (NULL);
+ }
+ if ((ldata->l_data[0] = libc_malloc(memsz)) == NULL) {
+ lfree(ldata, sizeof (*ldata));
+ errno = ENOMEM;
+ return (NULL);
+ }
+ (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
+
+ return (ldata);
+}
+
+/*
+ * Normally we never free locale data truly, but if we failed to load it
+ * for some reason, this routine is used to cleanup the partial mess.
+ */
+void
+__locdata_free(struct locdata *ldata)
+{
+ for (int i = 0; i < NLOCDATA; i++)
+ libc_free(ldata->l_data[i]);
+ if (ldata->l_map != NULL && ldata->l_map_len)
+ (void) munmap(ldata->l_map, ldata->l_map_len);
+ lfree(ldata, sizeof (*ldata));
+}
+
+/*
+ * It turns out that for performance reasons we would really like to
+ * cache the most recently referenced locale data to avoid wasteful
+ * loading from files.
+ */
+
+static struct locdata *cache_data[LC_ALL];
+static struct locdata *cat_data[LC_ALL];
+static mutex_t cache_lock = DEFAULTMUTEX;
+
+/*
+ * Returns the cached data if the locale name is the same. If not,
+ * returns NULL (cache miss). The locdata is returned with a hold on
+ * it, taken on behalf of the caller. The caller should drop the hold
+ * when it is finished.
+ */
+static struct locdata *
+locdata_get_cache(int category, const char *locname)
+{
+ struct locdata *loc;
+
+ if (category < 0 || category >= LC_ALL)
+ return (NULL);
+
+ /* Try cache first. */
+ lmutex_lock(&cache_lock);
+ loc = cache_data[category];
+
+ if ((loc != NULL) && (strcmp(loc->l_lname, locname) == 0)) {
+ lmutex_unlock(&cache_lock);
+ return (loc);
+ }
+
+ /*
+ * Failing that try previously loaded locales (linear search) --
+ * this could be optimized to a hash, but its unlikely that a single
+ * application will ever need to work with more than a few locales.
+ */
+ for (loc = cat_data[category]; loc != NULL; loc = loc->l_next) {
+ if (strcmp(locname, loc->l_lname) == 0) {
+ break;
+ }
+ }
+
+ /*
+ * Finally, if we still don't have one, try loading the locale
+ * data from the actual on-disk data.
+ *
+ * We drop the lock (libc wants to ensure no internal locks
+ * are held when we call other routines required to read from
+ * files, allocate memory, etc.) There is a small race here,
+ * but the consequences of the race are benign -- if multiple
+ * threads hit this at precisely the same point, we could
+ * wind up with duplicates of the locale data in the cache.
+ *
+ * This wastes the memory for an extra copy of the locale
+ * data, but there is no further harm beyond that. Its not
+ * worth the effort to recode this to something "safe"
+ * (which would require rescanning the list, etc.), given
+ * that this race will probably never actually occur.
+ */
+ if (loc == NULL) {
+ lmutex_unlock(&cache_lock);
+ loc = (*loaders[category])(locname);
+ lmutex_lock(&cache_lock);
+ if (loc != NULL)
+ (void) strlcpy(loc->l_lname, locname,
+ sizeof (loc->l_lname));
+ }
+
+ /*
+ * Assuming we got one, update the cache, and stick us on the list
+ * of loaded locale data. We insert into the head (more recent
+ * use is likely to win.)
+ */
+ if (loc != NULL) {
+ cache_data[category] = loc;
+ if (!loc->l_cached) {
+ loc->l_cached = 1;
+ loc->l_next = cat_data[category];
+ cat_data[category] = loc;
+ }
+ }
+
+ lmutex_unlock(&cache_lock);
+ return (loc);
+}
+
+/*
+ * Routine to get the locdata for a given category and locale.
+ * This includes retrieving it from cache, retrieving it from
+ * a file, etc.
+ */
+static struct locdata *
+locdata_get(int category, const char *locname)
+{
+ char scratch[ENCODING_LEN + 1];
+ char *slash;
+ int cnt;
+ int len;
+
+ if (locname == NULL || *locname == 0) {
+ locname = get_locale_env(category);
+ }
+
+ /*
+ * Extract the locale name for the category if it is a composite
+ * locale.
+ */
+ if ((slash = strchr(locname, '/')) != NULL) {
+ for (cnt = category; cnt && slash != NULL; cnt--) {
+ locname = slash + 1;
+ slash = strchr(locname, '/');
+ }
+ if (slash) {
+ len = slash - locname + 1;
+ if (len >= sizeof (scratch)) {
+ len = sizeof (scratch);
+ }
+ } else {
+ len = sizeof (scratch);
+ }
+ (void) strlcpy(scratch, locname, len);
+ locname = scratch;
+ }
+
+ if ((strcmp(locname, "C") == 0) || (strcmp(locname, "POSIX") == 0))
+ return (posix_locale.locdata[category]);
+
+ return (locdata_get_cache(category, locname));
+}
+
+/* tsd destructor */
+static void
+freelocptr(void *arg)
+{
+ locale_t *locptr = arg;
+ if (*locptr != NULL)
+ freelocale(*locptr);
+}
+
+static const char *
+get_locale_env(int category)
+{
+ const char *env;
+
+ /* 1. check LC_ALL. */
+ env = getenv(categories[LC_ALL]);
+
+ /* 2. check LC_* */
+ if (env == NULL || *env == '\0')
+ env = getenv(categories[category]);
+
+ /* 3. check LANG */
+ if (env == NULL || *env == '\0')
+ env = getenv("LANG");
+
+ /* 4. if none is set, fall to "C" */
+ if (env == NULL || *env == '\0')
+ env = "C";
+
+ return (env);
+}
+
+
+/*
+ * This routine is exposed via the MB_CUR_MAX macro. Note that legacy
+ * code will continue to use _ctype[520], but we prefer this function as
+ * it is the only way to get thread-specific information.
+ */
+unsigned char
+__mb_cur_max_l(locale_t loc)
+{
+ return (loc->ctype->lc_max_mblen);
+}
+
+unsigned char
+__mb_cur_max(void)
+{
+ return (__mb_cur_max_l(uselocale(NULL)));
+}
+
+/*
+ * Public interfaces.
+ */
+
+locale_t
+duplocale(locale_t src)
+{
+ locale_t loc;
+ int i;
+
+ loc = lmalloc(sizeof (*loc));
+ if (loc == NULL) {
+ return (NULL);
+ }
+ if (src == NULL) {
+ /* illumos extension: POSIX says LC_GLOBAL_LOCALE here */
+ src = ___global_locale;
+ }
+ for (i = 0; i < LC_ALL; i++) {
+ loc->locdata[i] = src->locdata[i];
+ loc->loaded[i] = 0;
+ }
+ loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
+ loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
+ loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
+ loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
+ loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
+ loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
+ loc->time = loc->locdata[LC_TIME]->l_data[0];
+ return (loc);
+}
+
+void
+freelocale(locale_t loc)
+{
+ /*
+ * We take extra care never to free a saved locale created by
+ * setlocale(). This shouldn't be strictly necessary, but a little
+ * extra safety doesn't hurt here.
+ */
+ if ((loc != NULL) && (loc != &posix_locale) && (!loc->on_list))
+ lfree(loc, sizeof (*loc));
+}
+
+locale_t
+newlocale(int catmask, const char *locname, locale_t base)
+{
+ locale_t loc;
+ int i, e;
+
+ if (catmask & ~(LC_ALL_MASK)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Technically passing LC_GLOBAL_LOCALE here is illegal,
+ * but we allow it.
+ */
+ if (base == NULL || base == ___global_locale) {
+ loc = duplocale(___global_locale);
+ } else {
+ loc = duplocale(base);
+ }
+ if (loc == NULL) {
+ return (NULL);
+ }
+
+ for (i = 0; i < LC_ALL; i++) {
+ struct locdata *ldata;
+ loc->loaded[i] = 0;
+ if (((1 << i) & catmask) == 0) {
+ /* Default to base locale if not overriding */
+ continue;
+ }
+ ldata = locdata_get(i, locname);
+ if (ldata == NULL) {
+ e = errno;
+ freelocale(loc);
+ errno = e;
+ return (NULL);
+ }
+ loc->locdata[i] = ldata;
+ }
+ loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
+ loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
+ loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
+ loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
+ loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
+ loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
+ loc->time = loc->locdata[LC_TIME]->l_data[0];
+ freelocale(base);
+
+ return (mklocname(loc));
+}
+
+locale_t
+uselocale(locale_t loc)
+{
+ locale_t lastloc = ___global_locale;
+ locale_t *locptr;
+
+ locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
+ /* Should never occur */
+ if (locptr == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (*locptr != NULL)
+ lastloc = *locptr;
+
+ /* Argument loc is NULL if we are just querying. */
+ if (loc != NULL) {
+ /*
+ * Set it to LC_GLOBAL_LOCAL to return to using
+ * the global locale (setlocale).
+ */
+ if (loc == ___global_locale) {
+ *locptr = NULL;
+ } else {
+ /* No validation of the provided locale at present */
+ *locptr = loc;
+ }
+ }
+
+ /*
+ * The caller is responsible for freeing, of course it would be
+ * gross error to call freelocale() on a locale object that is still
+ * in use.
+ */
+ return (lastloc);
+}
+
+static locale_t
+mklocname(locale_t loc)
+{
+ int composite = 0;
+
+ /* Look to see if any category is different */
+ for (int i = 1; i < LC_ALL; ++i) {
+ if (strcmp(loc->locdata[0]->l_lname,
+ loc->locdata[i]->l_lname) != 0) {
+ composite = 1;
+ break;
+ }
+ }
+
+ if (composite) {
+ /*
+ * Note ordering of these follows the numeric order,
+ * if the order is changed, then setlocale() will need
+ * to be changed as well.
+ */
+ (void) snprintf(loc->locname, sizeof (loc->locname),
+ "%s/%s/%s/%s/%s/%s",
+ loc->locdata[LC_CTYPE]->l_lname,
+ loc->locdata[LC_NUMERIC]->l_lname,
+ loc->locdata[LC_TIME]->l_lname,
+ loc->locdata[LC_COLLATE]->l_lname,
+ loc->locdata[LC_MONETARY]->l_lname,
+ loc->locdata[LC_MESSAGES]->l_lname);
+ } else {
+ (void) strlcpy(loc->locname, loc->locdata[LC_CTYPE]->l_lname,
+ sizeof (loc->locname));
+ }
+ return (loc);
+}
diff --git a/usr/src/lib/libc/port/locale/localeimpl.h b/usr/src/lib/libc/port/locale/localeimpl.h
new file mode 100644
index 0000000000..94045209f8
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/localeimpl.h
@@ -0,0 +1,107 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * This file implements the 2008 newlocale and friends handling. It is
+ * private to libc.
+ */
+#ifndef _LOCALEIMPL_H_
+#define _LOCALEIMPL_H_
+
+#ifndef _LCONV_C99
+#define _LCONV_C99 /* so we get all the extensions */
+#endif
+
+#include <sys/types.h>
+#include <locale.h>
+#include <xlocale.h>
+#include "setlocale.h"
+#include "runetype.h"
+
+/* private locale structures */
+
+/*
+ * Because some locale data is rather ahem.. large, we would like to keep
+ * reference counts on it. We create an abstract header (locdata) structure
+ * which keeps a point to the opaque per-category data, along with a reference
+ * count to it. To be threadsafe, we will use atomics when holding it or
+ * freeing it. (This only occurs when locale objects are created or destroyed,
+ * so there should be no performance impact on hot code paths. If your code
+ * uses locale_t creation/destruction on a hot code path, its broken. But
+ * even so, the atomic and reference counting will probably *greatly* improve
+ * your life as bootstrapping locale data from files is quite expensive.
+ */
+
+#define NLOCDATA 4
+struct locdata {
+ char l_lname[ENCODING_LEN+1]; /* locale name */
+ void *l_data[NLOCDATA]; /* storage area */
+ void *l_map; /* mapped file */
+ size_t l_map_len;
+ struct locdata *l_next; /* link cached list */
+ int l_cached; /* nonzero if cached */
+};
+
+
+struct locale {
+ struct locdata *locdata[LC_ALL];
+ struct locale *next;
+ int on_list; /* on linked list */
+ char locname[(ENCODING_LEN+1)*NLOCDATA + 1];
+
+ /*
+ * Convenience pointers.
+ */
+ const struct lc_ctype *ctype;
+ const struct lc_collate *collate;
+ const struct lc_messages *messages;
+ const struct lc_monetary *monetary;
+ const struct lc_numeric *numeric;
+ const struct lc_time *time;
+ const _RuneLocale *runelocale;
+
+ /*
+ * The loaded value is used for localeconv. In paticular, when
+ * when we change the value of one of the above categories, we will
+ * also need to update the lconv structure. The loaded bit indicates
+ * that the lconv structure is "current" for that category. It's
+ * sort of an "inverse dirty" bit.
+ */
+ int loaded[LC_ALL];
+ struct lconv lconv;
+};
+
+
+struct locdata *__locdata_alloc(const char *, size_t);
+void __locdata_free(struct locdata *);
+struct locdata *__locdata_get_cache(int, const char *);
+void __locdata_set_cache(int, struct locdata *);
+
+struct locdata *__lc_numeric_load(const char *name);
+struct locdata *__lc_monetary_load(const char *name);
+struct locdata *__lc_messages_load(const char *name);
+struct locdata *__lc_time_load(const char *name);
+struct locdata *__lc_ctype_load(const char *name);
+struct locdata *__lc_collate_load(const char *name);
+
+extern struct locdata __posix_numeric_locdata;
+extern struct locdata __posix_monetary_locdata;
+extern struct locdata __posix_messages_locdata;
+extern struct locdata __posix_time_locdata;
+extern struct locdata __posix_ctype_locdata;
+extern struct locdata __posix_collate_locdata;
+extern locale_t ___global_locale;
+
+#endif /* _LOCALEIMPL_H_ */
diff --git a/usr/src/lib/libc/port/locale/mblen.c b/usr/src/lib/libc/port/locale/mblen.c
index 454aeead6c..773daf7478 100644
--- a/usr/src/lib/libc/port/locale/mblen.c
+++ b/usr/src/lib/libc/port/locale/mblen.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -28,22 +29,29 @@
#include "lint.h"
#include <stdlib.h>
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
+#include "localeimpl.h"
int
-mblen(const char *s, size_t n)
+mblen_l(const char *s, size_t n, locale_t loc)
{
- static const mbstate_t initial = { 0 };
- static mbstate_t mbs;
+ mbstate_t mbs = { 0 };
size_t rval;
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
return (0);
}
- rval = __mbrtowc(NULL, s, n, &mbs);
+ rval = mbrtowc_l(NULL, s, n, &mbs, loc);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+
+int
+mblen(const char *s, size_t n)
+{
+ return (mblen_l(s, n, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/mblocal.h b/usr/src/lib/libc/port/locale/mblocal.h
index c1b0ff502a..4412bec7cb 100644
--- a/usr/src/lib/libc/port/locale/mblocal.h
+++ b/usr/src/lib/libc/port/locale/mblocal.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
@@ -29,43 +30,31 @@
#define _MBLOCAL_H_
#include "runetype.h"
+#include "lctype.h"
/*
* Rune initialization function prototypes.
*/
-int _none_init(_RuneLocale *);
-int _UTF8_init(_RuneLocale *);
-int _EUC_CN_init(_RuneLocale *);
-int _EUC_JP_init(_RuneLocale *);
-int _EUC_KR_init(_RuneLocale *);
-int _EUC_TW_init(_RuneLocale *);
-int _GB18030_init(_RuneLocale *);
-int _GB2312_init(_RuneLocale *);
-int _GBK_init(_RuneLocale *);
-int _BIG5_init(_RuneLocale *);
-int _MSKanji_init(_RuneLocale *);
-
-/*
- * Conversion function pointers for current encoding.
- */
-extern size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD,
+void _none_init(struct lc_ctype *);
+void _UTF8_init(struct lc_ctype *);
+void _EUC_CN_init(struct lc_ctype *);
+void _EUC_JP_init(struct lc_ctype *);
+void _EUC_KR_init(struct lc_ctype *);
+void _EUC_TW_init(struct lc_ctype *);
+void _GB18030_init(struct lc_ctype *);
+void _GB2312_init(struct lc_ctype *);
+void _GBK_init(struct lc_ctype *);
+void _BIG5_init(struct lc_ctype *);
+void _MSKanji_init(struct lc_ctype *);
+
+typedef size_t (*mbrtowc_pfn_t)(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
-extern int (*__mbsinit)(const mbstate_t *);
-extern size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
- const char **_RESTRICT_KYWD, size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-
-extern size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
+typedef size_t (*wcrtomb_pfn_t)(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
-
-extern size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD,
- const wchar_t **_RESTRICT_KYWD, size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-
-extern int charset_is_ascii;
-
size_t __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
- size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, size_t, mbstate_t *_RESTRICT_KYWD, mbrtowc_pfn_t);
size_t __wcsnrtombs_std(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
- size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, size_t, mbstate_t *_RESTRICT_KYWD, wcrtomb_pfn_t);
#define MIN(a, b) ((a) < (b) ? (a) : (b))
diff --git a/usr/src/lib/libc/port/locale/mbrlen.c b/usr/src/lib/libc/port/locale/mbrlen.c
index d01ac90b60..e2be484094 100644
--- a/usr/src/lib/libc/port/locale/mbrlen.c
+++ b/usr/src/lib/libc/port/locale/mbrlen.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -27,14 +28,23 @@
#include "lint.h"
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
size_t
-mbrlen(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps)
+mbrlen_l(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps,
+ locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__mbrtowc(NULL, s, n, ps));
+ return (mbrtowc_l(NULL, s, n, ps, loc));
+}
+
+size_t
+mbrlen(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (mbrlen_l(s, n, ps, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/mbrtowc.c b/usr/src/lib/libc/port/locale/mbrtowc.c
index 2d155d2bca..cd1e7b064f 100644
--- a/usr/src/lib/libc/port/locale/mbrtowc.c
+++ b/usr/src/lib/libc/port/locale/mbrtowc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -28,14 +29,23 @@
#include "lint.h"
#include <wchar.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
size_t
-mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+mbrtowc_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__mbrtowc(pwc, s, n, ps));
+ return (loc->ctype->lc_mbrtowc(pwc, s, n, ps));
+}
+
+size_t
+mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+ size_t n, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (mbrtowc_l(pwc, s, n, ps, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/mbsinit.c b/usr/src/lib/libc/port/locale/mbsinit.c
index 036f704260..ae956d0f15 100644
--- a/usr/src/lib/libc/port/locale/mbsinit.c
+++ b/usr/src/lib/libc/port/locale/mbsinit.c
@@ -1,37 +1,31 @@
/*
- * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2002-2004 Tim J. Robbins.
- * All rights reserved.
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
*
- * 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.
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
*/
#include "lint.h"
-#include <wchar.h>
-#include "mblocal.h"
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
int
-mbsinit(const mbstate_t *ps)
+mbsinit_l(const mbstate_t *s, locale_t loc)
{
+ return (loc->ctype->lc_mbsinit(s));
+}
- return (__mbsinit(ps));
+int
+mbsinit(const mbstate_t *s)
+{
+ return (mbsinit_l(s, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/mbsnrtowcs.c b/usr/src/lib/libc/port/locale/mbsnrtowcs.c
index 3ed93cfeb5..533b7776e0 100644
--- a/usr/src/lib/libc/port/locale/mbsnrtowcs.c
+++ b/usr/src/lib/libc/port/locale/mbsnrtowcs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -31,22 +32,32 @@
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
size_t
-mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
- size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+mbsnrtowcs_l(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__mbsnrtowcs(dst, src, nms, len, ps));
+ return (loc->ctype->lc_mbsnrtowcs(dst, src, nms, len, ps));
}
size_t
-__mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
{
+ return (mbsnrtowcs_l(dst, src, nms, len, ps, uselocale(NULL)));
+}
+
+size_t
+__mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+ size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps,
+ mbrtowc_pfn_t pmbrtowc)
+{
const char *s;
size_t nchr;
wchar_t wc;
@@ -57,7 +68,7 @@ __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
if (dst == NULL) {
for (;;) {
- if ((nb = __mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+ if ((nb = pmbrtowc(&wc, s, nms, ps)) == (size_t)-1)
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
else if (nb == 0 || nb == (size_t)-2)
@@ -70,7 +81,7 @@ __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
}
while (len-- > 0) {
- if ((nb = __mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+ if ((nb = pmbrtowc(dst, s, nms, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
diff --git a/usr/src/lib/libc/port/locale/mbsrtowcs.c b/usr/src/lib/libc/port/locale/mbsrtowcs.c
index 592a0e3c83..1f219e308e 100644
--- a/usr/src/lib/libc/port/locale/mbsrtowcs.c
+++ b/usr/src/lib/libc/port/locale/mbsrtowcs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -26,19 +27,24 @@
*/
#include "lint.h"
-#include <errno.h>
+#include <locale.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
+
+size_t
+mbsrtowcs_l(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+ size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
+{
+ return (loc->ctype->lc_mbsnrtowcs(dst, src, ULONG_MAX, len, ps));
+}
size_t
mbsrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
size_t len, mbstate_t *_RESTRICT_KYWD ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbsnrtowcs(dst, src, ULONG_MAX, len, ps));
+ return (mbsrtowcs_l(dst, src, len, ps, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/mbstowcs.c b/usr/src/lib/libc/port/locale/mbstowcs.c
index 343564ec93..1e853f2682 100644
--- a/usr/src/lib/libc/port/locale/mbstowcs.c
+++ b/usr/src/lib/libc/port/locale/mbstowcs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -29,10 +30,14 @@
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
+#include <locale.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
size_t
-mbstowcs(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s, size_t n)
+mbstowcs_l(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s,
+ size_t n, locale_t loc)
{
static const mbstate_t initial = { 0 };
mbstate_t mbs;
@@ -40,5 +45,11 @@ mbstowcs(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s, size_t n)
mbs = initial;
sp = s;
- return (__mbsnrtowcs(pwcs, &sp, ULONG_MAX, n, &mbs));
+ return (loc->ctype->lc_mbsnrtowcs(pwcs, &sp, ULONG_MAX, n, &mbs));
+}
+
+size_t
+mbstowcs(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s, size_t n)
+{
+ return (mbstowcs_l(pwcs, s, n, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/mbtowc.c b/usr/src/lib/libc/port/locale/mbtowc.c
index 66718fa90a..90dc2e6080 100644
--- a/usr/src/lib/libc/port/locale/mbtowc.c
+++ b/usr/src/lib/libc/port/locale/mbtowc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -28,22 +29,29 @@
#include "lint.h"
#include <stdlib.h>
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
int
-mbtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n)
+mbtowc_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n,
+ locale_t loc)
{
- static const mbstate_t initial = { 0 };
- static mbstate_t mbs;
+ mbstate_t mbs = { 0 };
size_t rval;
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
return (0);
}
- rval = __mbrtowc(pwc, s, n, &mbs);
+ rval = mbrtowc_l(pwc, s, n, &mbs, loc);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+
+int
+mbtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n)
+{
+ return (mbtowc_l(pwc, s, n, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/mskanji.c b/usr/src/lib/libc/port/locale/mskanji.c
index 1b6c2d0584..5d9b899aae 100644
--- a/usr/src/lib/libc/port/locale/mskanji.c
+++ b/usr/src/lib/libc/port/locale/mskanji.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
*
@@ -37,11 +38,11 @@
#include "lint.h"
#include <sys/types.h>
#include <errno.h>
-#include "runetype.h"
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -49,22 +50,28 @@ static size_t _MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD,
static int _MSKanji_mbsinit(const mbstate_t *);
static size_t _MSKanji_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
+static size_t _MSKanji_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+ const char **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
+static size_t _MSKanji_wcsnrtombs(char *_RESTRICT_KYWD,
+ const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+ mbstate_t *_RESTRICT_KYWD);
typedef struct {
wchar_t ch;
} _MSKanjiState;
-int
-_MSKanji_init(_RuneLocale *rl)
+void
+_MSKanji_init(struct lc_ctype *lct)
{
- __mbrtowc = _MSKanji_mbrtowc;
- __wcrtomb = _MSKanji_wcrtomb;
- __mbsinit = _MSKanji_mbsinit;
- _CurrentRuneLocale = rl;
- __ctype[520] = 2;
- charset_is_ascii = 0;
- return (0);
+ lct->lc_mbrtowc = _MSKanji_mbrtowc;
+ lct->lc_wcrtomb = _MSKanji_wcrtomb;
+ lct->lc_mbsnrtowcs = _MSKanji_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _MSKanji_wcsnrtombs;
+ lct->lc_mbsinit = _MSKanji_mbsinit;
+ lct->lc_max_mblen = 2;
+ lct->lc_is_ascii = 0;
}
static int
@@ -154,3 +161,19 @@ _MSKanji_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
*s++ = wc >> (i << 3);
return (len);
}
+
+static size_t
+_MSKanji_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+ const char **_RESTRICT_KYWD src, size_t nms,
+ size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _MSKanji_mbrtowc));
+}
+
+static size_t
+_MSKanji_wcsnrtombs(char *_RESTRICT_KYWD dst,
+ const wchar_t **_RESTRICT_KYWD src, size_t nwc,
+ size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _MSKanji_wcrtomb));
+}
diff --git a/usr/src/lib/libc/port/locale/nextwctype.c b/usr/src/lib/libc/port/locale/nextwctype.c
index 54a9d2a07b..53b0c163e8 100644
--- a/usr/src/lib/libc/port/locale/nextwctype.c
+++ b/usr/src/lib/libc/port/locale/nextwctype.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
@@ -28,20 +29,32 @@
#include "runetype.h"
#include <wchar.h>
#include <wctype.h>
+#include "localeimpl.h"
-wint_t
-__nextwctype(wint_t wc, wctype_t wct)
+/*
+ * nextwctype, while exposed on *BSD/MacOS X, is considered "consolidation
+ * private" for illumos. Hence, we keep the _l version static for now.
+ * If we decide to make this public, just remove the static keyword and
+ * put it in the headers and mapfile. (Should fix up the underscore prefix
+ * to __nextwctype() as well.)
+ */
+static wint_t
+nextwctype_l(wint_t wc, wctype_t wct, locale_t loc)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
- _RuneEntry *base, *re;
+ const _RuneLocale *rl;
+ const _RuneRange *rr;
+ const _RuneEntry *base, *re;
int noinc;
+ rl = loc->runelocale;
+ rr = &rl->__runetype_ext;
+
noinc = 0;
if (wc < _CACHED_RUNES) {
wc++;
while (wc < _CACHED_RUNES) {
- if (_CurrentRuneLocale->__runetype[wc] & wct)
+ if (rl->__runetype[wc] & wct)
return (wc);
wc++;
}
@@ -86,3 +99,12 @@ found:
}
return (-1);
}
+
+/*
+ * External, but consolidation private routine.
+ */
+wint_t
+__nextwctype(wint_t wc, wctype_t wct)
+{
+ return (nextwctype_l(wc, wct, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/nl_langinfo.c b/usr/src/lib/libc/port/locale/nl_langinfo.c
index 840f45ef45..01de8b78d7 100644
--- a/usr/src/lib/libc/port/locale/nl_langinfo.c
+++ b/usr/src/lib/libc/port/locale/nl_langinfo.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -36,33 +37,38 @@
#include "lmessages.h"
#include "lmonetary.h"
#include "timelocal.h"
+#include "localeimpl.h"
#define _REL(BASE) ((int)item-BASE)
-#define MONETARY (__get_current_monetary_locale())
-#define TIME (__get_current_time_locale())
-#define MESSAGES (__get_current_messages_locale())
-#define NUMERIC (__get_current_numeric_locale())
-
#pragma weak _nl_langinfo = nl_langinfo
char *
-nl_langinfo(nl_item item)
+nl_langinfo_l(nl_item item, locale_t loc)
{
char *ret, *s, *cs;
- static char *csym = NULL;
+ struct locdata *ldata;
+ const struct lc_monetary *lmon = loc->monetary;
+ const struct lc_numeric *lnum = loc->numeric;
+ const struct lc_messages *lmsgs = loc->messages;
+ const struct lc_time *ltime = loc->time;
switch (item) {
case CODESET:
ret = "";
/*
* The codeset is the suffix of a locale, for most it will
- * will be UTF-8, as in "en.UTF-8". Short form locales are
+ * will be UTF-8, as in "en_US.UTF-8". Short form locales are
* not supported. Note also that although FreeBSD uses
* US-ASCII, Solaris historically has reported "646" for the
* C locale.
+ *
+ * Note that this code will need to change if we ever support
+ * POSIX defined locale variants (suffixes with an @ sign)
*/
- if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
+ ldata = loc->locdata[LC_CTYPE];
+ s = ldata ? ldata->l_lname : NULL;
+ if (s != NULL) {
if ((cs = strchr(s, '.')) != NULL)
ret = cs + 1;
else if (strcmp(s, "C") == 0 || strcmp(s, "POSIX") == 0)
@@ -70,40 +76,40 @@ nl_langinfo(nl_item item)
}
break;
case D_T_FMT:
- ret = (char *)TIME->c_fmt;
+ ret = (char *)ltime->c_fmt;
break;
case D_FMT:
- ret = (char *)TIME->x_fmt;
+ ret = (char *)ltime->x_fmt;
break;
case T_FMT:
- ret = (char *)TIME->X_fmt;
+ ret = (char *)ltime->X_fmt;
break;
case T_FMT_AMPM:
- ret = (char *)TIME->ampm_fmt;
+ ret = (char *)ltime->ampm_fmt;
break;
case AM_STR:
- ret = (char *)TIME->am;
+ ret = (char *)ltime->am;
break;
case PM_STR:
- ret = (char *)TIME->pm;
+ ret = (char *)ltime->pm;
break;
case DAY_1: case DAY_2: case DAY_3:
case DAY_4: case DAY_5: case DAY_6: case DAY_7:
- ret = (char *)TIME->weekday[_REL(DAY_1)];
+ ret = (char *)ltime->weekday[_REL(DAY_1)];
break;
case ABDAY_1: case ABDAY_2: case ABDAY_3:
case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
- ret = (char *)TIME->wday[_REL(ABDAY_1)];
+ ret = (char *)ltime->wday[_REL(ABDAY_1)];
break;
case MON_1: case MON_2: case MON_3: case MON_4:
case MON_5: case MON_6: case MON_7: case MON_8:
case MON_9: case MON_10: case MON_11: case MON_12:
- ret = (char *)TIME->month[_REL(MON_1)];
+ ret = (char *)ltime->month[_REL(MON_1)];
break;
case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
- ret = (char *)TIME->mon[_REL(ABMON_1)];
+ ret = (char *)ltime->mon[_REL(ABMON_1)];
break;
case ERA:
/* XXX: need to be implemented */
@@ -126,64 +132,37 @@ nl_langinfo(nl_item item)
ret = "";
break;
case RADIXCHAR:
- ret = (char *)NUMERIC->decimal_point;
+ ret = (char *)lnum->decimal_point;
break;
case THOUSEP:
- ret = (char *)NUMERIC->thousands_sep;
+ ret = (char *)lnum->thousands_sep;
break;
case YESEXPR:
- ret = (char *)MESSAGES->yesexpr;
+ ret = (char *)lmsgs->yesexpr;
break;
case NOEXPR:
- ret = (char *)MESSAGES->noexpr;
+ ret = (char *)lmsgs->noexpr;
break;
/*
- * YESSTR and NOSTR items marked with LEGACY are available, but not
- * recomended by SUSv2 to be used in portable applications since
- * they're subject to remove in future specification editions.
+ * YESSTR and NOSTR items were removed from Issue 7. But
+ * older applications might still need them. Their use is
+ * discouraged.
*/
case YESSTR: /* LEGACY */
- ret = (char *)MESSAGES->yesstr;
+ ret = (char *)lmsgs->yesstr;
break;
case NOSTR: /* LEGACY */
- ret = (char *)MESSAGES->nostr;
+ ret = (char *)lmsgs->nostr;
break;
/*
* SUSv2 special formatted currency string
*/
case CRNCYSTR:
- ret = "";
- cs = (char *)MONETARY->currency_symbol;
- if (*cs != '\0') {
- char pos = localeconv()->p_cs_precedes;
-
- if (pos == localeconv()->n_cs_precedes) {
- char psn = '\0';
-
- if (pos == CHAR_MAX) {
- if (strcmp(cs,
- MONETARY->mon_decimal_point) == 0)
- psn = '.';
- } else
- psn = pos ? '-' : '+';
- if (psn != '\0') {
- int clen = strlen(cs);
- char *newc;
-
- newc = realloc(csym, clen + 2);
- if (newc != NULL) {
- free(csym);
- csym = newc;
- *csym = psn;
- (void) strcpy(csym + 1, cs);
- ret = csym;
- }
- }
- }
- }
+ ret = lmon->crncystr;
break;
+
case _DATE_FMT: /* Solaris specific extension */
- ret = (char *)TIME->date_fmt;
+ ret = (char *)ltime->date_fmt;
break;
/*
* Note that FreeBSD also had a private D_MD_ORDER, but that appears
@@ -194,3 +173,9 @@ nl_langinfo(nl_item item)
}
return (ret);
}
+
+char *
+nl_langinfo(nl_item item)
+{
+ return (nl_langinfo_l(item, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/none.c b/usr/src/lib/libc/port/locale/none.c
index 14b6d71abb..0511563cb1 100644
--- a/usr/src/lib/libc/port/locale/none.c
+++ b/usr/src/lib/libc/port/locale/none.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
@@ -41,40 +42,25 @@
#include <string.h>
#include <wchar.h>
#include <note.h>
-#include "runetype.h"
#include "mblocal.h"
-
-static size_t _none_mbrtowc(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
-
-static int _none_mbsinit(const mbstate_t *);
-static size_t _none_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
- const char **_RESTRICT_KYWD src, size_t nms, size_t len,
- mbstate_t *_RESTRICT_KYWD);
-static size_t _none_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
- mbstate_t *_RESTRICT_KYWD);
-static size_t _none_wcsnrtombs(char *_RESTRICT_KYWD,
- const wchar_t **_RESTRICT_KYWD,
- size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+#include "lctype.h"
/* setup defaults */
-int
-_none_init(_RuneLocale *rl)
+void
+_none_init(struct lc_ctype *lct)
{
- charset_is_ascii = 1;
-
- __mbrtowc = _none_mbrtowc;
- __mbsinit = _none_mbsinit;
- __mbsnrtowcs = _none_mbsnrtowcs;
- __wcrtomb = _none_wcrtomb;
- __wcsnrtombs = _none_wcsnrtombs;
- _CurrentRuneLocale = rl;
- return (0);
+ lct->lc_is_ascii = 1;
+ lct->lc_mbrtowc = __mbrtowc_ascii;
+ lct->lc_mbsinit = __mbsinit_ascii;
+ lct->lc_mbsnrtowcs = __mbsnrtowcs_ascii;
+ lct->lc_wcrtomb = __wcrtomb_ascii;
+ lct->lc_wcsnrtombs = __wcsnrtombs_ascii;
+ lct->lc_max_mblen = 1;
}
-static int
-_none_mbsinit(const mbstate_t *unused)
+int
+__mbsinit_ascii(const mbstate_t *unused)
{
_NOTE(ARGUNUSED(unused));
@@ -85,8 +71,8 @@ _none_mbsinit(const mbstate_t *unused)
return (1);
}
-static size_t
-_none_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+size_t
+__mbrtowc_ascii(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
size_t n, mbstate_t *_RESTRICT_KYWD unused)
{
_NOTE(ARGUNUSED(unused));
@@ -102,8 +88,8 @@ _none_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
return (*s == '\0' ? 0 : 1);
}
-static size_t
-_none_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
+size_t
+__wcrtomb_ascii(char *_RESTRICT_KYWD s, wchar_t wc,
mbstate_t *_RESTRICT_KYWD unused)
{
_NOTE(ARGUNUSED(unused));
@@ -119,8 +105,8 @@ _none_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
return (1);
}
-static size_t
-_none_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+size_t
+__mbsnrtowcs_ascii(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD unused)
{
const char *s;
@@ -146,8 +132,8 @@ _none_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
return (nchr);
}
-static size_t
-_none_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+size_t
+__wcsnrtombs_ascii(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD unused)
{
const wchar_t *s;
@@ -181,19 +167,3 @@ _none_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
*src = s;
return (nchr);
}
-
-/* setup defaults */
-
-size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD) = _none_mbrtowc;
-
-int (*__mbsinit)(const mbstate_t *) = _none_mbsinit;
-
-size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
- size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_mbsnrtowcs;
-
-size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t, mbstate_t *_RESTRICT_KYWD) =
- _none_wcrtomb;
-
-size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
- size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_wcsnrtombs;
diff --git a/usr/src/lib/libc/port/locale/regcomp.c b/usr/src/lib/libc/port/locale/regcomp.c
index f67e5cadf7..f3027d8a02 100644
--- a/usr/src/lib/libc/port/locale/regcomp.c
+++ b/usr/src/lib/libc/port/locale/regcomp.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
@@ -725,6 +726,7 @@ p_b_term(struct parse *p, cset *cs)
char c;
wint_t start, finish;
wint_t i;
+ locale_t loc = uselocale(NULL);
/* classify what we've got */
switch ((MORE()) ? PEEK() : '\0') {
@@ -772,16 +774,18 @@ p_b_term(struct parse *p, cset *cs)
if (start == finish)
CHadd(p, cs, start);
else {
- if (_collate_load_error) {
+ if (loc->collate->lc_is_posix) {
(void) REQUIRE((uch)start <= (uch)finish,
REG_ERANGE);
CHaddrange(p, cs, start, finish);
} else {
(void) REQUIRE(_collate_range_cmp(start,
- finish) <= 0, REG_ERANGE);
+ finish, loc) <= 0, REG_ERANGE);
for (i = 0; i <= UCHAR_MAX; i++) {
- if (_collate_range_cmp(start, i) <= 0 &&
- _collate_range_cmp(i, finish) <= 0)
+ if (_collate_range_cmp(start, i, loc)
+ <= 0 &&
+ _collate_range_cmp(i, finish, loc)
+ <= 0)
CHadd(p, cs, i);
}
}
@@ -1367,6 +1371,7 @@ findmust(struct parse *p, struct re_guts *g)
char buf[MB_LEN_MAX];
size_t clen;
mbstate_t mbs;
+ locale_t loc = uselocale(NULL);
/* avoid making error situations worse */
if (p->error != 0)
@@ -1378,7 +1383,7 @@ findmust(struct parse *p, struct re_guts *g)
* UTF-8 (see RFC 3629).
*/
if (MB_CUR_MAX > 1 &&
- strcmp(_CurrentRuneLocale->__encoding, "UTF-8") != 0)
+ strcmp(loc->runelocale->__encoding, "UTF-8") != 0)
return;
/* find the longest OCHAR sequence in strip */
diff --git a/usr/src/lib/libc/port/locale/rune.c b/usr/src/lib/libc/port/locale/rune.c
index 545682691e..38e32d42ba 100644
--- a/usr/src/lib/libc/port/locale/rune.c
+++ b/usr/src/lib/libc/port/locale/rune.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -39,14 +40,16 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "libc.h"
#include "runetype.h"
#include "runefile.h"
-_RuneLocale *_Read_RuneMagi(FILE *);
-
_RuneLocale *
-_Read_RuneMagi(FILE *fp)
+_Read_RuneMagi(const char *fname)
{
char *fdata, *data;
void *lastp;
@@ -61,31 +64,30 @@ _Read_RuneMagi(FILE *fp)
_FileRuneEntry *maplower_ext_ranges;
_FileRuneEntry *mapupper_ext_ranges;
int runetype_ext_len = 0;
+ int fd;
- if (fstat(fileno(fp), &sb) < 0)
- return (NULL);
-
- if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
+ if ((fd = open(fname, O_RDONLY)) < 0) {
errno = EINVAL;
return (NULL);
}
- if ((fdata = malloc(sb.st_size)) == NULL)
+ if (fstat(fd, &sb) < 0) {
+ (void) close(fd);
+ errno = EINVAL;
return (NULL);
+ }
- errno = 0;
- rewind(fp); /* Someone might have read the magic number once already */
- if (errno) {
- saverr = errno;
- free(fdata);
- errno = saverr;
+ if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
+ (void) close(fd);
+ errno = EINVAL;
return (NULL);
}
- if (fread(fdata, sb.st_size, 1, fp) != 1) {
- saverr = errno;
- free(fdata);
- errno = saverr;
+
+ fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ (void) close(fd);
+ if (fdata == NULL) {
+ errno = EINVAL;
return (NULL);
}
@@ -95,33 +97,25 @@ _Read_RuneMagi(FILE *fp)
variable = frl + 1;
if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
runetype_ext_ranges = (_FileRuneEntry *)variable;
variable = runetype_ext_ranges + frl->runetype_ext_nranges;
if (variable > lastp) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
maplower_ext_ranges = (_FileRuneEntry *)variable;
variable = maplower_ext_ranges + frl->maplower_ext_nranges;
if (variable > lastp) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
mapupper_ext_ranges = (_FileRuneEntry *)variable;
variable = mapupper_ext_ranges + frl->mapupper_ext_nranges;
if (variable > lastp) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
frr = runetype_ext_ranges;
@@ -134,30 +128,26 @@ _Read_RuneMagi(FILE *fp)
variable = types + len;
runetype_ext_len += len;
if (variable > lastp) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
}
}
if ((char *)variable + frl->variable_len > (char *)lastp) {
- free(fdata);
- errno = EINVAL;
- return (NULL);
+ goto invalid;
}
/*
* Convert from disk format to host format.
*/
- data = malloc(sizeof (_RuneLocale) +
+ data = libc_malloc(sizeof (_RuneLocale) +
(frl->runetype_ext_nranges + frl->maplower_ext_nranges +
frl->mapupper_ext_nranges) * sizeof (_RuneEntry) +
runetype_ext_len * sizeof (*rr->__types) +
frl->variable_len);
if (data == NULL) {
saverr = errno;
- free(fdata);
+ (void) munmap(fdata, sb.st_size);
errno = saverr;
return (NULL);
}
@@ -229,7 +219,7 @@ _Read_RuneMagi(FILE *fp)
}
(void) memcpy(rl->__variable, variable, rl->__variable_len);
- free(fdata);
+ (void) munmap(fdata, sb.st_size);
/*
* Go out and zero pointers that should be zero.
@@ -247,4 +237,9 @@ _Read_RuneMagi(FILE *fp)
rl->__mapupper_ext.__ranges = NULL;
return (rl);
+
+invalid:
+ (void) munmap(fdata, sb.st_size);
+ errno = EINVAL;
+ return (NULL);
}
diff --git a/usr/src/lib/libc/port/locale/runetype.c b/usr/src/lib/libc/port/locale/runetype.c
index 3a978fe038..102f483449 100644
--- a/usr/src/lib/libc/port/locale/runetype.c
+++ b/usr/src/lib/libc/port/locale/runetype.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -37,11 +38,11 @@
#include "runetype.h"
unsigned int
-___runetype(__ct_rune_t c)
+__runetype(const _RuneLocale *rl, __ct_rune_t c)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
- _RuneEntry *base, *re;
+ const _RuneRange *rr = &rl->__runetype_ext;
+ const _RuneEntry *base, *re;
if (c < 0 || c == EOF)
return (0L);
diff --git a/usr/src/lib/libc/port/locale/runetype.h b/usr/src/lib/libc/port/locale/runetype.h
index 9d5648496c..3abdd1afa9 100644
--- a/usr/src/lib/libc/port/locale/runetype.h
+++ b/usr/src/lib/libc/port/locale/runetype.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -110,7 +111,7 @@ typedef struct {
typedef struct {
char __magic[8]; /* Magic saying what version we are */
- char __encoding[32]; /* ASCII name of this encoding */
+ char __encoding[32]; /* ASCII name of encoding */
unsigned int __runetype[_CACHED_RUNES];
__rune_t __maplower[_CACHED_RUNES];
@@ -132,6 +133,7 @@ typedef struct {
#define _RUNE_MAGIC_1 "RuneMagi" /* Indicates version 0 of RuneLocale */
extern _RuneLocale _DefaultRuneLocale;
-extern _RuneLocale *_CurrentRuneLocale;
+
+unsigned int __runetype(const _RuneLocale *, int);
#endif /* !_RUNETYPE_H_ */
diff --git a/usr/src/lib/libc/port/locale/setlocale.c b/usr/src/lib/libc/port/locale/setlocale.c
index 8cf7f88f98..e0a56ef8de 100644
--- a/usr/src/lib/libc/port/locale/setlocale.c
+++ b/usr/src/lib/libc/port/locale/setlocale.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1996 - 2002 FreeBSD Project
* Copyright (c) 1991, 1993
@@ -41,289 +42,144 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <alloca.h>
#include <stdio.h>
+#include "mtlib.h"
#include "collate.h"
-#include "lmonetary.h" /* for __monetary_load_locale() */
-#include "lnumeric.h" /* for __numeric_load_locale() */
-#include "lmessages.h" /* for __messages_load_locale() */
+#include "lnumeric.h" /* for struct lc_numeric */
+#include "lctype.h" /* for struct lc_ctype */
#include "setlocale.h"
-#include "ldpart.h"
-#include "timelocal.h" /* for __time_load_locale() */
#include "../i18n/_loc_path.h"
-
-/*
- * Category names for getenv() Note that this was modified
- * for Solaris. See <iso/locale_iso.h>.
- */
-#define NUM_CATS 7
-static char *categories[7] = {
- "LC_CTYPE",
- "LC_NUMERIC",
- "LC_TIME",
- "LC_COLLATE",
- "LC_MONETARY",
- "LC_MESSAGES",
- "LC_ALL",
-};
-
-/*
- * Current locales for each category
- */
-static char current_categories[NUM_CATS][ENCODING_LEN + 1] = {
- "C",
- "C",
- "C",
- "C",
- "C",
- "C",
- "C",
-};
+#include "localeimpl.h"
+#include "../i18n/_locale.h"
/*
* Path to locale storage directory. See ../i18n/_loc_path.h
*/
char *_PathLocale = _DFLT_LOC_PATH;
-/*
- * The locales we are going to try and load
- */
-static char new_categories[NUM_CATS][ENCODING_LEN + 1];
-static char saved_categories[NUM_CATS][ENCODING_LEN + 1];
-static char current_locale_string[NUM_CATS * (ENCODING_LEN + 1 + 1)];
+static char *current_locale(locale_t, int);
+static void install_legacy(locale_t, int);
-static char *currentlocale(void);
-static char *loadlocale(int);
-static const char *__get_locale_env(int);
+static mutex_t setlocale_lock = DEFAULTMUTEX;
+static locale_t setlocale_list = NULL;
char *
-setlocale(int category, const char *locale)
+setlocale(int category, const char *locname)
{
- int i, j, saverr;
- const char *env, *r;
+ locale_t loc;
+ locale_t srch;
+ int mask;
- if (category < 0 || category >= NUM_CATS) {
+ if (category < 0 || category > LC_ALL) {
errno = EINVAL;
return (NULL);
}
- if (locale == NULL)
- return (category != LC_ALL ?
- current_categories[category] : currentlocale());
-
- /*
- * Default to the current locale for everything.
- */
- for (i = 0; i < NUM_CATS; ++i)
- (void) strcpy(new_categories[i], current_categories[i]);
-
- /*
- * Now go fill up new_categories from the locale argument
- */
- if (!*locale) {
- if (category == LC_ALL) {
- for (i = 0; i < NUM_CATS; ++i) {
- if (i == LC_ALL)
- continue;
- env = __get_locale_env(i);
- if (strlen(env) > ENCODING_LEN) {
- errno = EINVAL;
- return (NULL);
- }
- (void) strcpy(new_categories[i], env);
- }
- } else {
- env = __get_locale_env(category);
- if (strlen(env) > ENCODING_LEN) {
- errno = EINVAL;
- return (NULL);
- }
- (void) strcpy(new_categories[category], env);
- }
- } else if (category != LC_ALL) {
- if (strlen(locale) > ENCODING_LEN) {
- errno = EINVAL;
- return (NULL);
- }
- (void) strcpy(new_categories[category], locale);
- } else {
- if ((r = strchr(locale, '/')) == NULL) {
- if (strlen(locale) > ENCODING_LEN) {
- errno = EINVAL;
- return (NULL);
- }
- for (i = 0; i < NUM_CATS; ++i)
- (void) strcpy(new_categories[i], locale);
- } else {
- char *buf;
- char *save;
-
- buf = alloca(strlen(locale) + 1);
- (void) strcpy(buf, locale);
-
- save = NULL;
- r = strtok_r(buf, "/", &save);
- for (i = 0; i < NUM_CATS; i++) {
- if (i == LC_ALL)
- continue;
- if (r == NULL) {
- /*
- * Composite Locale is inadequately
- * specified! (Or with empty fields.)
- * The old code would fill fields
- * out from the last one, but I think
- * this is suboptimal.
- */
- errno = EINVAL;
- return (NULL);
- }
- (void) strlcpy(new_categories[i], r,
- ENCODING_LEN);
- r = strtok_r(NULL, "/", &save);
- }
- if (r != NULL) {
- /*
- * Too many components - we had left over
- * data in the LC_ALL. It is malformed.
- */
- errno = EINVAL;
- return (NULL);
- }
- }
- }
+ if (locname == NULL)
+ return (current_locale(___global_locale, category));
- if (category != LC_ALL)
- return (loadlocale(category));
+ mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
- for (i = 0; i < NUM_CATS; ++i) {
- (void) strcpy(saved_categories[i], current_categories[i]);
- if (i == LC_ALL)
- continue;
- if (loadlocale(i) == NULL) {
- saverr = errno;
- for (j = 0; j < i; j++) {
- (void) strcpy(new_categories[j],
- saved_categories[j]);
- if (i == LC_ALL)
- continue;
- if (loadlocale(j) == NULL) {
- (void) strcpy(new_categories[j], "C");
- (void) loadlocale(j);
- }
- }
- errno = saverr;
- return (NULL);
- }
+ loc = newlocale(mask, locname, NULL);
+ if (loc == NULL) {
+ return (NULL);
}
- return (currentlocale());
-}
-static char *
-currentlocale(void)
-{
- int i;
- int composite = 0;
-
- /* Look to see if any category is different */
- for (i = 1; i < NUM_CATS; ++i) {
- if (i == LC_ALL)
- continue;
- if (strcmp(current_categories[0], current_categories[i])) {
- composite = 1;
+ /*
+ * This next logic looks to see if we have ever used the same locale
+ * settings before. If so, we reuse it. We avoid ever calling
+ * freelocale() on a locale setting built up by setlocale, this
+ * ensures that consumers (uselocale) will always be thread safe;
+ * the actual locale data objects are never freed, and unique
+ * locale objects are also never freed. We reuse to avoid leaking
+ * memory in applications that call setlocale repeatedly.
+ */
+ lmutex_lock(&setlocale_lock);
+ for (srch = setlocale_list; srch != NULL; srch = srch->next) {
+ if (strcmp(srch->locname, loc->locname) == 0) {
break;
}
}
- if (composite) {
- /*
- * Note ordering of these follows the numeric order,
- * if the order is changed, then setlocale() will need
- * to be changed as well.
- */
- (void) snprintf(current_locale_string,
- sizeof (current_locale_string),
- "%s/%s/%s/%s/%s/%s",
- current_categories[LC_CTYPE],
- current_categories[LC_NUMERIC],
- current_categories[LC_TIME],
- current_categories[LC_COLLATE],
- current_categories[LC_MONETARY],
- current_categories[LC_MESSAGES]);
+ if (srch == NULL) {
+ /* this is a new locale, save it for reuse later */
+ loc->next = setlocale_list;
+ loc->on_list = 1;
+ setlocale_list = loc;
} else {
- (void) strlcpy(current_locale_string, current_categories[0],
- sizeof (current_locale_string));
+ /* we already had it, toss the new, and use what we found */
+ freelocale(loc);
+ loc = srch;
}
- return (current_locale_string);
+ ___global_locale = loc;
+
+ install_legacy(loc, mask);
+ lmutex_unlock(&setlocale_lock);
+
+ return (current_locale(loc, category));
}
static char *
-loadlocale(int category)
+current_locale(locale_t loc, int cat)
{
- char *new = new_categories[category];
- char *old = current_categories[category];
- int (*func)(const char *);
-
- if ((new[0] == '.' &&
- (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
- strchr(new, '/') != NULL) {
- errno = EINVAL;
- return (NULL);
- }
-
- switch (category) {
+ switch (cat) {
case LC_CTYPE:
- func = __wrap_setrunelocale;
- break;
case LC_COLLATE:
- func = _collate_load_tables;
- break;
- case LC_TIME:
- func = __time_load_locale;
- break;
- case LC_NUMERIC:
- func = __numeric_load_locale;
- break;
- case LC_MONETARY:
- func = __monetary_load_locale;
- break;
case LC_MESSAGES:
- func = __messages_load_locale;
- break;
+ case LC_MONETARY:
+ case LC_NUMERIC:
+ case LC_TIME:
+ return (loc->locdata[cat]->l_lname);
+ case LC_ALL:
+ return (loc->locname);
default:
- errno = EINVAL;
return (NULL);
}
-
- if (strcmp(new, old) == 0)
- return (old);
-
- if (func(new) != _LDP_ERROR) {
- (void) strcpy(old, new);
- return (old);
- }
-
- return (NULL);
}
-static const char *
-__get_locale_env(int category)
+static void
+install_legacy(locale_t loc, int mask)
{
- const char *env;
-
- /* 1. check LC_ALL. */
- env = getenv(categories[LC_ALL]);
-
- /* 2. check LC_* */
- if (env == NULL || !*env)
- env = getenv(categories[category]);
+ /*
+ * Update the legacy fixed variables that may be baked into
+ * legacy programs. This is really unfortunate, but we can't
+ * solve for them otherwise. Note that such legacy programs
+ * are only going to see the global locale settings, and cannot
+ * benefit from uselocale().
+ */
+ if (mask & LC_NUMERIC_MASK) {
+ struct lc_numeric *lnum;
+ lnum = loc->locdata[LC_NUMERIC]->l_data[0];
+ _numeric[0] = *lnum->decimal_point;
+ _numeric[1] = *lnum->thousands_sep;
+ }
- /* 3. check LANG */
- if (env == NULL || !*env)
- env = getenv("LANG");
+ if (mask & LC_CTYPE_MASK) {
+ struct lc_ctype *lct;
+ lct = loc->locdata[LC_CTYPE]->l_data[0];
+ for (int i = 0; i < _CACHED_RUNES; i++) {
+ /* ctype can only encode the lower 8 bits. */
+ __ctype[i+1] = lct->lc_ctype_mask[i] & 0xff;
+ __ctype_mask[i] = lct->lc_ctype_mask[i];
+ }
- /* 4. if none is set, fall to "C" */
- if (env == NULL || !*env)
- env = "C";
+ /* The bottom half is the toupper/lower array */
+ for (int i = 0; i < _CACHED_RUNES; i++) {
+ int u, l;
+ __ctype[258 + i] = i;
+ u = lct->lc_trans_upper[i];
+ l = lct->lc_trans_lower[i];
+ if (u && u != i)
+ __ctype[258+i] = u;
+ if (l && l != i)
+ __ctype[258+i] = l;
+
+ /* Don't forget these annoyances either! */
+ __trans_upper[i] = u;
+ __trans_lower[i] = l;
+ }
- return (env);
+ /* Maximum mblen, cswidth, weird legacy */
+ __ctype[520] = lct->lc_max_mblen;
+ }
}
diff --git a/usr/src/lib/libc/port/locale/setlocale.h b/usr/src/lib/libc/port/locale/setlocale.h
index ee27ed804a..79af54e8d4 100644
--- a/usr/src/lib/libc/port/locale/setlocale.h
+++ b/usr/src/lib/libc/port/locale/setlocale.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
@@ -33,7 +34,4 @@
extern char *_PathLocale;
-int __detect_path_locale(void);
-int __wrap_setrunelocale(const char *);
-
#endif /* !_SETLOCALE_H_ */
diff --git a/usr/src/lib/libc/port/locale/setrunelocale.c b/usr/src/lib/libc/port/locale/setrunelocale.c
index d56c0029ac..7f6cabdc4a 100644
--- a/usr/src/lib/libc/port/locale/setrunelocale.c
+++ b/usr/src/lib/libc/port/locale/setrunelocale.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -45,208 +46,103 @@
#include "mblocal.h"
#include "setlocale.h"
#include "_ctype.h"
-#include "../i18n/_locale.h"
+#include "lctype.h"
+#include "localeimpl.h"
+
+extern _RuneLocale *_Read_RuneMagi(const char *);
+
+struct lc_ctype lc_ctype_posix = {
+ .lc_mbrtowc = __mbrtowc_ascii,
+ .lc_mbsinit = __mbsinit_ascii,
+ .lc_mbsnrtowcs = __mbsnrtowcs_ascii,
+ .lc_wcrtomb = __wcrtomb_ascii,
+ .lc_wcsnrtombs = __wcsnrtombs_ascii,
+ .lc_is_ascii = 1,
+ .lc_max_mblen = 1,
+ .lc_trans_upper = _DefaultRuneLocale.__mapupper,
+ .lc_trans_lower = _DefaultRuneLocale.__maplower,
+ .lc_ctype_mask = _DefaultRuneLocale.__runetype,
+};
+
+struct locdata __posix_ctype_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_ctype_posix, &_DefaultRuneLocale }
+};
-extern _RuneLocale *_Read_RuneMagi(FILE *);
-extern unsigned char __ctype_C[];
-static int __setrunelocale(const char *);
-
-static int
-__setrunelocale(const char *encoding)
+/*
+ * Table of initializers for encodings. When you add a new encoding type,
+ * this table should be updated.
+ */
+static struct {
+ const char *e_name;
+ void (*e_init)(struct lc_ctype *);
+} encodings[] = {
+ { "NONE", _none_init },
+ { "UTF-8", _UTF8_init },
+ { "EUC-CN", _EUC_CN_init },
+ { "EUC-JP", _EUC_JP_init },
+ { "EUC-KR", _EUC_KR_init },
+ { "EUC-TW", _EUC_TW_init },
+ { "GB18030", _GB18030_init },
+ { "GB2312", _GB2312_init },
+ { "GBK", _GBK_init },
+ { "BIG5", _BIG5_init },
+ { "MSKanji", _MSKanji_init },
+ { NULL, NULL }
+};
+
+
+struct locdata *
+__lc_ctype_load(const char *name)
{
- FILE *fp;
- char name[PATH_MAX];
+ struct locdata *ldata;
+ struct lc_ctype *lct;
_RuneLocale *rl;
- int saverr, ret;
- size_t (*old__mbrtowc)(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
- size_t (*old__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
- mbstate_t *_RESTRICT_KYWD);
- int (*old__mbsinit)(const mbstate_t *);
- size_t (*old__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
- const char **_RESTRICT_KYWD, size_t, size_t,
- mbstate_t *_RESTRICT_KYWD);
- size_t (*old__wcsnrtombs)(char *_RESTRICT_KYWD,
- const wchar_t **_RESTRICT_KYWD, size_t, size_t,
- mbstate_t *_RESTRICT_KYWD);
- static char ctype_encoding[ENCODING_LEN + 1];
- static _RuneLocale *CachedRuneLocale;
- static size_t (*Cached__mbrtowc)(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
- static size_t (*Cached__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
- mbstate_t *_RESTRICT_KYWD);
- static int (*Cached__mbsinit)(const mbstate_t *);
- static size_t (*Cached__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
- const char **_RESTRICT_KYWD, size_t, size_t,
- mbstate_t *_RESTRICT_KYWD);
- static size_t (*Cached__wcsnrtombs)(char *_RESTRICT_KYWD,
- const wchar_t **_RESTRICT_KYWD, size_t, size_t,
- mbstate_t *_RESTRICT_KYWD);
-
- /*
- * The "C" and "POSIX" locale are always here.
- */
- if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
- int i;
-
- (void) memcpy(__ctype, __ctype_C, SZ_TOTAL);
-
- for (i = 0; i < _CACHED_RUNES; i++) {
- __ctype_mask[i] = _DefaultRuneLocale.__runetype[i];
- __trans_upper[i] = _DefaultRuneLocale.__mapupper[i];
- __trans_lower[i] = _DefaultRuneLocale.__maplower[i];
- }
-
- (void) _none_init(&_DefaultRuneLocale);
- return (0);
- }
-
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (CachedRuneLocale != NULL &&
- strcmp(encoding, ctype_encoding) == 0) {
- _CurrentRuneLocale = CachedRuneLocale;
- __mbrtowc = Cached__mbrtowc;
- __mbsinit = Cached__mbsinit;
- __mbsnrtowcs = Cached__mbsnrtowcs;
- __wcrtomb = Cached__wcrtomb;
- __wcsnrtombs = Cached__wcsnrtombs;
- return (0);
- }
+ int i;
+ char path[PATH_MAX];
+ if ((ldata = __locdata_alloc(name, sizeof (*lct))) == NULL)
+ return (NULL);
+ lct = ldata->l_data[0];
/*
* Slurp the locale file into the cache.
*/
- (void) snprintf(name, sizeof (name), "%s/%s/LC_CTYPE/LCL_DATA",
- _PathLocale, encoding);
-
- if ((fp = fopen(name, "r")) == NULL)
- return (errno == 0 ? ENOENT : errno);
+ (void) snprintf(path, sizeof (path), "%s/%s/LC_CTYPE/LCL_DATA",
+ _PathLocale, name);
- if ((rl = _Read_RuneMagi(fp)) == NULL) {
- saverr = (errno == 0 ? EINVAL : errno);
- (void) fclose(fp);
- return (saverr);
+ if ((rl = _Read_RuneMagi(path)) == NULL) {
+ __locdata_free(ldata);
+ errno = EINVAL;
+ return (NULL);
}
- (void) fclose(fp);
-
- old__mbrtowc = __mbrtowc;
- old__mbsinit = __mbsinit;
- old__mbsnrtowcs = __mbsnrtowcs;
- old__wcrtomb = __wcrtomb;
- old__wcsnrtombs = __wcsnrtombs;
-
- __mbrtowc = NULL;
- __mbsinit = NULL;
- __mbsnrtowcs = __mbsnrtowcs_std;
- __wcrtomb = NULL;
- __wcsnrtombs = __wcsnrtombs_std;
-
- if (strcmp(rl->__encoding, "NONE") == 0)
- ret = _none_init(rl);
- else if (strcmp(rl->__encoding, "UTF-8") == 0)
- ret = _UTF8_init(rl);
- else if (strcmp(rl->__encoding, "EUC-CN") == 0)
- ret = _EUC_CN_init(rl);
- else if (strcmp(rl->__encoding, "EUC-JP") == 0)
- ret = _EUC_JP_init(rl);
- else if (strcmp(rl->__encoding, "EUC-KR") == 0)
- ret = _EUC_KR_init(rl);
- else if (strcmp(rl->__encoding, "EUC-TW") == 0)
- ret = _EUC_TW_init(rl);
- else if (strcmp(rl->__encoding, "GB18030") == 0)
- ret = _GB18030_init(rl);
- else if (strcmp(rl->__encoding, "GB2312") == 0)
- ret = _GB2312_init(rl);
- else if (strcmp(rl->__encoding, "GBK") == 0)
- ret = _GBK_init(rl);
- else if (strcmp(rl->__encoding, "BIG5") == 0)
- ret = _BIG5_init(rl);
- else if (strcmp(rl->__encoding, "MSKanji") == 0)
- ret = _MSKanji_init(rl);
- else
- ret = EINVAL;
-
- if (ret == 0) {
- if (CachedRuneLocale != NULL) {
- free(CachedRuneLocale);
- }
- CachedRuneLocale = _CurrentRuneLocale;
- Cached__mbrtowc = __mbrtowc;
- Cached__mbsinit = __mbsinit;
- Cached__mbsnrtowcs = __mbsnrtowcs;
- Cached__wcrtomb = __wcrtomb;
- Cached__wcsnrtombs = __wcsnrtombs;
- (void) strcpy(ctype_encoding, encoding);
-
- /*
- * We need to overwrite the _ctype array. This requires
- * some finagling. This is because references to it may
- * have been baked into applications.
- *
- * Note that it is interesting that toupper/tolower only
- * produce defined results when the input is representable
- * as a byte.
- */
-
- /*
- * The top half is the type mask array. Because we
- * want to support both legacy Solaris code (which have
- * mask valeus baked in to them), and we want to be able
- * to import locale files from other sources (FreeBSD)
- * which probably uses different masks, we have to perform
- * a conversion here. Ugh. Note that the _CTYPE definitions
- * we use from FreeBSD are richer than the Solaris legacy.
- *
- * We have to cope with these limitations though, because the
- * inadequate Solaris definitions were baked into binaries.
- */
- for (int i = 0; i < _CACHED_RUNES; i++) {
- /* ctype can only encode the lower 8 bits. */
- __ctype[i+1] = rl->__runetype[i] & 0xff;
- __ctype_mask[i] = rl->__runetype[i];
- }
-
- /* The bottom half is the toupper/lower array */
- for (int i = 0; i < _CACHED_RUNES; i++) {
- __ctype[258 + i] = i;
- if (rl->__mapupper[i] && rl->__mapupper[i] != i)
- __ctype[258+i] = rl->__mapupper[i];
- if (rl->__maplower[i] && rl->__maplower[i] != i)
- __ctype[258+i] = rl->__maplower[i];
-
- /* Don't forget these annoyances either! */
- __trans_upper[i] = rl->__mapupper[i];
- __trans_lower[i] = rl->__maplower[i];
+ ldata->l_data[1] = rl;
+
+ lct->lc_mbrtowc = NULL;
+ lct->lc_mbsinit = NULL;
+ lct->lc_mbsnrtowcs = NULL;
+ lct->lc_wcrtomb = NULL;
+ lct->lc_wcsnrtombs = NULL;
+ lct->lc_ctype_mask = rl->__runetype;
+ lct->lc_trans_upper = rl->__mapupper;
+ lct->lc_trans_lower = rl->__maplower;
+
+ /* set up the function pointers */
+ for (i = 0; encodings[i].e_name != NULL; i++) {
+ int l = strlen(encodings[i].e_name);
+ if ((strncmp(rl->__encoding, encodings[i].e_name, l) == 0) &&
+ (rl->__encoding[l] == '\0' || rl->__encoding[l] == '@')) {
+ encodings[i].e_init(lct);
+ break;
}
-
- /*
- * Note that we expect the init code will have populated
- * the CSWIDTH array (__ctype[514-520]) properly.
- */
- } else {
- __mbrtowc = old__mbrtowc;
- __mbsinit = old__mbsinit;
- __mbsnrtowcs = old__mbsnrtowcs;
- __wcrtomb = old__wcrtomb;
- __wcsnrtombs = old__wcsnrtombs;
- free(rl);
+ }
+ if (encodings[i].e_name == NULL) {
+ __locdata_free(ldata);
+ errno = EINVAL;
+ return (NULL);
}
- return (ret);
-}
-
-int
-__wrap_setrunelocale(const char *locale)
-{
- int ret = __setrunelocale(locale);
- if (ret != 0) {
- errno = ret;
- return (_LDP_ERROR);
- }
- return (_LDP_LOADED);
+ return (ldata);
}
diff --git a/usr/src/lib/libc/port/i18n/strcasecmp.c b/usr/src/lib/libc/port/locale/strcasecmp.c
index 44bcf2c9e4..03da7cec5d 100644
--- a/usr/src/lib/libc/port/i18n/strcasecmp.c
+++ b/usr/src/lib/libc/port/locale/strcasecmp.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -35,24 +36,27 @@
#include <sys/types.h>
#include <strings.h>
#include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
int
-strcasecmp(const char *s1, const char *s2)
+strcasecmp_l(const char *s1, const char *s2, locale_t loc)
{
- extern int charset_is_ascii;
extern int ascii_strcasecmp(const char *s1, const char *s2);
- int *cm;
+ const int *cm;
const uchar_t *us1;
const uchar_t *us2;
+ const struct lc_ctype *lct = loc->ctype;
/*
* If we are in a locale that uses the ASCII character set
* (C or POSIX), use the fast ascii_strcasecmp() function.
*/
- if (charset_is_ascii)
+ if (lct->lc_is_ascii)
return (ascii_strcasecmp(s1, s2));
- cm = __trans_lower;
+ cm = lct->lc_trans_lower;
us1 = (const uchar_t *)s1;
us2 = (const uchar_t *)s2;
@@ -61,3 +65,10 @@ strcasecmp(const char *s1, const char *s2)
return (0);
return (cm[*us1] - cm[*(us2 - 1)]);
}
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ /* would be nice to avoid uselocale()... but I don't see how */
+ return (strcasecmp_l(s1, s2, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/i18n/strcasestr.c b/usr/src/lib/libc/port/locale/strcasestr.c
index a8f590263a..8791f44560 100644
--- a/usr/src/lib/libc/port/i18n/strcasestr.c
+++ b/usr/src/lib/libc/port/locale/strcasestr.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -30,6 +31,9 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
+#include <locale.h>
+#include "lctype.h"
+#include "localeimpl.h"
/*
* strcasestr() locates the first occurrence in the string s1 of the
@@ -40,9 +44,9 @@
*/
char *
-strcasestr(const char *s1, const char *s2)
+strcasestr_l(const char *s1, const char *s2, locale_t loc)
{
- int *cm = __trans_lower;
+ const int *cm = loc->ctype->lc_trans_lower;
const uchar_t *us1 = (const uchar_t *)s1;
const uchar_t *us2 = (const uchar_t *)s2;
const uchar_t *tptr;
@@ -67,3 +71,9 @@ strcasestr(const char *s1, const char *s2)
return (NULL);
}
+
+char *
+strcasestr(const char *s1, const char *s2)
+{
+ return (strcasestr_l(s1, s2, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/strcoll.c b/usr/src/lib/libc/port/locale/strcoll.c
index be20f23e0b..55cf459215 100644
--- a/usr/src/lib/libc/port/locale/strcoll.c
+++ b/usr/src/lib/libc/port/locale/strcoll.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
@@ -33,6 +34,8 @@
#include <string.h>
#include <errno.h>
#include <wchar.h>
+#include <xlocale.h>
+#include "localeimpl.h"
#include "collate.h"
#define ALLOCA_LIMIT 16
@@ -44,15 +47,19 @@
* should check errno.
*/
int
-strcoll(const char *s1, const char *s2)
+strcoll_l(const char *s1, const char *s2, locale_t loc)
{
int ret;
wchar_t *t1 = NULL, *t2 = NULL;
wchar_t *w1 = NULL, *w2 = NULL;
size_t sz1, sz2;
+ const struct lc_collate *lcc = loc->collate;
- if (_collate_load_error)
- goto error;
+ mbstate_t mbs1 = { 0 }; /* initial states */
+ mbstate_t mbs2 = { 0 };
+
+ if (lcc->lc_is_posix)
+ return (strcmp(s1, s2));
sz1 = strlen(s1) + 1;
sz2 = strlen(s2) + 1;
@@ -82,13 +89,13 @@ strcoll(const char *s1, const char *s2)
goto error;
}
- if ((mbstowcs(w1, s1, sz1)) == (size_t)-1)
+ if ((mbsrtowcs_l(w1, &s1, sz1, &mbs1, loc)) == (size_t)-1)
goto error;
- if ((mbstowcs(w2, s2, sz2)) == (size_t)-1)
+ if ((mbsrtowcs_l(w2, &s2, sz2, &mbs2, loc)) == (size_t)-1)
goto error;
- ret = wcscoll(w1, w2);
+ ret = wcscoll_l(w1, w2, loc);
if (t1)
free(t1);
if (t2)
@@ -103,3 +110,9 @@ error:
free(t2);
return (strcmp(s1, s2));
}
+
+int
+strcoll(const char *s1, const char *s2)
+{
+ return (strcoll_l(s1, s2, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/strfmon.c b/usr/src/lib/libc/port/locale/strfmon.c
index 18ba631ddc..cc90ddf9f1 100644
--- a/usr/src/lib/libc/port/locale/strfmon.c
+++ b/usr/src/lib/libc/port/locale/strfmon.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
@@ -41,6 +42,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "localeimpl.h"
+#include "lmonetary.h"
+#include "lnumeric.h"
/* internal flags */
#define NEED_GROUPING 0x01 /* print digits grouped (default) */
@@ -60,7 +64,7 @@
}
#define PRINTS(STR) { \
- char *tmps = STR; \
+ const char *tmps = STR; \
while (*tmps != '\0') \
PRINT(*tmps++); \
}
@@ -87,22 +91,23 @@
}
#define GRPSEP { \
- *--bufend = thousands_sep; \
+ bufend -= thousands_len; \
+ (void) memcpy(bufend, thousands_sep, thousands_len); \
groups++; \
}
-static void __setup_vars(int, char *, char *, char *, char **);
-static int __calc_left_pad(int, char *);
-static char *__format_grouped_double(double, int *, int, int, int);
+static void setup_vars(const struct lc_monetary *, int, char *, char *, char *,
+ const char **);
+static int calc_left_pad(const struct lc_monetary *, int, const char *);
+static char *format_grouped_double(const struct lc_monetary *,
+ const struct lc_numeric *, double, int *, int, int, int);
ssize_t
-strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
- const char *_RESTRICT_KYWD format, ...)
+strfmon_impl(char *_RESTRICT_KYWD s, size_t maxsize, locale_t loc,
+ const char *_RESTRICT_KYWD format, va_list ap)
{
- va_list ap;
char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */
- struct lconv *lc; /* pointer to lconv structure */
char *asciivalue; /* formatted double pointer */
int flags; /* formatting options */
@@ -114,18 +119,20 @@ strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
double value; /* just value */
char space_char = ' '; /* space after currency */
- char cs_precedes; /* values gathered from struct lconv */
+ char cs_precedes; /* values from struct lc_monetary */
char sep_by_space;
char sign_posn;
- char *signstr;
- char *currency_symbol;
+ const char *signstr;
+ const char *currency_symbol;
char *tmpptr; /* temporary vars */
int sverrno;
+ const struct lc_monetary *lmon; /* monetary structure */
+ const struct lc_numeric *lnum; /* numeric structure */
- va_start(ap, format);
+ lmon = loc->monetary;
+ lnum = loc->numeric;
- lc = localeconv();
dst = s;
fmt = format;
asciivalue = NULL;
@@ -231,17 +238,13 @@ strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
goto format_error;
}
- if (currency_symbol != NULL)
- free(currency_symbol);
if (flags & USE_INTL_CURRENCY) {
- currency_symbol = strdup(lc->int_curr_symbol);
+ currency_symbol = lmon->int_curr_symbol;
+ /* by definition three letters followed by a space */
if (currency_symbol != NULL)
- space_char = *(currency_symbol+3);
+ space_char = currency_symbol[3];
} else
- currency_symbol = strdup(lc->currency_symbol);
-
- if (currency_symbol == NULL)
- goto end_error; /* ENOMEM. */
+ currency_symbol = lmon->currency_symbol;
/* value itself */
value = va_arg(ap, double);
@@ -254,24 +257,24 @@ strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
/* fill left_prec with amount of padding chars */
if (left_prec >= 0) {
- pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
+ pad_size = calc_left_pad(lmon, (flags ^ IS_NEGATIVE),
currency_symbol) -
- __calc_left_pad(flags, currency_symbol);
+ calc_left_pad(lmon, flags, currency_symbol);
if (pad_size < 0)
pad_size = 0;
}
if (asciivalue != NULL)
free(asciivalue);
- asciivalue = __format_grouped_double(value, &flags,
+ asciivalue = format_grouped_double(lmon, lnum, value, &flags,
left_prec, right_prec, pad_char);
if (asciivalue == NULL)
goto end_error; /* errno already set */
/* to ENOMEM by malloc() */
/* set some variables for later use */
- __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn,
- &signstr);
+ setup_vars(lmon, flags, &cs_precedes, &sep_by_space,
+ &sign_posn, &signstr);
/*
* Description of some LC_MONETARY's values:
@@ -315,7 +318,7 @@ strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
if (cs_precedes == 1) {
if (sign_posn == 1 || sign_posn == 3) {
PRINTS(signstr);
- if (sep_by_space == 2) /* XXX: ? */
+ if (sep_by_space == 2)
PRINT(' ');
}
@@ -382,9 +385,7 @@ strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
}
PRINT('\0');
- va_end(ap);
free(asciivalue);
- free(currency_symbol);
return (dst - s - 1); /* size of put data except trailing '\0' */
e2big_error:
@@ -398,45 +399,66 @@ end_error:
sverrno = errno;
if (asciivalue != NULL)
free(asciivalue);
- if (currency_symbol != NULL)
- free(currency_symbol);
errno = sverrno;
- va_end(ap);
return (-1);
}
-static void
-__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
- char *sign_posn, char **signstr)
+ssize_t
+strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
+ const char *_RESTRICT_KYWD format, ...)
{
+ va_list ap;
+ ssize_t ret;
+
+ va_start(ap, format);
+ ret = strfmon_impl(s, maxsize, uselocale(NULL), format, ap);
+ va_end(ap);
+ return (ret);
+}
- struct lconv *lc = localeconv();
+ssize_t
+strfmon_l(char *_RESTRICT_KYWD s, size_t maxsize, locale_t loc,
+ const char *_RESTRICT_KYWD format, ...)
+{
+ ssize_t ret;
+ va_list ap;
+ va_start(ap, format);
+ ret = strfmon_impl(s, maxsize, loc, format, ap);
+ va_end(ap);
+ return (ret);
+}
+static void
+setup_vars(const struct lc_monetary *lmon, int flags, char *cs_precedes,
+ char *sep_by_space, char *sign_posn, const char **signstr)
+{
if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
- *cs_precedes = lc->int_n_cs_precedes;
- *sep_by_space = lc->int_n_sep_by_space;
- *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
- *signstr = (lc->negative_sign[0] == '\0') ? "-"
- : lc->negative_sign;
+ *cs_precedes = lmon->int_n_cs_precedes[0];
+ *sep_by_space = lmon->int_n_sep_by_space[0];
+ *sign_posn = (flags & PARENTH_POSN) ? 0 :
+ lmon->int_n_sign_posn[0];
+ *signstr = (lmon->negative_sign[0] == '\0') ? "-" :
+ lmon->negative_sign;
} else if (flags & USE_INTL_CURRENCY) {
- *cs_precedes = lc->int_p_cs_precedes;
- *sep_by_space = lc->int_p_sep_by_space;
- *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
- *signstr = lc->positive_sign;
+ *cs_precedes = lmon->int_p_cs_precedes[0];
+ *sep_by_space = lmon->int_p_sep_by_space[0];
+ *sign_posn = (flags & PARENTH_POSN) ? 0 :
+ lmon->int_p_sign_posn[0];
+ *signstr = lmon->positive_sign;
} else if (flags & IS_NEGATIVE) {
- *cs_precedes = lc->n_cs_precedes;
- *sep_by_space = lc->n_sep_by_space;
- *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
- *signstr = (lc->negative_sign[0] == '\0') ? "-"
- : lc->negative_sign;
+ *cs_precedes = lmon->n_cs_precedes[0];
+ *sep_by_space = lmon->n_sep_by_space[0];
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lmon->n_sign_posn[0];
+ *signstr = (lmon->negative_sign[0] == '\0') ? "-" :
+ lmon->negative_sign;
} else {
- *cs_precedes = lc->p_cs_precedes;
- *sep_by_space = lc->p_sep_by_space;
- *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
- *signstr = lc->positive_sign;
+ *cs_precedes = lmon->p_cs_precedes[0];
+ *sep_by_space = lmon->p_sep_by_space[0];
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lmon->p_sign_posn[0];
+ *signstr = lmon->positive_sign;
}
- /* Set defult values for unspecified information. */
+ /* Set default values for unspecified information. */
if (*cs_precedes != 0)
*cs_precedes = 1;
if (*sep_by_space == CHAR_MAX)
@@ -446,13 +468,14 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space,
}
static int
-__calc_left_pad(int flags, char *cur_symb)
+calc_left_pad(const struct lc_monetary *lmon, int flags, const char *cur_symb)
{
-
- char cs_precedes, sep_by_space, sign_posn, *signstr;
+ char cs_precedes, sep_by_space, sign_posn;
+ const char *signstr;
int left_chars = 0;
- __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
+ setup_vars(lmon, flags, &cs_precedes, &sep_by_space, &sign_posn,
+ &signstr);
if (cs_precedes != 0) {
left_chars += strlen(cur_symb);
@@ -473,7 +496,7 @@ __calc_left_pad(int flags, char *cur_symb)
}
static int
-get_groups(int size, char *grouping)
+get_groups(int size, const char *grouping)
{
int chars = 0;
@@ -498,8 +521,9 @@ get_groups(int size, char *grouping)
/* convert double to ASCII */
static char *
-__format_grouped_double(double value, int *flags,
- int left_prec, int right_prec, int pad_char)
+format_grouped_double(const struct lc_monetary *lmon,
+ const struct lc_numeric *lnum,
+ double value, int *flags, int left_prec, int right_prec, int pad_char)
{
char *rslt;
@@ -512,20 +536,24 @@ __format_grouped_double(double value, int *flags,
int padded;
- struct lconv *lc = localeconv();
- char *grouping;
- char decimal_point;
- char thousands_sep;
+ const char *grouping;
+ const char *decimal_point;
+ const char *thousands_sep;
+ int decimal_len;
+ int thousands_len;
int groups = 0;
- grouping = lc->mon_grouping;
- decimal_point = *lc->mon_decimal_point;
- if (decimal_point == '\0')
- decimal_point = *lc->decimal_point;
- thousands_sep = *lc->mon_thousands_sep;
- if (thousands_sep == '\0')
- thousands_sep = *lc->thousands_sep;
+ grouping = lmon->mon_grouping;
+ decimal_point = lmon->mon_decimal_point;
+ if (*decimal_point == '\0')
+ decimal_point = lnum->decimal_point;
+ thousands_sep = lmon->mon_thousands_sep;
+ if (*thousands_sep == '\0')
+ thousands_sep = lnum->thousands_sep;
+
+ decimal_len = strlen(decimal_point); /* usually 1 */
+ thousands_len = strlen(thousands_sep); /* 0 or 1 usually */
/* fill left_prec with default value */
if (left_prec == -1)
@@ -534,9 +562,9 @@ __format_grouped_double(double value, int *flags,
/* fill right_prec with default value */
if (right_prec == -1) {
if (*flags & USE_INTL_CURRENCY)
- right_prec = lc->int_frac_digits;
+ right_prec = lmon->int_frac_digits[0];
else
- right_prec = lc->frac_digits;
+ right_prec = lmon->frac_digits[0];
if (right_prec == CHAR_MAX) /* POSIX locale ? */
right_prec = 2;
@@ -552,7 +580,15 @@ __format_grouped_double(double value, int *flags,
if (avalue_size < 0)
return (NULL);
- /* make sure that we've enough space for result string */
+ /*
+ * Make sure that we've enough space for result string.
+ * This assumes that digits take up at least much space as
+ * grouping and radix characters. The worst case currently known
+ * is for Arabic, where two-byte UTF-8 sequences are used for both
+ * decimal and thousands seperators, and groups can be a small as two
+ * decimal digits. This will do no worse than doubling the storage
+ * requirement.
+ */
bufsize = strlen(avalue)*2+1;
rslt = calloc(1, bufsize);
if (rslt == NULL) {
@@ -561,7 +597,7 @@ __format_grouped_double(double value, int *flags,
}
bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */
- /* skip spaces at beggining */
+ /* skip spaces at beginning */
padded = 0;
while (avalue[padded] == ' ') {
padded++;
@@ -572,12 +608,13 @@ __format_grouped_double(double value, int *flags,
bufend -= right_prec;
(void) memcpy(bufend, avalue + avalue_size+padded-right_prec,
right_prec);
- *--bufend = decimal_point;
- avalue_size -= (right_prec + 1);
+ bufend -= decimal_len;
+ (void) memcpy(bufend, decimal_point, decimal_len);
+ avalue_size -= (right_prec + decimal_len);
}
if ((*flags & NEED_GROUPING) &&
- thousands_sep != '\0' && /* XXX: need investigation */
+ thousands_len != 0 &&
*grouping != CHAR_MAX &&
*grouping > 0) {
while (avalue_size > (int)*grouping) {
diff --git a/usr/src/lib/libc/port/locale/strftime.c b/usr/src/lib/libc/port/locale/strftime.c
index 9e8d4cbe56..b314151838 100644
--- a/usr/src/lib/libc/port/locale/strftime.c
+++ b/usr/src/lib/libc/port/locale/strftime.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
@@ -22,11 +23,14 @@
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
+#include <locale.h>
#include "timelocal.h"
+#include "localeimpl.h"
static char *_add(const char *, char *, const char *);
static char *_conv(int, const char *, char *, const char *);
-static char *_fmt(const char *, const struct tm *, char *, const char * const);
+static char *_fmt(locale_t, const char *, const struct tm *, char *,
+ const char * const);
static char *_yconv(int, int, int, int, char *, const char *);
extern char *tzname[];
@@ -62,24 +66,33 @@ static const char *fmt_padding[][4] = {
size_t
-strftime(char *_RESTRICT_KYWD s, size_t maxsize,
- const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t)
+strftime_l(char *_RESTRICT_KYWD s, size_t maxsize,
+ const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t,
+ locale_t loc)
{
char *p;
tzset();
- p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize);
+ p = _fmt(loc, ((format == NULL) ? "%c" : format), t, s, s + maxsize);
if (p == s + maxsize)
return (0);
*p = '\0';
return (p - s);
}
+size_t
+strftime(char *_RESTRICT_KYWD s, size_t maxsize,
+ const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t)
+{
+ return (strftime_l(s, maxsize, format, t, uselocale(NULL)));
+}
+
static char *
-_fmt(const char *format, const struct tm *t, char *pt, const char * const ptlim)
+_fmt(locale_t loc, const char *format, const struct tm *t, char *pt,
+ const char * const ptlim)
{
int Ealternative, Oalternative, PadIndex;
- struct lc_time_T *tptr = __get_current_time_locale();
+ const struct lc_time *tptr = loc->time;
#define PADDING(x) fmt_padding[x][PadIndex]
@@ -130,10 +143,10 @@ label:
pt, ptlim);
continue;
case 'c':
- pt = _fmt(tptr->c_fmt, t, pt, ptlim);
+ pt = _fmt(loc, tptr->c_fmt, t, pt, ptlim);
continue;
case 'D':
- pt = _fmt("%m/%d/%y", t, pt, ptlim);
+ pt = _fmt(loc, "%m/%d/%y", t, pt, ptlim);
continue;
case 'd':
pt = _conv(t->tm_mday,
@@ -163,7 +176,7 @@ label:
PADDING(PAD_FMT_SDAYOFMONTH), pt, ptlim);
continue;
case 'F':
- pt = _fmt("%Y-%m-%d", t, pt, ptlim);
+ pt = _fmt(loc, "%Y-%m-%d", t, pt, ptlim);
continue;
case 'H':
pt = _conv(t->tm_hour, PADDING(PAD_FMT_HMS),
@@ -223,10 +236,10 @@ label:
tptr->pm : tptr->am, pt, ptlim);
continue;
case 'R':
- pt = _fmt("%H:%M", t, pt, ptlim);
+ pt = _fmt(loc, "%H:%M", t, pt, ptlim);
continue;
case 'r':
- pt = _fmt(tptr->ampm_fmt, t, pt, ptlim);
+ pt = _fmt(loc, tptr->ampm_fmt, t, pt, ptlim);
continue;
case 'S':
pt = _conv(t->tm_sec, PADDING(PAD_FMT_HMS),
@@ -245,7 +258,7 @@ label:
}
case 'T':
- pt = _fmt("%H:%M:%S", t, pt, ptlim);
+ pt = _fmt(loc, "%H:%M:%S", t, pt, ptlim);
continue;
case 't':
pt = _add("\t", pt, ptlim);
@@ -357,7 +370,7 @@ label:
* "date as dd-bbb-YYYY"
* (ado, 1993-05-24)
*/
- pt = _fmt("%e-%b-%Y", t, pt, ptlim);
+ pt = _fmt(loc, "%e-%b-%Y", t, pt, ptlim);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -371,10 +384,10 @@ label:
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
- pt = _fmt(tptr->X_fmt, t, pt, ptlim);
+ pt = _fmt(loc, tptr->X_fmt, t, pt, ptlim);
continue;
case 'x':
- pt = _fmt(tptr->x_fmt, t, pt, ptlim);
+ pt = _fmt(loc, tptr->x_fmt, t, pt, ptlim);
continue;
case 'y':
pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
@@ -438,7 +451,7 @@ label:
}
continue;
case '+':
- pt = _fmt(tptr->date_fmt, t, pt, ptlim);
+ pt = _fmt(loc, tptr->date_fmt, t, pt, ptlim);
continue;
case '-':
if (PadIndex != PAD_DEFAULT)
diff --git a/usr/src/lib/libc/port/i18n/strncasecmp.c b/usr/src/lib/libc/port/locale/strncasecmp.c
index 67c6687e08..32ae17c8a2 100644
--- a/usr/src/lib/libc/port/i18n/strncasecmp.c
+++ b/usr/src/lib/libc/port/locale/strncasecmp.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -35,24 +36,27 @@
#include <sys/types.h>
#include <strings.h>
#include <ctype.h>
+#include <locale.h>
+#include "lctype.h"
+#include "localeimpl.h"
int
-strncasecmp(const char *s1, const char *s2, size_t n)
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t loc)
{
- extern int charset_is_ascii;
extern int ascii_strncasecmp(const char *s1, const char *s2, size_t n);
- int *cm;
+ const int *cm;
const uchar_t *us1;
const uchar_t *us2;
+ const struct lc_ctype *lct = loc->ctype;
/*
* If we are in a locale that uses the ASCII character set
* (C or POSIX), use the fast ascii_strncasecmp() function.
*/
- if (charset_is_ascii)
+ if (lct->lc_is_ascii)
return (ascii_strncasecmp(s1, s2, n));
- cm = __trans_lower;
+ cm = lct->lc_trans_lower;
us1 = (const uchar_t *)s1;
us2 = (const uchar_t *)s2;
@@ -63,3 +67,9 @@ strncasecmp(const char *s1, const char *s2, size_t n)
}
return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ return (strncasecmp_l(s1, s2, n, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/strptime.c b/usr/src/lib/libc/port/locale/strptime.c
index 90150e37e9..f5be4eba8c 100644
--- a/usr/src/lib/libc/port/locale/strptime.c
+++ b/usr/src/lib/libc/port/locale/strptime.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014 Gary Mills
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2011, Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1994 Powerdog Industries. All rights reserved.
*
@@ -40,31 +41,30 @@
#include <string.h>
#include <pthread.h>
#include <alloca.h>
+#include <locale.h>
#include "timelocal.h"
+#include "localeimpl.h"
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
#define F_GMT (1 << 0)
-#define F_ZERO (1 << 1)
#define F_RECURSE (1 << 2)
static char *
-__strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
+__strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+ struct tm *_RESTRICT_KYWD tm, int *_RESTRICT_KYWD flagsp,
+ locale_t _RESTRICT_KYWD loc)
{
char c;
const char *ptr;
int i, len, recurse = 0;
int Ealternative, Oalternative;
- struct lc_time_T *tptr = __get_current_time_locale();
+ const struct lc_time *tptr = loc->time;
if (*flagsp & F_RECURSE)
recurse = 1;
*flagsp |= F_RECURSE;
- if (*flagsp & F_ZERO)
- (void) memset(tm, 0, sizeof (*tm));
- *flagsp &= ~F_ZERO;
-
ptr = fmt;
while (*ptr != 0) {
if (*buf == 0)
@@ -93,7 +93,7 @@ label:
break;
case '+':
- buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
+ buf = __strptime(buf, tptr->date_fmt, tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
@@ -116,13 +116,13 @@ label:
break;
case 'c':
- buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
+ buf = __strptime(buf, tptr->c_fmt, tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'D':
- buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
+ buf = __strptime(buf, "%m/%d/%y", tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
@@ -140,37 +140,37 @@ label:
goto label;
case 'F':
- buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
+ buf = __strptime(buf, "%Y-%m-%d", tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'R':
- buf = __strptime(buf, "%H:%M", tm, flagsp);
+ buf = __strptime(buf, "%H:%M", tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'r':
- buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
+ buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'T':
- buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
+ buf = __strptime(buf, "%H:%M:%S", tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'X':
- buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
+ buf = __strptime(buf, tptr->X_fmt, tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
case 'x':
- buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
+ buf = __strptime(buf, tptr->x_fmt, tm, flagsp, loc);
if (buf == NULL)
return (NULL);
break;
@@ -519,11 +519,14 @@ label:
}
char *
-strptime(const char *buf, const char *fmt, struct tm *tm)
+strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+ struct tm *_RESTRICT_KYWD tm)
{
- int flags = F_ZERO;
+ int flags = 0;
+
+ (void) memset(tm, 0, sizeof (*tm));
- return (__strptime(buf, fmt, tm, &flags));
+ return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
}
/*
@@ -531,9 +534,31 @@ strptime(const char *buf, const char *fmt, struct tm *tm)
* incoming tm. It is triggered by -D_STRPTIME_DONTZERO.
*/
char *
-__strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
+__strptime_dontzero(const char *_RESTRICT_KYWD buf,
+ const char *_RESTRICT_KYWD fmt, struct tm *_RESTRICT_KYWD tm)
{
int flags = 0;
- return (__strptime(buf, fmt, tm, &flags));
+ return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
+}
+
+/*
+ * strptime_l is an extension that seems natural, and indeed, MacOS X
+ * includes it within their <xlocale.h> and it is part of GNU libc as well.
+ * For now we restrict it to the cases where strict namespaces are not
+ * included. We expect to see it in a future version of POSIX. locale_t is
+ * not a restrict, since the spec for it doesn't assume its a pointer. We
+ * therefore pass it analagously to the way strftime_l is specified.
+ *
+ * We are not providing a non-zeroing version at this time.
+ */
+char *
+strptime_l(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+ struct tm *_RESTRICT_KYWD tm, locale_t loc)
+{
+ int flags = 0;
+
+ (void) memset(tm, 0, sizeof (*tm));
+
+ return (__strptime(buf, fmt, tm, &flags, loc));
}
diff --git a/usr/src/lib/libc/port/locale/strxfrm.c b/usr/src/lib/libc/port/locale/strxfrm.c
index 08366cef69..d617094add 100644
--- a/usr/src/lib/libc/port/locale/strxfrm.c
+++ b/usr/src/lib/libc/port/locale/strxfrm.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
@@ -32,10 +33,12 @@
#include <errno.h>
#include <wchar.h>
#include <assert.h>
+#include <xlocale.h>
#include "collate.h"
size_t
-strxfrm(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src, size_t dlen)
+strxfrm_l(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src,
+ size_t dlen, locale_t loc)
{
size_t slen;
size_t xlen;
@@ -54,16 +57,16 @@ strxfrm(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src, size_t dlen)
*/
slen = strlen(src);
- if (_collate_load_error)
+ if (loc->collate->lc_is_posix)
goto error;
if ((wcs = malloc((slen + 1) * sizeof (wchar_t))) == NULL)
goto error;
- if (mbstowcs(wcs, src, slen + 1) == (size_t)-1)
+ if (mbstowcs_l(wcs, src, slen + 1, loc) == (size_t)-1)
goto error;
- if ((xlen = _collate_sxfrm(wcs, xf, dlen)) == (size_t)-1)
+ if ((xlen = _collate_sxfrm(wcs, xf, dlen, loc)) == (size_t)-1)
goto error;
if (wcs)
@@ -85,3 +88,9 @@ error:
return (slen);
}
+
+size_t
+strxfrm(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src, size_t dlen)
+{
+ return (strxfrm_l(xf, src, dlen, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/table.c b/usr/src/lib/libc/port/locale/table.c
index c48c51062b..272e3d18d2 100644
--- a/usr/src/lib/libc/port/locale/table.c
+++ b/usr/src/lib/libc/port/locale/table.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -260,16 +261,8 @@ _RuneLocale _DefaultRuneLocale = {
/* END CSTYLED */
};
-_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
-
/* Taken from former _ctype.c */
unsigned int *__ctype_mask = _DefaultRuneLocale.__runetype;
int *__trans_lower = _DefaultRuneLocale.__maplower;
int *__trans_upper = _DefaultRuneLocale.__mapupper;
-
-/*
- * Used in various string routines to conditionalize versions optimized for
- * the ASCII case
- */
-int charset_is_ascii = 1;
diff --git a/usr/src/lib/libc/port/locale/timelocal.c b/usr/src/lib/libc/port/locale/timelocal.c
index 98af393f48..4dba212af3 100644
--- a/usr/src/lib/libc/port/locale/timelocal.c
+++ b/usr/src/lib/libc/port/locale/timelocal.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* Copyright (c) 1997 FreeBSD Inc.
@@ -28,16 +29,14 @@
#include "lint.h"
#include <stddef.h>
+#include <errno.h>
#include "ldpart.h"
#include "timelocal.h"
+#include "localeimpl.h"
-static struct lc_time_T _time_locale;
-static int _time_using_locale;
-static char *time_locale_buf;
+#define LCTIME_SIZE (sizeof (struct lc_time) / sizeof (char *))
-#define LCTIME_SIZE (sizeof (struct lc_time_T) / sizeof (char *))
-
-static const struct lc_time_T _C_time_locale = {
+struct lc_time lc_time_posix = {
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
@@ -84,17 +83,32 @@ static const struct lc_time_T _C_time_locale = {
"%I:%M:%S %p"
};
-struct lc_time_T *
-__get_current_time_locale(void)
-{
- return (_time_using_locale ? &_time_locale :
- (struct lc_time_T *)&_C_time_locale);
-}
+struct locdata __posix_time_locdata = {
+ .l_lname = "C",
+ .l_data = { &lc_time_posix }
+};
-int
-__time_load_locale(const char *name)
+struct locdata *
+__lc_time_load(const char *name)
{
- return (__part_load_locale(name, &_time_using_locale,
- &time_locale_buf, "LC_TIME", LCTIME_SIZE, LCTIME_SIZE,
- (const char **)&_time_locale));
+ struct locdata *ldata;
+ struct lc_time *ltime;
+ int ret;
+
+ if ((ldata = __locdata_alloc(name, sizeof (*ltime))) == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ ltime = ldata->l_data[0];
+
+ ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+ "LC_TIME", LCTIME_SIZE, LCTIME_SIZE, (const char **)ltime);
+
+ if (ret != _LDP_LOADED) {
+ __locdata_free(ldata);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (ldata);
}
diff --git a/usr/src/lib/libc/port/locale/timelocal.h b/usr/src/lib/libc/port/locale/timelocal.h
index e0c89945a1..6f49a89b97 100644
--- a/usr/src/lib/libc/port/locale/timelocal.h
+++ b/usr/src/lib/libc/port/locale/timelocal.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1997-2002 FreeBSD Project.
* All rights reserved.
@@ -32,7 +33,7 @@
* Private header file for the strftime and strptime localization
* stuff.
*/
-struct lc_time_T {
+struct lc_time {
const char *mon[12];
const char *month[12];
const char *wday[7];
@@ -46,7 +47,7 @@ struct lc_time_T {
const char *ampm_fmt;
};
-struct lc_time_T *__get_current_time_locale(void);
+struct lc_time *__get_current_time_locale(void);
int __time_load_locale(const char *);
#endif /* !_TIMELOCAL_H_ */
diff --git a/usr/src/lib/libc/port/locale/tolower.c b/usr/src/lib/libc/port/locale/tolower.c
index 52bcf162f2..59fb6ec673 100644
--- a/usr/src/lib/libc/port/locale/tolower.c
+++ b/usr/src/lib/libc/port/locale/tolower.c
@@ -10,22 +10,40 @@
*/
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
*/
#include "lint.h"
#include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
#pragma weak _tolower = tolower
#pragma weak _toupper = toupper
int
+tolower_l(int c, locale_t loc)
+{
+ return (((unsigned)c > 255) ? c : loc->ctype->lc_trans_lower[c]);
+}
+
+int
+toupper_l(int c, locale_t loc)
+{
+ return (((unsigned)c > 255) ? c : loc->ctype->lc_trans_upper[c]);
+}
+
+#undef tolower
+int
tolower(int c)
{
- return (((unsigned)c > 255) ? c : __trans_lower[c]);
+ return (isascii(c) ? __trans_lower[c] : tolower_l(c, uselocale(NULL)));
}
+#undef toupper
int
toupper(int c)
{
- return (((unsigned)c > 255) ? c : __trans_upper[c]);
+ return (isascii(c) ? __trans_upper[c] : toupper_l(c, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/towlower.c b/usr/src/lib/libc/port/locale/towlower.c
index 13a20100d9..a40825d3c3 100644
--- a/usr/src/lib/libc/port/locale/towlower.c
+++ b/usr/src/lib/libc/port/locale/towlower.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -39,21 +40,23 @@
#include "lint.h"
#include <wctype.h>
#include <stdio.h>
+#include "localeimpl.h"
+#include "lctype.h"
#include "runetype.h"
static wint_t
-__change_case_ext(wint_t c, int lower)
+change_case_ext(locale_t loc, wint_t c, int lower)
{
+ const _RuneLocale *rl;
+ const _RuneRange *rr;
+ const _RuneEntry *base, *re;
size_t lim;
- _RuneRange *rr;
- _RuneEntry *base, *re;
if (c < 0 || c == EOF)
return (c);
- rr = lower ?
- &_CurrentRuneLocale->__maplower_ext :
- &_CurrentRuneLocale->__mapupper_ext;
+ rl = loc->runelocale;
+ rr = lower ? &rl->__maplower_ext : &rl->__mapupper_ext;
/* Binary search -- see bsearch.c for explanation. */
base = rr->__ranges;
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
@@ -69,20 +72,40 @@ __change_case_ext(wint_t c, int lower)
return (c);
}
+wint_t
+towlower_l(wint_t wc, locale_t loc)
+{
+ return (iswascii(wc) ? __trans_lower[wc] :
+ (wc < 0 || wc >= _CACHED_RUNES) ?
+ change_case_ext(loc, wc, 1) :
+ loc->runelocale->__maplower[wc]);
+}
+
#undef towlower
wint_t
towlower(wint_t wc)
{
- return ((wc < 0 || wc >= _CACHED_RUNES) ?
- __change_case_ext(wc, 1) :
- _CurrentRuneLocale->__maplower[wc]);
+ return (iswascii(wc) ? __trans_lower[wc] :
+ (wc < 0 || wc >= _CACHED_RUNES) ?
+ change_case_ext(uselocale(NULL), wc, 1) :
+ uselocale(NULL)->runelocale->__maplower[wc]);
+}
+
+wint_t
+towupper_l(wint_t wc, locale_t loc)
+{
+ return (iswascii(wc) ? __trans_upper[wc] :
+ (wc < 0 || wc >= _CACHED_RUNES) ?
+ change_case_ext(loc, wc, 0) :
+ loc->runelocale->__mapupper[wc]);
}
#undef towupper
wint_t
towupper(wint_t wc)
{
- return ((wc < 0 || wc >= _CACHED_RUNES) ?
- __change_case_ext(wc, 0) :
- _CurrentRuneLocale->__mapupper[wc]);
+ return (iswascii(wc) ? __trans_upper[wc] :
+ (wc < 0 || wc >= _CACHED_RUNES) ?
+ change_case_ext(uselocale(NULL), wc, 0) :
+ uselocale(NULL)->runelocale->__mapupper[wc]);
}
diff --git a/usr/src/lib/libc/port/locale/utf8.c b/usr/src/lib/libc/port/locale/utf8.c
index af25ff39bb..e919b9dd4a 100644
--- a/usr/src/lib/libc/port/locale/utf8.c
+++ b/usr/src/lib/libc/port/locale/utf8.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
@@ -28,11 +29,11 @@
#include "lint.h"
#include <errno.h>
#include <limits.h>
-#include "runetype.h"
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
+#include "lctype.h"
static size_t _UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
@@ -53,29 +54,16 @@ typedef struct {
wchar_t lbound;
} _UTF8State;
-int
-_UTF8_init(_RuneLocale *rl)
+void
+_UTF8_init(struct lc_ctype *lct)
{
- __mbrtowc = _UTF8_mbrtowc;
- __wcrtomb = _UTF8_wcrtomb;
- __mbsinit = _UTF8_mbsinit;
- __mbsnrtowcs = _UTF8_mbsnrtowcs;
- __wcsnrtombs = _UTF8_wcsnrtombs;
- _CurrentRuneLocale = rl;
-
- charset_is_ascii = 0;
-
- /*
- * In theory up to 6 bytes can be used for the encoding,
- * but only encodings with more than 4 bytes are illegal.
- */
- __ctype[520] = 4;
- /*
- * Note that the other CSWIDTH members are nonsensical for this
- * this coding. They only are valid with EUC codings.
- */
-
- return (0);
+ lct->lc_mbrtowc = _UTF8_mbrtowc;
+ lct->lc_wcrtomb = _UTF8_wcrtomb;
+ lct->lc_mbsinit = _UTF8_mbsinit;
+ lct->lc_mbsnrtowcs = _UTF8_mbsnrtowcs;
+ lct->lc_wcsnrtombs = _UTF8_wcsnrtombs;
+ lct->lc_is_ascii = 0;
+ lct->lc_max_mblen = 4;
}
static int
diff --git a/usr/src/lib/libc/port/locale/wcrtomb.c b/usr/src/lib/libc/port/locale/wcrtomb.c
index a3fa0d3d4a..cc2ec60756 100644
--- a/usr/src/lib/libc/port/locale/wcrtomb.c
+++ b/usr/src/lib/libc/port/locale/wcrtomb.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -27,14 +28,25 @@
#include "lint.h"
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
+#include "localeimpl.h"
+#include "lctype.h"
#include "mblocal.h"
size_t
-wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
+wcrtomb_l(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps,
+ locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__wcrtomb(s, wc, ps));
+ return (loc->ctype->lc_wcrtomb(s, wc, ps));
+}
+
+size_t
+wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (wcrtomb_l(s, wc, ps, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/i18n/wsncasecmp.c b/usr/src/lib/libc/port/locale/wcscasecmp.c
index ee4fbb6028..ef0b734435 100644
--- a/usr/src/lib/libc/port/i18n/wsncasecmp.c
+++ b/usr/src/lib/libc/port/locale/wcscasecmp.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
*/
/*
@@ -29,28 +30,54 @@
* All letters are converted to the lowercase and compared.
*/
-#pragma weak _wsncasecmp = wsncasecmp
-
#include "lint.h"
#include <stdlib.h>
-#include <widec.h>
+#include <wchar.h>
+#include <locale.h>
#include "libc.h"
+/* Legacy Sun interfaces */
+#pragma weak wscasecmp = wcscasecmp
+#pragma weak wsncasecmp = wcsncasecmp
+
int
-wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+wcscasecmp_l(const wchar_t *s1, const wchar_t *s2, locale_t loc)
+{
+ if (s1 == s2)
+ return (0);
+
+ while (towlower_l(*s1, loc) == towlower_l(*s2, loc)) {
+ if (*s1 == 0)
+ return (0);
+ s1++;
+ s2++;
+ }
+ return (towlower_l(*s1, loc) - towlower_l(*s2, loc));
+}
+
+int
+wcscasecmp(const wchar_t *s1, const wchar_t *s2)
+{
+ return (wcscasecmp_l(s1, s2, uselocale(NULL)));
+}
+
+int
+wcsncasecmp_l(const wchar_t *s1, const wchar_t *s2, size_t n, locale_t loc)
{
if (s1 == s2)
return (0);
- n++;
- while (--n > 0 && towlower(*s1) == towlower(*s2++))
- if (*s1++ == 0)
+ while ((towlower_l(*s1, loc) == towlower_l(*s2, loc)) && n--) {
+ if (*s1 == 0)
return (0);
- return ((n == 0) ? 0 : (towlower(*s1) - towlower(*(s2 - 1))));
+ s1++;
+ s2++;
+ }
+ return (towlower_l(*s1, loc) - towlower_l(*s2, loc));
}
int
-wsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
{
- return (wcsncasecmp(s1, s2, n));
+ return (wcsncasecmp_l(s1, s2, n, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/wcscoll.c b/usr/src/lib/libc/port/locale/wcscoll.c
index ac4218c356..4bf32ff010 100644
--- a/usr/src/lib/libc/port/locale/wcscoll.c
+++ b/usr/src/lib/libc/port/locale/wcscoll.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
@@ -32,17 +33,17 @@
#include <wchar.h>
#include <assert.h>
#include "collate.h"
+#include "localeimpl.h"
int
-wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc)
{
int len1, len2, pri1, pri2, ret;
wchar_t *tr1 = NULL, *tr2 = NULL;
int direc, pass;
+ const struct lc_collate *lcc = loc->collate;
- collate_info_t *info = _collate_info;
-
- if (_collate_load_error)
+ if (lcc->lc_is_posix)
/*
* Locale has no special collating order or could not be
* loaded, do a fast binary comparison.
@@ -63,18 +64,18 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
* Note that we do one final extra pass at the end to pick
* up UNDEFINED elements. There is special handling for them.
*/
- for (pass = 0; pass <= info->directive_count; pass++) {
+ for (pass = 0; pass <= lcc->lc_directive_count; pass++) {
- int32_t *st1 = NULL;
- int32_t *st2 = NULL;
+ const int32_t *st1 = NULL;
+ const int32_t *st2 = NULL;
const wchar_t *w1 = ws1;
const wchar_t *w2 = ws2;
/* special pass for UNDEFINED */
- if (pass == info->directive_count) {
+ if (pass == lcc->lc_directive_count) {
direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
} else {
- direc = info->directive[pass];
+ direc = lcc->lc_directive[pass];
}
if (direc & DIRECTIVE_BACKWARD) {
@@ -104,7 +105,8 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
if (direc & DIRECTIVE_POSITION) {
while ((*w1 || st1) && (*w2 || st2)) {
pri1 = pri2 = 0;
- _collate_lookup(w1, &len1, &pri1, pass, &st1);
+ _collate_lookup(lcc, w1, &len1, &pri1, pass,
+ &st1);
if (pri1 <= 0) {
if (pri1 < 0) {
errno = EINVAL;
@@ -112,7 +114,8 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
}
pri1 = COLLATE_MAX_PRIORITY;
}
- _collate_lookup(w2, &len2, &pri2, pass, &st2);
+ _collate_lookup(lcc, w2, &len2, &pri2, pass,
+ &st2);
if (pri2 <= 0) {
if (pri2 < 0) {
errno = EINVAL;
@@ -131,7 +134,7 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
while ((*w1 || st1) && (*w2 || st2)) {
pri1 = pri2 = 0;
while (*w1) {
- _collate_lookup(w1, &len1,
+ _collate_lookup(lcc, w1, &len1,
&pri1, pass, &st1);
if (pri1 > 0)
break;
@@ -142,7 +145,7 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
w1 += len1;
}
while (*w2) {
- _collate_lookup(w2, &len2,
+ _collate_lookup(lcc, w2, &len2,
&pri2, pass, &st2);
if (pri2 > 0)
break;
@@ -186,3 +189,10 @@ fail:
ret = wcscmp(ws1, ws2);
goto end;
}
+
+
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+ return (wcscoll_l(ws1, ws2, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wcsnrtombs.c b/usr/src/lib/libc/port/locale/wcsnrtombs.c
index ecf7b641c4..a2f467956f 100644
--- a/usr/src/lib/libc/port/locale/wcsnrtombs.c
+++ b/usr/src/lib/libc/port/locale/wcsnrtombs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -29,24 +30,35 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <locale.h>
#include <wchar.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
size_t
-wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
- size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+wcsnrtombs_l(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__wcsnrtombs(dst, src, nwc, len, ps));
+ return (loc->ctype->lc_wcsnrtombs(dst, src, nwc, len, ps));
}
size_t
-__wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
{
+ return (wcsnrtombs_l(dst, src, nwc, len, ps, uselocale(NULL)));
+}
+
+size_t
+__wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps,
+ wcrtomb_pfn_t pwcrtomb)
+{
mbstate_t mbsbak;
char buf[MB_LEN_MAX];
const wchar_t *s;
@@ -58,7 +70,7 @@ __wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
if (dst == NULL) {
while (nwc-- > 0) {
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1)
+ if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1)
/* Invalid character - wcrtomb() sets errno. */
return ((size_t)-1);
else if (*s == L'\0')
@@ -72,7 +84,7 @@ __wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
while (len > 0 && nwc-- > 0) {
if (len > (size_t)MB_CUR_MAX) {
/* Enough space to translate in-place. */
- if ((nb = __wcrtomb(dst, *s, ps)) == (size_t)-1) {
+ if ((nb = pwcrtomb(dst, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
@@ -85,7 +97,7 @@ __wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
* character is too long for the buffer.
*/
mbsbak = *ps;
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) {
+ if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
diff --git a/usr/src/lib/libc/port/locale/wcsrtombs.c b/usr/src/lib/libc/port/locale/wcsrtombs.c
index 8250e6302e..61a37d976a 100644
--- a/usr/src/lib/libc/port/locale/wcsrtombs.c
+++ b/usr/src/lib/libc/port/locale/wcsrtombs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -30,15 +31,24 @@
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
+#include "localeimpl.h"
+#include "lctype.h"
#include "mblocal.h"
size_t
-wcsrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
- size_t len, mbstate_t *_RESTRICT_KYWD ps)
+wcsrtombs_l(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
{
static mbstate_t mbs;
if (ps == NULL)
ps = &mbs;
- return (__wcsnrtombs(dst, src, ULONG_MAX, len, ps));
+ return (loc->ctype->lc_wcsnrtombs(dst, src, ULONG_MAX, len, ps));
+}
+
+size_t
+wcsrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+ size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (wcsrtombs_l(dst, src, len, ps, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/wcstombs.c b/usr/src/lib/libc/port/locale/wcstombs.c
index 28f31799d2..cc48ac47f9 100644
--- a/usr/src/lib/libc/port/locale/wcstombs.c
+++ b/usr/src/lib/libc/port/locale/wcstombs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -30,9 +31,12 @@
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
size_t
-wcstombs(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs, size_t n)
+wcstombs_l(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs,
+ size_t n, locale_t loc)
{
static const mbstate_t initial = { 0 };
mbstate_t mbs;
@@ -40,5 +44,11 @@ wcstombs(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs, size_t n)
mbs = initial;
pwcsp = pwcs;
- return (__wcsnrtombs(s, &pwcsp, ULONG_MAX, n, &mbs));
+ return (loc->ctype->lc_wcsnrtombs(s, &pwcsp, ULONG_MAX, n, &mbs));
+}
+
+size_t
+wcstombs(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs, size_t n)
+{
+ return (wcstombs_l(s, pwcs, n, uselocale(NULL)));
}
diff --git a/usr/src/lib/libc/port/locale/wcswidth.c b/usr/src/lib/libc/port/locale/wcswidth.c
index e6d98488d1..31e7c0e1d6 100644
--- a/usr/src/lib/libc/port/locale/wcswidth.c
+++ b/usr/src/lib/libc/port/locale/wcswidth.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -37,19 +38,27 @@
*/
#include "lint.h"
+#include <locale.h>
#include <wchar.h>
+#include <xlocale.h>
int
-wcswidth(const wchar_t *pwcs, size_t n)
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t loc)
{
wchar_t wc;
int len, l;
len = 0;
while (n-- > 0 && (wc = *pwcs++) != L'\0') {
- if ((l = wcwidth(wc)) < 0)
+ if ((l = wcwidth_l(wc, loc)) < 0)
return (-1);
len += l;
}
return (len);
}
+
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+ return (wcswidth_l(pwcs, n, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wcsxfrm.c b/usr/src/lib/libc/port/locale/wcsxfrm.c
index 6c21db391f..7001637b7e 100644
--- a/usr/src/lib/libc/port/locale/wcsxfrm.c
+++ b/usr/src/lib/libc/port/locale/wcsxfrm.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
@@ -36,10 +37,11 @@
#define WCS_XFRM_OFFSET 1
size_t
-wcsxfrm(wchar_t *_RESTRICT_KYWD dest,
- const wchar_t *_RESTRICT_KYWD src, size_t len)
+wcsxfrm_l(wchar_t *_RESTRICT_KYWD dest,
+ const wchar_t *_RESTRICT_KYWD src, size_t len, locale_t loc)
{
size_t slen;
+ const struct lc_collate *lcc = loc->collate;
if (*src == L'\0') {
if (len != 0)
@@ -47,8 +49,8 @@ wcsxfrm(wchar_t *_RESTRICT_KYWD dest,
return (0);
}
- if ((_collate_load_error) ||
- ((slen = _collate_wxfrm(src, dest, len)) == (size_t)-1)) {
+ if ((lcc->lc_is_posix) ||
+ ((slen = _collate_wxfrm(lcc, src, dest, len)) == (size_t)-1)) {
goto error;
}
@@ -71,3 +73,10 @@ error:
}
return (slen);
}
+
+size_t
+wcsxfrm(wchar_t *_RESTRICT_KYWD dest,
+ const wchar_t *_RESTRICT_KYWD src, size_t len)
+{
+ return (wcsxfrm_l(dest, src, len, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wctob.c b/usr/src/lib/libc/port/locale/wctob.c
index c44c10fbb7..62a07a0bb9 100644
--- a/usr/src/lib/libc/port/locale/wctob.c
+++ b/usr/src/lib/libc/port/locale/wctob.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -29,16 +30,24 @@
#include <limits.h>
#include <stdio.h>
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
int
-wctob(wint_t c)
+wctob_l(wint_t c, locale_t loc)
{
static const mbstate_t initial = { 0 };
mbstate_t mbs = initial;
char buf[MB_LEN_MAX];
- if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1)
+ if (c == WEOF || wcrtomb_l(buf, c, &mbs, loc) != 1)
return (EOF);
return ((unsigned char)*buf);
}
+
+int
+wctob(wint_t c)
+{
+ return (wctob_l(c, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wctomb.c b/usr/src/lib/libc/port/locale/wctomb.c
index 2c6bd77a61..b65444c97f 100644
--- a/usr/src/lib/libc/port/locale/wctomb.c
+++ b/usr/src/lib/libc/port/locale/wctomb.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
@@ -28,21 +29,27 @@
#include "lint.h"
#include <stdlib.h>
#include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
#include "mblocal.h"
int
-wctomb(char *s, wchar_t wchar)
+wctomb_l(char *s, wchar_t wchar, locale_t loc)
{
- static const mbstate_t initial = { 0 };
- static mbstate_t mbs;
+ mbstate_t mbs = { 0 };
size_t rval;
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
return (0);
}
- if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1)
+ if ((rval = wcrtomb_l(s, wchar, &mbs, loc)) == (size_t)-1)
return (-1);
return ((int)rval);
}
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+ return (wctomb_l(s, wchar, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wctrans.c b/usr/src/lib/libc/port/locale/wctrans.c
index c7f6fb597f..7c808d8e15 100644
--- a/usr/src/lib/libc/port/locale/wctrans.c
+++ b/usr/src/lib/libc/port/locale/wctrans.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
@@ -26,9 +27,11 @@
*/
#include "lint.h"
+#include <note.h>
#include <errno.h>
#include <string.h>
#include <wctype.h>
+#include <locale.h>
enum {
_WCT_ERROR = 0,
@@ -37,15 +40,14 @@ enum {
};
wint_t
-towctrans(wint_t wc, wctrans_t desc)
+towctrans_l(wint_t wc, wctrans_t desc, locale_t loc)
{
-
switch (desc) {
case _WCT_TOLOWER:
- wc = towlower(wc);
+ wc = towlower_l(wc, loc);
break;
case _WCT_TOUPPER:
- wc = towupper(wc);
+ wc = towupper_l(wc, loc);
break;
case _WCT_ERROR:
default:
@@ -56,8 +58,18 @@ towctrans(wint_t wc, wctrans_t desc)
return (wc);
}
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+ return (towctrans_l(wc, desc, uselocale(NULL)));
+}
+
+/*
+ * For *now* we don't support locale sensitive transforms besides toupper
+ * and tolower.
+ */
wctrans_t
-wctrans(const char *charclass)
+wctrans_l(const char *charclass, locale_t loc)
{
struct {
const char *name;
@@ -68,6 +80,7 @@ wctrans(const char *charclass)
{ NULL, _WCT_ERROR }, /* Default */
};
int i;
+ _NOTE(ARGUNUSED(loc));
i = 0;
while (ccls[i].name != NULL && strcmp(ccls[i].name, charclass) != 0)
@@ -77,3 +90,9 @@ wctrans(const char *charclass)
errno = EINVAL;
return (ccls[i].trans);
}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ return (wctrans_l(charclass, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wctype.c b/usr/src/lib/libc/port/locale/wctype.c
index 62a37ad794..3acc3b2d90 100644
--- a/usr/src/lib/libc/port/locale/wctype.c
+++ b/usr/src/lib/libc/port/locale/wctype.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
@@ -29,10 +30,17 @@
#include <ctype.h>
#include <string.h>
#include <wctype.h>
+#include <note.h>
+#include <locale.h>
#include "_ctype.h"
+/*
+ * For now, we don't support locale specific character classes. This is
+ * a capability that needs to be added (locales should be able to define
+ * their own character classes.)
+ */
wctype_t
-wctype(const char *property)
+wctype_l(const char *property, locale_t loc)
{
static const struct {
const char *name;
@@ -57,6 +65,7 @@ wctype(const char *property)
{ NULL, 0 }, /* Default */
};
int i;
+ _NOTE(ARGUNUSED(loc));
i = 0;
while (props[i].name != NULL && strcmp(props[i].name, property) != 0)
@@ -64,3 +73,9 @@ wctype(const char *property)
return (props[i].mask);
}
+
+wctype_t
+wctype(const char *property)
+{
+ return (wctype_l(property, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/wcwidth.c b/usr/src/lib/libc/port/locale/wcwidth.c
index a6ff73b357..5151f84951 100644
--- a/usr/src/lib/libc/port/locale/wcwidth.c
+++ b/usr/src/lib/libc/port/locale/wcwidth.c
@@ -1,4 +1,5 @@
/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
@@ -44,25 +45,33 @@
#include <wchar.h>
#include "_ctype.h"
#include "runetype.h"
+#include "localeimpl.h"
#undef wcwidth
int
-wcwidth(wchar_t wc)
+wcwidth_l(wchar_t wc, locale_t loc)
{
unsigned int x;
+ const _RuneLocale *rl = loc->runelocale;
if (wc == 0)
return (0);
- x = ((wc < 0 || wc >= _CACHED_RUNES) ? ___runetype(wc) :
- _CurrentRuneLocale->__runetype[wc]) & (_CTYPE_SWM|_CTYPE_R);
+ x = ((wc < 0 || wc >= _CACHED_RUNES) ? __runetype(rl, wc) :
+ rl->__runetype[wc]) & (_CTYPE_SWM|_CTYPE_R);
if ((x & _CTYPE_SWM) != 0)
return ((x & _CTYPE_SWM) >> _CTYPE_SWS);
return ((x & _CTYPE_R) != 0 ? 1 : -1);
}
+int
+wcwidth(wchar_t wc)
+{
+ return (wcwidth_l(wc, uselocale(NULL)));
+}
+
#pragma weak _scrwidth = scrwidth
/*
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 1882a337d5..c07a40aaf5 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -28,7 +28,7 @@
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright (c) 2013 Gary Mills
-#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
#
# MAPFILE HEADER START
@@ -93,6 +93,88 @@ $if _x86 && _ELF64
$add amd64
$endif
+SYMBOL_VERSION ILLUMOS_0.8 { # POSIX 2008 newlocale and friends
+ protected:
+ __global_locale;
+ __mb_cur_max;
+ __mb_cur_max_l;
+ btowc_l;
+ duplocale;
+ fgetwc_l;
+ freelocale;
+ getwc_l;
+ isalnum_l;
+ isalpha_l;
+ isblank_l;
+ iscntrl_l;
+ isdigit_l;
+ isgraph_l;
+ islower_l;
+ isprint_l;
+ ispunct_l;
+ isspace_l;
+ isupper_l;
+ iswideogram;
+ iswideogram_l;
+ iswnumber;
+ iswnumber_l;
+ iswhexnumber;
+ iswhexnumber_l;
+ iswphonogram;
+ iswphonogram_l;
+ iswspecial;
+ iswspecial_l;
+ iswalnum_l;
+ iswalpha_l;
+ iswblank_l;
+ iswcntrl_l;
+ iswctype_l;
+ iswdigit_l;
+ iswgraph_l;
+ iswlower_l;
+ iswprint_l;
+ iswpunct_l;
+ iswspace_l;
+ iswupper_l;
+ mblen_l;
+ mbrlen_l;
+ mbsinit_l;
+ mbsnrtowcs;
+ mbsnrtowcs_l;
+ mbsrtowcs_l;
+ mbstowcs_l;
+ mbtowc_l;
+ newlocale;
+ nl_langinfo_l;
+ strcasecmp_l;
+ strcasestr_l;
+ strcoll_l;
+ strfmon_l;
+ strftime_l;
+ strncasecmp_l;
+ strptime_l;
+ strxfrm_l;
+ tolower_l;
+ toupper_l;
+ towlower_l;
+ towupper_l;
+ towctrans_l;
+ uselocale;
+ wcrtomb_l;
+ wcscasecmp_l;
+ wcscoll_l;
+ wcsncasecmp_l;
+ wcsrtombs_l;
+ wcstombs_l;
+ wcswidth_l;
+ wcsxfrm_l;
+ wctob_l;
+ wctomb_l;
+ wctrans_l;
+ wctype_l;
+ wcwidth_l;
+} ILLUMOS_0.7;
+
SYMBOL_VERSION ILLUMOS_0.7 { # Illumos additions
protected:
_glob_ext;
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 25482d7324..15c5c2b092 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -22,6 +22,7 @@
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
#
# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Use is subject to license terms.
@@ -732,16 +733,12 @@ PORTI18N= \
getwchar.o \
putwchar.o \
putws.o \
- strcasecmp.o \
- strcasestr.o \
- strncasecmp.o \
strtows.o \
wcsnlen.o \
wcstoimax.o \
wcstol.o \
wcstoul.o \
wcswcs.o \
- wscasecmp.o \
wscat.o \
wschr.o \
wscmp.o \
@@ -749,7 +746,6 @@ PORTI18N= \
wscspn.o \
wsdup.o \
wslen.o \
- wsncasecmp.o \
wsncat.o \
wsncmp.o \
wsncpy.o \
@@ -777,7 +773,6 @@ PORTI18N= \
wdresolve.o \
_ctype.o \
isascii.o \
- isdigit.o \
toascii.o
PORTI18N_COND= \
@@ -801,11 +796,13 @@ PORTLOCALE= \
gb2312.o \
gbk.o \
getdate.o \
+ isdigit.o \
iswctype.o \
ldpart.o \
lmessages.o \
lnumeric.o \
lmonetary.o \
+ localeimpl.o \
localeconv.o \
mbftowc.o \
mblen.o \
@@ -828,9 +825,12 @@ PORTLOCALE= \
runetype.o \
setlocale.o \
setrunelocale.o \
+ strcasecmp.o \
+ strcasestr.o \
strcoll.o \
strfmon.o \
strftime.o \
+ strncasecmp.o \
strptime.o \
strxfrm.o \
table.o \
@@ -840,6 +840,7 @@ PORTLOCALE= \
ungetwc.o \
utf8.o \
wcrtomb.o \
+ wcscasecmp.o \
wcscoll.o \
wcsftime.o \
wcsnrtombs.o \
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index fe6844273e..0c3f0a2e32 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -22,6 +22,7 @@
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
#
# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Use is subject to license terms.
@@ -679,16 +680,12 @@ PORTI18N= \
getwchar.o \
putwchar.o \
putws.o \
- strcasecmp.o \
- strcasestr.o \
- strncasecmp.o \
strtows.o \
wcsnlen.o \
wcstoimax.o \
wcstol.o \
wcstoul.o \
wcswcs.o \
- wscasecmp.o \
wscat.o \
wschr.o \
wscmp.o \
@@ -696,7 +693,6 @@ PORTI18N= \
wscspn.o \
wsdup.o \
wslen.o \
- wsncasecmp.o \
wsncat.o \
wsncmp.o \
wsncpy.o \
@@ -724,7 +720,6 @@ PORTI18N= \
wdresolve.o \
_ctype.o \
isascii.o \
- isdigit.o \
toascii.o
PORTI18N_COND= \
@@ -748,12 +743,14 @@ PORTLOCALE= \
gb2312.o \
gbk.o \
getdate.o \
+ isdigit.o \
iswctype.o \
ldpart.o \
lmessages.o \
lnumeric.o \
lmonetary.o \
localeconv.o \
+ localeimpl.o \
mbftowc.o \
mblen.o \
mbrlen.o \
@@ -775,9 +772,12 @@ PORTLOCALE= \
runetype.o \
setlocale.o \
setrunelocale.o \
+ strcasecmp.o \
+ strcasestr.o \
strcoll.o \
strfmon.o \
strftime.o \
+ strncasecmp.o \
strptime.o \
strxfrm.o \
table.o \
@@ -787,6 +787,7 @@ PORTLOCALE= \
ungetwc.o \
utf8.o \
wcrtomb.o \
+ wcscasecmp.o \
wcscoll.o \
wcsftime.o \
wcsnrtombs.o \