setlocale.c revision 32524
11573Srgrimes/* 223661Speter * Copyright (c) 1991, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Paul Borman at Krystal Technologies. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 161573Srgrimes * 3. All advertising materials mentioning features or use of this software 171573Srgrimes * must display the following acknowledgement: 181573Srgrimes * This product includes software developed by the University of 191573Srgrimes * California, Berkeley and its contributors. 201573Srgrimes * 4. Neither the name of the University nor the names of its contributors 211573Srgrimes * may be used to endorse or promote products derived from this software 221573Srgrimes * without specific prior written permission. 231573Srgrimes * 241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3123661Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3390041Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3490041Sobrien * SUCH DAMAGE. 351573Srgrimes * 3671579Sdeischen * $Id: setlocale.c,v 1.21 1997/04/07 08:54:35 ache Exp $ 371573Srgrimes */ 381573Srgrimes 391573Srgrimes#ifdef LIBC_RCS 4023661Speterstatic const char rcsid[] = 411573Srgrimes "$Id: setlocale.c,v 1.21 1997/04/07 08:54:35 ache Exp $"; 4223661Speter#endif 431573Srgrimes 441573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 451573Srgrimesstatic char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; 461573Srgrimes#endif /* LIBC_SCCS and not lint */ 4771579Sdeischen 481573Srgrimes#include <sys/types.h> 491573Srgrimes#include <sys/stat.h> 501573Srgrimes#include <limits.h> 5117141Sjkh#include <locale.h> 521573Srgrimes#include <rune.h> 53109039Stjr#include <stdlib.h> 54109039Stjr#include <string.h> 551573Srgrimes#include <unistd.h> 561573Srgrimes#include "collate.h" 571573Srgrimes#include "setlocale.h" 581573Srgrimes 591573Srgrimes/* 6090041Sobrien * Category names for getenv() 6190041Sobrien */ 6290041Sobrienstatic char *categories[_LC_LAST] = { 6390041Sobrien "LC_ALL", 6490041Sobrien "LC_COLLATE", 65198053Sjilles "LC_CTYPE", 661573Srgrimes "LC_MONETARY", 671573Srgrimes "LC_NUMERIC", 681573Srgrimes "LC_TIME", 69198053Sjilles}; 701573Srgrimes 71198053Sjilles/* 72198053Sjilles * Current locales for each category 731573Srgrimes */ 741573Srgrimesstatic char current_categories[_LC_LAST][ENCODING_LEN + 1] = { 751573Srgrimes "C", 761573Srgrimes "C", 771573Srgrimes "C", 781573Srgrimes "C", 791573Srgrimes "C", 801573Srgrimes "C", 811573Srgrimes}; 821573Srgrimes 831573Srgrimes/* 841573Srgrimes * The locales we are going to try and load 855072Sbde */ 865072Sbdestatic char new_categories[_LC_LAST][ENCODING_LEN + 1]; 875072Sbdestatic char saved_categories[_LC_LAST][ENCODING_LEN + 1]; 885072Sbde 891573Srgrimesstatic char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; 901573Srgrimes 91150172Sachestatic char *currentlocale __P((void)); 921573Srgrimesstatic char *loadlocale __P((int)); 931573Srgrimesstatic int stub_load_locale __P((const char *)); 941573Srgrimes 9565468Speterextern int __time_load_locale __P((const char *)); /* strftime.c */ 9665468Speter 9765468Speter#ifdef XPG4 9865468Speterextern int _xpg4_setrunelocale __P((char *)); 9965468Speter#endif 10065468Speter 10165468Speterchar * 10265468Spetersetlocale(category, locale) 10329476Sphk int category; 10429392Sphk const char *locale; 10565468Speter{ 10629392Sphk int i, j, len; 1071573Srgrimes char *env, *r; 1081573Srgrimes 1091573Srgrimes if (category < LC_ALL || category >= _LC_LAST) 1101573Srgrimes return (NULL); 1111573Srgrimes 1121573Srgrimes if (!locale) 1131573Srgrimes return (category != LC_ALL ? 1141573Srgrimes current_categories[category] : currentlocale()); 1151573Srgrimes 1161573Srgrimes /* 1171573Srgrimes * Default to the current locale for everything. 1181573Srgrimes */ 1191573Srgrimes for (i = 1; i < _LC_LAST; ++i) 120198053Sjilles (void)strcpy(new_categories[i], current_categories[i]); 1211573Srgrimes 1221573Srgrimes /* 1231573Srgrimes * Now go fill up new_categories from the locale argument 1241573Srgrimes */ 1251573Srgrimes if (!*locale) { 1261573Srgrimes env = getenv(categories[category]); 1271573Srgrimes 1281573Srgrimes if (category != LC_ALL && (!env || !*env)) 1291573Srgrimes env = getenv(categories[LC_ALL]); 1301573Srgrimes 1311573Srgrimes if (!env || !*env) 1321573Srgrimes env = getenv("LANG"); 1331573Srgrimes 1341573Srgrimes if (!env || !*env) 1359272Shsu env = "C"; 136198053Sjilles 137198053Sjilles (void) strncpy(new_categories[category], env, ENCODING_LEN); 1381573Srgrimes new_categories[category][ENCODING_LEN] = '\0'; 1391573Srgrimes if (category == LC_ALL) { 1401573Srgrimes for (i = 1; i < _LC_LAST; ++i) { 1411573Srgrimes if (!(env = getenv(categories[i])) || !*env) 142198053Sjilles env = new_categories[LC_ALL]; 143198053Sjilles (void)strncpy(new_categories[i], env, ENCODING_LEN); 144198053Sjilles new_categories[i][ENCODING_LEN] = '\0'; 1451573Srgrimes } 146198053Sjilles } 147198053Sjilles } else if (category != LC_ALL) { 148198053Sjilles (void)strncpy(new_categories[category], locale, ENCODING_LEN); 149198053Sjilles new_categories[category][ENCODING_LEN] = '\0'; 150198053Sjilles } else { 151198053Sjilles if ((r = strchr(locale, '/')) == NULL) { 1521573Srgrimes for (i = 1; i < _LC_LAST; ++i) { 1531573Srgrimes (void)strncpy(new_categories[i], locale, ENCODING_LEN); 1541573Srgrimes new_categories[i][ENCODING_LEN] = '\0'; 1551573Srgrimes } 1561573Srgrimes } else { 1571573Srgrimes for (i = 1; r[1] == '/'; ++r); 1581573Srgrimes if (!r[1]) 1591573Srgrimes return (NULL); /* Hmm, just slashes... */ 1601573Srgrimes do { 1611573Srgrimes len = r - locale > ENCODING_LEN ? ENCODING_LEN : r - locale; 1621573Srgrimes (void)strncpy(new_categories[i], locale, len); 1631573Srgrimes new_categories[i][len] = '\0'; 1641573Srgrimes i++; 1651573Srgrimes locale = r; 1661573Srgrimes while (*locale == '/') 1671573Srgrimes ++locale; 1681573Srgrimes while (*++r && *r != '/'); 1691573Srgrimes } while (*locale); 1701573Srgrimes while (i < _LC_LAST) 1711573Srgrimes (void)strcpy(new_categories[i], 1721573Srgrimes new_categories[i-1]); 1731573Srgrimes } 174198053Sjilles } 175198053Sjilles 1761573Srgrimes if (category) 1771573Srgrimes return (loadlocale(category)); 1781573Srgrimes 1791573Srgrimes for (i = 1; i < _LC_LAST; ++i) { 1801573Srgrimes (void)strcpy(saved_categories[i], current_categories[i]); 1811573Srgrimes if (loadlocale(i) == NULL) { 1821573Srgrimes for (j = 1; j < i; j++) { 1831573Srgrimes (void)strcpy(new_categories[j], 1841573Srgrimes saved_categories[j]); 1851573Srgrimes /* XXX can fail too */ 1861573Srgrimes (void)loadlocale(j); 1871573Srgrimes } 1881573Srgrimes return (NULL); 189150297Sache } 1901573Srgrimes } 1911573Srgrimes return (currentlocale()); 1921573Srgrimes} 1931573Srgrimes 1941573Srgrimesstatic char * 1951573Srgrimescurrentlocale() 1961573Srgrimes{ 1971573Srgrimes int i; 198109040Stjr 1991573Srgrimes (void)strcpy(current_locale_string, current_categories[1]); 2001573Srgrimes 2011573Srgrimes for (i = 2; i < _LC_LAST; ++i) 2029272Shsu if (strcmp(current_categories[1], current_categories[i])) { 2031573Srgrimes (void) strcpy(current_locale_string, current_categories[1]); 2041573Srgrimes (void) strcat(current_locale_string, "/"); 2051573Srgrimes (void) strcat(current_locale_string, current_categories[2]); 2061573Srgrimes (void) strcat(current_locale_string, "/"); 2071573Srgrimes (void) strcat(current_locale_string, current_categories[3]); 2081573Srgrimes (void) strcat(current_locale_string, "/"); 2091573Srgrimes (void) strcat(current_locale_string, current_categories[4]); 2101573Srgrimes (void) strcat(current_locale_string, "/"); 2111573Srgrimes (void) strcat(current_locale_string, current_categories[5]); 2121573Srgrimes break; 2131573Srgrimes } 2141573Srgrimes return (current_locale_string); 2151573Srgrimes} 2161573Srgrimes 2171573Srgrimesstatic char * 2181573Srgrimesloadlocale(category) 2191573Srgrimes int category; 2201573Srgrimes{ 22132530Smckay char *ret; 22232530Smckay char *new = new_categories[category]; 2231573Srgrimes char *old = current_categories[category]; 2241573Srgrimes 22528235Sdg if (_PathLocale == NULL) { 22628235Sdg char *p = getenv("PATH_LOCALE"); 22732530Smckay 22832530Smckay if (p != NULL 2291573Srgrimes#ifndef __NETBSD_SYSCALLS 2301573Srgrimes && !issetugid() 231#endif 232 ) { 233 if (strlen(p) + 1/*"/"*/ + ENCODING_LEN + 234 1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) 235 return (NULL); 236 _PathLocale = strdup(p); 237 if (_PathLocale == NULL) 238 return (NULL); 239 } else 240 _PathLocale = _PATH_LOCALE; 241 } 242 243 if (strcmp(new, old) == 0) 244 return (old); 245 246 if (category == LC_CTYPE) { 247#ifdef XPG4 248 ret = _xpg4_setrunelocale(new) ? NULL : new; 249#else 250 ret = setrunelocale(new) ? NULL : new; 251#endif 252 if (!ret) { 253#ifdef XPG4 254 (void)_xpg4_setrunelocale(old); 255#else 256 (void)setrunelocale(old); 257#endif 258 } else 259 (void)strcpy(old, new); 260 return (ret); 261 } 262 263 if (category == LC_COLLATE) { 264 ret = (__collate_load_tables(new) < 0) ? NULL : new; 265 if (!ret) 266 (void)__collate_load_tables(old); 267 else 268 (void)strcpy(old, new); 269 return (ret); 270 } 271 272 if (category == LC_TIME) { 273 ret = (__time_load_locale(new) < 0) ? NULL : new; 274 if (!ret) 275 (void)__time_load_locale(old); 276 else 277 (void)strcpy(old, new); 278 return (ret); 279 } 280 281 if (category == LC_MONETARY || category == LC_NUMERIC) { 282 ret = stub_load_locale(new) ? NULL : new; 283 if (!ret) 284 (void)stub_load_locale(old); 285 else 286 (void)strcpy(old, new); 287 return (ret); 288 } 289 290 /* Just in case...*/ 291 return (NULL); 292} 293 294static int 295stub_load_locale(encoding) 296const char *encoding; 297{ 298 char name[PATH_MAX]; 299 struct stat st; 300 301 if (!encoding) 302 return(1); 303 /* 304 * The "C" and "POSIX" locale are always here. 305 */ 306 if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) 307 return(0); 308 if (!_PathLocale) 309 return(1); 310 /* Range checking not needed, encoding has fixed size */ 311 strcpy(name, _PathLocale); 312 strcat(name, "/"); 313 strcat(name, encoding); 314#if 0 315 /* 316 * Some day we will actually look at this file. 317 */ 318#endif 319 return (stat(name, &st) != 0 || !S_ISDIR(st.st_mode)); 320} 321