Release 1.4-rc5.
[wine] / dlls / kernel32 / tests / locale.c
1 /*
2  * Unit tests for locale functions
3  *
4  * Copyright 2002 YASAR Mehmet
5  * Copyright 2003 Dmitry Timoshkov
6  * Copyright 2003 Jon Griffiths
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * NOTES
23  *  We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24  *  even when the user has overridden their default i8n settings (e.g. in
25  *  the control panel i8n page), we will still get the expected results.
26  */
27
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38
39 static inline unsigned int strlenW( const WCHAR *str )
40 {
41     const WCHAR *s = str;
42     while (*s) s++;
43     return s - str;
44 }
45
46 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
47 {
48     if (n <= 0) return 0;
49     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
50     return *str1 - *str2;
51 }
52
53 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
54 {
55     do { if (*str == ch) return (WCHAR *)str; } while (*str++);
56     return NULL;
57 }
58
59 static inline int isdigitW( WCHAR wc )
60 {
61     WORD type;
62     GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
63     return type & C1_DIGIT;
64 }
65
66 /* Some functions are only in later versions of kernel32.dll */
67 static HMODULE hKernel32;
68 static WORD enumCount;
69
70 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
71 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
72 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
73 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
74 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
75 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
76 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
77
78 static void InitFunctionPointers(void)
79 {
80   hKernel32 = GetModuleHandleA("kernel32");
81   pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
82   pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
83   pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
84   pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
85   pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
86   pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
87   pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
88 }
89
90 #define eq(received, expected, label, type) \
91         ok((received) == (expected), "%s: got " type " instead of " type "\n", \
92            (label), (received), (expected))
93
94 #define BUFFER_SIZE    128
95 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
96
97 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
98 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
99 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
100   "Expected '%s', got '%s'\n", Expected, buffer)
101
102 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
103    MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
104    SetLastError(0xdeadbeef); buffer[0] = '\0'
105 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
106 #define EXPECT_EQW  ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
107
108 #define NUO LOCALE_NOUSEROVERRIDE
109
110 static void test_GetLocaleInfoA(void)
111 {
112   int ret;
113   int len;
114   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
115   char buffer[BUFFER_SIZE];
116   char expected[BUFFER_SIZE];
117
118   ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
119
120   /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
121      Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
122      assumes SUBLANG_NEUTRAL for zh */
123   memset(expected, 0, COUNTOF(expected));
124   len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
125   SetLastError(0xdeadbeef);
126   memset(buffer, 0, COUNTOF(buffer));
127   ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
128   ok((ret == len) && !lstrcmpA(buffer, expected),
129       "got %d with '%s' (expected %d with '%s')\n",
130       ret, buffer, len, expected);
131
132   memset(expected, 0, COUNTOF(expected));
133   len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
134   if (len) {
135       SetLastError(0xdeadbeef);
136       memset(buffer, 0, COUNTOF(buffer));
137       ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
138       ok((ret == len) && !lstrcmpA(buffer, expected),
139           "got %d with '%s' (expected %d with '%s')\n",
140           ret, buffer, len, expected);
141   }
142   else
143       win_skip("LANG_ARABIC not installed\n");
144
145   /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
146   memset(expected, 0, COUNTOF(expected));
147   len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
148   SetLastError(0xdeadbeef);
149   memset(buffer, 0, COUNTOF(buffer));
150   ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
151   ok((ret == len) && !lstrcmpA(buffer, expected),
152       "got %d with '%s' (expected %d with '%s')\n",
153       ret, buffer, len, expected);
154
155
156   /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
157    * partially fill the buffer even if it is too short. See bug 637.
158    */
159   SetLastError(0xdeadbeef);
160   memset(buffer, 0, COUNTOF(buffer));
161   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
162   ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
163
164   SetLastError(0xdeadbeef);
165   memset(buffer, 0, COUNTOF(buffer));
166   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
167   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
168       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
169   ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
170
171   SetLastError(0xdeadbeef);
172   memset(buffer, 0, COUNTOF(buffer));
173   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
174   ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
175   ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
176 }
177
178 static void test_GetLocaleInfoW(void)
179 {
180   LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
181   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
182   WCHAR bufferW[80], buffer2W[80];
183   CHAR bufferA[80];
184   DWORD ret;
185   INT i;
186
187   ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
188   if (!ret) {
189       win_skip("GetLocaleInfoW() isn't implemented\n");
190       return;
191   }
192   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
193   if (!ret) {
194       win_skip("LANG_RUSSIAN locale data unavailable\n");
195       return;
196   }
197   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
198                        bufferW, COUNTOF(bufferW));
199   if (!ret) {
200       win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
201       return;
202   }
203
204   /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
205   bufferA[0] = 'a';
206   SetLastError(0xdeadbeef);
207   ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
208                        bufferA, COUNTOF(bufferA));
209   ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
210   ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
211   ok(GetLastError() == ERROR_INVALID_FLAGS,
212      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
213
214   bufferW[0] = 'a';
215   SetLastError(0xdeadbeef);
216   ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
217                        bufferW, COUNTOF(bufferW));
218   ok(ret == 0,
219      "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
220   ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
221   ok(GetLastError() == ERROR_INVALID_FLAGS,
222      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
223
224   /* yes, test empty 13 month entry too */
225   for (i = 0; i < 12; i++) {
226       bufferW[0] = 0;
227       ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
228                            bufferW, COUNTOF(bufferW));
229       ok(ret, "Expected non zero result\n");
230       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
231                                     ret, lstrlenW(bufferW));
232       buffer2W[0] = 0;
233       ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
234                            buffer2W, COUNTOF(buffer2W));
235       ok(ret, "Expected non zero result\n");
236       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
237                                     ret, lstrlenW(buffer2W));
238
239       ok(lstrcmpW(bufferW, buffer2W) != 0,
240            "Expected genitive name to differ, got the same for month %d\n", i+1);
241
242       /* for locale without genitive names nominative returned in both cases */
243       bufferW[0] = 0;
244       ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
245                            bufferW, COUNTOF(bufferW));
246       ok(ret, "Expected non zero result\n");
247       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
248                                     ret, lstrlenW(bufferW));
249       buffer2W[0] = 0;
250       ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
251                            buffer2W, COUNTOF(buffer2W));
252       ok(ret, "Expected non zero result\n");
253       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
254                                     ret, lstrlenW(buffer2W));
255
256       ok(lstrcmpW(bufferW, buffer2W) == 0,
257          "Expected same names, got different for month %d\n", i+1);
258   }
259 }
260
261 static void test_GetTimeFormatA(void)
262 {
263   int ret;
264   SYSTEMTIME  curtime;
265   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
266   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
267
268   memset(&curtime, 2, sizeof(SYSTEMTIME));
269   STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
270   SetLastError(0xdeadbeef);
271   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
272   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
273       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
274
275   curtime.wHour = 8;
276   curtime.wMinute = 56;
277   curtime.wSecond = 13;
278   curtime.wMilliseconds = 22;
279   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
280   SetLastError(0xdeadbeef);
281   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
282   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
283   EXPECT_LENA; EXPECT_EQA;
284
285   /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
286   SetLastError(0xdeadbeef);
287   ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
288   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
289      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
290
291   STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
292   SetLastError(0xdeadbeef);
293   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
294   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
295       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
296
297   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
298   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
299   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
300   EXPECT_LENA;
301
302   STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
303   ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
304   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
305   EXPECT_LENA; EXPECT_EQA;
306
307   STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
308   ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
309   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
310   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
311       "Expected '', got '%s'\n", buffer );
312
313   STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
314   ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
315   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
316   EXPECT_LENA; EXPECT_EQA;
317
318   STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
319   strcpy(Expected, "8:56 AM");
320   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
321   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
322   EXPECT_LENA; EXPECT_EQA;
323
324   STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
325   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
326   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
327   ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
328       "Expected '8.@:56AM', got '%s'\n", buffer );
329
330   STRINGSA("s1s2s3", ""); /* Duplicate tokens */
331   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
332   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
333   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
334       "Expected '', got '%s'\n", buffer );
335
336   STRINGSA("t/tt", "A/AM"); /* AM time marker */
337   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
338   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
339   EXPECT_LENA; EXPECT_EQA;
340
341   curtime.wHour = 13;
342   STRINGSA("t/tt", "P/PM"); /* PM time marker */
343   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
344   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
345   EXPECT_LENA; EXPECT_EQA;
346
347   STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
348   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
349   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
350   EXPECT_LENA; EXPECT_EQA;
351
352   STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
353   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
354   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
355   EXPECT_LENA; EXPECT_EQA;
356
357   STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
358   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
359   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
360   EXPECT_LENA; EXPECT_EQA;
361
362   curtime.wHour = 14; /* change this to 14 or 2pm */
363   curtime.wMinute = 5;
364   curtime.wSecond = 3;
365   STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
366   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
367   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
368   EXPECT_LENA; EXPECT_EQA;
369
370   curtime.wHour = 0;
371   STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
372   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
373   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
374   EXPECT_LENA; EXPECT_EQA;
375
376   STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
377   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
378   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
379   EXPECT_LENA; EXPECT_EQA;
380
381   /* try to convert formatting strings with more than two letters
382    * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
383    * NOTE: We expect any letter for which there is an upper case value
384    *       we should see a replacement.  For letters that DO NOT have
385    *       upper case values we should see NO REPLACEMENT.
386    */
387   curtime.wHour = 8;
388   curtime.wMinute = 56;
389   curtime.wSecond = 13;
390   curtime.wMilliseconds = 22;
391   STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
392            "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
393   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
394   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
395   EXPECT_LENA; EXPECT_EQA;
396
397   STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
398   strcpy(buffer, "text");
399   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
400   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
401   EXPECT_EQA;
402
403   STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
404            "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
405   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
406   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
407   EXPECT_LENA; EXPECT_EQA;
408
409   STRINGSA("'''", "'"); /* invalid quoted string */
410   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
411   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
412   EXPECT_LENA; EXPECT_EQA;
413
414   /* test that msdn suggested single quotation usage works as expected */
415   STRINGSA("''''", "'"); /* single quote mark */
416   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
417   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
418   EXPECT_LENA; EXPECT_EQA;
419
420   STRINGSA("''HHHHHH", "08"); /* Normal use */
421   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
422   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
423   EXPECT_LENA; EXPECT_EQA;
424
425   /* and test for normal use of the single quotation mark */
426   STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
427   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
428   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
429   EXPECT_LENA; EXPECT_EQA;
430
431   STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
432   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
433   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
434   EXPECT_LENA; EXPECT_EQA;
435
436   STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
437   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
438   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
439   EXPECT_LENA; EXPECT_EQA;
440
441   curtime.wHour = 25;
442   STRINGSA("'123'tt", ""); /* Invalid time */
443   SetLastError(0xdeadbeef);
444   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
445   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
446       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
447
448   curtime.wHour = 12;
449   curtime.wMonth = 60; /* Invalid */
450   STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
451   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
452   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
453   EXPECT_LENA; EXPECT_EQA;
454 }
455
456 static void test_GetDateFormatA(void)
457 {
458   int ret;
459   SYSTEMTIME  curtime;
460   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
461   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
462   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
463   char Broken[BUFFER_SIZE];
464   char short_day[10], month[10], genitive_month[10];
465
466   memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
467   STRINGSA("ddd',' MMM dd yy","");
468   SetLastError(0xdeadbeef);
469   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
470   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
471       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
472
473   curtime.wYear = 2002;
474   curtime.wMonth = 5;
475   curtime.wDay = 4;
476   curtime.wDayOfWeek = 3;
477   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
478   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
479   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
480   EXPECT_LENA; EXPECT_EQA;
481
482   /* Same as above but with LOCALE_NOUSEROVERRIDE */
483   STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
484   SetLastError(0xdeadbeef);
485   ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
486   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
487      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
488   EXPECT_EQA;
489
490   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
491   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
492   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493   EXPECT_LENA; EXPECT_EQA;
494
495   curtime.wHour = 36; /* Invalid */
496   STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
497   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
498   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
499   EXPECT_LENA; EXPECT_EQA;
500
501   STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
502   ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
503   ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
504   EXPECT_EQA;
505
506   STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
507   SetLastError(0xdeadbeef);
508   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
509   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
510       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
511
512   STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
513   ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
514   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
515   if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
516           ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
517
518   STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
519   ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
520   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
521   EXPECT_LENA; EXPECT_EQA;
522
523   /* test for expected DATE_YEARMONTH behavior with null format */
524   /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
525   STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
526   SetLastError(0xdeadbeef);
527   ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
528   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
529      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
530   EXPECT_EQA;
531
532   /* Test that using invalid DATE_* flags results in the correct error */
533   /* and return values */
534   STRINGSA("m/d/y", ""); /* Invalid flags */
535   SetLastError(0xdeadbeef);
536   ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
537                       &curtime, input, buffer, COUNTOF(buffer));
538   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
539      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
540
541   ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
542   if (!ret)
543   {
544     win_skip("LANG_RUSSIAN locale data unavailable\n");
545     return;
546   }
547
548   /* month part should be in genitive form */
549   strcpy(genitive_month, buffer + 2);
550   ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
551   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
552   strcpy(month, buffer);
553   ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
554
555   ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
556   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
557   strcpy(short_day, buffer);
558
559   STRINGSA("dd MMMMddd dd", "");
560   sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
561   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
562   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
563   EXPECT_EQA;
564
565   STRINGSA("MMMMddd dd", "");
566   sprintf(Expected, "%s%s 04", month, short_day);
567   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
568   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
569   EXPECT_EQA;
570
571   STRINGSA("MMMMddd", "");
572   sprintf(Expected, "%s%s", month, short_day);
573   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
574   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
575   EXPECT_EQA;
576
577   STRINGSA("MMMMdd", "");
578   sprintf(Expected, "%s04", genitive_month);
579   sprintf(Broken, "%s04", month);
580   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
581   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
582   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
583      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
584      "Expected '%s', got '%s'\n", Expected, buffer);
585
586   STRINGSA("MMMMdd ddd", "");
587   sprintf(Expected, "%s04 %s", genitive_month, short_day);
588   sprintf(Broken, "%s04 %s", month, short_day);
589   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
590   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
591   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
592      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
593      "Expected '%s', got '%s'\n", Expected, buffer);
594
595   STRINGSA("dd dddMMMM", "");
596   sprintf(Expected, "04 %s%s", short_day, month);
597   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
598   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
599   EXPECT_EQA;
600
601   STRINGSA("dd dddMMMM ddd MMMMdd", "");
602   sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
603   sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
604   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
605   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
606   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
607      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
608      "Expected '%s', got '%s'\n", Expected, buffer);
609
610   /* with literal part */
611   STRINGSA("ddd',' MMMM dd", "");
612   sprintf(Expected, "%s, %s 04", short_day, genitive_month);
613   sprintf(Broken, "%s, %s 04", short_day, month);
614   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
615   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
616   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
617      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
618      "Expected '%s', got '%s'\n", Expected, buffer);
619 }
620
621 static void test_GetDateFormatW(void)
622 {
623   int ret;
624   SYSTEMTIME  curtime;
625   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
626   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
627
628   STRINGSW("",""); /* If flags is not zero then format must be NULL */
629   ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
630                        input, buffer, COUNTOF(buffer));
631   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
632   {
633     win_skip("GetDateFormatW is not implemented\n");
634     return;
635   }
636   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
637      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
638   EXPECT_EQW;
639
640   STRINGSW("",""); /* NULL buffer, len > 0 */
641   SetLastError(0xdeadbeef);
642   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
643   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
644       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
645
646   STRINGSW("",""); /* NULL buffer, len == 0 */
647   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
648   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
649   EXPECT_LENW; EXPECT_EQW;
650
651   curtime.wYear = 2002;
652   curtime.wMonth = 10;
653   curtime.wDay = 23;
654   curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
655   curtime.wHour = 65432; /* Invalid */
656   curtime.wMinute = 34512; /* Invalid */
657   curtime.wSecond = 65535; /* Invalid */
658   curtime.wMilliseconds = 12345;
659   STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
660   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
661   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
662   EXPECT_LENW; EXPECT_EQW;
663
664   /* Limit tests */
665
666   curtime.wYear = 1601;
667   curtime.wMonth = 1;
668   curtime.wDay = 1;
669   curtime.wDayOfWeek = 0; /* Irrelevant */
670   curtime.wHour = 0;
671   curtime.wMinute = 0;
672   curtime.wSecond = 0;
673   curtime.wMilliseconds = 0;
674   STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
675   SetLastError(0xdeadbeef);
676   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
677   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
678   EXPECT_LENW; EXPECT_EQW;
679
680   curtime.wYear = 1600;
681   curtime.wMonth = 12;
682   curtime.wDay = 31;
683   curtime.wDayOfWeek = 0; /* Irrelevant */
684   curtime.wHour = 23;
685   curtime.wMinute = 59;
686   curtime.wSecond = 59;
687   curtime.wMilliseconds = 999;
688   STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
689   SetLastError(0xdeadbeef);
690   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
691   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
692       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
693 }
694
695
696 #define CY_POS_LEFT  0
697 #define CY_POS_RIGHT 1
698 #define CY_POS_LEFT_SPACE  2
699 #define CY_POS_RIGHT_SPACE 3
700
701 static void test_GetCurrencyFormatA(void)
702 {
703   static char szDot[] = { '.', '\0' };
704   static char szComma[] = { ',', '\0' };
705   static char szDollar[] = { '$', '\0' };
706   int ret;
707   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
708   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
709   CURRENCYFMTA format;
710
711   memset(&format, 0, sizeof(format));
712
713   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
714   SetLastError(0xdeadbeef);
715   ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
716   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
717       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
718
719   STRINGSA("23,53",""); /* Invalid character --> Error */
720   SetLastError(0xdeadbeef);
721   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
722   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
723       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
724
725   STRINGSA("--",""); /* Double '-' --> Error */
726   SetLastError(0xdeadbeef);
727   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
728   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
729       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
730
731   STRINGSA("0-",""); /* Trailing '-' --> Error */
732   SetLastError(0xdeadbeef);
733   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
734   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
735       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
736
737   STRINGSA("0..",""); /* Double '.' --> Error */
738   SetLastError(0xdeadbeef);
739   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
740   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
741       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
742
743   STRINGSA(" 0.1",""); /* Leading space --> Error */
744   SetLastError(0xdeadbeef);
745   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
746   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
747       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
748
749   STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
750   SetLastError(0xdeadbeef);
751   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
752   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
753       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
754
755   STRINGSA("2353",""); /* Format and flags given --> Error */
756   SetLastError(0xdeadbeef);
757   ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
758   ok( !ret, "Expected ret == 0, got %d\n", ret);
759   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
760       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
761
762   STRINGSA("2353",""); /* Invalid format --> Error */
763   SetLastError(0xdeadbeef);
764   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
765   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
766       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
767
768   STRINGSA("2353","$2,353.00"); /* Valid number */
769   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
770   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
771   EXPECT_LENA; EXPECT_EQA;
772
773   STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
774   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
775   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
776   EXPECT_LENA; EXPECT_EQA;
777
778   STRINGSA("2353.1","$2,353.10"); /* Valid real number */
779   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
780   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781   EXPECT_LENA; EXPECT_EQA;
782
783   STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
784   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
785   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786   EXPECT_LENA; EXPECT_EQA;
787
788   STRINGSA("2353.119","$2,353.12");  /* Too many DP --> Rounded */
789   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
790   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
791   EXPECT_LENA; EXPECT_EQA;
792
793   format.NumDigits = 0; /* No decimal separator */
794   format.LeadingZero = 0;
795   format.Grouping = 0;  /* No grouping char */
796   format.NegativeOrder = 0;
797   format.PositiveOrder = CY_POS_LEFT;
798   format.lpDecimalSep = szDot;
799   format.lpThousandSep = szComma;
800   format.lpCurrencySymbol = szDollar;
801
802   STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
803   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
804   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
805   EXPECT_LENA; EXPECT_EQA;
806
807   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
808   STRINGSA("2353","$2353.0");
809   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
810   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
811   EXPECT_LENA; EXPECT_EQA;
812
813   format.Grouping = 2; /* Group by 100's */
814   STRINGSA("2353","$23,53.0");
815   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
816   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
817   EXPECT_LENA; EXPECT_EQA;
818
819   STRINGSA("235","$235.0"); /* Grouping of a positive number */
820   format.Grouping = 3;
821   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
822   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
823   EXPECT_LENA; EXPECT_EQA;
824
825   STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
826   format.NegativeOrder = 2;
827   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
828   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
829   EXPECT_LENA; EXPECT_EQA;
830
831   format.LeadingZero = 1; /* Always provide leading zero */
832   STRINGSA(".5","$0.5");
833   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
834   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
835   EXPECT_LENA; EXPECT_EQA;
836
837   format.PositiveOrder = CY_POS_RIGHT;
838   STRINGSA("1","1.0$");
839   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
840   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
841   EXPECT_LENA; EXPECT_EQA;
842
843   format.PositiveOrder = CY_POS_LEFT_SPACE;
844   STRINGSA("1","$ 1.0");
845   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
846   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
847   EXPECT_LENA; EXPECT_EQA;
848
849   format.PositiveOrder = CY_POS_RIGHT_SPACE;
850   STRINGSA("1","1.0 $");
851   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
852   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
853   EXPECT_LENA; EXPECT_EQA;
854
855   format.NegativeOrder = 0;
856   STRINGSA("-1","($1.0)");
857   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
858   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
859   EXPECT_LENA; EXPECT_EQA;
860
861   format.NegativeOrder = 1;
862   STRINGSA("-1","-$1.0");
863   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
864   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
865   EXPECT_LENA; EXPECT_EQA;
866
867   format.NegativeOrder = 2;
868   STRINGSA("-1","$-1.0");
869   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
870   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
871   EXPECT_LENA; EXPECT_EQA;
872
873   format.NegativeOrder = 3;
874   STRINGSA("-1","$1.0-");
875   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
876   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
877   EXPECT_LENA; EXPECT_EQA;
878
879   format.NegativeOrder = 4;
880   STRINGSA("-1","(1.0$)");
881   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
882   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
883   EXPECT_LENA; EXPECT_EQA;
884
885   format.NegativeOrder = 5;
886   STRINGSA("-1","-1.0$");
887   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
888   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
889   EXPECT_LENA; EXPECT_EQA;
890
891   format.NegativeOrder = 6;
892   STRINGSA("-1","1.0-$");
893   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
894   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
895   EXPECT_LENA; EXPECT_EQA;
896
897   format.NegativeOrder = 7;
898   STRINGSA("-1","1.0$-");
899   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
900   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
901   EXPECT_LENA; EXPECT_EQA;
902
903   format.NegativeOrder = 8;
904   STRINGSA("-1","-1.0 $");
905   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
906   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
907   EXPECT_LENA; EXPECT_EQA;
908
909   format.NegativeOrder = 9;
910   STRINGSA("-1","-$ 1.0");
911   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
912   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
913   EXPECT_LENA; EXPECT_EQA;
914
915   format.NegativeOrder = 10;
916   STRINGSA("-1","1.0 $-");
917   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
918   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919   EXPECT_LENA; EXPECT_EQA;
920
921   format.NegativeOrder = 11;
922   STRINGSA("-1","$ 1.0-");
923   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
924   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
925   EXPECT_LENA; EXPECT_EQA;
926
927   format.NegativeOrder = 12;
928   STRINGSA("-1","$ -1.0");
929   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
930   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
931   EXPECT_LENA; EXPECT_EQA;
932
933   format.NegativeOrder = 13;
934   STRINGSA("-1","1.0- $");
935   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
936   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
937   EXPECT_LENA; EXPECT_EQA;
938
939   format.NegativeOrder = 14;
940   STRINGSA("-1","($ 1.0)");
941   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
942   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
943   EXPECT_LENA; EXPECT_EQA;
944
945   format.NegativeOrder = 15;
946   STRINGSA("-1","(1.0 $)");
947   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
948   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
949   EXPECT_LENA; EXPECT_EQA;
950 }
951
952 #define NEG_PARENS      0 /* "(1.1)" */
953 #define NEG_LEFT        1 /* "-1.1"  */
954 #define NEG_LEFT_SPACE  2 /* "- 1.1" */
955 #define NEG_RIGHT       3 /* "1.1-"  */
956 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
957
958 static void test_GetNumberFormatA(void)
959 {
960   static char szDot[] = { '.', '\0' };
961   static char szComma[] = { ',', '\0' };
962   int ret;
963   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
964   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
965   NUMBERFMTA format;
966
967   memset(&format, 0, sizeof(format));
968
969   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
970   SetLastError(0xdeadbeef);
971   ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
972   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
973       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
974
975   STRINGSA("23,53",""); /* Invalid character --> Error */
976   SetLastError(0xdeadbeef);
977   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
978   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
979       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
980
981   STRINGSA("--",""); /* Double '-' --> Error */
982   SetLastError(0xdeadbeef);
983   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
984   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
985       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
986
987   STRINGSA("0-",""); /* Trailing '-' --> Error */
988   SetLastError(0xdeadbeef);
989   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
990   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
991       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
992
993   STRINGSA("0..",""); /* Double '.' --> Error */
994   SetLastError(0xdeadbeef);
995   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
996   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
997       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
998
999   STRINGSA(" 0.1",""); /* Leading space --> Error */
1000   SetLastError(0xdeadbeef);
1001   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1002   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1003       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1004
1005   STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1006   SetLastError(0xdeadbeef);
1007   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1008   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1009       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1010
1011   STRINGSA("2353",""); /* Format and flags given --> Error */
1012   SetLastError(0xdeadbeef);
1013   ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1014   ok( !ret, "Expected ret == 0, got %d\n", ret);
1015   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1016       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1017
1018   STRINGSA("2353",""); /* Invalid format --> Error */
1019   SetLastError(0xdeadbeef);
1020   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1021   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1022       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1023
1024   STRINGSA("2353","2,353.00"); /* Valid number */
1025   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1026   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1027   EXPECT_LENA; EXPECT_EQA;
1028
1029   STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1030   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1031   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1032   EXPECT_LENA; EXPECT_EQA;
1033
1034   STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1035   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1036   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1037   EXPECT_LENA; EXPECT_EQA;
1038
1039   STRINGSA("2353.1","2,353.10"); /* Valid real number */
1040   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1041   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1042   EXPECT_LENA; EXPECT_EQA;
1043
1044   STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1045   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1046   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1047   EXPECT_LENA; EXPECT_EQA;
1048
1049   STRINGSA("2353.119","2,353.12");  /* Too many DP --> Rounded */
1050   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1051   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1052   EXPECT_LENA; EXPECT_EQA;
1053
1054   format.NumDigits = 0; /* No decimal separator */
1055   format.LeadingZero = 0;
1056   format.Grouping = 0;  /* No grouping char */
1057   format.NegativeOrder = 0;
1058   format.lpDecimalSep = szDot;
1059   format.lpThousandSep = szComma;
1060
1061   STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1062   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1063   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064   EXPECT_LENA; EXPECT_EQA;
1065
1066   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1067   STRINGSA("2353","2353.0");
1068   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1069   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1070   EXPECT_LENA; EXPECT_EQA;
1071
1072   format.Grouping = 2; /* Group by 100's */
1073   STRINGSA("2353","23,53.0");
1074   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1075   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1076   EXPECT_LENA; EXPECT_EQA;
1077
1078   STRINGSA("235","235.0"); /* Grouping of a positive number */
1079   format.Grouping = 3;
1080   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1081   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1082   EXPECT_LENA; EXPECT_EQA;
1083
1084   STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1085   format.NegativeOrder = NEG_LEFT;
1086   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1087   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1088   EXPECT_LENA; EXPECT_EQA;
1089
1090   format.LeadingZero = 1; /* Always provide leading zero */
1091   STRINGSA(".5","0.5");
1092   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1093   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1094   EXPECT_LENA; EXPECT_EQA;
1095
1096   format.NegativeOrder = NEG_PARENS;
1097   STRINGSA("-1","(1.0)");
1098   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1099   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1100   EXPECT_LENA; EXPECT_EQA;
1101
1102   format.NegativeOrder = NEG_LEFT;
1103   STRINGSA("-1","-1.0");
1104   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1105   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1106   EXPECT_LENA; EXPECT_EQA;
1107
1108   format.NegativeOrder = NEG_LEFT_SPACE;
1109   STRINGSA("-1","- 1.0");
1110   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1111   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1112   EXPECT_LENA; EXPECT_EQA;
1113
1114   format.NegativeOrder = NEG_RIGHT;
1115   STRINGSA("-1","1.0-");
1116   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1117   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1118   EXPECT_LENA; EXPECT_EQA;
1119
1120   format.NegativeOrder = NEG_RIGHT_SPACE;
1121   STRINGSA("-1","1.0 -");
1122   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1123   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1124   EXPECT_LENA; EXPECT_EQA;
1125
1126   lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1127
1128   if (IsValidLocale(lcid, 0))
1129   {
1130     STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1131     Expected[3] = 160; /* Non breaking space */
1132     ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1133     ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1134     EXPECT_LENA; EXPECT_EQA;
1135   }
1136 }
1137
1138 struct comparestringa_entry {
1139   LCID lcid;
1140   DWORD flags;
1141   const char *first;
1142   int first_len;
1143   const char *second;
1144   int second_len;
1145   int ret;
1146 };
1147
1148 static const struct comparestringa_entry comparestringa_data[] = {
1149   { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1150   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1151   { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1152   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1153   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1154   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1155   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1156   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1157   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1158   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1159   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1160   { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1161   { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1162   { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1163   { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1164   { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1165   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1166   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1167   { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1168   /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1169   { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1170   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1171   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1172   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1173   { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1174   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1175   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1176   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1177   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1178   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1179 };
1180
1181 static void test_CompareStringA(void)
1182 {
1183   int ret, i;
1184   LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1185
1186   for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1187   {
1188       const struct comparestringa_entry *entry = &comparestringa_data[i];
1189
1190       ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1191           entry->second, entry->second_len);
1192       ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1193   }
1194
1195   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1196   ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1197
1198   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1199   ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1200
1201   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1202   ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1203
1204   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1205   ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1206
1207   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1208
1209   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1210   ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1211
1212   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1213   ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1214
1215     ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1216     ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1217
1218     /* test for CompareStringA flags */
1219     SetLastError(0xdeadbeef);
1220     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1221     ok(GetLastError() == ERROR_INVALID_FLAGS,
1222         "unexpected error code %d\n", GetLastError());
1223     ok(!ret, "CompareStringA must fail with invalid flag\n");
1224
1225     SetLastError(0xdeadbeef);
1226     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1227     ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1228     ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1229     /* end of test for CompareStringA flags */
1230
1231     ret = lstrcmpA("", "");
1232     ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1233
1234     ret = lstrcmpA(NULL, NULL);
1235     ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1236
1237     ret = lstrcmpA("", NULL);
1238     ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1239
1240     ret = lstrcmpA(NULL, "");
1241     ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1242  
1243
1244     if (0) { /* this requires collation table patch to make it MS compatible */
1245     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1246     ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1247
1248     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1249     ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1250
1251     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1252     ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1253
1254     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1255     ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1256
1257     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1258     ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1259
1260     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1261     ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1262
1263     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1264     ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1265
1266     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1267     ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1268
1269     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1270     ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1271
1272     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1273     ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1274
1275     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1276     ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1277
1278     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1279     ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1280     }
1281
1282
1283     /* WinXP handles embedded NULLs differently than earlier versions */
1284     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1285     ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1286
1287     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1288     ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1289
1290     ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1291     ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1292
1293     ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1294     ok(ret == CSTR_EQUAL || /* win2k */
1295        ret == CSTR_GREATER_THAN,
1296        "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1297
1298     ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1299     todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1300
1301     ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1302     todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1303
1304     ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1305     todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1306
1307     ret = lstrcmpi("#", ".");
1308     todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1309
1310     lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1311
1312     /* \xB9 character lies between a and b */
1313     ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1314     todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1315     ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1316     ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1317 }
1318
1319 static void test_LCMapStringA(void)
1320 {
1321     int ret, ret2;
1322     char buf[256], buf2[256];
1323     static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1324     static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1325     static const char symbols_stripped[] = "justateststring1";
1326
1327     SetLastError(0xdeadbeef);
1328     ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1329                        lower_case, -1, buf, sizeof(buf));
1330     ok(ret == lstrlenA(lower_case) + 1,
1331        "ret %d, error %d, expected value %d\n",
1332        ret, GetLastError(), lstrlenA(lower_case) + 1);
1333     ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1334
1335     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1336                        upper_case, -1, buf, sizeof(buf));
1337     ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1338     ok(GetLastError() == ERROR_INVALID_FLAGS,
1339        "unexpected error code %d\n", GetLastError());
1340
1341     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1342                        upper_case, -1, buf, sizeof(buf));
1343     ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1344     ok(GetLastError() == ERROR_INVALID_FLAGS,
1345        "unexpected error code %d\n", GetLastError());
1346
1347     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1348                        upper_case, -1, buf, sizeof(buf));
1349     ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1350     ok(GetLastError() == ERROR_INVALID_FLAGS,
1351        "unexpected error code %d\n", GetLastError());
1352
1353     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1354                        upper_case, -1, buf, sizeof(buf));
1355     ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1356     ok(GetLastError() == ERROR_INVALID_FLAGS,
1357        "unexpected error code %d\n", GetLastError());
1358
1359     /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1360     SetLastError(0xdeadbeef);
1361     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1362                        upper_case, -1, buf, sizeof(buf));
1363     ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1364     ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1365
1366     /* test LCMAP_LOWERCASE */
1367     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1368                        upper_case, -1, buf, sizeof(buf));
1369     ok(ret == lstrlenA(upper_case) + 1,
1370        "ret %d, error %d, expected value %d\n",
1371        ret, GetLastError(), lstrlenA(upper_case) + 1);
1372     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1373
1374     /* test LCMAP_UPPERCASE */
1375     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1376                        lower_case, -1, buf, sizeof(buf));
1377     ok(ret == lstrlenA(lower_case) + 1,
1378        "ret %d, error %d, expected value %d\n",
1379        ret, GetLastError(), lstrlenA(lower_case) + 1);
1380     ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1381
1382     /* test buffer overflow */
1383     SetLastError(0xdeadbeef);
1384     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1385                        lower_case, -1, buf, 4);
1386     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1387        "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1388
1389     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1390     lstrcpyA(buf, lower_case);
1391     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1392                        buf, -1, buf, sizeof(buf));
1393     if (!ret) /* Win9x */
1394         trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1395     else
1396     {
1397         ok(ret == lstrlenA(lower_case) + 1,
1398            "ret %d, error %d, expected value %d\n",
1399            ret, GetLastError(), lstrlenA(lower_case) + 1);
1400         ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1401     }
1402     lstrcpyA(buf, upper_case);
1403     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1404                        buf, -1, buf, sizeof(buf));
1405     if (!ret) /* Win9x */
1406         trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1407     else
1408     {
1409         ok(ret == lstrlenA(upper_case) + 1,
1410            "ret %d, error %d, expected value %d\n",
1411            ret, GetLastError(), lstrlenA(lower_case) + 1);
1412         ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1413     }
1414
1415     /* otherwise src == dst should fail */
1416     SetLastError(0xdeadbeef);
1417     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1418                        buf, 10, buf, sizeof(buf));
1419     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1420        GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1421        "unexpected error code %d\n", GetLastError());
1422     ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1423
1424     /* test whether '\0' is always appended */
1425     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1426                        upper_case, -1, buf, sizeof(buf));
1427     ok(ret, "LCMapStringA must succeed\n");
1428     ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1429     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1430                        upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1431     ok(ret2, "LCMapStringA must succeed\n");
1432     ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1433     ok(ret == ret2, "lengths of sort keys must be equal\n");
1434     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1435
1436     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1437     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1438                        upper_case, -1, buf, sizeof(buf));
1439     ok(ret, "LCMapStringA must succeed\n");
1440     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1441                        lower_case, -1, buf2, sizeof(buf2));
1442     ok(ret2, "LCMapStringA must succeed\n");
1443     ok(ret == ret2, "lengths of sort keys must be equal\n");
1444     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1445
1446     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1447        results from plain LCMAP_SORTKEY on Vista */
1448
1449     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1450     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1451                        lower_case, -1, buf, sizeof(buf));
1452     ok(ret, "LCMapStringA must succeed\n");
1453     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1454                        symbols_stripped, -1, buf2, sizeof(buf2));
1455     ok(ret2, "LCMapStringA must succeed\n");
1456     ok(ret == ret2, "lengths of sort keys must be equal\n");
1457     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1458
1459     /* test NORM_IGNORENONSPACE */
1460     lstrcpyA(buf, "foo");
1461     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1462                        lower_case, -1, buf, sizeof(buf));
1463     ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1464         lstrlenA(lower_case) + 1, ret);
1465     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1466
1467     /* test NORM_IGNORESYMBOLS */
1468     lstrcpyA(buf, "foo");
1469     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1470                        lower_case, -1, buf, sizeof(buf));
1471     ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1472         lstrlenA(symbols_stripped) + 1, ret);
1473     ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1474
1475     /* test srclen = 0 */
1476     SetLastError(0xdeadbeef);
1477     ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1478     ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1479     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1480        "unexpected error code %d\n", GetLastError());
1481 }
1482
1483 static void test_LCMapStringW(void)
1484 {
1485     int ret, ret2;
1486     WCHAR buf[256], buf2[256];
1487     char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1488     static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
1489     static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
1490     static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1491     static const WCHAR fooW[] = {'f','o','o',0};
1492
1493     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1494                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1495     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1496     {
1497         win_skip("LCMapStringW is not implemented\n");
1498         return;
1499     }
1500     if (broken(ret))
1501         ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1502     else
1503     {
1504         ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1505         ok(GetLastError() == ERROR_INVALID_FLAGS,
1506            "unexpected error code %d\n", GetLastError());
1507     }
1508
1509     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1510                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1511     ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1512     ok(GetLastError() == ERROR_INVALID_FLAGS,
1513        "unexpected error code %d\n", GetLastError());
1514
1515     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1516                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1517     ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1518     ok(GetLastError() == ERROR_INVALID_FLAGS,
1519        "unexpected error code %d\n", GetLastError());
1520
1521     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1522                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1523     ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1524     ok(GetLastError() == ERROR_INVALID_FLAGS,
1525        "unexpected error code %d\n", GetLastError());
1526
1527     /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1528     SetLastError(0xdeadbeef);
1529     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1530                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1531     ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1532     ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1533
1534     /* test LCMAP_LOWERCASE */
1535     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1536                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1537     ok(ret == lstrlenW(upper_case) + 1,
1538        "ret %d, error %d, expected value %d\n",
1539        ret, GetLastError(), lstrlenW(upper_case) + 1);
1540     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1541
1542     /* test LCMAP_UPPERCASE */
1543     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1544                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1545     ok(ret == lstrlenW(lower_case) + 1,
1546        "ret %d, error %d, expected value %d\n",
1547        ret, GetLastError(), lstrlenW(lower_case) + 1);
1548     ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1549
1550     /* test buffer overflow */
1551     SetLastError(0xdeadbeef);
1552     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1553                        lower_case, -1, buf, 4);
1554     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1555        "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1556
1557     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1558     lstrcpyW(buf, lower_case);
1559     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1560                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1561     ok(ret == lstrlenW(lower_case) + 1,
1562        "ret %d, error %d, expected value %d\n",
1563        ret, GetLastError(), lstrlenW(lower_case) + 1);
1564     ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1565
1566     lstrcpyW(buf, upper_case);
1567     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1568                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1569     ok(ret == lstrlenW(upper_case) + 1,
1570        "ret %d, error %d, expected value %d\n",
1571        ret, GetLastError(), lstrlenW(lower_case) + 1);
1572     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1573
1574     /* otherwise src == dst should fail */
1575     SetLastError(0xdeadbeef);
1576     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1577                        buf, 10, buf, sizeof(buf));
1578     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1579        GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1580        "unexpected error code %d\n", GetLastError());
1581     ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1582
1583     /* test whether '\0' is always appended */
1584     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1585                        upper_case, -1, buf, sizeof(buf));
1586     ok(ret, "LCMapStringW must succeed\n");
1587     ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1588                        upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1589     ok(ret, "LCMapStringW must succeed\n");
1590     ok(ret == ret2, "lengths of sort keys must be equal\n");
1591     ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1592
1593     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1594     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1595                        upper_case, -1, buf, sizeof(buf));
1596     ok(ret, "LCMapStringW must succeed\n");
1597     ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1598                        lower_case, -1, buf2, sizeof(buf2));
1599     ok(ret2, "LCMapStringW must succeed\n");
1600     ok(ret == ret2, "lengths of sort keys must be equal\n");
1601     ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1602
1603     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1604        results from plain LCMAP_SORTKEY on Vista */
1605
1606     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1607     ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1608                        lower_case, -1, buf, sizeof(buf));
1609     ok(ret, "LCMapStringW must succeed\n");
1610     ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1611                        symbols_stripped, -1, buf2, sizeof(buf2));
1612     ok(ret2, "LCMapStringW must succeed\n");
1613     ok(ret == ret2, "lengths of sort keys must be equal\n");
1614     ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1615
1616     /* test NORM_IGNORENONSPACE */
1617     lstrcpyW(buf, fooW);
1618     ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1619                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1620     ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1621         lstrlenW(lower_case) + 1, ret);
1622     ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1623
1624     /* test NORM_IGNORESYMBOLS */
1625     lstrcpyW(buf, fooW);
1626     ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1627                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1628     ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1629         lstrlenW(symbols_stripped) + 1, ret);
1630     ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1631
1632     /* test srclen = 0 */
1633     SetLastError(0xdeadbeef);
1634     ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1635     ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1636     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1637        "unexpected error code %d\n", GetLastError());
1638 }
1639
1640 /* this requires collation table patch to make it MS compatible */
1641 static const char * const strings_sorted[] =
1642 {
1643 "'",
1644 "-",
1645 "!",
1646 "\"",
1647 ".",
1648 ":",
1649 "\\",
1650 "_",
1651 "`",
1652 "{",
1653 "}",
1654 "+",
1655 "0",
1656 "1",
1657 "2",
1658 "3",
1659 "4",
1660 "5",
1661 "6",
1662 "7",
1663 "8",
1664 "9",
1665 "a",
1666 "A",
1667 "b",
1668 "B",
1669 "c",
1670 "C"
1671 };
1672
1673 static const char * const strings[] =
1674 {
1675 "C",
1676 "\"",
1677 "9",
1678 "'",
1679 "}",
1680 "-",
1681 "7",
1682 "+",
1683 "`",
1684 "1",
1685 "a",
1686 "5",
1687 "\\",
1688 "8",
1689 "B",
1690 "3",
1691 "_",
1692 "6",
1693 "{",
1694 "2",
1695 "c",
1696 "4",
1697 "!",
1698 "0",
1699 "A",
1700 ":",
1701 "b",
1702 "."
1703 };
1704
1705 static int compare_string1(const void *e1, const void *e2)
1706 {
1707     const char *s1 = *(const char *const *)e1;
1708     const char *s2 = *(const char *const *)e2;
1709
1710     return lstrcmpA(s1, s2);
1711 }
1712
1713 static int compare_string2(const void *e1, const void *e2)
1714 {
1715     const char *s1 = *(const char *const *)e1;
1716     const char *s2 = *(const char *const *)e2;
1717
1718     return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1719 }
1720
1721 static int compare_string3(const void *e1, const void *e2)
1722 {
1723     const char *s1 = *(const char *const *)e1;
1724     const char *s2 = *(const char *const *)e2;
1725     char key1[256], key2[256];
1726
1727     LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1728     LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1729     return strcmp(key1, key2);
1730 }
1731
1732 static void test_sorting(void)
1733 {
1734     char buf[256];
1735     char **str_buf = (char **)buf;
1736     int i;
1737
1738     assert(sizeof(buf) >= sizeof(strings));
1739
1740     /* 1. sort using lstrcmpA */
1741     memcpy(buf, strings, sizeof(strings));
1742     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1743     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1744     {
1745         ok(!strcmp(strings_sorted[i], str_buf[i]),
1746            "qsort using lstrcmpA failed for element %d\n", i);
1747     }
1748     /* 2. sort using CompareStringA */
1749     memcpy(buf, strings, sizeof(strings));
1750     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1751     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1752     {
1753         ok(!strcmp(strings_sorted[i], str_buf[i]),
1754            "qsort using CompareStringA failed for element %d\n", i);
1755     }
1756     /* 3. sort using sort keys */
1757     memcpy(buf, strings, sizeof(strings));
1758     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1759     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1760     {
1761         ok(!strcmp(strings_sorted[i], str_buf[i]),
1762            "qsort using sort keys failed for element %d\n", i);
1763     }
1764 }
1765
1766 static void test_FoldStringA(void)
1767 {
1768   int ret, i, j;
1769   BOOL is_special;
1770   char src[256], dst[256];
1771   static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0'  };
1772   static const char digits_dst[] = { '1','2','3','\0'  };
1773   static const char composite_src[] =
1774   {
1775     0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1776     0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1777     0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1778     0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1779     0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1780     0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1781     0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1782     0xfb,0xfc,0xfd,0xff,'\0'
1783   };
1784   static const char composite_dst[] =
1785   {
1786     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1787     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1788     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1789     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1790     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1791     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1792     0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1793     0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1794     0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1795     0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1796     0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1797     0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1798     0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1799     0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1800     0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1801   };
1802   static const char composite_dst_alt[] =
1803   {
1804     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1805     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1806     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1807     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1808     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1809     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1810     0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1811     0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1812     0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1813     0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1814     0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1815     0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1816     0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1817     0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1818     0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1819   };
1820   static const char ligatures_src[] =
1821   {
1822     0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1823   };
1824   static const char ligatures_dst[] =
1825   {
1826     'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1827   };
1828   static const struct special
1829   {
1830     char src;
1831     char dst[4];
1832   }  foldczone_special[] =
1833   {
1834     /* src   dst                   */
1835     { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1836     { 0x98, { 0x20, 0x7e, 0x00 } },
1837     { 0x99, { 0x54, 0x4d, 0x00 } },
1838     { 0xa0, { 0x20, 0x00 } },
1839     { 0xa8, { 0x20, 0xa8, 0x00 } },
1840     { 0xaa, { 0x61, 0x00 } },
1841     { 0xaf, { 0x20, 0xaf, 0x00 } },
1842     { 0xb2, { 0x32, 0x00 } },
1843     { 0xb3, { 0x33, 0x00 } },
1844     { 0xb4, { 0x20, 0xb4, 0x00 } },
1845     { 0xb8, { 0x20, 0xb8, 0x00 } },
1846     { 0xb9, { 0x31, 0x00 } },
1847     { 0xba, { 0x6f, 0x00 } },
1848     { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1849     { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1850     { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1851     { 0x00 }
1852   };
1853
1854   if (!pFoldStringA)
1855     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1856
1857   /* these tests are locale specific */
1858   if (GetACP() != 1252)
1859   {
1860       trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1861       return;
1862   }
1863
1864   /* MAP_FOLDDIGITS */
1865   SetLastError(0);
1866   ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1867   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1868   {
1869     win_skip("FoldStringA is not implemented\n");
1870     return;
1871   }
1872   ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1873   ok(strcmp(dst, digits_dst) == 0,
1874      "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1875   for (i = 1; i < 256; i++)
1876   {
1877     if (!strchr(digits_src, i))
1878     {
1879       src[0] = i;
1880       src[1] = '\0';
1881       SetLastError(0);
1882       ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1883       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1884       ok(dst[0] == src[0],
1885          "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1886     }
1887   }
1888
1889   /* MAP_EXPAND_LIGATURES */
1890   SetLastError(0);
1891   ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1892   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1893   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1894     ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1895     ok(strcmp(dst, ligatures_dst) == 0,
1896        "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1897     for (i = 1; i < 256; i++)
1898     {
1899       if (!strchr(ligatures_src, i))
1900       {
1901         src[0] = i;
1902         src[1] = '\0';
1903         SetLastError(0);
1904         ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1905         if (ret == 3)
1906         {
1907           /* Vista */
1908           ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1909              (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1910              "Got %s for %d\n", dst, i);
1911         }
1912         else
1913         {
1914           ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1915           ok(dst[0] == src[0],
1916              "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1917         }
1918       }
1919     }
1920   }
1921
1922   /* MAP_COMPOSITE */
1923   SetLastError(0);
1924   ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1925   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1926   ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1927   ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1928      "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1929
1930   for (i = 1; i < 256; i++)
1931   {
1932     if (!strchr(composite_src, i))
1933     {
1934       src[0] = i;
1935       src[1] = '\0';
1936       SetLastError(0);
1937       ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1938       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1939       ok(dst[0] == src[0],
1940          "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1941          (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1942     }
1943   }
1944
1945   /* MAP_FOLDCZONE */
1946   for (i = 1; i < 256; i++)
1947   {
1948     src[0] = i;
1949     src[1] = '\0';
1950     SetLastError(0);
1951     ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1952     is_special = FALSE;
1953     for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1954     {
1955       if (foldczone_special[j].src == src[0])
1956       {
1957         ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1958            "Expected ret == 2 or %d, got %d, error %d\n",
1959            lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
1960         ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
1961            "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
1962            (unsigned char)src[0]);
1963         is_special = TRUE;
1964       }
1965     }
1966     if (! is_special)
1967     {
1968       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1969       ok(src[0] == dst[0],
1970          "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1971          (unsigned char)src[0], (unsigned char)dst[0]);
1972     }
1973   }
1974
1975   /* MAP_PRECOMPOSED */
1976   for (i = 1; i < 256; i++)
1977   {
1978     src[0] = i;
1979     src[1] = '\0';
1980     SetLastError(0);
1981     ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1982     ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1983     ok(src[0] == dst[0],
1984        "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1985        (unsigned char)src[0], (unsigned char)dst[0]);
1986   }
1987 }
1988
1989 static void test_FoldStringW(void)
1990 {
1991   int ret;
1992   unsigned int i, j;
1993   WCHAR src[256], dst[256], ch, prev_ch = 1;
1994   static const DWORD badFlags[] =
1995   {
1996     0,
1997     MAP_PRECOMPOSED|MAP_COMPOSITE,
1998     MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1999     MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2000   };
2001   /* Ranges of digits 0-9 : Must be sorted! */
2002   static const WCHAR digitRanges[] =
2003   {
2004     0x0030, /* '0'-'9' */
2005     0x0660, /* Eastern Arabic */
2006     0x06F0, /* Arabic - Hindu */
2007     0x0966, /* Devengari */
2008     0x09E6, /* Bengalii */
2009     0x0A66, /* Gurmukhi */
2010     0x0AE6, /* Gujarati */
2011     0x0B66, /* Oriya */
2012     0x0BE6, /* Tamil - No 0 */
2013     0x0C66, /* Telugu */
2014     0x0CE6, /* Kannada */
2015     0x0D66, /* Maylayalam */
2016     0x0E50, /* Thai */
2017     0x0ED0, /* Laos */
2018     0x0F29, /* Tibet - 0 is out of sequence */
2019     0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2020     0x2080, /* Subscript */
2021     0x245F, /* Circled - 0 is out of sequence */
2022     0x2473, /* Bracketed */
2023     0x2487, /* Full stop */
2024     0x2775, /* Inverted circled - No 0 */
2025     0x277F, /* Patterned circled - No 0 */
2026     0x2789, /* Inverted Patterned circled - No 0 */
2027     0x3020, /* Hangzhou */
2028     0xff10, /* Pliene chasse (?) */
2029     0xffff  /* Terminator */
2030   };
2031   /* Digits which are represented, but out of sequence */
2032   static const WCHAR outOfSequenceDigits[] =
2033   {
2034       0xB9,   /* Superscript 1 */
2035       0xB2,   /* Superscript 2 */
2036       0xB3,   /* Superscript 3 */
2037       0x0F33, /* Tibetan half zero */
2038       0x24EA, /* Circled 0 */
2039       0x3007, /* Ideographic number zero */
2040       '\0'    /* Terminator */
2041   };
2042   /* Digits in digitRanges for which no representation is available */
2043   static const WCHAR noDigitAvailable[] =
2044   {
2045       0x0BE6, /* No Tamil 0 */
2046       0x0F29, /* No Tibetan half zero (out of sequence) */
2047       0x2473, /* No Bracketed 0 */
2048       0x2487, /* No 0 Full stop */
2049       0x2775, /* No inverted circled 0 */
2050       0x277F, /* No patterned circled */
2051       0x2789, /* No inverted Patterned circled */
2052       0x3020, /* No Hangzhou 0 */
2053       '\0'    /* Terminator */
2054   };
2055   static const WCHAR foldczone_src[] =
2056   {
2057     'W',    'i',    'n',    'e',    0x0348, 0x0551, 0x1323, 0x280d,
2058     0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2059   };
2060   static const WCHAR foldczone_dst[] =
2061   {
2062     'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2063   };
2064   static const WCHAR ligatures_src[] =
2065   {
2066     'W',    'i',    'n',    'e',    0x03a6, 0x03b9, 0x03bd, 0x03b5,
2067     0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2068     0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2069     0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2070     0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2071     0xfb04, 0xfb05, 0xfb06, '\0'
2072   };
2073   static const WCHAR ligatures_dst[] =
2074   {
2075     'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2076     'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2077     'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2078     'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2079     0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2080     'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2081   };
2082
2083   if (!pFoldStringW)
2084   {
2085     win_skip("FoldStringW is not available\n");
2086     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2087   }
2088
2089   /* Invalid flag combinations */
2090   for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2091   {
2092     src[0] = dst[0] = '\0';
2093     SetLastError(0);
2094     ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2095     if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2096     {
2097       win_skip("FoldStringW is not implemented\n");
2098       return;
2099     }
2100     ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2101        "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2102   }
2103
2104   /* src & dst cannot be the same */
2105   SetLastError(0);
2106   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2107   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2108       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2109
2110   /* src can't be NULL */
2111   SetLastError(0);
2112   ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2113   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2114       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2115
2116   /* srclen can't be 0 */
2117   SetLastError(0);
2118   ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2119   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2120       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2121
2122   /* dstlen can't be < 0 */
2123   SetLastError(0);
2124   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2125   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2126       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2127
2128   /* Ret includes terminating NUL which is appended if srclen = -1 */
2129   SetLastError(0);
2130   src[0] = 'A';
2131   src[1] = '\0';
2132   dst[0] = '\0';
2133   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2134   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2135   ok(dst[0] == 'A' && dst[1] == '\0',
2136      "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2137      'A', '\0', ret, dst[0], dst[1], GetLastError());
2138
2139   /* If size is given, result is not NUL terminated */
2140   SetLastError(0);
2141   src[0] = 'A';
2142   src[1] = 'A';
2143   dst[0] = 'X';
2144   dst[1] = 'X';
2145   ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2146   ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2147   ok(dst[0] == 'A' && dst[1] == 'X',
2148      "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2149      'A','X', ret, dst[0], dst[1], GetLastError());
2150
2151   /* MAP_FOLDDIGITS */
2152   for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2153   {
2154     /* Check everything before this range */
2155     for (ch = prev_ch; ch < digitRanges[j]; ch++)
2156     {
2157       SetLastError(0);
2158       src[0] = ch;
2159       src[1] = dst[0] = '\0';
2160       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2161       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2162
2163       ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2164          /* Wine (correctly) maps all Unicode 4.0+ digits */
2165          isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2166          (ch >= 0x1369 && ch <= 0x1371),
2167          "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2168     }
2169
2170     if (digitRanges[j] == 0xffff)
2171       break; /* Finished the whole code point space */
2172
2173     for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2174     {
2175       WCHAR c;
2176
2177       /* Map out of sequence characters */
2178       if      (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2179       else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2180       else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2181       else if (ch == 0x245F) c = 0x24EA; /* Circled 0     */
2182       else                   c = ch;
2183       SetLastError(0);
2184       src[0] = c;
2185       src[1] = dst[0] = '\0';
2186       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2187       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2188
2189       ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2190          broken( dst[0] == ch ) ||  /* old Windows versions don't have all mappings */
2191          (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2192          (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2193          strchrW(noDigitAvailable, c),
2194          "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2195          ch, '0' + digitRanges[j] - ch, dst[0]);
2196     }
2197     prev_ch = ch;
2198   }
2199
2200   /* MAP_FOLDCZONE */
2201   SetLastError(0);
2202   ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2203   ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2204      "Got %d, error %d\n", ret, GetLastError());
2205   ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2206      "MAP_FOLDCZONE: Expanded incorrectly\n");
2207
2208   /* MAP_EXPAND_LIGATURES */
2209   SetLastError(0);
2210   ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2211   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2212   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2213     ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2214        "Got %d, error %d\n", ret, GetLastError());
2215     ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2216        "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2217   }
2218
2219   /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2220 }
2221
2222
2223
2224 #define LCID_OK(l) \
2225   ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2226 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2227 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2228 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2229 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2230
2231 static void test_ConvertDefaultLocale(void)
2232 {
2233   LCID lcid;
2234
2235   /* Doesn't change lcid, even if non default sublang/sort used */
2236   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_US, SORT_DEFAULT);
2237   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2238   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_DEFAULT);
2239   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_JAPANESE_UNICODE);
2240
2241   /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2242   LCID_RES(MKLCID(LANG_ENGLISH,  SUBLANG_NEUTRAL, SORT_DEFAULT),
2243            MKLCID(LANG_ENGLISH,  SUBLANG_DEFAULT, SORT_DEFAULT));
2244   LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2245            MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2246
2247   /* Invariant language is not treated specially */
2248   TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2249
2250   /* User/system default languages alone are not mapped */
2251   TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2252   TEST_LCIDLANG(LANG_USER_DEFAULT,   SORT_JAPANESE_UNICODE);
2253
2254   /* Default lcids */
2255   LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2256   LCID_RES(LOCALE_USER_DEFAULT,   GetUserDefaultLCID());
2257   LCID_RES(LOCALE_NEUTRAL,        GetUserDefaultLCID());
2258 }
2259
2260 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2261                                     DWORD dwFlags, LONG_PTR lParam)
2262 {
2263   trace("%08x, %s, %s, %08x, %08lx\n",
2264         lgrpid, lpszNum, lpszName, dwFlags, lParam);
2265
2266   ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2267      "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2268
2269   /* If lParam is one, we are calling with flags defaulted from 0 */
2270   ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2271          "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2272
2273   return TRUE;
2274 }
2275
2276 static void test_EnumSystemLanguageGroupsA(void)
2277 {
2278   BOOL ret;
2279
2280   if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2281   {
2282     win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2283     return;
2284   }
2285
2286   /* No enumeration proc */
2287   SetLastError(0);
2288   ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2289   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2290   {
2291     win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2292     return;
2293   }
2294   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2295       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2296
2297   /* Invalid flags */
2298   SetLastError(0);
2299   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2300   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2301
2302   /* No flags - defaults to LGRPID_INSTALLED */
2303   SetLastError(0xdeadbeef);
2304   pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2305   ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2306
2307   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2308   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2309 }
2310
2311 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2312 {
2313     trace( "%s %x\n", wine_dbgstr_w(name), flags );
2314     return TRUE;
2315 }
2316
2317 static void test_EnumSystemLocalesEx(void)
2318 {
2319     BOOL ret;
2320
2321     if (!pEnumSystemLocalesEx)
2322     {
2323         win_skip( "EnumSystemLocalesEx not available\n" );
2324         return;
2325     }
2326     SetLastError( 0xdeadbeef );
2327     ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2328     ok( !ret, "should have failed\n" );
2329     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2330     SetLastError( 0xdeadbeef );
2331     ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2332     ok( ret, "failed err %u\n", GetLastError() );
2333 }
2334
2335 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2336                                       LONG_PTR lParam)
2337 {
2338   trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2339
2340   /* invalid locale enumerated on some platforms */
2341   if (lcid == 0)
2342       return TRUE;
2343
2344   ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2345      "Enumerated grp %d not valid\n", lgrpid);
2346   ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2347      "Enumerated grp locale %d not valid\n", lcid);
2348   return TRUE;
2349 }
2350
2351 static void test_EnumLanguageGroupLocalesA(void)
2352 {
2353   BOOL ret;
2354
2355   if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2356   {
2357     win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2358     return;
2359   }
2360
2361   /* No enumeration proc */
2362   SetLastError(0);
2363   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2364   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2365   {
2366     win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2367     return;
2368   }
2369   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2370       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2371
2372   /* lgrpid too small */
2373   SetLastError(0);
2374   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2375   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2376       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2377
2378   /* lgrpid too big */
2379   SetLastError(0);
2380   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2381   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2382       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2383
2384   /* dwFlags is reserved */
2385   SetLastError(0);
2386   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2387   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2388       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2389
2390   pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2391 }
2392
2393 static void test_SetLocaleInfoA(void)
2394 {
2395   BOOL bRet;
2396   LCID lcid = GetUserDefaultLCID();
2397
2398   /* Null data */
2399   SetLastError(0);
2400   bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2401   ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2402       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2403
2404   /* IDATE */
2405   SetLastError(0);
2406   bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2407   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2408      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2409
2410   /* ILDATE */
2411   SetLastError(0);
2412   bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2413   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2414      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2415 }
2416
2417 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2418 {
2419   trace("%s %08lx\n", value, lParam);
2420   return(TRUE);
2421 }
2422
2423 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2424 {
2425   ok(!enumCount, "callback called again unexpected\n");
2426   enumCount++;
2427   return(FALSE);
2428 }
2429
2430 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2431 {
2432   ok(0,"callback called unexpected\n");
2433   return(FALSE);
2434 }
2435
2436 static void test_EnumUILanguageA(void)
2437 {
2438   BOOL ret;
2439   if (!pEnumUILanguagesA) {
2440     win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2441     return;
2442   }
2443
2444   SetLastError(ERROR_SUCCESS);
2445   ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2446   if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2447   {
2448     win_skip("EnumUILanguagesA is not implemented\n");
2449     return;
2450   }
2451   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2452
2453   enumCount = 0;
2454   SetLastError(ERROR_SUCCESS);
2455   ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2456   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2457
2458   SetLastError(ERROR_SUCCESS);
2459   ret = pEnumUILanguagesA(NULL, 0, 0);
2460   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2461   ok(GetLastError() == ERROR_INVALID_PARAMETER,
2462       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2463
2464   SetLastError(ERROR_SUCCESS);
2465   ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2466   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2467   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2468
2469   SetLastError(ERROR_SUCCESS);
2470   ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2471   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2472   ok(GetLastError() == ERROR_INVALID_PARAMETER,
2473       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2474 }
2475
2476 static char date_fmt_buf[1024];
2477
2478 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2479 {
2480     lstrcatA(date_fmt_buf, fmt);
2481     lstrcatA(date_fmt_buf, "\n");
2482     return TRUE;
2483 }
2484
2485 static void test_EnumDateFormatsA(void)
2486 {
2487     char *p, buf[256];
2488     BOOL ret;
2489     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2490
2491     trace("EnumDateFormatsA 0\n");
2492     date_fmt_buf[0] = 0;
2493     SetLastError(0xdeadbeef);
2494     ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2495     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2496     {
2497         win_skip("0 for dwFlags is not supported\n");
2498     }
2499     else
2500     {
2501         ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2502         trace("%s\n", date_fmt_buf);
2503         /* test the 1st enumerated format */
2504         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2505         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2506         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2507         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2508     }
2509
2510     trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2511     date_fmt_buf[0] = 0;
2512     SetLastError(0xdeadbeef);
2513     ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2514     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2515     {
2516         win_skip("LOCALE_USE_CP_ACP is not supported\n");
2517     }
2518     else
2519     {
2520         ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2521         trace("%s\n", date_fmt_buf);
2522         /* test the 1st enumerated format */
2523         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2524         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2525         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2526         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2527     }
2528
2529     trace("EnumDateFormatsA DATE_SHORTDATE\n");
2530     date_fmt_buf[0] = 0;
2531     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2532     ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2533     trace("%s\n", date_fmt_buf);
2534     /* test the 1st enumerated format */
2535     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2536     ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2537     ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2538     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2539
2540     trace("EnumDateFormatsA DATE_LONGDATE\n");
2541     date_fmt_buf[0] = 0;
2542     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2543     ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2544     trace("%s\n", date_fmt_buf);
2545     /* test the 1st enumerated format */
2546     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2547     ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2548     ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2549     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2550
2551     trace("EnumDateFormatsA DATE_YEARMONTH\n");
2552     date_fmt_buf[0] = 0;
2553     SetLastError(0xdeadbeef);
2554     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2555     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2556     {
2557         skip("DATE_YEARMONTH is only present on W2K and later\n");
2558         return;
2559     }
2560     ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2561     trace("%s\n", date_fmt_buf);
2562     /* test the 1st enumerated format */
2563     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2564     ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2565     ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2566     ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2567        "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2568 }
2569
2570 static void test_EnumTimeFormatsA(void)
2571 {
2572     char *p, buf[256];
2573     BOOL ret;
2574     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2575
2576     trace("EnumTimeFormatsA 0\n");
2577     date_fmt_buf[0] = 0;
2578     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2579     ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2580     trace("%s\n", date_fmt_buf);
2581     /* test the 1st enumerated format */
2582     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2583     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2584     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2585     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2586
2587     trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2588     date_fmt_buf[0] = 0;
2589     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2590     ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2591     trace("%s\n", date_fmt_buf);
2592     /* test the 1st enumerated format */
2593     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2594     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2595     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2596     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2597 }
2598
2599 static void test_GetCPInfo(void)
2600 {
2601     BOOL ret;
2602     CPINFO cpinfo;
2603
2604     SetLastError(0xdeadbeef);
2605     ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2606     ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2607     ok(GetLastError() == ERROR_INVALID_PARAMETER,
2608        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2609
2610     SetLastError(0xdeadbeef);
2611     ret = GetCPInfo(CP_UTF7, &cpinfo);
2612     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2613     {
2614         skip("Codepage CP_UTF7 is not installed/available\n");
2615     }
2616     else
2617     {
2618         ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2619         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2620         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2621         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2622         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2623         ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2624     }
2625
2626     SetLastError(0xdeadbeef);
2627     ret = GetCPInfo(CP_UTF8, &cpinfo);
2628     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2629     {
2630         skip("Codepage CP_UTF8 is not installed/available\n");
2631     }
2632     else
2633     {
2634         ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2635         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2636         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2637         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2638         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2639         ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2640            "expected 4, got %u\n", cpinfo.MaxCharSize);
2641     }
2642 }
2643
2644 /*
2645  * The CT_TYPE1 has varied over windows version.
2646  * The current target for correct behavior is windows 7.
2647  * There was a big shift between windows 2000 (first introduced) and windows Xp
2648  * Most of the old values below are from windows 2000.
2649  * A smaller subset of changes happened between windows Xp and Window vista/7
2650  */
2651 static void test_GetStringTypeW(void)
2652 {
2653     static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2654     static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2655                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2656                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2657                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2658                                  C1_CNTRL | C1_BLANK | C1_DEFINED};
2659     static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2660                                     C1_SPACE | C1_BLANK,
2661                                     C1_SPACE | C1_BLANK,
2662                                     C1_SPACE | C1_BLANK,
2663                                     C1_SPACE | C1_BLANK};
2664
2665     static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2666
2667                                   /* Lu, Ll, Lt */
2668     static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2669     static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2670                                      C1_LOWER | C1_ALPHA,
2671                                      C1_UPPER | C1_LOWER | C1_ALPHA,
2672                                      C1_ALPHA};
2673
2674                                   /* Sk, Sk, Mn, So, Me */
2675     static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2676                                  /* Sc, Sm, No,*/
2677                                      0xffe0, 0xffe9, 0x2153};
2678
2679                                 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2680     static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2681     static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2682     static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2683                                       C1_ALPHA | C1_DEFINED,
2684                                       C1_CNTRL | C1_DEFINED,
2685                                       C1_PUNCT | C1_DEFINED,
2686                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2687                                       C1_ALPHA | C1_LOWER | C1_DEFINED,
2688                                       C1_ALPHA | C1_DEFINED };
2689     static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2690                                       C1_ALPHA | C1_DEFINED,
2691                                       C1_CNTRL | C1_DEFINED,
2692                                       C1_PUNCT | C1_CNTRL | C1_DEFINED,
2693                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2694                                       C1_ALPHA | C1_DEFINED,
2695                                       C1_DEFINED
2696  };
2697                                 /* Pc,  Pd, Ps, Pe, Pi, Pf, Po*/
2698     static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2699
2700     static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2701                                           0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2702     static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2703     static const WCHAR lower_special[] = {0x2071, 0x207f};
2704     static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2705                   0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2706                   0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2707                   0xfff9, 0xfffa, 0xfffb};
2708     static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2709
2710     WORD types[20];
2711     int i;
2712
2713     memset(types,0,sizeof(types));
2714     GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2715     for (i = 0; i < 5; i++)
2716         ok(types[i] == blanks_new[i] || broken(types[i] == blanks_old[i] || broken(types[i] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks[i],types[i],blanks_new[i]);
2717
2718     memset(types,0,sizeof(types));
2719     GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2720     for (i = 0; i < 3; i++)
2721         ok(types[i] == (C1_DEFINED | alpha_old[i]) || broken(types[i] == alpha_old[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha[i], types[i],(C1_DEFINED | alpha_old[i]));
2722     memset(types,0,sizeof(types));
2723     GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2724     for (i = 0; i < 5; i++)
2725         ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2726
2727     memset(types,0,sizeof(types));
2728     GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2729     for (i = 0; i < 8; i++)
2730         ok(types[i] == C1_DEFINED || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc[i], types[i], C1_DEFINED);
2731
2732     memset(types,0,sizeof(types));
2733     GetStringTypeW(CT_CTYPE1, changed, 7, types);
2734     for (i = 0; i < 7; i++)
2735         ok(types[i] == changed_new[i] || broken(types[i] == changed_old[i]) || broken(types[i] == changed_xp[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed[i], types[i], changed_new[i]);
2736
2737     memset(types,0,sizeof(types));
2738     GetStringTypeW(CT_CTYPE1, punct, 7, types);
2739     for (i = 0; i < 7; i++)
2740         ok(types[i] == (C1_PUNCT | C1_DEFINED) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct[i], types[i], (C1_PUNCT | C1_DEFINED));
2741
2742
2743     memset(types,0,sizeof(types));
2744     GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
2745     for (i = 0; i < 12; i++)
2746         ok(types[i]  & C1_PUNCT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special[i], types[i], C1_PUNCT);
2747
2748     memset(types,0,sizeof(types));
2749     GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
2750     for (i = 0; i < 3; i++)
2751         ok(types[i] & C1_DIGIT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special[i], types[i], C1_DIGIT);
2752
2753     memset(types,0,sizeof(types));
2754     GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
2755     for (i = 0; i < 2; i++)
2756         ok(types[i] & C1_LOWER || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special[i], types[i], C1_LOWER);
2757
2758     memset(types,0,sizeof(types));
2759     GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
2760     for (i = 0; i < 20; i++)
2761         ok(types[i] & C1_CNTRL || broken(types[i] == (C1_BLANK|C1_SPACE)) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special[i], types[i], C1_CNTRL);
2762
2763     memset(types,0,sizeof(types));
2764     GetStringTypeW(CT_CTYPE1, space_special, 3, types);
2765     for (i = 0; i < 3; i++)
2766         ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
2767 }
2768
2769 START_TEST(locale)
2770 {
2771   InitFunctionPointers();
2772
2773   test_EnumTimeFormatsA();
2774   test_EnumDateFormatsA();
2775   test_GetLocaleInfoA();
2776   test_GetLocaleInfoW();
2777   test_GetTimeFormatA();
2778   test_GetDateFormatA();
2779   test_GetDateFormatW();
2780   test_GetCurrencyFormatA(); /* Also tests the W version */
2781   test_GetNumberFormatA();   /* Also tests the W version */
2782   test_CompareStringA();
2783   test_LCMapStringA();
2784   test_LCMapStringW();
2785   test_FoldStringA();
2786   test_FoldStringW();
2787   test_ConvertDefaultLocale();
2788   test_EnumSystemLanguageGroupsA();
2789   test_EnumSystemLocalesEx();
2790   test_EnumLanguageGroupLocalesA();
2791   test_SetLocaleInfoA();
2792   test_EnumUILanguageA();
2793   test_GetCPInfo();
2794   test_GetStringTypeW();
2795   /* this requires collation table patch to make it MS compatible */
2796   if (0) test_sorting();
2797 }