diff options
author | Keith M Wesolowski <wesolows@foobazco.org> | 2014-07-14 18:15:43 +0000 |
---|---|---|
committer | Keith M Wesolowski <wesolows@foobazco.org> | 2014-07-14 18:15:43 +0000 |
commit | bcc902ab131af782d25fde71a21d71ab2bccb677 (patch) | |
tree | 4f4eb16f84eedc791b2a7f6adb73e9e281ca1bbb /usr/src/lib/libc | |
parent | 1bce44cb939839753c1f6934c0da4cfe42f02e44 (diff) | |
parent | 5e74f94d8c2a16c2ef7cf2940a157ffabb379c27 (diff) | |
download | illumos-joyent-bcc902ab131af782d25fde71a21d71ab2bccb677.tar.gz |
[illumos-gate merge]
commit 5e74f94d8c2a16c2ef7cf2940a157ffabb379c27
3347 zonecfg(1M) is confused about selection
commit 5a81b4ad6a940aead6f0789e059a6f8fbc678be0
4544 sock2path(4) man page needs to be updated for configuration fragments
commit 2d08521bd15501c8370ba2153b9cca4f094979d0
2964 need POSIX 2008 locale object support
Conflicts:
usr/src/man/man3c/Makefile (copyright)
usr/src/lib/libzonecfg/common/libzonecfg.c (OS-216)
usr/src/lib/libc/sparcv9/Makefile.com (copyright)
usr/src/lib/libc/sparc/Makefile.com (copyright)
Manifests:
usr/src/pkg/manifests/system-header.mf
usr/src/pkg/manifests/system-library.man3c.inc
Diffstat (limited to 'usr/src/lib/libc')
81 files changed, 2779 insertions, 1735 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index cec30a4fbd..4afe40c01b 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -23,6 +23,7 @@ # Copyright (c) 2014, 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 ddbed44735..f229dec61d 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) 2014, 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 c08f234962..d095860439 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -28,7 +28,7 @@ # Copyright (c) 2012 by Delphix. 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 34d35699d0..b6f50d3263 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -21,6 +21,7 @@ # # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. +# Copyright 2013 Garrett D'Amore <garrett@damore.org> # Copyright (c) 2014, Joyent, Inc. All rights reserved. # # Copyright 2011 Nexenta Systems, Inc. All rights reserved. @@ -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 65ac2dedc7..c67d0734d1 100644 --- a/usr/src/lib/libc/sparcv9/Makefile.com +++ b/usr/src/lib/libc/sparcv9/Makefile.com @@ -21,6 +21,7 @@ # # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. +# Copyright 2013 Garrett D'Amore <garrett@damore.org> # Copyright (c) 2014, Joyent, Inc. All rights reserved. # # Copyright 2011 Nexenta Systems, Inc. All rights reserved. @@ -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 \ |