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