1 /* $NetBSD: setlocale.c,v 1.11 1997/06/02 09:52:50 kleink 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 #if defined(LIBC_SCCS) && !defined(lint) 40 #if 0 41 static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; 42 #else 43 static char rcsid[] = "$NetBSD: setlocale.c,v 1.11 1997/06/02 09:52:50 kleink Exp $"; 44 #endif 45 #endif /* LIBC_SCCS and not lint */ 46 47 #define _CTYPE_PRIVATE 48 49 #include <sys/localedef.h> 50 #include <ctype.h> 51 #include <limits.h> 52 #include <locale.h> 53 #include <paths.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include "ctypeio.h" 58 59 /* 60 * Category names for getenv() 61 */ 62 static char *categories[_LC_LAST] = { 63 "LC_ALL", 64 "LC_COLLATE", 65 "LC_CTYPE", 66 "LC_MONETARY", 67 "LC_NUMERIC", 68 "LC_TIME", 69 "LC_MESSAGES" 70 }; 71 72 /* 73 * Current locales for each category 74 */ 75 static char current_categories[_LC_LAST][32] = { 76 "C", 77 "C", 78 "C", 79 "C", 80 "C", 81 "C", 82 "C" 83 }; 84 85 /* 86 * The locales we are going to try and load 87 */ 88 static char new_categories[_LC_LAST][32]; 89 90 static char current_locale_string[_LC_LAST * 33]; 91 static char *PathLocale; 92 93 static char *currentlocale __P((void)); 94 static char *loadlocale __P((int)); 95 96 char * 97 setlocale(category, locale) 98 int category; 99 const char *locale; 100 { 101 int i, len; 102 char *env, *r; 103 104 /* 105 * XXX potential security problem here with set-id programs 106 * being able to read files the user can not normally read. 107 */ 108 if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE"))) 109 PathLocale = _PATH_LOCALE; 110 111 if (category < 0 || category >= _LC_LAST) 112 return (NULL); 113 114 if (!locale) 115 return (category ? 116 current_categories[category] : currentlocale()); 117 118 /* 119 * Default to the current locale for everything. 120 */ 121 for (i = 1; i < _LC_LAST; ++i) 122 (void)strncpy(new_categories[i], current_categories[i], 123 sizeof(new_categories[i]) - 1); 124 125 /* 126 * Now go fill up new_categories from the locale argument 127 */ 128 if (!*locale) { 129 env = getenv(categories[category]); 130 131 if (!env || !*env) 132 env = getenv(categories[0]); 133 134 if (!env || !*env) 135 env = getenv("LANG"); 136 137 if (!env || !*env) 138 env = "C"; 139 140 (void)strncpy(new_categories[category], env, 31); 141 new_categories[category][31] = 0; 142 if (!category) { 143 for (i = 1; i < _LC_LAST; ++i) { 144 if (!(env = getenv(categories[i])) || !*env) 145 env = new_categories[0]; 146 (void)strncpy(new_categories[i], env, 31); 147 new_categories[i][31] = 0; 148 } 149 } 150 } else if (category) { 151 (void)strncpy(new_categories[category], locale, 31); 152 new_categories[category][31] = 0; 153 } else { 154 if ((r = strchr(locale, '/')) == 0) { 155 for (i = 1; i < _LC_LAST; ++i) { 156 (void)strncpy(new_categories[i], locale, 31); 157 new_categories[i][31] = 0; 158 } 159 } else { 160 for (i = 1; r[1] == '/'; ++r); 161 if (!r[1]) 162 return (NULL); /* Hmm, just slashes... */ 163 do { 164 len = r - locale > 31 ? 31 : r - locale; 165 (void)strncpy(new_categories[i++], locale, len); 166 new_categories[i++][len] = 0; 167 locale = r; 168 while (*locale == '/') 169 ++locale; 170 while (*++r && *r != '/'); 171 } while (*locale); 172 while (i < _LC_LAST) 173 (void)strncpy(new_categories[i], 174 new_categories[i-1], 175 sizeof(new_categories[i]) - 1); 176 } 177 } 178 179 if (category) 180 return (loadlocale(category)); 181 182 for (i = 1; i < _LC_LAST; ++i) 183 if (loadlocale(i) == NULL) 184 return (NULL); 185 186 return (currentlocale()); 187 } 188 189 static char * 190 currentlocale() 191 { 192 int i; 193 194 (void)strncpy(current_locale_string, current_categories[1], 195 sizeof(current_locale_string) - 1); 196 197 for (i = 2; i < _LC_LAST; ++i) 198 if (strcmp(current_categories[1], current_categories[i])) { 199 (void)snprintf(current_locale_string, 200 sizeof(current_locale_string), "%s/%s/%s/%s/%s", 201 current_categories[1], current_categories[2], 202 current_categories[3], current_categories[4], 203 current_categories[5]); 204 break; 205 } 206 return (current_locale_string); 207 } 208 209 char * 210 loadlocale(category) 211 int category; 212 { 213 char name[PATH_MAX]; 214 215 if (strcmp(new_categories[category], current_categories[category]) == 0) 216 return (current_categories[category]); 217 218 if (!strcmp(new_categories[category], "C") || 219 !strcmp(new_categories[category], "POSIX")) { 220 221 switch (category) { 222 case LC_CTYPE: 223 if (_ctype_ != _C_ctype_) { 224 free((void *)_ctype_); 225 _ctype_ = _C_ctype_; 226 } 227 if (_toupper_tab_ != _C_toupper_) { 228 free((void *)_toupper_tab_); 229 _toupper_tab_ = _C_toupper_; 230 } 231 if (_tolower_tab_ != _C_tolower_) { 232 free((void *)_tolower_tab_); 233 _tolower_tab_ = _C_tolower_; 234 } 235 } 236 237 (void)strncpy(current_categories[category], 238 new_categories[category], 239 sizeof(current_categories[category]) - 1); 240 return current_categories[category]; 241 } 242 243 /* 244 * Some day we will actually look at this file. 245 */ 246 (void)snprintf(name, sizeof(name), "%s/%s/%s", 247 PathLocale, new_categories[category], categories[category]); 248 249 switch (category) { 250 case LC_CTYPE: 251 if (__loadctype(name)) { 252 (void)strncpy(current_categories[category], 253 new_categories[category], 254 sizeof(current_categories[category]) - 1); 255 return current_categories[category]; 256 } 257 return NULL; 258 259 case LC_COLLATE: 260 case LC_MESSAGES: 261 case LC_MONETARY: 262 case LC_NUMERIC: 263 case LC_TIME: 264 return NULL; 265 } 266 267 return NULL; 268 } 269