xref: /haiku/src/system/libroot/posix/locale/setlocale.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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  */
6 
7 
8 #include <ctype.h>
9 #include <locale.h>
10 #include <strings.h>
11 
12 #include <ErrnoMaintainer.h>
13 
14 #include "LocaleBackend.h"
15 #include "LocaleInternal.h"
16 
17 
18 using BPrivate::Libroot::gGlobalLocaleBackend;
19 using BPrivate::Libroot::GetLocalesFromEnvironment;
20 using BPrivate::Libroot::LocaleBackend;
21 
22 
23 extern "C" char*
24 setlocale(int category, const char* locale)
25 {
26 	BPrivate::ErrnoMaintainer errnoMaintainer;
27 
28 	if (category < 0 || category > LC_LAST)
29 		return NULL;
30 
31 	if (locale == NULL) {
32 		// query the locale of the given category
33 		if (gGlobalLocaleBackend != NULL)
34 			return const_cast<char*>(gGlobalLocaleBackend->SetLocale(category, NULL));
35 		else
36 			return const_cast<char*>("POSIX");
37 	}
38 
39 	// we may have to invoke SetLocale once for each category, so we use an
40 	// array to collect the locale per category
41 	const char* locales[LC_LAST + 1];
42 	for (int lc = 0; lc <= LC_LAST; lc++)
43 		locales[lc] = NULL;
44 
45 	if (*locale == '\0')
46 		GetLocalesFromEnvironment(category, locales);
47 	else
48 		locales[category] = locale;
49 
50 	if (gGlobalLocaleBackend == NULL) {
51 		// for any locale other than POSIX/C, we try to activate the ICU
52 		// backend
53 		bool needBackend = false;
54 		for (int lc = 0; lc <= LC_LAST; lc++) {
55 			if (locales[lc] != NULL && strcasecmp(locales[lc], "POSIX") != 0
56 					&& strcasecmp(locales[lc], "C") != 0) {
57 				needBackend = true;
58 				break;
59 			}
60 		}
61 		if (needBackend && LocaleBackend::LoadBackend() != B_OK)
62 			return NULL;
63 	}
64 
65 	if (gGlobalLocaleBackend != NULL) {
66 		for (int lc = 0; lc <= LC_LAST; lc++) {
67 			if (locales[lc] != NULL) {
68 				locale = gGlobalLocaleBackend->SetLocale(lc, locales[lc]);
69 				if (lc == LC_ALL) {
70 					// skip the rest, LC_ALL overrides
71 					return const_cast<char*>(locale);
72 				}
73 			}
74 		}
75 		return const_cast<char*>(gGlobalLocaleBackend->SetLocale(category, NULL));
76 	}
77 
78 	return const_cast<char*>("POSIX");
79 }
80