dmime: The soft synth doesn't supports sharing the channel groups.
[wine.git] / libs / xslt / libxslt / xsltlocale.c
blobc69735cd2a26c1e2f379a02fc15c6b4fb6e0b100
1 /*
2 * xsltlocale.c: locale handling
4 * Reference:
5 * RFC 3066: Tags for the Identification of Languages
6 * http://www.ietf.org/rfc/rfc3066.txt
7 * ISO 639-1, ISO 3166-1
9 * Author: Nick Wellnhofer
10 * winapi port: Roumen Petrov
13 #define IN_LIBXSLT
14 #include "libxslt.h"
16 #include <string.h>
17 #include <libxml/xmlmemory.h>
19 #include "xsltlocale.h"
20 #include "xsltutils.h"
22 #define TOUPPER(c) (c & ~0x20)
23 #define TOLOWER(c) (c | 0x20)
24 #define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26)
26 /*without terminating null character*/
27 #define XSLTMAX_ISO639LANGLEN 8
28 #define XSLTMAX_ISO3166CNTRYLEN 8
29 /* <lang>-<cntry> */
30 #define XSLTMAX_LANGTAGLEN (XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN)
32 static const xmlChar* xsltDefaultRegion(const xmlChar *localeName);
34 #ifdef XSLT_LOCALE_WINAPI
35 xmlRMutexPtr xsltLocaleMutex = NULL;
37 struct xsltRFC1766Info_s {
38 /*note typedef unsigned char xmlChar !*/
39 xmlChar tag[XSLTMAX_LANGTAGLEN+1];
40 /*note typedef LCID xsltLocale !*/
41 xsltLocale lcid;
43 typedef struct xsltRFC1766Info_s xsltRFC1766Info;
45 static int xsltLocaleListSize = 0;
46 static xsltRFC1766Info *xsltLocaleList = NULL;
49 static xsltLocale
50 xslt_locale_WINAPI(const xmlChar *languageTag) {
51 int k;
52 xsltRFC1766Info *p = xsltLocaleList;
54 for (k=0; k<xsltLocaleListSize; k++, p++)
55 if (xmlStrcmp(p->tag, languageTag) == 0) return p->lcid;
56 return((xsltLocale)0);
59 static void xsltEnumSupportedLocales(void);
60 #endif
62 /**
63 * xsltFreeLocales:
65 * Cleanup function for the locale support on shutdown
67 void
68 xsltFreeLocales(void) {
69 #ifdef XSLT_LOCALE_WINAPI
70 xmlRMutexLock(xsltLocaleMutex);
71 xmlFree(xsltLocaleList);
72 xsltLocaleList = NULL;
73 xmlRMutexUnlock(xsltLocaleMutex);
74 #endif
77 /**
78 * xsltNewLocale:
79 * @languageTag: RFC 3066 language tag
81 * Creates a new locale of an opaque system dependent type based on the
82 * language tag.
84 * Returns the locale or NULL on error or if no matching locale was found
86 xsltLocale
87 xsltNewLocale(const xmlChar *languageTag) {
88 #ifdef XSLT_LOCALE_POSIX
89 xsltLocale locale;
90 char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */
91 const xmlChar *p = languageTag;
92 const char *region = NULL;
93 char *q = localeName;
94 int i, llen;
96 /* Convert something like "pt-br" to "pt_BR.utf8" */
98 if (languageTag == NULL)
99 return(NULL);
101 for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i)
102 *q++ = TOLOWER(*p++);
104 if (i == 0)
105 return(NULL);
107 llen = i;
109 if (*p) {
110 if (*p++ != '-')
111 return(NULL);
112 *q++ = '_';
114 for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i)
115 *q++ = TOUPPER(*p++);
117 if (i == 0 || *p)
118 return(NULL);
120 memcpy(q, ".utf8", 6);
121 locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
122 if (locale != NULL)
123 return(locale);
125 /* Continue without using country code */
127 q = localeName + llen;
130 /* Try locale without territory, e.g. for Esperanto (eo) */
132 memcpy(q, ".utf8", 6);
133 locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
134 if (locale != NULL)
135 return(locale);
137 /* Try to find most common country for language */
139 if (llen != 2)
140 return(NULL);
142 region = (char *)xsltDefaultRegion((xmlChar *)localeName);
143 if (region == NULL)
144 return(NULL);
146 q = localeName + llen;
147 *q++ = '_';
148 *q++ = region[0];
149 *q++ = region[1];
150 memcpy(q, ".utf8", 6);
151 locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
153 return(locale);
154 #endif
156 #ifdef XSLT_LOCALE_WINAPI
158 xsltLocale locale = (xsltLocale)0;
159 xmlChar localeName[XSLTMAX_LANGTAGLEN+1];
160 xmlChar *q = localeName;
161 const xmlChar *p = languageTag;
162 int i, llen;
163 const xmlChar *region = NULL;
165 if (languageTag == NULL) goto end;
167 xsltEnumSupportedLocales();
169 for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i)
170 *q++ = TOLOWER(*p++);
171 if (i == 0) goto end;
173 llen = i;
174 *q++ = '-';
175 if (*p) { /*if country tag is given*/
176 if (*p++ != '-') goto end;
178 for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i)
179 *q++ = TOUPPER(*p++);
180 if (i == 0 || *p) goto end;
182 *q = '\0';
183 locale = xslt_locale_WINAPI(localeName);
184 if (locale != (xsltLocale)0) goto end;
186 /* Try to find most common country for language */
187 region = xsltDefaultRegion(localeName);
188 if (region == NULL) goto end;
190 strcpy((char *) localeName + llen + 1, (char *) region);
191 locale = xslt_locale_WINAPI(localeName);
192 end:
193 return(locale);
195 #endif
197 #ifdef XSLT_LOCALE_NONE
198 return(NULL);
199 #endif
202 static const xmlChar*
203 xsltDefaultRegion(const xmlChar *localeName) {
204 xmlChar c;
205 /* region should be xmlChar, but gcc warns on all string assignments */
206 const char *region = NULL;
208 c = localeName[1];
209 /* This is based on the locales from glibc 2.3.3 */
211 switch (localeName[0]) {
212 case 'a':
213 if (c == 'a' || c == 'm') region = "ET";
214 else if (c == 'f') region = "ZA";
215 else if (c == 'n') region = "ES";
216 else if (c == 'r') region = "AE";
217 else if (c == 'z') region = "AZ";
218 break;
219 case 'b':
220 if (c == 'e') region = "BY";
221 else if (c == 'g') region = "BG";
222 else if (c == 'n') region = "BD";
223 else if (c == 'r') region = "FR";
224 else if (c == 's') region = "BA";
225 break;
226 case 'c':
227 if (c == 'a') region = "ES";
228 else if (c == 's') region = "CZ";
229 else if (c == 'y') region = "GB";
230 break;
231 case 'd':
232 if (c == 'a') region = "DK";
233 else if (c == 'e') region = "DE";
234 break;
235 case 'e':
236 if (c == 'l') region = "GR";
237 else if (c == 'n' || c == 'o') region = "US";
238 else if (c == 's' || c == 'u') region = "ES";
239 else if (c == 't') region = "EE";
240 break;
241 case 'f':
242 if (c == 'a') region = "IR";
243 else if (c == 'i') region = "FI";
244 else if (c == 'o') region = "FO";
245 else if (c == 'r') region = "FR";
246 break;
247 case 'g':
248 if (c == 'a') region = "IE";
249 else if (c == 'l') region = "ES";
250 else if (c == 'v') region = "GB";
251 break;
252 case 'h':
253 if (c == 'e') region = "IL";
254 else if (c == 'i') region = "IN";
255 else if (c == 'r') region = "HT";
256 else if (c == 'u') region = "HU";
257 break;
258 case 'i':
259 if (c == 'd') region = "ID";
260 else if (c == 's') region = "IS";
261 else if (c == 't') region = "IT";
262 else if (c == 'w') region = "IL";
263 break;
264 case 'j':
265 if (c == 'a') region = "JP";
266 break;
267 case 'k':
268 if (c == 'l') region = "GL";
269 else if (c == 'o') region = "KR";
270 else if (c == 'w') region = "GB";
271 break;
272 case 'l':
273 if (c == 't') region = "LT";
274 else if (c == 'v') region = "LV";
275 break;
276 case 'm':
277 if (c == 'k') region = "MK";
278 else if (c == 'l' || c == 'r') region = "IN";
279 else if (c == 'n') region = "MN";
280 else if (c == 's') region = "MY";
281 else if (c == 't') region = "MT";
282 break;
283 case 'n':
284 if (c == 'b' || c == 'n' || c == 'o') region = "NO";
285 else if (c == 'e') region = "NP";
286 else if (c == 'l') region = "NL";
287 break;
288 case 'o':
289 if (c == 'm') region = "ET";
290 break;
291 case 'p':
292 if (c == 'a') region = "IN";
293 else if (c == 'l') region = "PL";
294 else if (c == 't') region = "PT";
295 break;
296 case 'r':
297 if (c == 'o') region = "RO";
298 else if (c == 'u') region = "RU";
299 break;
300 case 's':
301 switch (c) {
302 case 'e': region = "NO"; break;
303 case 'h': region = "YU"; break;
304 case 'k': region = "SK"; break;
305 case 'l': region = "SI"; break;
306 case 'o': region = "ET"; break;
307 case 'q': region = "AL"; break;
308 case 't': region = "ZA"; break;
309 case 'v': region = "SE"; break;
311 break;
312 case 't':
313 if (c == 'a' || c == 'e') region = "IN";
314 else if (c == 'h') region = "TH";
315 else if (c == 'i') region = "ER";
316 else if (c == 'r') region = "TR";
317 else if (c == 't') region = "RU";
318 break;
319 case 'u':
320 if (c == 'k') region = "UA";
321 else if (c == 'r') region = "PK";
322 break;
323 case 'v':
324 if (c == 'i') region = "VN";
325 break;
326 case 'w':
327 if (c == 'a') region = "BE";
328 break;
329 case 'x':
330 if (c == 'h') region = "ZA";
331 break;
332 case 'z':
333 if (c == 'h') region = "CN";
334 else if (c == 'u') region = "ZA";
335 break;
337 return((xmlChar *)region);
341 * xsltFreeLocale:
342 * @locale: the locale to free
344 * Frees a locale created with xsltNewLocale
346 void
347 xsltFreeLocale(xsltLocale locale) {
348 #ifdef XSLT_LOCALE_POSIX
349 freelocale(locale);
350 #endif
354 * xsltStrxfrm:
355 * @locale: locale created with xsltNewLocale
356 * @string: UTF-8 string to transform
358 * Transforms a string according to locale. The transformed string must then be
359 * compared with xsltLocaleStrcmp and freed with xmlFree.
361 * Returns the transformed string or NULL on error
363 xsltLocaleChar *
364 xsltStrxfrm(xsltLocale locale, const xmlChar *string)
366 #ifdef XSLT_LOCALE_NONE
367 return(NULL);
368 #else
369 size_t xstrlen, r;
370 xsltLocaleChar *xstr;
372 #ifdef XSLT_LOCALE_POSIX
373 xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1;
374 xstr = (xsltLocaleChar *) xmlMalloc(xstrlen);
375 if (xstr == NULL) {
376 xsltTransformError(NULL, NULL, NULL,
377 "xsltStrxfrm : out of memory error\n");
378 return(NULL);
381 r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, locale);
382 #endif
384 #ifdef XSLT_LOCALE_WINAPI
385 xstrlen = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, NULL, 0);
386 if (xstrlen == 0) {
387 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n");
388 return(NULL);
390 xstr = (xsltLocaleChar*) xmlMalloc(xstrlen * sizeof(xsltLocaleChar));
391 if (xstr == NULL) {
392 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n");
393 return(NULL);
395 r = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, xstr, xstrlen);
396 if (r == 0) {
397 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n");
398 xmlFree(xstr);
399 return(NULL);
401 return(xstr);
402 #endif /* XSLT_LOCALE_WINAPI */
404 if (r >= xstrlen) {
405 xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n");
406 xmlFree(xstr);
407 return(NULL);
410 return(xstr);
411 #endif /* XSLT_LOCALE_NONE */
415 * xsltLocaleStrcmp:
416 * @locale: a locale identifier
417 * @str1: a string transformed with xsltStrxfrm
418 * @str2: a string transformed with xsltStrxfrm
420 * Compares two strings transformed with xsltStrxfrm
422 * Returns a value < 0 if str1 sorts before str2,
423 * a value > 0 if str1 sorts after str2,
424 * 0 if str1 and str2 are equal wrt sorting
427 xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2) {
428 (void)locale;
429 #ifdef XSLT_LOCALE_WINAPI
431 int ret;
432 if (str1 == str2) return(0);
433 if (str1 == NULL) return(-1);
434 if (str2 == NULL) return(1);
435 ret = CompareStringW(locale, 0, str1, -1, str2, -1);
436 if (ret == 0) {
437 xsltTransformError(NULL, NULL, NULL, "xsltLocaleStrcmp : CompareStringW fail\n");
438 return(0);
440 return(ret - 2);
442 #else
443 return(xmlStrcmp(str1, str2));
444 #endif
447 #ifdef XSLT_LOCALE_WINAPI
449 * xsltCountSupportedLocales:
450 * @lcid: not used
452 * callback used to count locales
454 * Returns TRUE
456 BOOL CALLBACK
457 xsltCountSupportedLocales(LPSTR lcid) {
458 (void) lcid;
459 ++xsltLocaleListSize;
460 return(TRUE);
464 * xsltIterateSupportedLocales:
465 * @lcid: not used
467 * callback used to track locales
469 * Returns TRUE if not at the end of the array
471 BOOL CALLBACK
472 xsltIterateSupportedLocales(LPSTR lcid) {
473 static int count = 0;
474 xmlChar iso639lang [XSLTMAX_ISO639LANGLEN +1];
475 xmlChar iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1];
476 int k, l;
477 xsltRFC1766Info *p = xsltLocaleList + count;
479 k = sscanf(lcid, "%lx", (long*)&p->lcid);
480 if (k < 1) goto end;
481 /*don't count terminating null character*/
482 k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME,
483 (char *) iso639lang, sizeof(iso639lang));
484 if (--k < 1) goto end;
485 l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME,
486 (char *) iso3136ctry, sizeof(iso3136ctry));
487 if (--l < 1) goto end;
489 { /*fill results*/
490 xmlChar *q = p->tag;
491 memcpy(q, iso639lang, k);
492 q += k;
493 *q++ = '-';
494 memcpy(q, iso3136ctry, l);
495 q += l;
496 *q = '\0';
498 ++count;
499 end:
500 return((count < xsltLocaleListSize) ? TRUE : FALSE);
504 static void
505 xsltEnumSupportedLocales(void) {
506 xmlRMutexLock(xsltLocaleMutex);
507 if (xsltLocaleListSize <= 0) {
508 size_t len;
510 EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED);
512 len = xsltLocaleListSize * sizeof(xsltRFC1766Info);
513 xsltLocaleList = xmlMalloc(len);
514 memset(xsltLocaleList, 0, len);
515 EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED);
517 xmlRMutexUnlock(xsltLocaleMutex);
520 #endif /*def XSLT_LOCALE_WINAPI*/