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