7977780316d38d99ea06d1fcf9f8f466e536c77c
[haiku.git] / src / system / libroot / posix / locale / setlocale.cpp
blob7977780316d38d99ea06d1fcf9f8f466e536c77c
1 /*
2 * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de
3 * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
8 #include <ctype.h>
9 #include <locale.h>
10 #include <stdlib.h>
11 #include <strings.h>
13 #include <ErrnoMaintainer.h>
15 #include "LocaleBackend.h"
18 using BPrivate::Libroot::gLocaleBackend;
19 using BPrivate::Libroot::LocaleBackend;
22 static status_t
23 GetLocalesFromEnvironment(int category, const char** locales)
25 const char* locale = getenv("LC_ALL");
26 if (locale && *locale)
27 locales[category] = locale;
28 else {
29 // the order of the names must match the one specified in locale.h
30 const char* categoryNames[] = {
31 "LC_ALL",
32 "LC_COLLATE",
33 "LC_CTYPE",
34 "LC_MONETARY",
35 "LC_NUMERIC",
36 "LC_TIME",
37 "LC_MESSAGES"
39 int from, to;
40 if (category == LC_ALL) {
41 // we need to check each real category if all of them should be set
42 from = 1;
43 to = LC_LAST;
44 } else
45 from = to = category;
46 bool haveDifferentLocales = false;
47 locale = NULL;
48 for (int lc = from; lc <= to; lc++) {
49 const char* lastLocale = locale;
50 locale = getenv(categoryNames[lc]);
51 if (!locale || *locale == '\0')
52 locale = getenv("LANG");
53 if (!locale || *locale == '\0')
54 locale = "POSIX";
55 locales[lc] = locale;
56 if (lastLocale && strcasecmp(locale, lastLocale) != 0)
57 haveDifferentLocales = true;
59 if (!haveDifferentLocales) {
60 // we can set all locales at once
61 locales[LC_ALL] = locale;
65 return B_OK;
69 extern "C" char*
70 setlocale(int category, const char* locale)
72 BPrivate::ErrnoMaintainer errnoMaintainer;
74 if (category < 0 || category > LC_LAST)
75 return NULL;
77 if (locale == NULL) {
78 // query the locale of the given category
79 if (gLocaleBackend != NULL)
80 return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL));
81 else
82 return const_cast<char*>("POSIX");
85 // we may have to invoke SetLocale once for each category, so we use an
86 // array to collect the locale per category
87 const char* locales[LC_LAST + 1];
88 for (int lc = 0; lc <= LC_LAST; lc++)
89 locales[lc] = NULL;
91 if (*locale == '\0')
92 GetLocalesFromEnvironment(category, locales);
93 else
94 locales[category] = locale;
96 if (!gLocaleBackend) {
97 // for any locale other than POSIX/C, we try to activate the ICU
98 // backend
99 bool needBackend = false;
100 for (int lc = 0; lc <= LC_LAST; lc++) {
101 if (locales[lc] != NULL && strcasecmp(locales[lc], "POSIX") != 0
102 && strcasecmp(locales[lc], "C") != 0) {
103 needBackend = true;
104 break;
107 if (needBackend && LocaleBackend::LoadBackend() != B_OK)
108 return NULL;
111 if (gLocaleBackend != NULL) {
112 for (int lc = 0; lc <= LC_LAST; lc++) {
113 if (locales[lc] != NULL) {
114 locale = gLocaleBackend->SetLocale(lc, locales[lc]);
115 if (lc == LC_ALL) {
116 // skip the rest, LC_ALL overrides
117 return const_cast<char*>(locale);
121 return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL));
124 return const_cast<char*>("POSIX");