nsLocaleService.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsCOMPtr.h"
  6. #include "nsILocale.h"
  7. #include "nsILocaleService.h"
  8. #include "nsLocale.h"
  9. #include "nsCRT.h"
  10. #include "prprf.h"
  11. #include "nsTArray.h"
  12. #include "nsString.h"
  13. #include "mozilla/UniquePtr.h"
  14. #include <ctype.h>
  15. #if defined(XP_WIN)
  16. # include "nsWin32Locale.h"
  17. #elif defined(XP_UNIX)
  18. # include <locale.h>
  19. # include <stdlib.h>
  20. # include "nsPosixLocale.h"
  21. #endif
  22. //
  23. // implementation constants
  24. const int LocaleListLength = 6;
  25. const char* LocaleList[LocaleListLength] =
  26. {
  27. NSILOCALE_COLLATE,
  28. NSILOCALE_CTYPE,
  29. NSILOCALE_MONETARY,
  30. NSILOCALE_NUMERIC,
  31. NSILOCALE_TIME,
  32. NSILOCALE_MESSAGE
  33. };
  34. #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
  35. #define NSILOCALE_MAX_ACCEPT_LENGTH 18
  36. #if defined(XP_UNIX)
  37. static int posix_locale_category[LocaleListLength] =
  38. {
  39. LC_COLLATE,
  40. LC_CTYPE,
  41. LC_MONETARY,
  42. LC_NUMERIC,
  43. LC_TIME,
  44. #ifdef HAVE_I18N_LC_MESSAGES
  45. LC_MESSAGES
  46. #else
  47. LC_CTYPE
  48. #endif
  49. };
  50. #endif
  51. //
  52. // nsILocaleService implementation
  53. //
  54. class nsLocaleService: public nsILocaleService {
  55. public:
  56. //
  57. // nsISupports
  58. //
  59. NS_DECL_THREADSAFE_ISUPPORTS
  60. //
  61. // nsILocaleService
  62. //
  63. NS_DECL_NSILOCALESERVICE
  64. nsLocaleService(void);
  65. protected:
  66. nsresult SetSystemLocale(void);
  67. nsresult SetApplicationLocale(void);
  68. nsCOMPtr<nsILocale> mSystemLocale;
  69. nsCOMPtr<nsILocale> mApplicationLocale;
  70. virtual ~nsLocaleService(void);
  71. };
  72. //
  73. // nsLocaleService methods
  74. //
  75. nsLocaleService::nsLocaleService(void)
  76. {
  77. #ifdef XP_WIN
  78. nsAutoString xpLocale;
  79. //
  80. // get the system LCID
  81. //
  82. LCID win_lcid = GetSystemDefaultLCID();
  83. NS_ENSURE_TRUE_VOID(win_lcid);
  84. nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
  85. nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
  86. NS_ENSURE_SUCCESS_VOID(rv);
  87. //
  88. // get the application LCID
  89. //
  90. win_lcid = GetUserDefaultLCID();
  91. NS_ENSURE_TRUE_VOID(win_lcid);
  92. nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
  93. rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
  94. NS_ENSURE_SUCCESS_VOID(rv);
  95. #endif
  96. #if defined(XP_UNIX)
  97. RefPtr<nsLocale> resultLocale(new nsLocale());
  98. NS_ENSURE_TRUE_VOID(resultLocale);
  99. // Get system configuration
  100. const char* lang = getenv("LANG");
  101. nsAutoString xpLocale, platformLocale;
  102. nsAutoString category, category_platform;
  103. int i;
  104. for( i = 0; i < LocaleListLength; i++ ) {
  105. nsresult result;
  106. // setlocale( , "") evaluates LC_* and LANG
  107. char* lc_temp = setlocale(posix_locale_category[i], "");
  108. CopyASCIItoUTF16(LocaleList[i], category);
  109. category_platform = category;
  110. category_platform.AppendLiteral("##PLATFORM");
  111. bool lc_temp_valid = lc_temp != nullptr;
  112. if (lc_temp_valid) {
  113. result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
  114. CopyASCIItoUTF16(lc_temp, platformLocale);
  115. } else {
  116. if ( lang == nullptr ) {
  117. platformLocale.AssignLiteral("en_US");
  118. result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
  119. } else {
  120. CopyASCIItoUTF16(lang, platformLocale);
  121. result = nsPosixLocale::GetXPLocale(lang, xpLocale);
  122. }
  123. }
  124. if (NS_FAILED(result)) {
  125. return;
  126. }
  127. resultLocale->AddCategory(category, xpLocale);
  128. resultLocale->AddCategory(category_platform, platformLocale);
  129. }
  130. mSystemLocale = do_QueryInterface(resultLocale);
  131. mApplicationLocale = do_QueryInterface(resultLocale);
  132. #endif // XP_UNIX
  133. }
  134. nsLocaleService::~nsLocaleService(void)
  135. {
  136. }
  137. NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
  138. NS_IMETHODIMP
  139. nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
  140. {
  141. nsresult result;
  142. *_retval = nullptr;
  143. RefPtr<nsLocale> resultLocale(new nsLocale());
  144. if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
  145. for (int32_t i = 0; i < LocaleListLength; i++) {
  146. NS_ConvertASCIItoUTF16 category(LocaleList[i]);
  147. result = resultLocale->AddCategory(category, aLocale);
  148. if (NS_FAILED(result)) return result;
  149. #if defined(XP_UNIX)
  150. category.AppendLiteral("##PLATFORM");
  151. result = resultLocale->AddCategory(category, aLocale);
  152. if (NS_FAILED(result)) return result;
  153. #endif
  154. }
  155. NS_ADDREF(*_retval = resultLocale);
  156. return NS_OK;
  157. }
  158. NS_IMETHODIMP
  159. nsLocaleService::GetSystemLocale(nsILocale **_retval)
  160. {
  161. if (mSystemLocale) {
  162. NS_ADDREF(*_retval = mSystemLocale);
  163. return NS_OK;
  164. }
  165. *_retval = (nsILocale*)nullptr;
  166. return NS_ERROR_FAILURE;
  167. }
  168. NS_IMETHODIMP
  169. nsLocaleService::GetApplicationLocale(nsILocale **_retval)
  170. {
  171. if (mApplicationLocale) {
  172. NS_ADDREF(*_retval = mApplicationLocale);
  173. return NS_OK;
  174. }
  175. *_retval=(nsILocale*)nullptr;
  176. return NS_ERROR_FAILURE;
  177. }
  178. NS_IMETHODIMP
  179. nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
  180. {
  181. char* cPtr;
  182. char* cPtr1;
  183. char* cPtr2;
  184. int i;
  185. int j;
  186. int countLang = 0;
  187. char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
  188. nsresult result;
  189. auto input = MakeUnique<char[]>(strlen(acceptLanguage)+1);
  190. strcpy(input.get(), acceptLanguage);
  191. cPtr1 = input.get()-1;
  192. cPtr2 = input.get();
  193. /* put in standard form */
  194. while (*(++cPtr1)) {
  195. if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
  196. else if (isspace(*cPtr1)) ; /* ignore any space */
  197. else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
  198. else if (*cPtr1=='*') ; /* ignore "*" */
  199. else *cPtr2++ = *cPtr1; /* else unchanged */
  200. }
  201. *cPtr2 = '\0';
  202. countLang = 0;
  203. if (strchr(input.get(), ';')) {
  204. /* deal with the quality values */
  205. float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
  206. float qSwap;
  207. float bias = 0.0f;
  208. char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
  209. char* ptrSwap;
  210. cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
  211. while (cPtr) {
  212. qvalue[countLang] = 1.0f;
  213. /* add extra parens to get rid of warning */
  214. if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
  215. PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
  216. *cPtr1 = '\0';
  217. }
  218. if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
  219. qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
  220. ptrLanguage[countLang++] = cPtr;
  221. if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
  222. }
  223. cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
  224. }
  225. /* sort according to decending qvalue */
  226. /* not a very good algorithm, but count is not likely large */
  227. for ( i=0 ; i<countLang-1 ; i++ ) {
  228. for ( j=i+1 ; j<countLang ; j++ ) {
  229. if (qvalue[i]<qvalue[j]) {
  230. qSwap = qvalue[i];
  231. qvalue[i] = qvalue[j];
  232. qvalue[j] = qSwap;
  233. ptrSwap = ptrLanguage[i];
  234. ptrLanguage[i] = ptrLanguage[j];
  235. ptrLanguage[j] = ptrSwap;
  236. }
  237. }
  238. }
  239. for ( i=0 ; i<countLang ; i++ ) {
  240. PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
  241. }
  242. } else {
  243. /* simple case: no quality values */
  244. cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
  245. while (cPtr) {
  246. if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
  247. PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
  248. if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
  249. }
  250. cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
  251. }
  252. }
  253. //
  254. // now create the locale
  255. //
  256. result = NS_ERROR_FAILURE;
  257. if (countLang>0) {
  258. result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
  259. }
  260. //
  261. // clean up
  262. //
  263. return result;
  264. }
  265. nsresult
  266. nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
  267. {
  268. nsCOMPtr<nsILocale> system_locale;
  269. nsresult result;
  270. result = GetSystemLocale(getter_AddRefs(system_locale));
  271. if (NS_SUCCEEDED(result))
  272. {
  273. result = system_locale->
  274. GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
  275. return result;
  276. }
  277. return result;
  278. }
  279. nsresult
  280. NS_NewLocaleService(nsILocaleService** result)
  281. {
  282. if(!result)
  283. return NS_ERROR_NULL_POINTER;
  284. *result = new nsLocaleService();
  285. if (! *result)
  286. return NS_ERROR_OUT_OF_MEMORY;
  287. NS_ADDREF(*result);
  288. return NS_OK;
  289. }