- Merge aicom-network-fixes up to r36740
[reactos.git] / reactos / lib / sdk / crt / locale / locale.c
1 /*
2 * Some stuff takem from wine msvcrt\locale.c
3 *
4 * Copyright 2000 Jon Griffiths
5 */
6
7 #include <precomp.h>
8 #include <locale.h>
9
10 #include "mbctype.h"
11
12 // mtdll.h
13 #define _SETLOCALE_LOCK 19
14
15 // msvcrt.h
16 #define MSVCRT_LC_ALL 0
17 #define MSVCRT_LC_COLLATE 1
18 #define MSVCRT_LC_CTYPE 2
19 #define MSVCRT_LC_MONETARY 3
20 #define MSVCRT_LC_NUMERIC 4
21 #define MSVCRT_LC_TIME 5
22 #define MSVCRT_LC_MIN MSVCRT_LC_ALL
23 #define MSVCRT_LC_MAX MSVCRT_LC_TIME
24
25 /* FIXME: Need to hold locale for each LC_* type and aggregate
26 * string to produce lc_all.
27 */
28 #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */
29
30 unsigned char MSVCRT_mbctype[257] = { 0 };
31 static int g_mbcp_is_multibyte = 0;
32
33 /* It seems that the data about valid trail bytes is not available from kernel32
34 * so we have to store is here. The format is the same as for lead bytes in CPINFO */
35 struct cp_extra_info_t
36 {
37 int cp;
38 BYTE TrailBytes[MAX_LEADBYTES];
39 };
40
41 static struct cp_extra_info_t g_cpextrainfo[] =
42 {
43 {932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
44 {936, {0x40, 0xfe, 0, 0}},
45 {949, {0x41, 0xfe, 0, 0}},
46 {950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
47 {20932, {1, 255, 0, 0}}, /* seems to give different results on different systems */
48 {0, {1, 255, 0, 0}} /* match all with FIXME */
49 };
50
51
52 char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH] = { 0 };
53 LCID MSVCRT_current_lc_all_lcid = 0;
54 int MSVCRT___lc_codepage = 0;
55 int MSVCRT___lc_collate_cp = 0;
56 HANDLE MSVCRT___lc_handle[MSVCRT_LC_MAX - MSVCRT_LC_MIN + 1] = { 0 };
57
58 /* MT */
59 #define LOCK_LOCALE _mlock(_SETLOCALE_LOCK);
60 #define UNLOCK_LOCALE _munlock(_SETLOCALE_LOCK);
61
62 #define MSVCRT_LEADBYTE 0x8000
63
64 typedef struct {
65 char search_language[MAX_ELEM_LEN];
66 char search_country[MAX_ELEM_LEN];
67 char search_codepage[MAX_ELEM_LEN];
68 char found_language[MAX_ELEM_LEN];
69 char found_country[MAX_ELEM_LEN];
70 char found_codepage[MAX_ELEM_LEN];
71 unsigned int match_flags;
72 LANGID found_lang_id;
73 } locale_search_t;
74
75 unsigned int __setlc_active;
76 unsigned int __unguarded_readlc_active;
77 int _current_category; /* used by setlocale */
78 const char *_current_locale;
79
80
81 int parse_locale(const char *locale, char *lang, char *country, char *code_page);
82
83 #define _C_ _CONTROL
84 #define _S_ _SPACE
85 #define _P_ _PUNCT
86 #define _D_ _DIGIT
87 #define _H_ _HEX
88 #define _U_ _UPPER
89 #define _L_ _LOWER
90
91 WORD MSVCRT__ctype [257] = {
92 0, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_C_, _S_|_C_,
93 _S_|_C_, _S_|_C_, _S_|_C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_,
94 _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_BLANK,
95 _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_,
96 _P_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_,
97 _D_|_H_, _D_|_H_, _D_|_H_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _U_|_H_,
98 _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_, _U_, _U_, _U_, _U_,
99 _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_,
100 _U_, _P_, _P_, _P_, _P_, _P_, _P_, _L_|_H_, _L_|_H_, _L_|_H_, _L_|_H_,
101 _L_|_H_, _L_|_H_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_,
102 _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _P_, _P_, _P_, _P_,
103 _C_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109 };
110
111 /* Internal: Current ctype table for locale */
112 WORD MSVCRT_current_ctype[257];
113
114 /* pctype is used by macros in the Win32 headers. It must point
115 * To a table of flags exactly like ctype. To allow locale
116 * changes to affect ctypes (i.e. isleadbyte), we use a second table
117 * and update its flags whenever the current locale changes.
118 */
119 WORD* MSVCRT__pctype = MSVCRT_current_ctype + 1;
120
121 /* Friendly country strings & iso codes for synonym support.
122 * Based on MS documentation for setlocale().
123 */
124 static const char * const _country_synonyms[] =
125 {
126 "Hong Kong","HK",
127 "Hong-Kong","HK",
128 "New Zealand","NZ",
129 "New-Zealand","NZ",
130 "PR China","CN",
131 "PR-China","CN",
132 "United Kingdom","GB",
133 "United-Kingdom","GB",
134 "Britain","GB",
135 "England","GB",
136 "Great Britain","GB",
137 "United States","US",
138 "United-States","US",
139 "America","US"
140 };
141
142 /* Note: Flags are weighted in order of matching importance */
143 #define FOUND_LANGUAGE 0x4
144 #define FOUND_COUNTRY 0x2
145 #define FOUND_CODEPAGE 0x1
146
147 /* INTERNAL: Map a synonym to an ISO code */
148 static void remap_synonym(char *name)
149 {
150 size_t i;
151 for (i = 0; i < sizeof(_country_synonyms)/sizeof(char*); i += 2 )
152 {
153 if (!strcasecmp(_country_synonyms[i],name))
154 {
155 TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]);
156 name[0] = _country_synonyms[i+1][0];
157 name[1] = _country_synonyms[i+1][1];
158 name[2] = '\0';
159 return;
160 }
161 }
162 }
163
164 #define CONTINUE_LOOKING TRUE
165 #define STOP_LOOKING FALSE
166
167 /* INTERNAL: Get and compare locale info with a given string */
168 static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp)
169 {
170 buff[0] = 0;
171 GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE,buff, MAX_ELEM_LEN);
172 if (!buff[0] || !cmp[0])
173 return 0;
174 /* Partial matches are allowed, e.g. "Germ" matches "Germany" */
175 return !strncasecmp(cmp, buff, strlen(cmp));
176 }
177
178
179 static BOOL CALLBACK
180 find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam)
181 {
182 locale_search_t *res = (locale_search_t *)lParam;
183 const LCID lcid = MAKELCID(LangID, SORT_DEFAULT);
184 char buff[MAX_ELEM_LEN];
185 unsigned int flags = 0;
186
187 if(PRIMARYLANGID(LangID) == LANG_NEUTRAL)
188 return CONTINUE_LOOKING;
189
190 /* Check Language */
191 if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language) ||
192 compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language) ||
193 compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language))
194 {
195 TRACE(":Found language: %s->%s\n", res->search_language, buff);
196 flags |= FOUND_LANGUAGE;
197 memcpy(res->found_language,res->search_language,MAX_ELEM_LEN);
198 }
199 else if (res->match_flags & FOUND_LANGUAGE)
200 {
201 return CONTINUE_LOOKING;
202 }
203
204 /* Check Country */
205 if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country) ||
206 compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country) ||
207 compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country))
208 {
209 TRACE("Found country:%s->%s\n", res->search_country, buff);
210 flags |= FOUND_COUNTRY;
211 memcpy(res->found_country,res->search_country,MAX_ELEM_LEN);
212 }
213 else if (res->match_flags & FOUND_COUNTRY)
214 {
215 return CONTINUE_LOOKING;
216 }
217
218 /* Check codepage */
219 if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage) ||
220 (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage)))
221 {
222 TRACE("Found codepage:%s->%s\n", res->search_codepage, buff);
223 flags |= FOUND_CODEPAGE;
224 memcpy(res->found_codepage,res->search_codepage,MAX_ELEM_LEN);
225 }
226 else if (res->match_flags & FOUND_CODEPAGE)
227 {
228 return CONTINUE_LOOKING;
229 }
230
231 if (flags > res->match_flags)
232 {
233 /* Found a better match than previously */
234 res->match_flags = flags;
235 res->found_lang_id = LangID;
236 }
237 if (flags & (FOUND_LANGUAGE & FOUND_COUNTRY & FOUND_CODEPAGE))
238 {
239 TRACE(":found exact locale match\n");
240 return STOP_LOOKING;
241 }
242 return CONTINUE_LOOKING;
243 }
244
245 /* Internal: Find the LCID for a locale specification */
246 static LCID MSVCRT_locale_to_LCID(locale_search_t* locale)
247 {
248 LCID lcid;
249 EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR)RT_STRING,
250 (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc,
251 (LONG_PTR)locale);
252
253 if (!locale->match_flags)
254 return 0;
255
256 /* If we were given something that didn't match, fail */
257 if (locale->search_country[0] && !(locale->match_flags & FOUND_COUNTRY))
258 return 0;
259
260 lcid = MAKELCID(locale->found_lang_id, SORT_DEFAULT);
261
262 /* Populate partial locale, translating LCID to locale string elements */
263 if (!locale->found_codepage[0])
264 {
265 /* Even if a codepage is not enumerated for a locale
266 * it can be set if valid */
267 if (locale->search_codepage[0])
268 {
269 if (IsValidCodePage(atoi(locale->search_codepage)))
270 memcpy(locale->found_codepage,locale->search_codepage,MAX_ELEM_LEN);
271 else
272 {
273 /* Special codepage values: OEM & ANSI */
274 if (strcasecmp(locale->search_codepage,"OCP"))
275 {
276 GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE,
277 locale->found_codepage, MAX_ELEM_LEN);
278 }
279 if (strcasecmp(locale->search_codepage,"ACP"))
280 {
281 GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE,
282 locale->found_codepage, MAX_ELEM_LEN);
283 }
284 else
285 return 0;
286
287 if (!atoi(locale->found_codepage))
288 return 0;
289 }
290 }
291 else
292 {
293 /* Prefer ANSI codepages if present */
294 GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE,
295 locale->found_codepage, MAX_ELEM_LEN);
296 if (!locale->found_codepage[0] || !atoi(locale->found_codepage))
297 GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE,
298 locale->found_codepage, MAX_ELEM_LEN);
299 }
300 }
301 GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE,
302 locale->found_language, MAX_ELEM_LEN);
303 GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY|LOCALE_NOUSEROVERRIDE,
304 locale->found_country, MAX_ELEM_LEN);
305 return lcid;
306 }
307
308 /* INTERNAL: Set ctype behaviour for a codepage */
309 static void msvcrt_set_ctype(unsigned int codepage, LCID lcid)
310 {
311 CPINFO cp;
312
313 memset(&cp, 0, sizeof(CPINFO));
314
315 if (GetCPInfo(codepage, &cp))
316 {
317 int i;
318 char str[3];
319 unsigned char *traverse = (unsigned char *)cp.LeadByte;
320
321 memset(MSVCRT_current_ctype, 0, sizeof(MSVCRT__ctype));
322 MSVCRT___lc_codepage = codepage;
323 MSVCRT___lc_collate_cp = codepage;
324
325 /* Switch ctype macros to MBCS if needed */
326 __mb_cur_max = cp.MaxCharSize;
327
328 /* Set remaining ctype flags: FIXME: faster way to do this? */
329 str[1] = str[2] = 0;
330 for (i = 0; i < 256; i++)
331 {
332 if (!(MSVCRT__pctype[i] & MSVCRT_LEADBYTE))
333 {
334 str[0] = i;
335 GetStringTypeA(lcid, CT_CTYPE1, str, 1, MSVCRT__pctype + i);
336 }
337 }
338
339 /* Set leadbyte flags */
340 while (traverse[0] || traverse[1])
341 {
342 for( i = traverse[0]; i <= traverse[1]; i++ )
343 MSVCRT_current_ctype[i+1] |= MSVCRT_LEADBYTE;
344 traverse += 2;
345 };
346 }
347 }
348
349
350 /*
351 * @implemented
352 */
353 char *setlocale(int category, const char *locale)
354 {
355 LCID lcid = 0;
356 locale_search_t lc;
357 int haveLang, haveCountry, haveCP;
358 char* next;
359 int lc_all = 0;
360
361 TRACE("(%d %s)\n",category,locale);
362
363 if (category < MSVCRT_LC_MIN || category > MSVCRT_LC_MAX)
364 return NULL;
365
366 if (locale == NULL)
367 {
368 /* Report the current Locale */
369 return MSVCRT_current_lc_all;
370 }
371
372 LOCK_LOCALE;
373
374 if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_')
375 {
376 WARN(":restore previous locale not implemented!\n");
377 /* FIXME: Easiest way to do this is parse the string and
378 * call this function recursively with its elements,
379 * Where they differ for each lc_ type.
380 */
381 UNLOCK_LOCALE;
382 return MSVCRT_current_lc_all;
383 }
384
385 /* Default Locale: Special case handling */
386 if (!strlen(locale) || ((toupper(locale[0]) == 'C') && !locale[1]))
387 {
388 MSVCRT_current_lc_all[0] = 'C';
389 MSVCRT_current_lc_all[1] = '\0';
390 MSVCRT___lc_codepage = 1252;
391 MSVCRT___lc_collate_cp = 1252;
392
393 switch (category) {
394 case MSVCRT_LC_ALL:
395 lc_all = 1; /* Fall through all cases ... */
396 case MSVCRT_LC_COLLATE:
397 if (!lc_all) break;
398 case MSVCRT_LC_CTYPE:
399 /* Restore C locale ctype info */
400 __mb_cur_max = 1;
401 memcpy(MSVCRT_current_ctype, MSVCRT__ctype, sizeof(MSVCRT__ctype));
402 if (!lc_all) break;
403 case MSVCRT_LC_MONETARY:
404 if (!lc_all) break;
405 case MSVCRT_LC_NUMERIC:
406 if (!lc_all) break;
407 case MSVCRT_LC_TIME:
408 break;
409 }
410 UNLOCK_LOCALE;
411 return MSVCRT_current_lc_all;
412 }
413
414 /* Get locale elements */
415 haveLang = haveCountry = haveCP = 0;
416 memset(&lc,0,sizeof(lc));
417
418 next = strchr(locale,'_');
419 if (next && next != locale)
420 {
421 haveLang = 1;
422 memcpy(lc.search_language,locale,next-locale);
423 locale += next-locale+1;
424 }
425
426 next = strchr(locale,'.');
427 if (next)
428 {
429 haveCP = 1;
430 if (next == locale)
431 {
432 locale++;
433 lstrcpynA(lc.search_codepage, locale, MAX_ELEM_LEN);
434 }
435 else
436 {
437 if (haveLang)
438 {
439 haveCountry = 1;
440 memcpy(lc.search_country,locale,next-locale);
441 locale += next-locale+1;
442 }
443 else
444 {
445 haveLang = 1;
446 memcpy(lc.search_language,locale,next-locale);
447 locale += next-locale+1;
448 }
449 lstrcpynA(lc.search_codepage, locale, MAX_ELEM_LEN);
450 }
451 }
452 else
453 {
454 if (haveLang)
455 {
456 haveCountry = 1;
457 lstrcpynA(lc.search_country, locale, MAX_ELEM_LEN);
458 }
459 else
460 {
461 haveLang = 1;
462 lstrcpynA(lc.search_language, locale, MAX_ELEM_LEN);
463 }
464 }
465
466 if (haveCountry)
467 remap_synonym(lc.search_country);
468
469 if (haveCP && !haveCountry && !haveLang)
470 {
471 ERR(":Codepage only locale not implemented\n");
472 /* FIXME: Use default lang/country and skip locale_to_LCID()
473 * call below...
474 */
475 UNLOCK_LOCALE;
476 return NULL;
477 }
478
479 lcid = MSVCRT_locale_to_LCID(&lc);
480
481 TRACE(":found LCID %d\n",lcid);
482
483 if (lcid == 0)
484 {
485 UNLOCK_LOCALE;
486 return NULL;
487 }
488
489 MSVCRT_current_lc_all_lcid = lcid;
490
491 _snprintf(MSVCRT_current_lc_all,MAX_LOCALE_LENGTH,"%s_%s.%s",
492 lc.found_language,lc.found_country,lc.found_codepage);
493
494 switch (category) {
495 case MSVCRT_LC_ALL:
496 lc_all = 1; /* Fall through all cases ... */
497 case MSVCRT_LC_COLLATE:
498 if (!lc_all) break;
499 case MSVCRT_LC_CTYPE:
500 msvcrt_set_ctype(atoi(lc.found_codepage),lcid);
501 if (!lc_all) break;
502 case MSVCRT_LC_MONETARY:
503 if (!lc_all) break;
504 case MSVCRT_LC_NUMERIC:
505 if (!lc_all) break;
506 case MSVCRT_LC_TIME:
507 break;
508 }
509 UNLOCK_LOCALE;
510 return MSVCRT_current_lc_all;
511 }
512
513 /*
514 * @unimplemented
515 */
516 wchar_t* _wsetlocale(int category, const wchar_t* locale)
517 {
518 static wchar_t fake[] = {
519 'E','n','g','l','i','s','h','_','U','n','i','t','e','d',' ',
520 'S','t','a','t','e','s','.','1','2','5','2',0 };
521
522 TRACE("%d %S\n", category, locale);
523
524 return fake;
525 }
526
527 /*
528
529 locale "lang[_country[.code_page]]"
530 | ".code_page"
531 | ""
532 | NULL
533
534 */
535 int parse_locale(const char *locale, char *lang, char *country, char *code_page)
536 {
537 while ( *locale != 0 && *locale != '.' && *locale != '_' )
538 {
539 *lang = *locale;
540 lang++;
541 locale++;
542 }
543 *lang = 0;
544 if ( *locale == '_' ) {
545 locale++;
546 while ( *locale != 0 && *locale != '.' )
547 {
548 *country = *locale;
549 country++;
550 locale++;
551 }
552 }
553 *country = 0;
554
555
556 if ( *locale == '.' ) {
557 locale++;
558 while ( *locale != 0 && *locale != '.' )
559 {
560 *code_page = *locale;
561 code_page++;
562 locale++;
563 }
564 }
565
566 *code_page = 0;
567 return 0;
568 }
569
570 const struct map_lcid2str {
571 short langid;
572 const char *langname;
573 const char *country;
574 } languages[]={
575 {0x0409,"English", "United States"},
576 {0x0809,"English", "United Kingdom"},
577 {0x0000,"Unknown", "Unknown"}
578
579 };
580
581 const struct map_cntr {
582 const char *abrev;
583 const char *country;
584 } abrev[] = {
585 {"britain", "united kingdom"},
586 {"england", "united kingdom"},
587 {"gbr", "united kingdom"},
588 {"great britain", "united kingdom"},
589 {"uk", "united kingdom"},
590 {"united kingdom", "united kingdom"},
591 {"united-kingdom", "united kingdom"},
592 {"america", "united states" },
593 {"united states", "united states"},
594 {"united-states", "united states"},
595 {"us", "united states"},
596 {"usa" "united states"}
597 };
598
599
600 struct lconv _lconv = {
601 ".", // decimal_point
602 ",", // thousands_sep
603 "", // grouping;
604 "DOL", // int_curr_symbol
605 "$", // currency_symbol
606 ".", // mon_decimal_point
607 ",", // mon_thousands_sep
608 "", // mon_grouping;
609 "+", // positive_sign
610 "-", // negative_sign
611 127, // int_frac_digits
612 127, // frac_digits
613 127, // p_cs_precedes
614 127, // p_sep_by_space
615 127, // n_cs_precedes
616 127, // n_sep_by_space
617 127, // p_sign_posn;
618 127 // n_sign_posn;
619 };
620
621 /*
622 * @implemented
623 */
624 struct lconv *localeconv(void)
625 {
626 return (struct lconv *) &_lconv;
627 }
628
629 /*********************************************************************
630 * _setmbcp (MSVCRT.@)
631 * @implemented
632 */
633 int CDECL _setmbcp(int cp)
634 {
635 int newcp;
636 CPINFO cpi;
637 BYTE *bytes;
638 WORD chartypes[256];
639 WORD *curr_type;
640 char bufA[256];
641 WCHAR bufW[256];
642 int charcount;
643 int ret;
644 int i;
645
646 TRACE("_setmbcp %d\n",cp);
647 switch (cp)
648 {
649 case _MB_CP_ANSI:
650 newcp = GetACP();
651 break;
652 case _MB_CP_OEM:
653 newcp = GetOEMCP();
654 break;
655 case _MB_CP_LOCALE:
656 newcp = MSVCRT___lc_codepage;
657 break;
658 case _MB_CP_SBCS:
659 newcp = 20127; /* ASCII */
660 break;
661 default:
662 newcp = cp;
663 break;
664 }
665
666 if (!GetCPInfo(newcp, &cpi))
667 {
668 ERR("Codepage %d not found\n", newcp);
669 __set_errno(EINVAL);
670 return -1;
671 }
672
673 /* setup the _mbctype */
674 memset(MSVCRT_mbctype, 0, sizeof(MSVCRT_mbctype));
675
676 bytes = cpi.LeadByte;
677 while (bytes[0] || bytes[1])
678 {
679 for (i = bytes[0]; i <= bytes[1]; i++)
680 MSVCRT_mbctype[i + 1] |= _M1;
681 bytes += 2;
682 }
683
684 if (cpi.MaxCharSize > 1)
685 {
686 /* trail bytes not available through kernel32 but stored in a structure in msvcrt */
687 struct cp_extra_info_t *cpextra = g_cpextrainfo;
688
689 g_mbcp_is_multibyte = 1;
690 while (TRUE)
691 {
692 if (cpextra->cp == 0 || cpextra->cp == newcp)
693 {
694 if (cpextra->cp == 0)
695 ERR("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
696
697 bytes = cpextra->TrailBytes;
698 while (bytes[0] || bytes[1])
699 {
700 for (i = bytes[0]; i <= bytes[1]; i++)
701 MSVCRT_mbctype[i + 1] |= _M2;
702 bytes += 2;
703 }
704 break;
705 }
706 cpextra++;
707 }
708 }
709 else
710 g_mbcp_is_multibyte = 0;
711
712 /* we can't use GetStringTypeA directly because we don't have a locale - only a code page
713 */
714 charcount = 0;
715 for (i = 0; i < 256; i++)
716 if (!(MSVCRT_mbctype[i + 1] & _M1))
717 bufA[charcount++] = i;
718
719 ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
720 if (ret != charcount)
721 ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
722
723 GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
724
725 curr_type = chartypes;
726 for (i = 0; i < 256; i++)
727 if (!(MSVCRT_mbctype[i + 1] & _M1))
728 {
729 if ((*curr_type) & C1_UPPER)
730 MSVCRT_mbctype[i + 1] |= _SBUP;
731 if ((*curr_type) & C1_LOWER)
732 MSVCRT_mbctype[i + 1] |= _SBLOW;
733 curr_type++;
734 }
735
736 if (newcp == 932) /* CP932 only - set _MP and _MS */
737 {
738 /* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
739 * and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
740 * it hard. As this is set only for codepage 932 we hardcode it what gives
741 * also faster execution.
742 */
743 for (i = 161; i <= 165; i++)
744 MSVCRT_mbctype[i + 1] |= _MP;
745 for (i = 166; i <= 223; i++)
746 MSVCRT_mbctype[i + 1] |= _MS;
747 }
748
749 MSVCRT___lc_collate_cp = MSVCRT___lc_codepage = newcp;
750 TRACE("(%d) -> %d\n", cp, MSVCRT___lc_codepage);
751 return 0;
752 }
753
754
755 /*********************************************************************
756 * __lc_collate_cp (MSVCRT.@)
757 *
758 * @unimplemented
759 */
760 void __lc_collate_cp(int cp)
761 {
762 FIXME("__lc_collate_cp - stub\n");
763 return;
764 }
765
766
767 /*********************************************************************
768 * __lc_handle (MSVCRT.@)
769 *
770 * @unimplemented
771 */
772 void __lc_handle(void)
773 {
774 FIXME("__lc_handle - stub\n");
775 return;
776 }
777
778
779 /*********************************************************************
780 * __lc_codepage (MSVCRT.@)
781 *
782 * @unimplemented
783 */
784 void __lc_codepage(void)
785 {
786 FIXME("__lc_codepage - stub\n");
787 return;
788 }
789
790
791 /*********************************************************************
792 * _Gettnames (MSVCRT.@)
793 */
794 void *_Gettnames(void)
795 {
796 FIXME("(void), stub!\n");
797 return NULL;
798 }
799
800 /*********************************************************************
801 * __lconv_init (MSVCRT.@)
802 */
803 void __lconv_init(void)
804 {
805 FIXME(" stub\n");
806 }
807
808
809 /*********************************************************************
810 * _Strftime (MSVCRT.@)
811 */
812 const char* _Strftime(char *out, unsigned int len, const char *fmt,
813 const void *tm, void *foo)
814 {
815 /* FIXME: */
816 FIXME("(%p %d %s %p %p) stub\n", out, len, fmt, tm, foo);
817 return "";
818 }
819
820
821 /*********************************************************************
822 * _Getdays (MSVCRT.@)
823 */
824 const char* _Getdays(void)
825 {
826 static const char *MSVCRT_days = ":Sun:Sunday:Mon:Monday:Tue:Tuesday:Wed:"
827 "Wednesday:Thu:Thursday:Fri:Friday:Sat:Saturday";
828 /* FIXME: Use locale */
829 FIXME("(void) semi-stub\n");
830 return MSVCRT_days;
831 }
832
833 /*********************************************************************
834 * _Getmonths (MSVCRT.@)
835 */
836 const char* _Getmonths(void)
837 {
838 static const char *MSVCRT_months = ":Jan:January:Feb:February:Mar:March:Apr:"
839 "April:May:May:Jun:June:Jul:July:Aug:August:Sep:September:Oct:"
840 "October:Nov:November:Dec:December";
841 /* FIXME: Use locale */
842 FIXME("(void) semi-stub\n");
843 return MSVCRT_months;
844 }
845
846 /*********************************************************************
847 * __crtLCMapStringA (MSVCRT.@)
848 */
849 int __crtLCMapStringA(
850 LCID lcid, DWORD mapflags, const char* src, int srclen, char* dst,
851 int dstlen, unsigned int codepage, int xflag
852 ) {
853 TRACE("(lcid %lx, flags %lx, %s(%d), %p(%d), %x, %d), partial stub!\n",
854 lcid,mapflags,src,srclen,dst,dstlen,codepage,xflag);
855 /* FIXME: A bit incorrect. But msvcrt itself just converts its
856 * arguments to wide strings and then calls LCMapStringW
857 */
858 return LCMapStringA(lcid,mapflags,src,srclen,dst,dstlen);
859 }
860
861 /*********************************************************************
862 * __crtLCMapStringW (MSVCRT.@)
863 */
864 int __crtLCMapStringW(
865 LCID lcid, DWORD mapflags, LPCWSTR src, int srclen, LPWSTR dst,
866 int dstlen, unsigned int codepage, int xflag
867 ) {
868 TRACE("(lcid %lx, flags %lx, %s(%d), %p(%d), %x, %d), partial stub!\n",
869 lcid,mapflags,src,srclen,dst,dstlen,codepage,xflag);
870
871 return LCMapStringW(lcid,mapflags,src,srclen,dst,dstlen);
872 }
873
874 int CDECL _getmbcp(void)
875 {
876 return MSVCRT___lc_codepage;
877 }
878
879 /*********************************************************************
880 * ___unguarded_readlc_active_add_func (MSVCRT.@)
881 */
882 unsigned int * CDECL ___unguarded_readlc_active_add_func(void)
883 {
884 return &__unguarded_readlc_active;
885 }
886
887 /*********************************************************************
888 * ___setlc_active_func (MSVCRT.@)
889 */
890 unsigned int CDECL ___setlc_active_func(void)
891 {
892 return __setlc_active;
893 }