Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
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/. */
6 #include "nscore.h"
7 #include "nsString.h"
8 #include "nsPosixLocale.h"
9 #include "prprf.h"
10 #include "plstr.h"
11 #include "nsReadableUtils.h"
13 static bool
14 ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator);
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);
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 }
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 }
49 posixLocale = posix_locale;
50 return NS_OK;
51 }
53 return NS_ERROR_FAILURE;
54 }
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];
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 }
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 }
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 }
89 CopyASCIItoUTF16(nsDependentCString(posix_locale), locale);
90 return NS_OK;
92 }
94 return NS_ERROR_FAILURE;
96 }
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;
108 *language = '\0';
109 *country = '\0';
110 *extra = '\0';
111 if (strlen(locale_string) < 2) {
112 return(false);
113 }
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 }
132 // check if all done
133 if (*src == '\0') {
134 return(true);
135 }
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 }
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 }
164 // check if all done
165 if (*src == '\0') {
166 return(true);
167 }
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 }
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 }
198 // check if all done
199 if (*src == '\0') {
200 return(true);
201 }
203 //
204 // handle the modifier part
205 //
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 }
227 // check if all done
228 if (*src == '\0') {
229 return(true);
230 }
232 NS_ASSERTION(*src == '\0', "extra/modifier code too long");
233 *language = '\0';
234 *country = '\0';
235 *extra = '\0';
237 return(false);
238 }