14297a3b0SGarrett D'Amore /* 22d08521bSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 36b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 44297a3b0SGarrett D'Amore * Copyright (c) 1996 - 2002 FreeBSD Project 54297a3b0SGarrett D'Amore * Copyright (c) 1991, 1993 64297a3b0SGarrett D'Amore * The Regents of the University of California. All rights reserved. 74297a3b0SGarrett D'Amore * 84297a3b0SGarrett D'Amore * This code is derived from software contributed to Berkeley by 94297a3b0SGarrett D'Amore * Paul Borman at Krystal Technologies. 104297a3b0SGarrett D'Amore * 114297a3b0SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 124297a3b0SGarrett D'Amore * modification, are permitted provided that the following conditions 134297a3b0SGarrett D'Amore * are met: 144297a3b0SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 154297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 164297a3b0SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 174297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 184297a3b0SGarrett D'Amore * documentation and/or other materials provided with the distribution. 194297a3b0SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 204297a3b0SGarrett D'Amore * may be used to endorse or promote products derived from this software 214297a3b0SGarrett D'Amore * without specific prior written permission. 224297a3b0SGarrett D'Amore * 234297a3b0SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 244297a3b0SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 254297a3b0SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 264297a3b0SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 274297a3b0SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 284297a3b0SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 294297a3b0SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 304297a3b0SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 314297a3b0SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 324297a3b0SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 334297a3b0SGarrett D'Amore * SUCH DAMAGE. 344297a3b0SGarrett D'Amore */ 354297a3b0SGarrett D'Amore 364297a3b0SGarrett D'Amore #include "lint.h" 374297a3b0SGarrett D'Amore #include <sys/types.h> 384297a3b0SGarrett D'Amore #include <sys/stat.h> 394297a3b0SGarrett D'Amore #include <errno.h> 404297a3b0SGarrett D'Amore #include <limits.h> 414297a3b0SGarrett D'Amore #include <locale.h> 424297a3b0SGarrett D'Amore #include <stdlib.h> 434297a3b0SGarrett D'Amore #include <string.h> 444297a3b0SGarrett D'Amore #include <unistd.h> 455f5fdac7SGarrett D'Amore #include <stdio.h> 462d08521bSGarrett D'Amore #include "mtlib.h" 474297a3b0SGarrett D'Amore #include "collate.h" 482d08521bSGarrett D'Amore #include "lnumeric.h" /* for struct lc_numeric */ 492d08521bSGarrett D'Amore #include "lctype.h" /* for struct lc_ctype */ 50*bc09504fSGordon Ross #include "runetype.h" 514297a3b0SGarrett D'Amore #include "setlocale.h" 524297a3b0SGarrett D'Amore #include "../i18n/_loc_path.h" 532d08521bSGarrett D'Amore #include "localeimpl.h" 542d08521bSGarrett D'Amore #include "../i18n/_locale.h" 55b599bd93SRobert Mustacchi #include "libc.h" 564297a3b0SGarrett D'Amore 574297a3b0SGarrett D'Amore /* 584297a3b0SGarrett D'Amore * Path to locale storage directory. See ../i18n/_loc_path.h 594297a3b0SGarrett D'Amore */ 604297a3b0SGarrett D'Amore char *_PathLocale = _DFLT_LOC_PATH; 614297a3b0SGarrett D'Amore 622d08521bSGarrett D'Amore static void install_legacy(locale_t, int); 634297a3b0SGarrett D'Amore 642d08521bSGarrett D'Amore static mutex_t setlocale_lock = DEFAULTMUTEX; 652d08521bSGarrett D'Amore static locale_t setlocale_list = NULL; 664297a3b0SGarrett D'Amore 674297a3b0SGarrett D'Amore char * 682d08521bSGarrett D'Amore setlocale(int category, const char *locname) 694297a3b0SGarrett D'Amore { 702d08521bSGarrett D'Amore locale_t loc; 712d08521bSGarrett D'Amore locale_t srch; 722d08521bSGarrett D'Amore int mask; 734297a3b0SGarrett D'Amore 742d08521bSGarrett D'Amore if (category < 0 || category > LC_ALL) { 754297a3b0SGarrett D'Amore errno = EINVAL; 764297a3b0SGarrett D'Amore return (NULL); 774297a3b0SGarrett D'Amore } 784297a3b0SGarrett D'Amore 792d08521bSGarrett D'Amore if (locname == NULL) 802d08521bSGarrett D'Amore return (current_locale(___global_locale, category)); 812d08521bSGarrett D'Amore 822d08521bSGarrett D'Amore mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category)); 832d08521bSGarrett D'Amore 842d08521bSGarrett D'Amore loc = newlocale(mask, locname, NULL); 852d08521bSGarrett D'Amore if (loc == NULL) { 862d08521bSGarrett D'Amore return (NULL); 872d08521bSGarrett D'Amore } 884297a3b0SGarrett D'Amore 894297a3b0SGarrett D'Amore /* 902d08521bSGarrett D'Amore * This next logic looks to see if we have ever used the same locale 912d08521bSGarrett D'Amore * settings before. If so, we reuse it. We avoid ever calling 922d08521bSGarrett D'Amore * freelocale() on a locale setting built up by setlocale, this 932d08521bSGarrett D'Amore * ensures that consumers (uselocale) will always be thread safe; 942d08521bSGarrett D'Amore * the actual locale data objects are never freed, and unique 952d08521bSGarrett D'Amore * locale objects are also never freed. We reuse to avoid leaking 962d08521bSGarrett D'Amore * memory in applications that call setlocale repeatedly. 974297a3b0SGarrett D'Amore */ 982d08521bSGarrett D'Amore lmutex_lock(&setlocale_lock); 992d08521bSGarrett D'Amore for (srch = setlocale_list; srch != NULL; srch = srch->next) { 1002d08521bSGarrett D'Amore if (strcmp(srch->locname, loc->locname) == 0) { 1014297a3b0SGarrett D'Amore break; 1024297a3b0SGarrett D'Amore } 1035f5fdac7SGarrett D'Amore } 1045f5fdac7SGarrett D'Amore 1052d08521bSGarrett D'Amore if (srch == NULL) { 1062d08521bSGarrett D'Amore /* this is a new locale, save it for reuse later */ 1072d08521bSGarrett D'Amore loc->next = setlocale_list; 1082d08521bSGarrett D'Amore loc->on_list = 1; 1092d08521bSGarrett D'Amore setlocale_list = loc; 1105f5fdac7SGarrett D'Amore } else { 1112d08521bSGarrett D'Amore /* we already had it, toss the new, and use what we found */ 1122d08521bSGarrett D'Amore freelocale(loc); 1132d08521bSGarrett D'Amore loc = srch; 1145f5fdac7SGarrett D'Amore } 1152d08521bSGarrett D'Amore ___global_locale = loc; 1162d08521bSGarrett D'Amore 1172d08521bSGarrett D'Amore install_legacy(loc, mask); 1182d08521bSGarrett D'Amore lmutex_unlock(&setlocale_lock); 1192d08521bSGarrett D'Amore 1202d08521bSGarrett D'Amore return (current_locale(loc, category)); 1214297a3b0SGarrett D'Amore } 1224297a3b0SGarrett D'Amore 123b599bd93SRobert Mustacchi char * 1242d08521bSGarrett D'Amore current_locale(locale_t loc, int cat) 1254297a3b0SGarrett D'Amore { 1262d08521bSGarrett D'Amore switch (cat) { 1274297a3b0SGarrett D'Amore case LC_CTYPE: 1284297a3b0SGarrett D'Amore case LC_COLLATE: 1294297a3b0SGarrett D'Amore case LC_MESSAGES: 1302d08521bSGarrett D'Amore case LC_MONETARY: 1312d08521bSGarrett D'Amore case LC_NUMERIC: 1322d08521bSGarrett D'Amore case LC_TIME: 1332d08521bSGarrett D'Amore return (loc->locdata[cat]->l_lname); 1342d08521bSGarrett D'Amore case LC_ALL: 1352d08521bSGarrett D'Amore return (loc->locname); 1364297a3b0SGarrett D'Amore default: 1374297a3b0SGarrett D'Amore return (NULL); 1384297a3b0SGarrett D'Amore } 1394297a3b0SGarrett D'Amore } 1404297a3b0SGarrett D'Amore 1412d08521bSGarrett D'Amore static void 1422d08521bSGarrett D'Amore install_legacy(locale_t loc, int mask) 1434297a3b0SGarrett D'Amore { 1442d08521bSGarrett D'Amore /* 1452d08521bSGarrett D'Amore * Update the legacy fixed variables that may be baked into 1462d08521bSGarrett D'Amore * legacy programs. This is really unfortunate, but we can't 1472d08521bSGarrett D'Amore * solve for them otherwise. Note that such legacy programs 1482d08521bSGarrett D'Amore * are only going to see the global locale settings, and cannot 1492d08521bSGarrett D'Amore * benefit from uselocale(). 1502d08521bSGarrett D'Amore */ 1512d08521bSGarrett D'Amore if (mask & LC_NUMERIC_MASK) { 1522d08521bSGarrett D'Amore struct lc_numeric *lnum; 1532d08521bSGarrett D'Amore lnum = loc->locdata[LC_NUMERIC]->l_data[0]; 1542d08521bSGarrett D'Amore _numeric[0] = *lnum->decimal_point; 1552d08521bSGarrett D'Amore _numeric[1] = *lnum->thousands_sep; 1562d08521bSGarrett D'Amore } 1574297a3b0SGarrett D'Amore 1582d08521bSGarrett D'Amore if (mask & LC_CTYPE_MASK) { 1592d08521bSGarrett D'Amore struct lc_ctype *lct; 1602d08521bSGarrett D'Amore lct = loc->locdata[LC_CTYPE]->l_data[0]; 1612d08521bSGarrett D'Amore for (int i = 0; i < _CACHED_RUNES; i++) { 1622d08521bSGarrett D'Amore /* ctype can only encode the lower 8 bits. */ 1632d08521bSGarrett D'Amore __ctype[i+1] = lct->lc_ctype_mask[i] & 0xff; 1642d08521bSGarrett D'Amore __ctype_mask[i] = lct->lc_ctype_mask[i]; 1652d08521bSGarrett D'Amore } 1664297a3b0SGarrett D'Amore 1672d08521bSGarrett D'Amore /* The bottom half is the toupper/lower array */ 1682d08521bSGarrett D'Amore for (int i = 0; i < _CACHED_RUNES; i++) { 1692d08521bSGarrett D'Amore int u, l; 1702d08521bSGarrett D'Amore __ctype[258 + i] = i; 1712d08521bSGarrett D'Amore u = lct->lc_trans_upper[i]; 1722d08521bSGarrett D'Amore l = lct->lc_trans_lower[i]; 1732d08521bSGarrett D'Amore if (u && u != i) 1742d08521bSGarrett D'Amore __ctype[258+i] = u; 1752d08521bSGarrett D'Amore if (l && l != i) 1762d08521bSGarrett D'Amore __ctype[258+i] = l; 1774297a3b0SGarrett D'Amore 1782d08521bSGarrett D'Amore /* Don't forget these annoyances either! */ 1792d08521bSGarrett D'Amore __trans_upper[i] = u; 1802d08521bSGarrett D'Amore __trans_lower[i] = l; 1812d08521bSGarrett D'Amore } 1824297a3b0SGarrett D'Amore 1832d08521bSGarrett D'Amore /* Maximum mblen, cswidth, weird legacy */ 1842d08521bSGarrett D'Amore __ctype[520] = lct->lc_max_mblen; 1852d08521bSGarrett D'Amore } 1864297a3b0SGarrett D'Amore } 187