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 <stdlib.h> 11 #include <string.h> 12 13 #include <ErrnoMaintainer.h> 14 15 #include "LocaleBackend.h" 16 17 18 using BPrivate::Libroot::gLocaleBackend; 19 using BPrivate::Libroot::LocaleBackend; 20 21 22 static status_t 23 GetLocalesFromEnvironment(int category, const char** locales) 24 { 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" 38 }; 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; 58 } 59 if (!haveDifferentLocales) { 60 // we can set all locales at once 61 locales[LC_ALL] = locale; 62 } 63 } 64 65 return B_OK; 66 } 67 68 69 extern "C" char* 70 setlocale(int category, const char* locale) 71 { 72 BPrivate::ErrnoMaintainer errnoMaintainer; 73 74 if (category < 0 || category > LC_LAST) 75 return NULL; 76 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"); 83 } 84 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; 90 91 if (*locale == '\0') 92 GetLocalesFromEnvironment(category, locales); 93 else 94 locales[category] = locale; 95 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; 105 } 106 } 107 if (needBackend && LocaleBackend::LoadBackend() != B_OK) 108 return NULL; 109 } 110 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); 118 } 119 } 120 } 121 return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL)); 122 } 123 124 return const_cast<char*>("POSIX"); 125 } 126