setlocale.c revision 19971
1193326Sed/* 2193326Sed * Copyright (c) 1991, 1993 3193326Sed * The Regents of the University of California. All rights reserved. 4193326Sed * 5193326Sed * This code is derived from software contributed to Berkeley by 6193326Sed * Paul Borman at Krystal Technologies. 7193326Sed * 8193326Sed * Redistribution and use in source and binary forms, with or without 9193326Sed * modification, are permitted provided that the following conditions 10193326Sed * are met: 11193326Sed * 1. Redistributions of source code must retain the above copyright 12193326Sed * notice, this list of conditions and the following disclaimer. 13193326Sed * 2. Redistributions in binary form must reproduce the above copyright 14193326Sed * notice, this list of conditions and the following disclaimer in the 15193326Sed * documentation and/or other materials provided with the distribution. 16193326Sed * 3. All advertising materials mentioning features or use of this software 17193326Sed * must display the following acknowledgement: 18252723Sdim * This product includes software developed by the University of 19245431Sdim * California, Berkeley and its contributors. 20207619Srdivacky * 4. Neither the name of the University nor the names of its contributors 21212904Sdim * may be used to endorse or promote products derived from this software 22252723Sdim * without specific prior written permission. 23226890Sdim * 24252723Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25252723Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26221345Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27252723Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28193326Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30198092Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31235633Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34252723Sdim * SUCH DAMAGE. 35193326Sed * 36252723Sdim * $Id$ 37252723Sdim */ 38252723Sdim 39252723Sdim#if defined(LIBC_SCCS) && !defined(lint) 40245431Sdimstatic char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; 41193326Sed#endif /* LIBC_SCCS and not lint */ 42193326Sed 43252723Sdim#include <limits.h> 44193326Sed#include <locale.h> 45218893Sdim#include <rune.h> 46218893Sdim#include <stdlib.h> 47252723Sdim#include <string.h> 48252723Sdim#include <sys/stat.h> 49252723Sdim#include "collate.h" 50193326Sed 51207619Srdivacky/* 52226890Sdim * Category names for getenv() 53207619Srdivacky */ 54245431Sdimstatic char *categories[_LC_LAST] = { 55245431Sdim "LC_ALL", 56245431Sdim "LC_COLLATE", 57245431Sdim "LC_CTYPE", 58245431Sdim "LC_MONETARY", 59245431Sdim "LC_NUMERIC", 60245431Sdim "LC_TIME", 61245431Sdim}; 62245431Sdim 63245431Sdim/* 64252723Sdim * Current locales for each category 65252723Sdim */ 66252723Sdimstatic char current_categories[_LC_LAST][32] = { 67252723Sdim "C", 68245431Sdim "C", 69252723Sdim "C", 70252723Sdim "C", 71252723Sdim "C", 72245431Sdim "C", 73245431Sdim}; 74252723Sdim 75252723Sdim/* 76252723Sdim * The locales we are going to try and load 77252723Sdim */ 78252723Sdimstatic char new_categories[_LC_LAST][32]; 79252723Sdimstatic char saved_categories[_LC_LAST][32]; 80245431Sdim 81245431Sdimstatic char current_locale_string[_LC_LAST * 33]; 82245431Sdimchar *_PathLocale; 83245431Sdim 84245431Sdimstatic char *currentlocale __P((void)); 85245431Sdimstatic char *loadlocale __P((int)); 86245431Sdimstatic int stub_load_locale __P((const char *)); 87245431Sdim 88245431Sdimextern int __time_load_locale __P((const char *)); /* strftime.c */ 89245431Sdim 90245431Sdim#ifdef XPG4 91245431Sdimextern int _xpg4_setrunelocale __P((char *)); 92245431Sdim#endif 93245431Sdim 94245431Sdimchar * 95245431Sdimsetlocale(category, locale) 96245431Sdim int category; 97245431Sdim const char *locale; 98245431Sdim{ 99193326Sed int i, j, len; 100193326Sed char *env, *r; 101193326Sed 102193326Sed if (category < LC_ALL || category >= _LC_LAST) 103193326Sed return (NULL); 104193326Sed 105193326Sed if (!locale) 106193326Sed return (category != LC_ALL ? 107218893Sdim current_categories[category] : currentlocale()); 108235633Sdim 109235633Sdim /* 110224145Sdim * Default to the current locale for everything. 111218893Sdim */ 112218893Sdim for (i = 1; i < _LC_LAST; ++i) 113224145Sdim (void)strcpy(new_categories[i], current_categories[i]); 114218893Sdim 115218893Sdim /* 116218893Sdim * Now go fill up new_categories from the locale argument 117193326Sed */ 118193326Sed if (!*locale) { 119193326Sed env = getenv(categories[category]); 120193326Sed 121193326Sed if (category != LC_ALL && (!env || !*env)) 122193326Sed env = getenv(categories[LC_ALL]); 123198092Srdivacky 124193326Sed if (!env || !*env) 125198092Srdivacky env = getenv("LANG"); 126193326Sed 127193326Sed if (!env || !*env) 128193326Sed env = "C"; 129193326Sed 130193326Sed (void) strncpy(new_categories[category], env, 31); 131193326Sed new_categories[category][31] = 0; 132193326Sed if (category == LC_ALL) { 133199482Srdivacky for (i = 1; i < _LC_LAST; ++i) { 134193326Sed if (!(env = getenv(categories[i])) || !*env) 135193326Sed env = new_categories[LC_ALL]; 136198092Srdivacky (void)strncpy(new_categories[i], env, 31); 137193326Sed new_categories[i][31] = 0; 138193326Sed } 139193326Sed } 140193326Sed } else if (category != LC_ALL) { 141193326Sed (void)strncpy(new_categories[category], locale, 31); 142198092Srdivacky new_categories[category][31] = 0; 143193326Sed } else { 144193326Sed if ((r = strchr(locale, '/')) == 0) { 145193326Sed for (i = 1; i < _LC_LAST; ++i) { 146218893Sdim (void)strncpy(new_categories[i], locale, 31); 147193326Sed new_categories[i][31] = 0; 148193326Sed } 149235633Sdim } else { 150235633Sdim for (i = 1; r[1] == '/'; ++r); 151224145Sdim if (!r[1]) 152224145Sdim return (NULL); /* Hmm, just slashes... */ 153224145Sdim do { 154193326Sed len = r - locale > 31 ? 31 : r - locale; 155193326Sed (void)strncpy(new_categories[i++], locale, len); 156193326Sed new_categories[i++][len] = 0; 157193326Sed locale = r; 158193326Sed while (*locale == '/') 159193326Sed ++locale; 160193326Sed while (*++r && *r != '/'); 161198092Srdivacky } while (*locale); 162193326Sed while (i < _LC_LAST) 163193326Sed (void)strcpy(new_categories[i], 164193326Sed new_categories[i-1]); 165193326Sed } 166218893Sdim } 167193326Sed 168193326Sed if (category) 169235633Sdim return (loadlocale(category)); 170235633Sdim 171224145Sdim for (i = 1; i < _LC_LAST; ++i) { 172224145Sdim (void)strcpy(saved_categories[i], current_categories[i]); 173224145Sdim if (loadlocale(i) == NULL) { 174193326Sed for (j = 1; j < i; j++) { 175224145Sdim (void)strcpy(new_categories[j], 176224145Sdim saved_categories[j]); 177224145Sdim /* XXX can fail too */ 178224145Sdim (void)loadlocale(j); 179224145Sdim } 180224145Sdim return (NULL); 181224145Sdim } 182224145Sdim } 183224145Sdim return (currentlocale()); 184224145Sdim} 185224145Sdim 186224145Sdim/* To be compatible with crt0 hack */ 187224145Sdimvoid 188224145Sdim_startup_setlocale(category, locale) 189224145Sdim int category; 190224145Sdim const char *locale; 191224145Sdim{ 192235633Sdim#ifndef XPG4 193235633Sdim (void) setlocale(category, locale); 194224145Sdim#endif 195235633Sdim} 196224145Sdim 197235633Sdimstatic char * 198224145Sdimcurrentlocale() 199224145Sdim{ 200224145Sdim int i; 201218893Sdim 202252723Sdim (void)strcpy(current_locale_string, current_categories[1]); 203218893Sdim 204218893Sdim for (i = 2; i < _LC_LAST; ++i) 205218893Sdim if (strcmp(current_categories[1], current_categories[i])) { 206218893Sdim (void) strcpy(current_locale_string, current_categories[1]); 207218893Sdim (void) strcat(current_locale_string, "/"); 208218893Sdim (void) strcat(current_locale_string, current_categories[2]); 209218893Sdim (void) strcat(current_locale_string, "/"); 210218893Sdim (void) strcat(current_locale_string, current_categories[3]); 211218893Sdim (void) strcat(current_locale_string, "/"); 212218893Sdim (void) strcat(current_locale_string, current_categories[4]); 213218893Sdim (void) strcat(current_locale_string, "/"); 214218893Sdim (void) strcat(current_locale_string, current_categories[5]); 215235633Sdim break; 216235633Sdim } 217218893Sdim return (current_locale_string); 218193326Sed} 219218893Sdim 220218893Sdimstatic char * 221218893Sdimloadlocale(category) 222218893Sdim int category; 223218893Sdim{ 224218893Sdim char *ret; 225193326Sed char *new = new_categories[category]; 226193326Sed char *old = current_categories[category]; 227235633Sdim 228198092Srdivacky if (strcmp(new, old) == 0) 229193326Sed return (old); 230245431Sdim 231245431Sdim if ( !_PathLocale 232245431Sdim && strcmp(new, "C") && strcmp(new, "POSIX") 233245431Sdim ) { 234245431Sdim char *pl = getenv("PATH_LOCALE"); 235245431Sdim 236198092Srdivacky if (!pl) 237218893Sdim _PathLocale = _PATH_LOCALE; 238218893Sdim else if ( strlen(pl) + 45 > PATH_MAX 239218893Sdim || !(_PathLocale = strdup(pl)) 240218893Sdim ) 241218893Sdim return (NULL); 242218893Sdim } 243193326Sed 244252723Sdim if (category == LC_CTYPE) { 245218893Sdim#ifdef XPG4 246218893Sdim ret = _xpg4_setrunelocale(new) ? NULL : new; 247218893Sdim#else 248218893Sdim ret = setrunelocale(new) ? NULL : new; 249218893Sdim#endif 250218893Sdim if (!ret) { 251218893Sdim#ifdef XPG4 252218893Sdim (void)_xpg4_setrunelocale(old); 253218893Sdim#else 254218893Sdim (void)setrunelocale(old); 255218893Sdim#endif 256193326Sed } else 257193326Sed (void)strcpy(old, new); 258193326Sed return (ret); 259193326Sed } 260193326Sed 261221345Sdim if (category == LC_COLLATE) { 262201361Srdivacky ret = (__collate_load_tables(new) < 0) ? NULL : new; 263203955Srdivacky if (!ret) 264245431Sdim (void)__collate_load_tables(old); 265245431Sdim else 266193326Sed (void)strcpy(old, new); 267218893Sdim return (ret); 268218893Sdim } 269193326Sed 270193326Sed if (category == LC_TIME) { 271193326Sed ret = (__time_load_locale(new) < 0) ? NULL : new; 272193326Sed if (!ret) 273193326Sed (void)__time_load_locale(old); 274193326Sed else 275193326Sed (void)strcpy(old, new); 276193326Sed return (ret); 277193326Sed } 278193326Sed 279193326Sed if (category == LC_MONETARY || category == LC_NUMERIC) { 280193326Sed ret = stub_load_locale(new) ? NULL : new; 281201361Srdivacky if (!ret) 282203955Srdivacky (void)stub_load_locale(old); 283221345Sdim else 284245431Sdim (void)strcpy(old, new); 285245431Sdim return (ret); 286193326Sed } 287245431Sdim 288245431Sdim /* Just in case...*/ 289245431Sdim return (NULL); 290245431Sdim} 291245431Sdim 292245431Sdimstatic int 293245431Sdimstub_load_locale(encoding) 294245431Sdimconst char *encoding; 295245431Sdim{ 296193326Sed char name[PATH_MAX]; 297193326Sed struct stat st; 298198092Srdivacky 299252723Sdim if (!encoding) 300210299Sed return(1); 301210299Sed /* 302210299Sed * The "C" and "POSIX" locale are always here. 303210299Sed */ 304210299Sed if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) 305210299Sed return(0); 306210299Sed if (!_PathLocale) 307210299Sed return(1); 308210299Sed strcpy(name, _PathLocale); 309221345Sdim strcat(name, "/"); 310210299Sed strcat(name, encoding); 311210299Sed#if 0 312210299Sed /* 313245431Sdim * Some day we will actually look at this file. 314245431Sdim */ 315221345Sdim#endif 316210299Sed return (stat(name, &st) != 0 || !S_ISDIR(st.st_mode)); 317210299Sed} 318210299Sed