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