1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nscore.h"
39 : #include "nsString.h"
40 : #include "nsPosixLocale.h"
41 : #include "prprf.h"
42 : #include "plstr.h"
43 : #include "nsReadableUtils.h"
44 :
45 : static bool
46 : ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator);
47 :
48 : nsresult
49 32 : nsPosixLocale::GetPlatformLocale(const nsAString& locale, nsACString& posixLocale)
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 64 : NS_LossyConvertUTF16toASCII xp_locale(locale);
56 :
57 32 : if (!xp_locale.IsEmpty()) {
58 32 : if (!ParseLocaleString(xp_locale.get(),lang_code,country_code,extra,'-')) {
59 : // strncpy(posixLocale,"C",length);
60 0 : posixLocale = xp_locale; // use xp locale if parse failed
61 0 : return NS_OK;
62 : }
63 :
64 32 : if (*country_code) {
65 32 : if (*extra) {
66 32 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s_%s.%s",lang_code,country_code,extra);
67 : }
68 : else {
69 0 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s_%s",lang_code,country_code);
70 : }
71 : }
72 : else {
73 0 : if (*extra) {
74 0 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s.%s",lang_code,extra);
75 : }
76 : else {
77 0 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s",lang_code);
78 : }
79 : }
80 :
81 32 : posixLocale = posix_locale;
82 32 : return NS_OK;
83 : }
84 :
85 0 : return NS_ERROR_FAILURE;
86 : }
87 :
88 : nsresult
89 498 : nsPosixLocale::GetXPLocale(const char* posixLocale, nsAString& locale)
90 : {
91 : char country_code[MAX_COUNTRY_CODE_LEN+1];
92 : char lang_code[MAX_LANGUAGE_CODE_LEN+1];
93 : char extra[MAX_EXTRA_LEN+1];
94 : char posix_locale[MAX_LOCALE_LEN+1];
95 :
96 498 : if (posixLocale!=nsnull) {
97 498 : if (strcmp(posixLocale,"C")==0 || strcmp(posixLocale,"POSIX")==0) {
98 0 : locale.AssignLiteral("en-US");
99 0 : return NS_OK;
100 : }
101 498 : if (!ParseLocaleString(posixLocale,lang_code,country_code,extra,'_')) {
102 : // * locale = "x-user-defined";
103 : // use posix if parse failed
104 0 : CopyASCIItoUTF16(nsDependentCString(posixLocale), locale);
105 0 : return NS_OK;
106 : }
107 :
108 : // Special case: substitute "nb" (Norwegian Bokmal) for macrolanguage
109 : // code "no" (Norwegian)
110 498 : if (nsDependentCString(lang_code).LowerCaseEqualsLiteral("no")) {
111 0 : lang_code[1] = 'b';
112 : }
113 :
114 498 : if (*country_code) {
115 498 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s-%s",lang_code,country_code);
116 : }
117 : else {
118 0 : PR_snprintf(posix_locale,sizeof(posix_locale),"%s",lang_code);
119 : }
120 :
121 498 : CopyASCIItoUTF16(nsDependentCString(posix_locale), locale);
122 498 : return NS_OK;
123 :
124 : }
125 :
126 0 : return NS_ERROR_FAILURE;
127 :
128 : }
129 :
130 : //
131 : // returns false/true depending on if it was of the form LL-CC.Extra
132 : static bool
133 530 : ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator)
134 : {
135 530 : const char *src = locale_string;
136 : char modifier[MAX_EXTRA_LEN+1];
137 : char *dest;
138 : int dest_space, len;
139 :
140 530 : *language = '\0';
141 530 : *country = '\0';
142 530 : *extra = '\0';
143 530 : if (strlen(locale_string) < 2) {
144 0 : return(false);
145 : }
146 :
147 : //
148 : // parse the language part
149 : //
150 530 : dest = language;
151 530 : dest_space = MAX_LANGUAGE_CODE_LEN;
152 2120 : while ((*src) && (isalpha(*src)) && (dest_space--)) {
153 1060 : *dest++ = tolower(*src++);
154 : }
155 530 : *dest = '\0';
156 530 : len = dest - language;
157 530 : if ((len != 2) && (len != 3)) {
158 0 : NS_ASSERTION((len == 2) || (len == 3), "language code too short");
159 0 : NS_ASSERTION(len < 3, "reminder: verify we can handle 3+ character language code in all parts of the system; eg: language packs");
160 0 : *language = '\0';
161 0 : return(false);
162 : }
163 :
164 : // check if all done
165 530 : if (*src == '\0') {
166 0 : return(true);
167 : }
168 :
169 530 : if ((*src != '_') && (*src != '-') && (*src != '.') && (*src != '@')) {
170 0 : NS_ASSERTION(isalpha(*src), "language code too long");
171 0 : NS_ASSERTION(!isalpha(*src), "unexpected language/country separator");
172 0 : *language = '\0';
173 0 : return(false);
174 : }
175 :
176 : //
177 : // parse the country part
178 : //
179 530 : if ((*src == '_') || (*src == '-')) {
180 530 : src++;
181 530 : dest = country;
182 530 : dest_space = MAX_COUNTRY_CODE_LEN;
183 2120 : while ((*src) && (isalpha(*src)) && (dest_space--)) {
184 1060 : *dest++ = toupper(*src++);
185 : }
186 530 : *dest = '\0';
187 530 : len = dest - country;
188 530 : if (len != 2) {
189 0 : NS_ASSERTION(len == 2, "unexpected country code length");
190 0 : *language = '\0';
191 0 : *country = '\0';
192 0 : return(false);
193 : }
194 : }
195 :
196 : // check if all done
197 530 : if (*src == '\0') {
198 0 : return(true);
199 : }
200 :
201 530 : if ((*src != '.') && (*src != '@')) {
202 0 : NS_ASSERTION(isalpha(*src), "country code too long");
203 0 : NS_ASSERTION(!isalpha(*src), "unexpected country/extra separator");
204 0 : *language = '\0';
205 0 : *country = '\0';
206 0 : return(false);
207 : }
208 :
209 : //
210 : // handle the extra part
211 : //
212 530 : if (*src == '.') {
213 530 : src++; // move past the extra part separator
214 530 : dest = extra;
215 530 : dest_space = MAX_EXTRA_LEN;
216 3710 : while ((*src) && (*src != '@') && (dest_space--)) {
217 2650 : *dest++ = *src++;
218 : }
219 530 : *dest = '\0';
220 530 : len = dest - extra;
221 530 : if (len < 1) {
222 0 : NS_ASSERTION(len > 0, "found country/extra separator but no extra code");
223 0 : *language = '\0';
224 0 : *country = '\0';
225 0 : *extra = '\0';
226 0 : return(false);
227 : }
228 : }
229 :
230 : // check if all done
231 530 : if (*src == '\0') {
232 530 : return(true);
233 : }
234 :
235 : //
236 : // handle the modifier part
237 : //
238 :
239 0 : if (*src == '@') {
240 0 : src++; // move past the modifier separator
241 0 : NS_ASSERTION(strcmp("euro",src) == 0, "found non euro modifier");
242 0 : dest = modifier;
243 0 : dest_space = MAX_EXTRA_LEN;
244 0 : while ((*src) && (dest_space--)) {
245 0 : *dest++ = *src++;
246 : }
247 0 : *dest = '\0';
248 0 : len = dest - modifier;
249 0 : if (len < 1) {
250 0 : NS_ASSERTION(len > 0, "found modifier separator but no modifier code");
251 0 : *language = '\0';
252 0 : *country = '\0';
253 0 : *extra = '\0';
254 0 : *modifier = '\0';
255 0 : return(false);
256 : }
257 : }
258 :
259 : // check if all done
260 0 : if (*src == '\0') {
261 0 : return(true);
262 : }
263 :
264 0 : NS_ASSERTION(*src == '\0', "extra/modifier code too long");
265 0 : *language = '\0';
266 0 : *country = '\0';
267 0 : *extra = '\0';
268 :
269 0 : return(false);
270 : }
271 :
|