14297a3b0SGarrett D'Amore /* 2*2d08521bSGarrett 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> 46*2d08521bSGarrett D'Amore #include "mtlib.h" 474297a3b0SGarrett D'Amore #include "collate.h" 48*2d08521bSGarrett D'Amore #include "lnumeric.h" /* for struct lc_numeric */ 49*2d08521bSGarrett D'Amore #include "lctype.h" /* for struct lc_ctype */ 504297a3b0SGarrett D'Amore #include "setlocale.h" 514297a3b0SGarrett D'Amore #include "../i18n/_loc_path.h" 52*2d08521bSGarrett D'Amore #include "localeimpl.h" 53*2d08521bSGarrett D'Amore #include "../i18n/_locale.h" 544297a3b0SGarrett D'Amore 554297a3b0SGarrett D'Amore /* 564297a3b0SGarrett D'Amore * Path to locale storage directory. See ../i18n/_loc_path.h 574297a3b0SGarrett D'Amore */ 584297a3b0SGarrett D'Amore char *_PathLocale = _DFLT_LOC_PATH; 594297a3b0SGarrett D'Amore 60*2d08521bSGarrett D'Amore static char *current_locale(locale_t, int); 61*2d08521bSGarrett D'Amore static void install_legacy(locale_t, int); 624297a3b0SGarrett D'Amore 63*2d08521bSGarrett D'Amore static mutex_t setlocale_lock = DEFAULTMUTEX; 64*2d08521bSGarrett D'Amore static locale_t setlocale_list = NULL; 654297a3b0SGarrett D'Amore 664297a3b0SGarrett D'Amore char * 67*2d08521bSGarrett D'Amore setlocale(int category, const char *locname) 684297a3b0SGarrett D'Amore { 69*2d08521bSGarrett D'Amore locale_t loc; 70*2d08521bSGarrett D'Amore locale_t srch; 71*2d08521bSGarrett D'Amore int mask; 724297a3b0SGarrett D'Amore 73*2d08521bSGarrett D'Amore if (category < 0 || category > LC_ALL) { 744297a3b0SGarrett D'Amore errno = EINVAL; 754297a3b0SGarrett D'Amore return (NULL); 764297a3b0SGarrett D'Amore } 774297a3b0SGarrett D'Amore 78*2d08521bSGarrett D'Amore if (locname == NULL) 79*2d08521bSGarrett D'Amore return (current_locale(___global_locale, category)); 804297a3b0SGarrett D'Amore 81*2d08521bSGarrett D'Amore mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category)); 824297a3b0SGarrett D'Amore 83*2d08521bSGarrett D'Amore loc = newlocale(mask, locname, NULL); 84*2d08521bSGarrett D'Amore if (loc == NULL) { 85*2d08521bSGarrett D'Amore return (NULL); 864297a3b0SGarrett D'Amore } 874297a3b0SGarrett D'Amore 88*2d08521bSGarrett D'Amore /* 89*2d08521bSGarrett D'Amore * This next logic looks to see if we have ever used the same locale 90*2d08521bSGarrett D'Amore * settings before. If so, we reuse it. We avoid ever calling 91*2d08521bSGarrett D'Amore * freelocale() on a locale setting built up by setlocale, this 92*2d08521bSGarrett D'Amore * ensures that consumers (uselocale) will always be thread safe; 93*2d08521bSGarrett D'Amore * the actual locale data objects are never freed, and unique 94*2d08521bSGarrett D'Amore * locale objects are also never freed. We reuse to avoid leaking 95*2d08521bSGarrett D'Amore * memory in applications that call setlocale repeatedly. 96*2d08521bSGarrett D'Amore */ 97*2d08521bSGarrett D'Amore lmutex_lock(&setlocale_lock); 98*2d08521bSGarrett D'Amore for (srch = setlocale_list; srch != NULL; srch = srch->next) { 99*2d08521bSGarrett D'Amore if (strcmp(srch->locname, loc->locname) == 0) { 1004297a3b0SGarrett D'Amore break; 1014297a3b0SGarrett D'Amore } 1025f5fdac7SGarrett D'Amore } 1035f5fdac7SGarrett D'Amore 104*2d08521bSGarrett D'Amore if (srch == NULL) { 105*2d08521bSGarrett D'Amore /* this is a new locale, save it for reuse later */ 106*2d08521bSGarrett D'Amore loc->next = setlocale_list; 107*2d08521bSGarrett D'Amore loc->on_list = 1; 108*2d08521bSGarrett D'Amore setlocale_list = loc; 1095f5fdac7SGarrett D'Amore } else { 110*2d08521bSGarrett D'Amore /* we already had it, toss the new, and use what we found */ 111*2d08521bSGarrett D'Amore freelocale(loc); 112*2d08521bSGarrett D'Amore loc = srch; 1135f5fdac7SGarrett D'Amore } 114*2d08521bSGarrett D'Amore ___global_locale = loc; 115*2d08521bSGarrett D'Amore 116*2d08521bSGarrett D'Amore install_legacy(loc, mask); 117*2d08521bSGarrett D'Amore lmutex_unlock(&setlocale_lock); 118*2d08521bSGarrett D'Amore 119*2d08521bSGarrett D'Amore return (current_locale(loc, category)); 1204297a3b0SGarrett D'Amore } 1214297a3b0SGarrett D'Amore 1224297a3b0SGarrett D'Amore static char * 123*2d08521bSGarrett D'Amore current_locale(locale_t loc, int cat) 1244297a3b0SGarrett D'Amore { 125*2d08521bSGarrett D'Amore switch (cat) { 1264297a3b0SGarrett D'Amore case LC_CTYPE: 1274297a3b0SGarrett D'Amore case LC_COLLATE: 1284297a3b0SGarrett D'Amore case LC_MESSAGES: 129*2d08521bSGarrett D'Amore case LC_MONETARY: 130*2d08521bSGarrett D'Amore case LC_NUMERIC: 131*2d08521bSGarrett D'Amore case LC_TIME: 132*2d08521bSGarrett D'Amore return (loc->locdata[cat]->l_lname); 133*2d08521bSGarrett D'Amore case LC_ALL: 134*2d08521bSGarrett D'Amore return (loc->locname); 1354297a3b0SGarrett D'Amore default: 1364297a3b0SGarrett D'Amore return (NULL); 1374297a3b0SGarrett D'Amore } 1384297a3b0SGarrett D'Amore } 1394297a3b0SGarrett D'Amore 140*2d08521bSGarrett D'Amore static void 141*2d08521bSGarrett D'Amore install_legacy(locale_t loc, int mask) 1424297a3b0SGarrett D'Amore { 143*2d08521bSGarrett D'Amore /* 144*2d08521bSGarrett D'Amore * Update the legacy fixed variables that may be baked into 145*2d08521bSGarrett D'Amore * legacy programs. This is really unfortunate, but we can't 146*2d08521bSGarrett D'Amore * solve for them otherwise. Note that such legacy programs 147*2d08521bSGarrett D'Amore * are only going to see the global locale settings, and cannot 148*2d08521bSGarrett D'Amore * benefit from uselocale(). 149*2d08521bSGarrett D'Amore */ 150*2d08521bSGarrett D'Amore if (mask & LC_NUMERIC_MASK) { 151*2d08521bSGarrett D'Amore struct lc_numeric *lnum; 152*2d08521bSGarrett D'Amore lnum = loc->locdata[LC_NUMERIC]->l_data[0]; 153*2d08521bSGarrett D'Amore _numeric[0] = *lnum->decimal_point; 154*2d08521bSGarrett D'Amore _numeric[1] = *lnum->thousands_sep; 155*2d08521bSGarrett D'Amore } 1564297a3b0SGarrett D'Amore 157*2d08521bSGarrett D'Amore if (mask & LC_CTYPE_MASK) { 158*2d08521bSGarrett D'Amore struct lc_ctype *lct; 159*2d08521bSGarrett D'Amore lct = loc->locdata[LC_CTYPE]->l_data[0]; 160*2d08521bSGarrett D'Amore for (int i = 0; i < _CACHED_RUNES; i++) { 161*2d08521bSGarrett D'Amore /* ctype can only encode the lower 8 bits. */ 162*2d08521bSGarrett D'Amore __ctype[i+1] = lct->lc_ctype_mask[i] & 0xff; 163*2d08521bSGarrett D'Amore __ctype_mask[i] = lct->lc_ctype_mask[i]; 164*2d08521bSGarrett D'Amore } 1654297a3b0SGarrett D'Amore 166*2d08521bSGarrett D'Amore /* The bottom half is the toupper/lower array */ 167*2d08521bSGarrett D'Amore for (int i = 0; i < _CACHED_RUNES; i++) { 168*2d08521bSGarrett D'Amore int u, l; 169*2d08521bSGarrett D'Amore __ctype[258 + i] = i; 170*2d08521bSGarrett D'Amore u = lct->lc_trans_upper[i]; 171*2d08521bSGarrett D'Amore l = lct->lc_trans_lower[i]; 172*2d08521bSGarrett D'Amore if (u && u != i) 173*2d08521bSGarrett D'Amore __ctype[258+i] = u; 174*2d08521bSGarrett D'Amore if (l && l != i) 175*2d08521bSGarrett D'Amore __ctype[258+i] = l; 176*2d08521bSGarrett D'Amore 177*2d08521bSGarrett D'Amore /* Don't forget these annoyances either! */ 178*2d08521bSGarrett D'Amore __trans_upper[i] = u; 179*2d08521bSGarrett D'Amore __trans_lower[i] = l; 180*2d08521bSGarrett D'Amore } 1814297a3b0SGarrett D'Amore 182*2d08521bSGarrett D'Amore /* Maximum mblen, cswidth, weird legacy */ 183*2d08521bSGarrett D'Amore __ctype[520] = lct->lc_max_mblen; 184*2d08521bSGarrett D'Amore } 1854297a3b0SGarrett D'Amore } 186