1 /*
2  * Unit test suite for locale functions.
3  *
4  * Copyright 2010 Piotr Caban for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 static BOOL (__cdecl *p__crtGetStringTypeW)(DWORD, DWORD, const wchar_t*, int, WORD*);
24 static int (__cdecl *pmemcpy_s)(void *, size_t, void*, size_t);
25 static int (__cdecl *p___mb_cur_max_func)(void);
26 static int *(__cdecl *p__p___mb_cur_max)(void);
27 void* __cdecl _Gettnames(void);
28 
29 static void init(void)
30 {
31     HMODULE hmod = GetModuleHandleA("msvcrt.dll");
32 
33     p__crtGetStringTypeW = (void*)GetProcAddress(hmod, "__crtGetStringTypeW");
34     pmemcpy_s = (void*)GetProcAddress(hmod, "memcpy_s");
35     p___mb_cur_max_func = (void*)GetProcAddress(hmod, "___mb_cur_max_func");
36     p__p___mb_cur_max = (void*)GetProcAddress(hmod, "__p___mb_cur_max");
37 }
38 
39 static void test_setlocale(void)
40 {
41     static const char lc_all[] = "LC_COLLATE=C;LC_CTYPE=C;"
42         "LC_MONETARY=Greek_Greece.1253;LC_NUMERIC=Polish_Poland.1250;LC_TIME=C";
43 
44     char *ret, buf[100];
45 
46     ret = setlocale(20, "C");
47     ok(ret == NULL, "ret = %s\n", ret);
48 
49     ret = setlocale(LC_ALL, "C");
50     ok(!strcmp(ret, "C"), "ret = %s\n", ret);
51 
52     ret = setlocale(LC_ALL, NULL);
53     ok(!strcmp(ret, "C"), "ret = %s\n", ret);
54 
55     if(!setlocale(LC_NUMERIC, "Polish")
56             || !setlocale(LC_NUMERIC, "Greek")
57             || !setlocale(LC_NUMERIC, "German")
58             || !setlocale(LC_NUMERIC, "English")) {
59         win_skip("System with limited locales\n");
60         return;
61     }
62 
63     ret = setlocale(LC_NUMERIC, "Polish");
64     ok(!strcmp(ret, "Polish_Poland.1250"), "ret = %s\n", ret);
65 
66     ret = setlocale(LC_MONETARY, "Greek");
67     ok(!strcmp(ret, "Greek_Greece.1253"), "ret = %s\n", ret);
68 
69     ret = setlocale(LC_ALL, NULL);
70     ok(!strcmp(ret, lc_all), "ret = %s\n", ret);
71 
72     strcpy(buf, ret);
73     ret = setlocale(LC_ALL, buf);
74     ok(!strcmp(ret, lc_all), "ret = %s\n", ret);
75 
76     ret = setlocale(LC_ALL, "German");
77     ok(!strcmp(ret, "German_Germany.1252"), "ret = %s\n", ret);
78 
79     ret = setlocale(LC_ALL, "american");
80     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
81     if(ret)
82         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
83 
84     ret = setlocale(LC_ALL, "american english");
85     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
86     if(ret)
87         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
88 
89     ret = setlocale(LC_ALL, "american-english");
90     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
91     if(ret)
92         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
93 
94     ret = setlocale(LC_ALL, "australian");
95     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
96     if(ret)
97         ok(!strcmp(ret, "English_Australia.1252"), "ret = %s\n", ret);
98 
99     ret = setlocale(LC_ALL, "belgian");
100     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
101     if(ret)
102         ok(!strcmp(ret, "Dutch_Belgium.1252"), "ret = %s\n", ret);
103 
104     ret = setlocale(LC_ALL, "canadian");
105     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
106     if(ret)
107         ok(!strcmp(ret, "English_Canada.1252"), "ret = %s\n", ret);
108 
109     ret = setlocale(LC_ALL, "chinese");
110     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
111     if(ret)
112         ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
113         || !strcmp(ret, "Chinese (Simplified)_China.936")
114         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
115 
116     ret = setlocale(LC_ALL, "chinese-simplified");
117     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
118     if(ret)
119         ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
120         || !strcmp(ret, "Chinese (Simplified)_China.936")
121         || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))
122         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
123 
124     ret = setlocale(LC_ALL, "chinese-traditional");
125     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
126     if(ret)
127         ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
128         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
129 
130     ret = setlocale(LC_ALL, "chs");
131     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
132     if(ret)
133         ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
134         || !strcmp(ret, "Chinese (Simplified)_China.936")
135         || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret);
136 
137     ret = setlocale(LC_ALL, "cht");
138     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
139     if(ret)
140         ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
141         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
142 
143     ret = setlocale(LC_ALL, "Chinese_China.936");
144 todo_wine
145     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
146     if(ret)
147     {
148         trace("Chinese_China.936=%s\n", ret);
149 todo_wine
150         ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") /* Vista - Win7 */
151         || !strcmp(ret, "Chinese (Simplified)_China.936") /* Win8 - Win10 */
152         || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret);
153     }
154 
155     ret = setlocale(LC_ALL, "csy");
156     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
157     if(ret)
158         ok(!strcmp(ret, "Czech_Czech Republic.1250"), "ret = %s\n", ret);
159 
160     ret = setlocale(LC_ALL, "czech");
161     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
162     if(ret)
163         ok(!strcmp(ret, "Czech_Czech Republic.1250"), "ret = %s\n", ret);
164 
165     ret = setlocale(LC_ALL, "dan");
166     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
167     if(ret)
168         ok(!strcmp(ret, "Danish_Denmark.1252"), "ret = %s\n", ret);
169 
170     ret = setlocale(LC_ALL, "danish");
171     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
172     if(ret)
173         ok(!strcmp(ret, "Danish_Denmark.1252"), "ret = %s\n", ret);
174 
175     ret = setlocale(LC_ALL, "dea");
176     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
177     if(ret)
178         ok(!strcmp(ret, "German_Austria.1252"), "ret = %s\n", ret);
179 
180     ret = setlocale(LC_ALL, "des");
181     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
182     if(ret)
183         ok(!strcmp(ret, "German_Switzerland.1252"), "ret = %s\n", ret);
184 
185     ret = setlocale(LC_ALL, "deu");
186     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
187     if(ret)
188         ok(!strcmp(ret, "German_Germany.1252"), "ret = %s\n", ret);
189 
190     ret = setlocale(LC_ALL, "dutch");
191     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
192     if(ret)
193         ok(!strcmp(ret, "Dutch_Netherlands.1252"), "ret = %s\n", ret);
194 
195     ret = setlocale(LC_ALL, "dutch-belgian");
196     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
197     if(ret)
198         ok(!strcmp(ret, "Dutch_Belgium.1252")
199         || broken(!strcmp(ret, "Dutch_Netherlands.1252")), "ret = %s\n", ret);
200 
201     ret = setlocale(LC_ALL, "ena");
202     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
203     if(ret)
204         ok(!strcmp(ret, "English_Australia.1252")
205         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
206 
207     ret = setlocale(LC_ALL, "ell");
208     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
209     if(ret)
210         ok(!strcmp(ret, "Greek_Greece.1253"), "ret = %s\n", ret);
211 
212     ret = setlocale(LC_ALL, "enc");
213     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
214     if(ret)
215         ok(!strcmp(ret, "English_Canada.1252")
216         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
217 
218     ret = setlocale(LC_ALL, "eng");
219     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
220     if(ret)
221         ok(!strcmp(ret, "English_United Kingdom.1252")
222         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
223 
224     ret = setlocale(LC_ALL, "enu");
225     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
226     if(ret)
227         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
228 
229     ret = setlocale(LC_ALL, "enz");
230     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
231     if(ret)
232         ok(!strcmp(ret, "English_New Zealand.1252")
233         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
234 
235     ret = setlocale(LC_ALL, "english");
236     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
237     if(ret)
238         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
239 
240     ret = setlocale(LC_ALL, "english-american");
241     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
242     if(ret)
243         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
244 
245     ret = setlocale(LC_ALL, "english-aus");
246     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
247     if(ret)
248         ok(!strcmp(ret, "English_Australia.1252")
249         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
250 
251     ret = setlocale(LC_ALL, "english-can");
252     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
253     if(ret)
254         ok(!strcmp(ret, "English_Canada.1252")
255         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
256 
257     ret = setlocale(LC_ALL, "english-nz");
258     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
259     if(ret)
260         ok(!strcmp(ret, "English_New Zealand.1252")
261         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
262 
263     ret = setlocale(LC_ALL, "english-uk");
264     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
265     if(ret)
266         ok(!strcmp(ret, "English_United Kingdom.1252")
267         || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret);
268 
269     ret = setlocale(LC_ALL, "english-us");
270     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
271     if(ret)
272         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
273 
274     ret = setlocale(LC_ALL, "english-usa");
275     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
276     if(ret)
277         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
278 
279     ret = setlocale(LC_ALL, "esm");
280     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
281     if(ret)
282         ok(!strcmp(ret, "Spanish_Mexico.1252"), "ret = %s\n", ret);
283 
284     ret = setlocale(LC_ALL, "esn");
285     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
286     if(ret)
287         ok(!strcmp(ret, "Spanish_Spain.1252")
288         || broken(!strcmp(ret, "Spanish - Modern Sort_Spain.1252")), "ret = %s\n", ret);
289 
290     ret = setlocale(LC_ALL, "esp");
291     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
292     if(ret)
293         ok(!strcmp(ret, "Spanish_Spain.1252")
294         || broken(!strcmp(ret, "Spanish - Traditional Sort_Spain.1252")), "ret = %s\n", ret);
295 
296     ret = setlocale(LC_ALL, "fin");
297     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
298     if(ret)
299         ok(!strcmp(ret, "Finnish_Finland.1252"), "ret = %s\n", ret);
300 
301     ret = setlocale(LC_ALL, "finnish");
302     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
303     if(ret)
304         ok(!strcmp(ret, "Finnish_Finland.1252"), "ret = %s\n", ret);
305 
306     ret = setlocale(LC_ALL, "fra");
307     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
308     if(ret)
309         ok(!strcmp(ret, "French_France.1252"), "ret = %s\n", ret);
310 
311     ret = setlocale(LC_ALL, "frb");
312     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
313     if(ret)
314         ok(!strcmp(ret, "French_Belgium.1252")
315         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
316 
317     ret = setlocale(LC_ALL, "frc");
318     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
319     if(ret)
320         ok(!strcmp(ret, "French_Canada.1252")
321         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
322 
323     ret = setlocale(LC_ALL, "french");
324     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
325     if(ret)
326         ok(!strcmp(ret, "French_France.1252"), "ret = %s\n", ret);
327 
328     ret = setlocale(LC_ALL, "french-belgian");
329     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
330     if(ret)
331         ok(!strcmp(ret, "French_Belgium.1252")
332         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
333 
334     ret = setlocale(LC_ALL, "french-canadian");
335     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
336     if(ret)
337         ok(!strcmp(ret, "French_Canada.1252")
338         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
339 
340     ret = setlocale(LC_ALL, "french-swiss");
341     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
342     if(ret)
343         ok(!strcmp(ret, "French_Switzerland.1252")
344         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
345 
346     ret = setlocale(LC_ALL, "frs");
347     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
348     if(ret)
349         ok(!strcmp(ret, "French_Switzerland.1252")
350         || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret);
351 
352     ret = setlocale(LC_ALL, "german");
353     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
354     if(ret)
355         ok(!strcmp(ret, "German_Germany.1252"), "ret = %s\n", ret);
356 
357     ret = setlocale(LC_ALL, "german-austrian");
358     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
359     if(ret)
360         ok(!strcmp(ret, "German_Austria.1252")
361         || broken(!strcmp(ret, "German_Germany.1252")), "ret = %s\n", ret);
362 
363     ret = setlocale(LC_ALL, "german-swiss");
364     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
365     if(ret)
366         ok(!strcmp(ret, "German_Switzerland.1252")
367         || broken(!strcmp(ret, "German_Germany.1252")), "ret = %s\n", ret);
368 
369     ret = setlocale(LC_ALL, "greek");
370     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
371     if(ret)
372         ok(!strcmp(ret, "Greek_Greece.1253"), "ret = %s\n", ret);
373 
374     ret = setlocale(LC_ALL, "hun");
375     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
376     if(ret)
377         ok(!strcmp(ret, "Hungarian_Hungary.1250"), "ret = %s\n", ret);
378 
379     ret = setlocale(LC_ALL, "hungarian");
380     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
381     if(ret)
382         ok(!strcmp(ret, "Hungarian_Hungary.1250"), "ret = %s\n", ret);
383 
384     ret = setlocale(LC_ALL, "icelandic");
385     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
386     if(ret)
387         ok(!strcmp(ret, "Icelandic_Iceland.1252"), "ret = %s\n", ret);
388 
389     ret = setlocale(LC_ALL, "isl");
390     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
391     if(ret)
392         ok(!strcmp(ret, "Icelandic_Iceland.1252"), "ret = %s\n", ret);
393 
394     ret = setlocale(LC_ALL, "ita");
395     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
396     if(ret)
397         ok(!strcmp(ret, "Italian_Italy.1252"), "ret = %s\n", ret);
398 
399     ret = setlocale(LC_ALL, "italian");
400     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
401     if(ret)
402         ok(!strcmp(ret, "Italian_Italy.1252"), "ret = %s\n", ret);
403 
404     ret = setlocale(LC_ALL, "italian-swiss");
405     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
406     if(ret)
407         ok(!strcmp(ret, "Italian_Switzerland.1252")
408         || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
409 
410     ret = setlocale(LC_ALL, "its");
411     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
412     if(ret)
413         ok(!strcmp(ret, "Italian_Switzerland.1252")
414         || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
415 
416     ret = setlocale(LC_ALL, "japanese");
417     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
418     if(ret)
419         ok(!strcmp(ret, "Japanese_Japan.932"), "ret = %s\n", ret);
420 
421     ret = setlocale(LC_ALL, "jpn");
422     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
423     if(ret)
424         ok(!strcmp(ret, "Japanese_Japan.932"), "ret = %s\n", ret);
425 
426     ret = setlocale(LC_ALL, "korean");
427     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
428     if(ret)
429         ok(!strcmp(ret, "Korean_Korea.949"), "ret = %s\n", ret);
430 
431     ret = setlocale(LC_ALL, "korean");
432     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
433     if(ret)
434         ok(!strcmp(ret, "Korean_Korea.949"), "ret = %s\n", ret);
435 
436     ret = setlocale(LC_ALL, "nlb");
437     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
438     if(ret)
439         ok(!strcmp(ret, "Dutch_Belgium.1252")
440         || broken(!strcmp(ret, "Dutch_Netherlands.1252")), "ret = %s\n", ret);
441 
442     ret = setlocale(LC_ALL, "nld");
443     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
444     if(ret)
445         ok(!strcmp(ret, "Dutch_Netherlands.1252"), "ret = %s\n", ret);
446 
447     ret = setlocale(LC_ALL, "non");
448     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
449     if(ret)
450         ok(!strcmp( ret, "Norwegian-Nynorsk_Norway.1252") /* XP - Win10 */
451         || !strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")
452         || broken(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252"))
453         || broken(!strcmp(ret, "Norwegian_Norway.1252")), /* WinME */
454            "ret = %s\n", ret);
455 
456     ret = setlocale(LC_ALL, "nor");
457     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
458     if(ret)
459         ok(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252") /* XP - Win8 */
460         || !strcmp(ret, "Norwegian Bokm\xe5l_Norway.1252") /* Win10 */
461         || !strcmp(ret, "Norwegian (Bokmal)_Norway.1252")
462         || broken(!strcmp(ret, "Norwegian_Norway.1252")), /* WinME */
463            "ret = %s\n", ret);
464 
465     ret = setlocale(LC_ALL, "norwegian-bokmal");
466     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
467     if(ret)
468         ok(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252") /* XP - Win8 */
469         || !strcmp(ret, "Norwegian Bokm\xe5l_Norway.1252") /* Win10 */
470         || !strcmp(ret, "Norwegian (Bokmal)_Norway.1252")
471         || broken(!strcmp(ret, "Norwegian_Norway.1252")), /* WinME */
472            "ret = %s\n", ret);
473 
474     ret = setlocale(LC_ALL, "norwegian-nynorsk");
475     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
476     if(ret)
477         ok(!strcmp(ret, "Norwegian-Nynorsk_Norway.1252") /* Vista - Win10 */
478         || !strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")
479         || broken(!strcmp(ret, "Norwegian_Norway.1252")) /* WinME */
480         || broken(!strcmp(ret, "Norwegian (Bokmal)_Norway.1252"))
481         || broken(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252")) /* XP & 2003 */,
482            "ret = %s\n", ret);
483 
484     ret = setlocale(LC_ALL, "plk");
485     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
486     if(ret)
487         ok(!strcmp(ret, "Polish_Poland.1250"), "ret = %s\n", ret);
488 
489     ret = setlocale(LC_ALL, "polish");
490     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
491     if(ret)
492         ok(!strcmp(ret, "Polish_Poland.1250"), "ret = %s\n", ret);
493 
494     ret = setlocale(LC_ALL, "portuguese");
495     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
496     if(ret)
497         ok(!strcmp(ret, "Portuguese_Brazil.1252")
498         || broken(!strcmp(ret, "Portuguese_Portugal.1252")) /* NT4 */, "ret = %s\n", ret);
499 
500     ret = setlocale(LC_ALL, "portuguese-brazil");
501     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
502     if(ret)
503         ok(!strcmp(ret, "Portuguese_Brazil.1252"), "ret = %s\n", ret);
504 
505     ret = setlocale(LC_ALL, "ptb");
506     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
507     if(ret)
508         ok(!strcmp(ret, "Portuguese_Brazil.1252"), "ret = %s\n", ret);
509 
510     ret = setlocale(LC_ALL, "ptg");
511     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
512     if(ret)
513         ok(!strcmp(ret, "Portuguese_Portugal.1252"), "ret = %s\n", ret);
514 
515     ret = setlocale(LC_ALL, "rus");
516     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
517     if(ret)
518         ok(!strcmp(ret, "Russian_Russia.1251"), "ret = %s\n", ret);
519 
520     ret = setlocale(LC_ALL, "russian");
521     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
522     if(ret)
523         ok(!strcmp(ret, "Russian_Russia.1251"), "ret = %s\n", ret);
524 
525     ret = setlocale(LC_ALL, "sky");
526     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
527     if(ret)
528         ok(!strcmp(ret, "Slovak_Slovakia.1250"), "ret = %s\n", ret);
529 
530     ret = setlocale(LC_ALL, "slovak");
531     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
532     if(ret)
533         ok(!strcmp(ret, "Slovak_Slovakia.1250"), "ret = %s\n", ret);
534 
535     ret = setlocale(LC_ALL, "spanish");
536     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
537     if(ret)
538         ok(!strcmp(ret, "Spanish_Spain.1252")
539         || broken(!strcmp(ret, "Spanish - Traditional Sort_Spain.1252")), "ret = %s\n", ret);
540 
541     ret = setlocale(LC_ALL, "spanish-mexican");
542     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
543     if(ret)
544         ok(!strcmp(ret, "Spanish_Mexico.1252")
545         || broken(!strcmp(ret, "Spanish_Spain.1252")), "ret = %s\n", ret);
546 
547     ret = setlocale(LC_ALL, "spanish-modern");
548     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
549     if(ret)
550         ok(!strcmp(ret, "Spanish - Modern Sort_Spain.1252")
551            || !strcmp(ret, "Spanish_Spain.1252"), "ret = %s\n", ret);
552 
553     ret = setlocale(LC_ALL, "sve");
554     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
555     if(ret)
556         ok(!strcmp(ret, "Swedish_Sweden.1252"), "ret = %s\n", ret);
557 
558     ret = setlocale(LC_ALL, "swedish");
559     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
560     if(ret)
561         ok(!strcmp(ret, "Swedish_Sweden.1252"), "ret = %s\n", ret);
562 
563     ret = setlocale(LC_ALL, "swiss");
564     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
565     if(ret)
566         ok(!strcmp(ret, "German_Switzerland.1252"), "ret = %s\n", ret);
567 
568     ret = setlocale(LC_ALL, "trk");
569     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
570     if(ret)
571         ok(!strcmp(ret, "Turkish_Turkey.1254"), "ret = %s\n", ret);
572 
573     ret = setlocale(LC_ALL, "turkish");
574     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
575     if(ret)
576         ok(!strcmp(ret, "Turkish_Turkey.1254"), "ret = %s\n", ret);
577 
578     ret = setlocale(LC_ALL, "uk");
579     ok(ret != NULL, "ret == NULL\n");
580     if(ret)
581         ok(!strcmp(ret, "English_United Kingdom.1252")
582         || broken(!strcmp(ret, "Ukrainian_Ukraine.1251")), "ret = %s\n", ret);
583 
584     ret = setlocale(LC_ALL, "us");
585     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
586     if(ret)
587         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
588 
589     ret = setlocale(LC_ALL, "usa");
590     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
591     if(ret)
592         ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret);
593 
594     ret = setlocale(LC_ALL, "English_United States.ACP");
595     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
596     if(ret) {
597         strcpy(buf, "English_United States.");
598         GetLocaleInfoA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
599                 LOCALE_IDEFAULTANSICODEPAGE, buf+strlen(buf), 80);
600         ok(!strcmp(ret, buf), "ret = %s, expected %s\n", ret, buf);
601     }
602 
603     ret = setlocale(LC_ALL, "English_United States.OCP");
604     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
605     if(ret) {
606         strcpy(buf, "English_United States.");
607         GetLocaleInfoA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
608                 LOCALE_IDEFAULTCODEPAGE, buf+strlen(buf), 80);
609         ok(!strcmp(ret, buf), "ret = %s, expected %s\n", ret, buf);
610     }
611 
612     ret = setlocale(LC_ALL, "English_United States.UTF8");
613     ok(ret == NULL, "ret != NULL\n");
614 }
615 
616 static void test_crtGetStringTypeW(void)
617 {
618     static const wchar_t str0[] = { '0', '\0' };
619     static const wchar_t strA[] = { 'A', '\0' };
620     static const wchar_t str_space[] = { ' ', '\0' };
621     static const wchar_t str_null[] = { '\0', '\0' };
622     static const wchar_t str_rand[] = { 1234, '\0' };
623 
624     const wchar_t *str[] = { str0, strA, str_space, str_null, str_rand };
625 
626     WORD out_crt, out;
627     BOOL ret_crt, ret;
628     int i;
629 
630     if(!p__crtGetStringTypeW) {
631         win_skip("Skipping __crtGetStringTypeW tests\n");
632         return;
633     }
634 
635     if(!pmemcpy_s) {
636         win_skip("Too old version of msvcrt.dll\n");
637         return;
638     }
639 
640     for(i=0; i<sizeof(str)/sizeof(*str); i++) {
641         ret_crt = p__crtGetStringTypeW(0, CT_CTYPE1, str[i], 1, &out_crt);
642         ret = GetStringTypeW(CT_CTYPE1, str[i], 1, &out);
643         ok(ret == ret_crt, "%d) ret_crt = %d\n", i, (int)ret_crt);
644         ok(out == out_crt, "%d) out_crt = %x, expected %x\n", i, (int)out_crt, (int)out);
645 
646         ret_crt = p__crtGetStringTypeW(0, CT_CTYPE2, str[i], 1, &out_crt);
647         ret = GetStringTypeW(CT_CTYPE2, str[i], 1, &out);
648         ok(ret == ret_crt, "%d) ret_crt = %d\n", i, (int)ret_crt);
649         ok(out == out_crt, "%d) out_crt = %x, expected %x\n", i, (int)out_crt, (int)out);
650 
651         ret_crt = p__crtGetStringTypeW(0, CT_CTYPE3, str[i], 1, &out_crt);
652         ret = GetStringTypeW(CT_CTYPE3, str[i], 1, &out);
653         ok(ret == ret_crt, "%d) ret_crt = %d\n", i, (int)ret_crt);
654         ok(out == out_crt, "%d) out_crt = %x, expected %x\n", i, (int)out_crt, (int)out);
655     }
656 
657     ret = p__crtGetStringTypeW(0, 3, str[0], 1, &out);
658     ok(!ret, "ret == TRUE\n");
659 }
660 
661 static void test__Gettnames(void)
662 {
663     static const DWORD time_data[] = {
664         LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
665         LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
666         LOCALE_SABBREVDAYNAME6,
667         LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
668         LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6,
669         LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
670         LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
671         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
672         LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
673         LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
674         LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
675         LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
676         LOCALE_S1159, LOCALE_S2359,
677         LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
678         LOCALE_STIMEFORMAT
679     };
680 
681     struct {
682         char *str[43];
683         LCID lcid;
684         int  unk[2];
685         wchar_t *wstr[43];
686         char data[1];
687     } *ret;
688     int size;
689     char buf[64];
690     int i;
691 
692     if(!setlocale(LC_ALL, "english"))
693         return;
694 
695     ret = _Gettnames();
696     size = ret->str[0]-(char*)ret;
697     /* Newer version of the structure stores both ascii and unicode strings.
698      * Unicode strings are only initialized on Windows 7
699      */
700     if(sizeof(void*) == 8)
701         ok(size==0x2c0 || broken(size==0x168), "structure size: %x\n", size);
702     else
703         ok(size==0x164 || broken(size==0xb8), "structure size: %x\n", size);
704 
705     for (i = 0; i < sizeof(time_data)/sizeof(time_data[0]); i++)
706     {
707         size = GetLocaleInfoA(MAKELCID(LANG_ENGLISH, SORT_DEFAULT),
708                               time_data[i], buf, sizeof(buf));
709         ok(size, "GetLocaleInfo failed: %x\n", GetLastError());
710         ok(!strcmp(ret->str[i], buf), "ret->str[%i] = %s, expected %s\n", i, ret->str[i], buf);
711     }
712 
713     free(ret);
714 
715     if(!setlocale(LC_TIME, "german"))
716         return;
717 
718     ret = _Gettnames();
719     for (i = 0; i < sizeof(time_data)/sizeof(time_data[0]); i++)
720     {
721         size = GetLocaleInfoA(MAKELCID(LANG_GERMAN, SORT_DEFAULT),
722                               time_data[i], buf, sizeof(buf));
723         ok(size, "GetLocaleInfo failed: %x\n", GetLastError());
724         ok(!strcmp(ret->str[i], buf), "ret->str[%i] = %s, expected %s\n", i, ret->str[i], buf);
725     }
726     free(ret);
727 
728     setlocale(LC_ALL, "C");
729 }
730 
731 static void test___mb_cur_max_func(void)
732 {
733     int mb_cur_max;
734 
735     setlocale(LC_ALL, "C");
736 
737     /* for newer Windows */
738     if(!p___mb_cur_max_func)
739         win_skip("Skipping ___mb_cur_max_func tests\n");
740     else {
741         mb_cur_max = p___mb_cur_max_func();
742         ok(mb_cur_max == 1, "mb_cur_max = %d, expected 1\n", mb_cur_max);
743 
744         /* some old Windows don't set chinese */
745         if (!setlocale(LC_ALL, "chinese"))
746             win_skip("Skipping test with chinese locale\n");
747         else {
748             mb_cur_max = p___mb_cur_max_func();
749             ok(mb_cur_max == 2, "mb_cur_max = %d, expected 2\n", mb_cur_max);
750             setlocale(LC_ALL, "C");
751         }
752     }
753 
754     /* for older Windows */
755     if (!p__p___mb_cur_max)
756         win_skip("Skipping __p___mb_cur_max tests\n");
757     else {
758         mb_cur_max = *p__p___mb_cur_max();
759         ok(mb_cur_max == 1, "mb_cur_max = %d, expected 1\n", mb_cur_max);
760 
761         /* some old Windows don't set chinese */
762         if (!setlocale(LC_ALL, "chinese"))
763             win_skip("Skipping test with chinese locale\n");
764         else {
765             mb_cur_max = *p__p___mb_cur_max();
766             ok(mb_cur_max == 2, "mb_cur_max = %d, expected 2\n", mb_cur_max);
767             setlocale(LC_ALL, "C");
768         }
769     }
770 }
771 
772 START_TEST(locale)
773 {
774     init();
775 
776     test_crtGetStringTypeW();
777     test_setlocale();
778     test__Gettnames();
779     test___mb_cur_max_func();
780 }
781