146445Storek /*
2*63711Sbostic * Copyright (c) 1991, 1993
3*63711Sbostic * The Regents of the University of California. All rights reserved.
446445Storek *
560469Sbostic * This code is derived from software contributed to Berkeley by
660469Sbostic * Paul Borman at Krystal Technologies.
760469Sbostic *
846445Storek * %sccs.include.redist.c%
946445Storek */
1046445Storek
1146445Storek #if defined(LIBC_SCCS) && !defined(lint)
12*63711Sbostic static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 07/04/93";
1346445Storek #endif /* LIBC_SCCS and not lint */
1446445Storek
1560469Sbostic #include <limits.h>
1646445Storek #include <locale.h>
1760469Sbostic #include <rune.h>
1860469Sbostic #include <stdlib.h>
1946603Sbostic #include <string.h>
2046445Storek
2160469Sbostic /*
2260469Sbostic * Category names for getenv()
2360469Sbostic */
2460469Sbostic static char *categories[_LC_LAST] = {
2560469Sbostic "LC_ALL",
2660469Sbostic "LC_COLLATE",
2760469Sbostic "LC_CTYPE",
2860469Sbostic "LC_MONETARY",
2960469Sbostic "LC_NUMERIC",
3060469Sbostic "LC_TIME",
3160469Sbostic };
3246445Storek
3346445Storek /*
3460469Sbostic * Current locales for each category
3546445Storek */
3660469Sbostic static char current_categories[_LC_LAST][32] = {
3760469Sbostic "C",
3860469Sbostic "C",
3960469Sbostic "C",
4060469Sbostic "C",
4160469Sbostic "C",
4260469Sbostic "C",
4360469Sbostic };
4460469Sbostic
4560469Sbostic /*
4660469Sbostic * The locales we are going to try and load
4760469Sbostic */
4860469Sbostic static char new_categories[_LC_LAST][32];
4960469Sbostic
5060469Sbostic static char current_locale_string[_LC_LAST * 33];
5160469Sbostic static char *PathLocale;
5260469Sbostic
5360469Sbostic static char *currentlocale __P((void));
5460469Sbostic static char *loadlocale __P((int));
5560469Sbostic
5646445Storek char *
setlocale(category,locale)5746445Storek setlocale(category, locale)
5846445Storek int category;
5946603Sbostic const char *locale;
6046445Storek {
6160469Sbostic int found, i, len;
6260469Sbostic char *env, *r;
6360469Sbostic
6460469Sbostic if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
6560469Sbostic PathLocale = _PATH_LOCALE;
6660469Sbostic
6760469Sbostic if (category < 0 || category >= _LC_LAST)
6846445Storek return (NULL);
6960469Sbostic
7060469Sbostic if (!locale)
7160469Sbostic return (category ?
7260469Sbostic current_categories[category] : currentlocale());
7360469Sbostic
7460469Sbostic /*
7560469Sbostic * Default to the current locale for everything.
7660469Sbostic */
7760469Sbostic for (i = 1; i < _LC_LAST; ++i)
7860469Sbostic (void)strcpy(new_categories[i], current_categories[i]);
7960469Sbostic
8060469Sbostic /*
8160469Sbostic * Now go fill up new_categories from the locale argument
8260469Sbostic */
8360469Sbostic if (!*locale) {
8460469Sbostic env = getenv(categories[category]);
8560469Sbostic
8660469Sbostic if (!env)
8760469Sbostic env = getenv(categories[0]);
8860469Sbostic
8960469Sbostic if (!env)
9060469Sbostic env = getenv("LANG");
9160469Sbostic
9260469Sbostic if (!env)
9360469Sbostic env = "C";
9460469Sbostic
9560469Sbostic (void) strncpy(new_categories[category], env, 31);
9660469Sbostic new_categories[category][31] = 0;
9760469Sbostic if (!category) {
9860469Sbostic for (i = 1; i < _LC_LAST; ++i) {
9960469Sbostic if (!(env = getenv(categories[i])))
10060469Sbostic env = new_categories[0];
10160469Sbostic (void)strncpy(new_categories[i], env, 31);
10260469Sbostic new_categories[i][31] = 0;
10360469Sbostic }
10460469Sbostic }
10560469Sbostic } else if (category) {
10660469Sbostic (void)strncpy(new_categories[category], locale, 31);
10760469Sbostic new_categories[category][31] = 0;
10860469Sbostic } else {
10960469Sbostic if ((r = strchr(locale, '/')) == 0) {
11060469Sbostic for (i = 1; i < _LC_LAST; ++i) {
11160469Sbostic (void)strncpy(new_categories[i], locale, 31);
11260469Sbostic new_categories[i][31] = 0;
11360469Sbostic }
11460469Sbostic } else {
11560469Sbostic for (i = 1; r[1] == '/'; ++r);
11660469Sbostic if (!r[1])
11760469Sbostic return (NULL); /* Hmm, just slashes... */
11860469Sbostic do {
11960469Sbostic len = r - locale > 31 ? 31 : r - locale;
12060469Sbostic (void)strncpy(new_categories[i++], locale, len);
12160469Sbostic new_categories[i++][len] = 0;
12260469Sbostic locale = r;
12360469Sbostic while (*locale == '/')
12460469Sbostic ++locale;
12560469Sbostic while (*++r && *r != '/');
12660469Sbostic } while (*locale);
12760469Sbostic while (i < _LC_LAST)
12860469Sbostic (void)strcpy(new_categories[i],
12960469Sbostic new_categories[i-1]);
13060469Sbostic }
13160469Sbostic }
13260469Sbostic
13360469Sbostic if (category)
13460469Sbostic return (loadlocale(category));
13560469Sbostic
13660469Sbostic found = 0;
13760469Sbostic for (i = 1; i < _LC_LAST; ++i)
13860469Sbostic if (loadlocale(i) != NULL)
13960469Sbostic found = 1;
14060469Sbostic if (found)
14160469Sbostic return (currentlocale());
14260469Sbostic return (NULL);
14346445Storek }
14460469Sbostic
14560469Sbostic static char *
currentlocale()14660469Sbostic currentlocale()
14760469Sbostic {
14860469Sbostic int i;
14960469Sbostic
15060469Sbostic (void)strcpy(current_locale_string, current_categories[1]);
15160469Sbostic
15260469Sbostic for (i = 2; i < _LC_LAST; ++i)
15360469Sbostic if (strcmp(current_categories[1], current_categories[i])) {
15460469Sbostic (void)snprintf(current_locale_string,
15560469Sbostic sizeof(current_locale_string), "%s/%s/%s/%s/%s",
15660469Sbostic current_categories[1], current_categories[2],
15760469Sbostic current_categories[3], current_categories[4],
15860469Sbostic current_categories[5]);
15960469Sbostic break;
16060469Sbostic }
16160469Sbostic return (current_locale_string);
16260469Sbostic }
16360469Sbostic
16460469Sbostic static char *
loadlocale(category)16560469Sbostic loadlocale(category)
16660469Sbostic int category;
16760469Sbostic {
16860469Sbostic char name[PATH_MAX];
16960469Sbostic
17060469Sbostic if (strcmp(new_categories[category],
17160469Sbostic current_categories[category]) == 0)
17260469Sbostic return (current_categories[category]);
17360469Sbostic
17460469Sbostic if (category == LC_CTYPE) {
17560469Sbostic if (setrunelocale(new_categories[LC_CTYPE]))
17660469Sbostic return (NULL);
17760469Sbostic (void)strcpy(current_categories[LC_CTYPE],
17860469Sbostic new_categories[LC_CTYPE]);
17960469Sbostic return (current_categories[LC_CTYPE]);
18060469Sbostic }
18160469Sbostic
18260469Sbostic if (!strcmp(new_categories[category], "C") ||
18360469Sbostic !strcmp(new_categories[category], "POSIX")) {
18460469Sbostic
18560469Sbostic /*
18660469Sbostic * Some day this will need to reset the locale to the default
18760469Sbostic * C locale. Since we have no way to change them as of yet,
18860469Sbostic * there is no need to reset them.
18960469Sbostic */
19060469Sbostic (void)strcpy(current_categories[category],
19160469Sbostic new_categories[category]);
19260469Sbostic return (current_categories[category]);
19360469Sbostic }
19460469Sbostic
19560469Sbostic /*
19660469Sbostic * Some day we will actually look at this file.
19760469Sbostic */
19863710Sbostic (void)snprintf(name, sizeof(name), "%s/%s/%s",
19960469Sbostic PathLocale, new_categories[category], categories[category]);
20060469Sbostic
20160469Sbostic switch (category) {
20260469Sbostic case LC_COLLATE:
20360469Sbostic case LC_MONETARY:
20460469Sbostic case LC_NUMERIC:
20560469Sbostic case LC_TIME:
20660469Sbostic return (NULL);
20760469Sbostic }
20860469Sbostic }
209