nsPosixLocale.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  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 "nscore.h"
  6. #include "nsString.h"
  7. #include "nsPosixLocale.h"
  8. #include "mozilla/Sprintf.h"
  9. #include "plstr.h"
  10. #include "nsReadableUtils.h"
  11. static bool
  12. ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator);
  13. nsresult
  14. nsPosixLocale::GetPlatformLocale(const nsAString& locale, nsACString& posixLocale)
  15. {
  16. char country_code[MAX_COUNTRY_CODE_LEN+1];
  17. char lang_code[MAX_LANGUAGE_CODE_LEN+1];
  18. char extra[MAX_EXTRA_LEN+1];
  19. char posix_locale[MAX_LOCALE_LEN+1];
  20. NS_LossyConvertUTF16toASCII xp_locale(locale);
  21. if (!xp_locale.IsEmpty()) {
  22. if (!ParseLocaleString(xp_locale.get(),lang_code,country_code,extra,'-')) {
  23. // strncpy(posixLocale,"C",length);
  24. posixLocale = xp_locale; // use xp locale if parse failed
  25. return NS_OK;
  26. }
  27. if (*country_code) {
  28. if (*extra) {
  29. SprintfLiteral(posix_locale,"%s_%s.%s",lang_code,country_code,extra);
  30. }
  31. else {
  32. SprintfLiteral(posix_locale,"%s_%s",lang_code,country_code);
  33. }
  34. }
  35. else {
  36. if (*extra) {
  37. SprintfLiteral(posix_locale,"%s.%s",lang_code,extra);
  38. }
  39. else {
  40. SprintfLiteral(posix_locale,"%s",lang_code);
  41. }
  42. }
  43. posixLocale = posix_locale;
  44. return NS_OK;
  45. }
  46. return NS_ERROR_FAILURE;
  47. }
  48. nsresult
  49. nsPosixLocale::GetXPLocale(const char* posixLocale, nsAString& locale)
  50. {
  51. char country_code[MAX_COUNTRY_CODE_LEN+1];
  52. char lang_code[MAX_LANGUAGE_CODE_LEN+1];
  53. char extra[MAX_EXTRA_LEN+1];
  54. char posix_locale[MAX_LOCALE_LEN+1];
  55. if (posixLocale!=nullptr) {
  56. if (strcmp(posixLocale,"C")==0 || strcmp(posixLocale,"POSIX")==0) {
  57. locale.AssignLiteral("en-US");
  58. return NS_OK;
  59. }
  60. if (strcmp(posixLocale,"C.UTF-8")==0) {
  61. locale.AssignLiteral("en-US.UTF-8");
  62. return NS_OK;
  63. }
  64. if (!ParseLocaleString(posixLocale,lang_code,country_code,extra,'_')) {
  65. // * locale = "x-user-defined";
  66. // use posix if parse failed
  67. CopyASCIItoUTF16(nsDependentCString(posixLocale), locale);
  68. return NS_OK;
  69. }
  70. // Special case: substitute "nb" (Norwegian Bokmal) for macrolanguage
  71. // code "no" (Norwegian)
  72. if (nsDependentCString(lang_code).LowerCaseEqualsLiteral("no")) {
  73. lang_code[1] = 'b';
  74. }
  75. if (*country_code) {
  76. SprintfLiteral(posix_locale,"%s-%s",lang_code,country_code);
  77. }
  78. else {
  79. SprintfLiteral(posix_locale,"%s",lang_code);
  80. }
  81. CopyASCIItoUTF16(nsDependentCString(posix_locale), locale);
  82. return NS_OK;
  83. }
  84. return NS_ERROR_FAILURE;
  85. }
  86. //
  87. // returns false/true depending on if it was of the form LL-CC.Extra
  88. static bool
  89. ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator)
  90. {
  91. const char *src = locale_string;
  92. char modifier[MAX_EXTRA_LEN+1];
  93. char *dest;
  94. int dest_space, len;
  95. *language = '\0';
  96. *country = '\0';
  97. *extra = '\0';
  98. if (strlen(locale_string) < 2) {
  99. return(false);
  100. }
  101. //
  102. // parse the language part
  103. //
  104. dest = language;
  105. dest_space = MAX_LANGUAGE_CODE_LEN;
  106. while ((*src) && (isalpha(*src)) && (dest_space--)) {
  107. *dest++ = tolower(*src++);
  108. }
  109. *dest = '\0';
  110. len = dest - language;
  111. if ((len != 2) && (len != 3)) {
  112. NS_ASSERTION((len == 2) || (len == 3), "language code too short");
  113. NS_ASSERTION(len < 3, "reminder: verify we can handle 3+ character language code in all parts of the system; eg: language packs");
  114. *language = '\0';
  115. return(false);
  116. }
  117. // check if all done
  118. if (*src == '\0') {
  119. return(true);
  120. }
  121. if ((*src != '_') && (*src != '-') && (*src != '.') && (*src != '@')) {
  122. NS_ASSERTION(isalpha(*src), "language code too long");
  123. NS_ASSERTION(!isalpha(*src), "unexpected language/country separator");
  124. *language = '\0';
  125. return(false);
  126. }
  127. //
  128. // parse the country part
  129. //
  130. if ((*src == '_') || (*src == '-')) {
  131. src++;
  132. dest = country;
  133. dest_space = MAX_COUNTRY_CODE_LEN;
  134. while ((*src) && (isalpha(*src)) && (dest_space--)) {
  135. *dest++ = toupper(*src++);
  136. }
  137. *dest = '\0';
  138. len = dest - country;
  139. if (len != 2) {
  140. NS_ASSERTION(len == 2, "unexpected country code length");
  141. *language = '\0';
  142. *country = '\0';
  143. return(false);
  144. }
  145. }
  146. // check if all done
  147. if (*src == '\0') {
  148. return(true);
  149. }
  150. if ((*src != '.') && (*src != '@')) {
  151. NS_ASSERTION(isalpha(*src), "country code too long");
  152. NS_ASSERTION(!isalpha(*src), "unexpected country/extra separator");
  153. *language = '\0';
  154. *country = '\0';
  155. return(false);
  156. }
  157. //
  158. // handle the extra part
  159. //
  160. if (*src == '.') {
  161. src++; // move past the extra part separator
  162. dest = extra;
  163. dest_space = MAX_EXTRA_LEN;
  164. while ((*src) && (*src != '@') && (dest_space--)) {
  165. *dest++ = *src++;
  166. }
  167. *dest = '\0';
  168. len = dest - extra;
  169. if (len < 1) {
  170. NS_ASSERTION(len > 0, "found country/extra separator but no extra code");
  171. *language = '\0';
  172. *country = '\0';
  173. *extra = '\0';
  174. return(false);
  175. }
  176. }
  177. // check if all done
  178. if (*src == '\0') {
  179. return(true);
  180. }
  181. //
  182. // handle the modifier part
  183. //
  184. if (*src == '@') {
  185. src++; // move past the modifier separator
  186. NS_ASSERTION(strcmp("euro",src) == 0, "found non euro modifier");
  187. dest = modifier;
  188. dest_space = MAX_EXTRA_LEN;
  189. while ((*src) && (dest_space--)) {
  190. *dest++ = *src++;
  191. }
  192. *dest = '\0';
  193. len = dest - modifier;
  194. if (len < 1) {
  195. NS_ASSERTION(len > 0, "found modifier separator but no modifier code");
  196. *language = '\0';
  197. *country = '\0';
  198. *extra = '\0';
  199. *modifier = '\0';
  200. return(false);
  201. }
  202. }
  203. // check if all done
  204. if (*src == '\0') {
  205. return(true);
  206. }
  207. NS_ASSERTION(*src == '\0', "extra/modifier code too long");
  208. *language = '\0';
  209. *country = '\0';
  210. *extra = '\0';
  211. return(false);
  212. }