1 /* $NetBSD: setlocale.c,v 1.17 1999/10/15 17:17:07 jdolecek Exp $ */ 2 3 /* 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Paul Borman at Krystal Technologies. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 #if 0 42 static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; 43 #else 44 __RCSID("$NetBSD: setlocale.c,v 1.17 1999/10/15 17:17:07 jdolecek Exp $"); 45 #endif 46 #endif /* LIBC_SCCS and not lint */ 47 48 #define _CTYPE_PRIVATE 49 50 #include "namespace.h" 51 #include <sys/localedef.h> 52 #include <ctype.h> 53 #include <limits.h> 54 #include <locale.h> 55 #include <paths.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include "ctypeio.h" 60 61 /* 62 * Category names for getenv() 63 */ 64 static const char *const categories[_LC_LAST] = { 65 "LC_ALL", 66 "LC_COLLATE", 67 "LC_CTYPE", 68 "LC_MONETARY", 69 "LC_NUMERIC", 70 "LC_TIME", 71 "LC_MESSAGES" 72 }; 73 74 /* 75 * Current locales for each category 76 */ 77 static char current_categories[_LC_LAST][32] = { 78 "C", 79 "C", 80 "C", 81 "C", 82 "C", 83 "C", 84 "C" 85 }; 86 87 /* 88 * The locales we are going to try and load 89 */ 90 static char new_categories[_LC_LAST][32]; 91 92 static char current_locale_string[_LC_LAST * 33]; 93 static char *PathLocale; 94 95 static char *currentlocale __P((void)); 96 static char *loadlocale __P((int)); 97 98 char * 99 setlocale(category, locale) 100 int category; 101 const char *locale; 102 { 103 int i; 104 size_t len; 105 char *env, *r; 106 107 /* 108 * XXX potential security problem here with set-id programs 109 * being able to read files the user can not normally read. 110 */ 111 if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE"))) 112 PathLocale = _PATH_LOCALE; 113 114 if (category < 0 || category >= _LC_LAST) 115 return (NULL); 116 117 if (!locale) 118 return (category ? 119 current_categories[category] : currentlocale()); 120 121 /* 122 * Default to the current locale for everything. 123 */ 124 for (i = 1; i < _LC_LAST; ++i) 125 (void)strncpy(new_categories[i], current_categories[i], 126 sizeof(new_categories[i]) - 1); 127 128 /* 129 * Now go fill up new_categories from the locale argument 130 */ 131 if (!*locale) { 132 env = getenv(categories[category]); 133 134 if (!env || !*env) 135 env = getenv(categories[0]); 136 137 if (!env || !*env) 138 env = getenv("LANG"); 139 140 if (!env || !*env) 141 env = "C"; 142 143 (void)strncpy(new_categories[category], env, 31); 144 new_categories[category][31] = 0; 145 if (!category) { 146 for (i = 1; i < _LC_LAST; ++i) { 147 if (!(env = getenv(categories[i])) || !*env) 148 env = new_categories[0]; 149 (void)strncpy(new_categories[i], env, 31); 150 new_categories[i][31] = 0; 151 } 152 } 153 } else if (category) { 154 (void)strncpy(new_categories[category], locale, 31); 155 new_categories[category][31] = 0; 156 } else { 157 if ((r = strchr(locale, '/')) == 0) { 158 for (i = 1; i < _LC_LAST; ++i) { 159 (void)strncpy(new_categories[i], locale, 31); 160 new_categories[i][31] = 0; 161 } 162 } else { 163 for (i = 1; r[1] == '/'; ++r); 164 if (!r[1]) 165 return (NULL); /* Hmm, just slashes... */ 166 do { 167 len = r - locale > 31 ? 31 : r - locale; 168 (void)strncpy(new_categories[i++], locale, len); 169 new_categories[i++][len] = 0; 170 locale = r; 171 while (*locale == '/') 172 ++locale; 173 while (*++r && *r != '/'); 174 } while (*locale); 175 while (i < _LC_LAST) 176 (void)strncpy(new_categories[i], 177 new_categories[i-1], 178 sizeof(new_categories[i]) - 1); 179 } 180 } 181 182 if (category) 183 return (loadlocale(category)); 184 185 for (i = 1; i < _LC_LAST; ++i) 186 (void) loadlocale(i); 187 188 return (currentlocale()); 189 } 190 191 static char * 192 currentlocale() 193 { 194 int i; 195 196 (void)strncpy(current_locale_string, current_categories[1], 197 sizeof(current_locale_string) - 1); 198 199 for (i = 2; i < _LC_LAST; ++i) 200 if (strcmp(current_categories[1], current_categories[i])) { 201 (void)snprintf(current_locale_string, 202 sizeof(current_locale_string), "%s/%s/%s/%s/%s", 203 current_categories[1], current_categories[2], 204 current_categories[3], current_categories[4], 205 current_categories[5]); 206 break; 207 } 208 return (current_locale_string); 209 } 210 211 static char * 212 loadlocale(category) 213 int category; 214 { 215 char name[PATH_MAX]; 216 217 if (strcmp(new_categories[category], current_categories[category]) == 0) 218 return (current_categories[category]); 219 220 if (!strcmp(new_categories[category], "C") || 221 !strcmp(new_categories[category], "POSIX")) { 222 223 switch (category) { 224 case LC_CTYPE: 225 if (_ctype_ != _C_ctype_) { 226 /* LINTED const castaway */ 227 free((void *)_ctype_); 228 _ctype_ = _C_ctype_; 229 } 230 if (_toupper_tab_ != _C_toupper_) { 231 /* LINTED const castaway */ 232 free((void *)_toupper_tab_); 233 _toupper_tab_ = _C_toupper_; 234 } 235 if (_tolower_tab_ != _C_tolower_) { 236 /* LINTED const castaway */ 237 free((void *)_tolower_tab_); 238 _tolower_tab_ = _C_tolower_; 239 } 240 } 241 242 (void)strncpy(current_categories[category], 243 new_categories[category], 244 sizeof(current_categories[category]) - 1); 245 return current_categories[category]; 246 } 247 248 /* 249 * Some day we will actually look at this file. 250 */ 251 (void)snprintf(name, sizeof(name), "%s/%s/%s", 252 PathLocale, new_categories[category], categories[category]); 253 254 switch (category) { 255 case LC_CTYPE: 256 if (__loadctype(name)) { 257 (void)strncpy(current_categories[category], 258 new_categories[category], 259 sizeof(current_categories[category]) - 1); 260 return current_categories[category]; 261 } 262 return NULL; 263 264 case LC_COLLATE: 265 case LC_MESSAGES: 266 case LC_MONETARY: 267 case LC_NUMERIC: 268 case LC_TIME: 269 return NULL; 270 } 271 272 return NULL; 273 } 274