diff options
Diffstat (limited to 'lib/libc/locale/setlocale.c')
-rw-r--r-- | lib/libc/locale/setlocale.c | 153 |
1 files changed, 89 insertions, 64 deletions
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c index 11f2139..9bcb88a 100644 --- a/lib/libc/locale/setlocale.c +++ b/lib/libc/locale/setlocale.c @@ -43,6 +43,7 @@ static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; #include <rune.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include "collate.h" /* @@ -73,12 +74,14 @@ static char current_categories[_LC_LAST][32] = { * The locales we are going to try and load */ static char new_categories[_LC_LAST][32]; +static char saved_categories[_LC_LAST][32]; static char current_locale_string[_LC_LAST * 33]; char *_PathLocale; static char *currentlocale __P((void)); static char *loadlocale __P((int)); +static int stub_load_locale __P((const char *)); extern int __time_load_locale __P((const char *)); /* strftime.c */ @@ -91,24 +94,23 @@ setlocale(category, locale) int category; const char *locale; { - int found, i, len; + int i, j, len; char *env, *r; - if (!_PathLocale && !(_PathLocale = getenv("PATH_LOCALE"))) - _PathLocale = _PATH_LOCALE; - - if (category < 0 || category >= _LC_LAST) + if (category < LC_ALL || category >= _LC_LAST) return (NULL); if (!locale) - return (category ? + return (category != LC_ALL ? current_categories[category] : currentlocale()); /* * Default to the current locale for everything. */ - for (i = 1; i < _LC_LAST; ++i) + for (i = 1; i < _LC_LAST; ++i) { (void)strcpy(new_categories[i], current_categories[i]); + (void)strcpy(saved_categories[i], current_categories[i]); + } /* * Now go fill up new_categories from the locale argument @@ -116,26 +118,26 @@ setlocale(category, locale) if (!*locale) { env = getenv(categories[category]); - if (!env) - env = getenv(categories[0]); + if (category != LC_ALL && (!env || !*env)) + env = getenv(categories[LC_ALL]); - if (!env) + if (!env || !*env) env = getenv("LANG"); - if (!env) + if (!env || !*env) env = "C"; (void) strncpy(new_categories[category], env, 31); new_categories[category][31] = 0; - if (!category) { + if (category == LC_ALL) { for (i = 1; i < _LC_LAST; ++i) { - if (!(env = getenv(categories[i]))) - env = new_categories[0]; + if (!(env = getenv(categories[i])) || !*env) + env = new_categories[LC_ALL]; (void)strncpy(new_categories[i], env, 31); new_categories[i][31] = 0; } } - } else if (category) { + } else if (category != LC_ALL) { (void)strncpy(new_categories[category], locale, 31); new_categories[category][31] = 0; } else { @@ -163,16 +165,27 @@ setlocale(category, locale) } } - if (category) - return (loadlocale(category)); + if (category) { + if ((r = loadlocale(category)) == NULL) { + (void)strcpy(new_categories[category], + saved_categories[category]); + /* XXX can fail too */ + (void)loadlocale(category); + } + return (r); + } - found = 0; for (i = 1; i < _LC_LAST; ++i) - if (loadlocale(i) != NULL) - found = 1; - if (found) - return (currentlocale()); - return (NULL); + if (loadlocale(i) == NULL) { + for (j = 1; j < i; j++) { + (void)strcpy(new_categories[j], + saved_categories[j]); + /* XXX can fail too */ + (void)loadlocale(j); + } + return (NULL); + } + return (currentlocale()); } /* To be compatible with crt0 hack */ @@ -189,19 +202,12 @@ _startup_setlocale(category, locale) static char * currentlocale() { - int i, len; + int i; (void)strcpy(current_locale_string, current_categories[1]); for (i = 2; i < _LC_LAST; ++i) if (strcmp(current_categories[1], current_categories[i])) { - len = strlen(current_categories[1]) + 1 + - strlen(current_categories[2]) + 1 + - strlen(current_categories[3]) + 1 + - strlen(current_categories[4]) + 1 + - strlen(current_categories[5]) + 1; - if (len > sizeof(current_locale_string)) - return NULL; (void) strcpy(current_locale_string, current_categories[1]); (void) strcat(current_locale_string, "/"); (void) strcat(current_locale_string, current_categories[2]); @@ -220,65 +226,84 @@ static char * loadlocale(category) int category; { -#if 0 - char name[PATH_MAX]; -#endif - if (strcmp(new_categories[category], + char *encoding = new_categories[category]; + + if (strcmp(encoding, current_categories[category]) == 0) return (current_categories[category]); + if ( !_PathLocale + && strcmp(encoding, "C") && strcmp(encoding, "POSIX") + ) { + char *pl = getenv("PATH_LOCALE"); + + if (!pl) + _PathLocale = _PATH_LOCALE; + else if ( strlen(pl) + 45 > PATH_MAX + || !(_PathLocale = strdup(pl)) + ) + return (NULL); + } + if (category == LC_CTYPE) { #ifdef XPG4 - if (_xpg4_setrunelocale(new_categories[LC_CTYPE])) + if (_xpg4_setrunelocale(encoding)) #else - if (setrunelocale(new_categories[LC_CTYPE])) + if (setrunelocale(encoding)) #endif return (NULL); - (void)strcpy(current_categories[LC_CTYPE], - new_categories[LC_CTYPE]); + (void)strcpy(current_categories[LC_CTYPE], encoding); return (current_categories[LC_CTYPE]); } if (category == LC_COLLATE) { - if (__collate_load_tables(new_categories[LC_COLLATE]) < 0) + if (__collate_load_tables(encoding) < 0) return (NULL); - (void)strcpy(current_categories[LC_COLLATE], - new_categories[LC_COLLATE]); + (void)strcpy(current_categories[LC_COLLATE], encoding); return (current_categories[LC_COLLATE]); } if (category == LC_TIME) { - if (__time_load_locale(new_categories[LC_TIME]) < 0) + if (__time_load_locale(encoding) < 0) return (NULL); - (void)strcpy(current_categories[LC_TIME], - new_categories[LC_TIME]); + (void)strcpy(current_categories[LC_TIME], encoding); return (current_categories[LC_TIME]); } - if (!strcmp(new_categories[category], "C") || - !strcmp(new_categories[category], "POSIX")) { - - /* - * Some day this will need to reset the locale to the default - * C locale. Since we have no way to change them as of yet, - * there is no need to reset them. - */ - (void)strcpy(current_categories[category], - new_categories[category]); + if (category == LC_MONETARY || category == LC_NUMERIC) { + if (stub_load_locale(encoding)) + return (NULL); + (void)strcpy(current_categories[category], encoding); return (current_categories[category]); } + + /* Just in case...*/ + return (NULL); +} + +static int +stub_load_locale(encoding) +const char *encoding; +{ + char name[PATH_MAX]; + struct stat st; + + if (!encoding) + return(1); + /* + * The "C" and "POSIX" locale are always here. + */ + if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) + return(0); + if (!_PathLocale) + return(1); + strcpy(name, _PathLocale); + strcat(name, "/"); + strcat(name, encoding); #if 0 /* * Some day we will actually look at this file. */ - (void)snprintf(name, sizeof(name), "%s/%s/%s", - _PathLocale, new_categories[category], categories[category]); #endif - switch (category) { - case LC_MONETARY: - case LC_NUMERIC: - return (NULL); - } - /* Just in case...*/ - return (NULL); + return (stat(name, &st) != 0 || !S_ISDIR(st.st_mode)); } |