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