Removed #include of wingdi.h and windef.h from winuser.h (and resolved
[wine] / ole / ole2nls.c
1 /*
2  *      OLE2NLS library
3  *
4  *      Copyright 1995  Martin von Loewis
5  *      Copyright 1998  David Lee Lambert
6  *      Copyright 2000  Julio César Gázquez
7  */
8
9 #include <string.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include "windef.h"
14 #include "wingdi.h"
15 #include "winuser.h"
16 #include "heap.h"
17 #include "options.h"
18 #include "winver.h"
19 #include "winnls.h"
20 #include "winreg.h"
21 #include "winerror.h"
22 #include "debugtools.h"
23 #include "crtdll.h"
24 #include "main.h"
25
26 DEFAULT_DEBUG_CHANNEL(ole);
27 DECLARE_DEBUG_CHANNEL(string);
28 DECLARE_DEBUG_CHANNEL(win32);
29
30 struct NLS_langlocale {
31         const int lang;
32         struct NLS_localevar {
33                 const int       type;
34                 const char      *val;
35         } locvars[150];
36 };
37
38 static LPVOID lpNLSInfo = NULL;
39
40 #define LANG_BEGIN(l,s) {       MAKELANGID(l,s), {
41
42 #define LOCVAL(type,value)                                      {type,value},
43
44 #define LANG_END                                         }},
45
46 static const struct NLS_langlocale langlocales[] = {
47 /* add languages in numerical order of main language (last two digits)
48  * it is much easier to find the missing holes that way */
49
50 LANG_BEGIN (LANG_CATALAN, SUBLANG_DEFAULT)      /*0x0403*/
51 #include "nls/cat.nls"
52 LANG_END
53
54 LANG_BEGIN (LANG_CZECH, SUBLANG_DEFAULT)        /*0x0405*/
55 #include "nls/cze.nls"
56 LANG_END
57
58 LANG_BEGIN (LANG_DANISH, SUBLANG_DEFAULT)       /*0x0406*/
59 #include "nls/dan.nls"
60 LANG_END
61
62 LANG_BEGIN (LANG_GERMAN, SUBLANG_GERMAN)                /*0x0407*/
63 #include "nls/deu.nls"
64 LANG_END
65 LANG_BEGIN (LANG_GERMAN, SUBLANG_GERMAN_SWISS)          /*0x0807*/
66 #include "nls/des.nls"
67 LANG_END
68 LANG_BEGIN (LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN)       /*0x0C07*/
69 #include "nls/dea.nls"
70 LANG_END
71 LANG_BEGIN (LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG)     /*0x1007*/
72 #include "nls/del.nls"
73 LANG_END
74 LANG_BEGIN (LANG_GERMAN, SUBLANG_GERMAN_LIECHTENSTEIN)  /*0x1407*/
75 #include "nls/dec.nls"
76 LANG_END
77
78 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_US)           /*0x0409*/
79 #include "nls/enu.nls"
80 LANG_END
81 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_UK)           /*0x0809*/
82 #include "nls/eng.nls"
83 LANG_END
84 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_AUS)          /*0x0C09*/
85 #include "nls/ena.nls"
86 LANG_END
87 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_CAN)          /*0x1009*/
88 #include "nls/enc.nls"
89 LANG_END
90 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_NZ)           /*0x1409*/
91 #include "nls/enz.nls"
92 LANG_END
93 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_EIRE)         /*0x1809*/
94 #include "nls/irl.nls"
95 LANG_END
96 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_SAFRICA)      /*0x1C09*/
97 #include "nls/ens.nls"
98 LANG_END
99 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_JAMAICA)      /*0x2009*/
100 #include "nls/enj.nls"
101 LANG_END
102 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_CARRIBEAN)    /*0x2409*/
103 #include "nls/enb.nls"
104 LANG_END
105 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE)       /*0x2809*/
106 #include "nls/enl.nls"
107 LANG_END
108 LANG_BEGIN (LANG_ENGLISH, SUBLANG_ENGLISH_TRINIDAD)     /*0x2C09*/
109 #include "nls/ent.nls"
110 LANG_END
111
112 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH)              /*0x040a*/
113 #include "nls/esp.nls"
114 LANG_END
115 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_MEXICAN)      /*0x080a*/
116 #include "nls/esm.nls"
117 LANG_END
118 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_MODERN)       /*0x0C0a*/
119 #include "nls/esn.nls"
120 LANG_END
121 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA)    /*0x100a*/
122 #include "nls/esg.nls"
123 LANG_END
124 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_COSTARICA)    /*0x140a*/
125 #include "nls/esc.nls"
126 LANG_END
127 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_PANAMA)       /*0x180a*/
128 #include "nls/esa.nls"
129 LANG_END
130 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_DOMINICAN)    /*0x1C0A*/
131 #include "nls/esd.nls"
132 LANG_END
133 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA)    /*0x200a*/
134 #include "nls/esv.nls"
135 LANG_END
136 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA)     /*0x240a*/
137 #include "nls/eso.nls"
138 LANG_END
139 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_PERU)         /*0x280a*/
140 #include "nls/esr.nls"
141 LANG_END
142 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA)    /*0x2c0a*/
143 #include "nls/ess.nls"
144 LANG_END
145 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_ECUADOR)      /*0x300a*/
146 #include "nls/esf.nls"
147 LANG_END
148 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_CHILE)        /*0x340a*/
149 #include "nls/esl.nls"
150 LANG_END
151 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_URUGUAY)      /*0x380a*/
152 #include "nls/esy.nls"
153 LANG_END
154 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY)     /*0x3c0a*/
155 #include "nls/esz.nls"
156 LANG_END
157 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA)      /*0x400a*/
158 #include "nls/esb.nls"
159 LANG_END
160 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR)  /*0x440a*/
161 #include "nls/ese.nls"
162 LANG_END
163 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_HONDURAS)     /*0x480a*/
164 #include "nls/esh.nls"
165 LANG_END
166 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA)    /*0x4c0a*/
167 #include "nls/esi.nls"
168 LANG_END
169 LANG_BEGIN (LANG_SPANISH, SUBLANG_SPANISH_PUERTO_RICO)  /*0x500a*/
170 #include "nls/esu.nls"
171 LANG_END
172
173 LANG_BEGIN (LANG_FINNISH, SUBLANG_DEFAULT)      /*0x040B*/
174 #include "nls/fin.nls"
175 LANG_END
176
177 LANG_BEGIN (LANG_FRENCH, SUBLANG_FRENCH)                /*0x040C*/
178 #include "nls/fra.nls"
179 LANG_END
180 LANG_BEGIN (LANG_FRENCH, SUBLANG_FRENCH_BELGIAN)        /*0x080C*/
181 #include "nls/frb.nls"
182 LANG_END
183 LANG_BEGIN (LANG_FRENCH, SUBLANG_FRENCH_CANADIAN)       /*0x0C0C*/
184 #include "nls/frc.nls"
185 LANG_END
186 LANG_BEGIN (LANG_FRENCH, SUBLANG_FRENCH_SWISS)          /*0x100C*/
187 #include "nls/frs.nls"
188 LANG_END
189 LANG_BEGIN (LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG)     /*0x140C*/
190 #include "nls/frl.nls"
191 LANG_END
192
193 LANG_BEGIN (LANG_HUNGARIAN, SUBLANG_DEFAULT)    /*0x040e*/
194 #include "nls/hun.nls"
195 LANG_END
196
197 LANG_BEGIN (LANG_ITALIAN, SUBLANG_ITALIAN)              /*0x0410*/
198 #include "nls/ita.nls"
199 LANG_END
200 LANG_BEGIN (LANG_ITALIAN, SUBLANG_ITALIAN_SWISS)        /*0x0810*/
201 #include "nls/its.nls"
202 LANG_END
203
204 LANG_BEGIN (LANG_KOREAN, SUBLANG_KOREAN)        /*0x0412*/
205 #include "nls/kor.nls"
206 LANG_END
207
208 LANG_BEGIN (LANG_DUTCH, SUBLANG_DUTCH)          /*0x0413*/
209 #include "nls/nld.nls"
210 LANG_END
211 LANG_BEGIN (LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)  /*0x0813*/
212 #include "nls/nlb.nls"
213 LANG_END
214 LANG_BEGIN (LANG_DUTCH, SUBLANG_DUTCH_SURINAM)  /*0x0C13*/
215 #include "nls/nls.nls"
216 LANG_END
217
218 LANG_BEGIN (LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL)   /*0x0414*/
219 #include "nls/nor.nls"
220 LANG_END
221 LANG_BEGIN (LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)  /*0x0814*/
222 #include "nls/non.nls"
223 LANG_END
224
225 LANG_BEGIN (LANG_POLISH, SUBLANG_DEFAULT)       /*0x0415*/
226 #include "nls/plk.nls"
227 LANG_END
228
229 LANG_BEGIN (LANG_PORTUGUESE ,SUBLANG_PORTUGUESE_BRAZILIAN)      /*0x0416*/
230 #include "nls/ptb.nls"
231 LANG_END
232 LANG_BEGIN (LANG_PORTUGUESE ,SUBLANG_PORTUGUESE)                /*0x0816*/
233 #include "nls/ptg.nls"
234 LANG_END
235
236 LANG_BEGIN (LANG_RUSSIAN, SUBLANG_DEFAULT)      /*0x419*/
237 #include "nls/rus.nls"
238 LANG_END
239
240 LANG_BEGIN (LANG_SLOVAK, SUBLANG_DEFAULT)       /*0x041b*/
241 #include "nls/sky.nls"
242 LANG_END
243
244 LANG_BEGIN (LANG_SWEDISH, SUBLANG_SWEDISH)              /*0x041d*/
245 #include "nls/sve.nls"
246 LANG_END
247 LANG_BEGIN (LANG_SWEDISH, SUBLANG_SWEDISH_FINLAND)      /*0x081d*/
248 #include "nls/svf.nls"
249 LANG_END
250
251 LANG_BEGIN (LANG_THAI, SUBLANG_DEFAULT) /*0x41e*/
252 #include "nls/tha.nls"
253 LANG_END
254
255 LANG_BEGIN (LANG_ESPERANTO, SUBLANG_DEFAULT)    /*0x048f*/
256 #include "nls/esperanto.nls"
257 LANG_END
258
259 LANG_BEGIN (LANG_WALON, SUBLANG_DEFAULT)        /*0x0490*/
260 #include "nls/wal.nls"
261 LANG_END
262             };
263
264
265 /* Locale name to id map. used by EnumSystemLocales, GetLocaleInfoA 
266  * MUST contain all #defines from winnls.h
267  * last entry has NULL name, 0 id.
268  */ 
269 #define LOCALE_ENTRY(x) {#x,LOCALE_##x}
270 static struct tagLOCALE_NAME2ID {
271         char    *name;
272         DWORD   id;
273 } locale_name2id[]= {
274         LOCALE_ENTRY(ILANGUAGE),
275         LOCALE_ENTRY(SLANGUAGE),
276         LOCALE_ENTRY(SENGLANGUAGE),
277         LOCALE_ENTRY(SABBREVLANGNAME),
278         LOCALE_ENTRY(SNATIVELANGNAME),
279         LOCALE_ENTRY(ICOUNTRY),
280         LOCALE_ENTRY(SCOUNTRY),
281         LOCALE_ENTRY(SENGCOUNTRY),
282         LOCALE_ENTRY(SABBREVCTRYNAME),
283         LOCALE_ENTRY(SNATIVECTRYNAME),
284         LOCALE_ENTRY(IDEFAULTLANGUAGE),
285         LOCALE_ENTRY(IDEFAULTCOUNTRY),
286         LOCALE_ENTRY(IDEFAULTCODEPAGE),
287         LOCALE_ENTRY(IDEFAULTANSICODEPAGE),
288         LOCALE_ENTRY(IDEFAULTMACCODEPAGE),
289         LOCALE_ENTRY(SLIST),
290         LOCALE_ENTRY(IMEASURE),
291         LOCALE_ENTRY(SDECIMAL),
292         LOCALE_ENTRY(STHOUSAND),
293         LOCALE_ENTRY(SGROUPING),
294         LOCALE_ENTRY(IDIGITS),
295         LOCALE_ENTRY(ILZERO),
296         LOCALE_ENTRY(INEGNUMBER),
297         LOCALE_ENTRY(SNATIVEDIGITS),
298         LOCALE_ENTRY(SCURRENCY),
299         LOCALE_ENTRY(SINTLSYMBOL),
300         LOCALE_ENTRY(SMONDECIMALSEP),
301         LOCALE_ENTRY(SMONTHOUSANDSEP),
302         LOCALE_ENTRY(SMONGROUPING),
303         LOCALE_ENTRY(ICURRDIGITS),
304         LOCALE_ENTRY(IINTLCURRDIGITS),
305         LOCALE_ENTRY(ICURRENCY),
306         LOCALE_ENTRY(INEGCURR),
307         LOCALE_ENTRY(SDATE),
308         LOCALE_ENTRY(STIME),
309         LOCALE_ENTRY(SSHORTDATE),
310         LOCALE_ENTRY(SLONGDATE),
311         LOCALE_ENTRY(STIMEFORMAT),
312         LOCALE_ENTRY(IDATE),
313         LOCALE_ENTRY(ILDATE),
314         LOCALE_ENTRY(ITIME),
315         LOCALE_ENTRY(ITIMEMARKPOSN),
316         LOCALE_ENTRY(ICENTURY),
317         LOCALE_ENTRY(ITLZERO),
318         LOCALE_ENTRY(IDAYLZERO),
319         LOCALE_ENTRY(IMONLZERO),
320         LOCALE_ENTRY(S1159),
321         LOCALE_ENTRY(S2359),
322         LOCALE_ENTRY(ICALENDARTYPE),
323         LOCALE_ENTRY(IOPTIONALCALENDAR),
324         LOCALE_ENTRY(IFIRSTDAYOFWEEK),
325         LOCALE_ENTRY(IFIRSTWEEKOFYEAR),
326         LOCALE_ENTRY(SDAYNAME1),
327         LOCALE_ENTRY(SDAYNAME2),
328         LOCALE_ENTRY(SDAYNAME3),
329         LOCALE_ENTRY(SDAYNAME4),
330         LOCALE_ENTRY(SDAYNAME5),
331         LOCALE_ENTRY(SDAYNAME6),
332         LOCALE_ENTRY(SDAYNAME7),
333         LOCALE_ENTRY(SABBREVDAYNAME1),
334         LOCALE_ENTRY(SABBREVDAYNAME2),
335         LOCALE_ENTRY(SABBREVDAYNAME3),
336         LOCALE_ENTRY(SABBREVDAYNAME4),
337         LOCALE_ENTRY(SABBREVDAYNAME5),
338         LOCALE_ENTRY(SABBREVDAYNAME6),
339         LOCALE_ENTRY(SABBREVDAYNAME7),
340         LOCALE_ENTRY(SMONTHNAME1),
341         LOCALE_ENTRY(SMONTHNAME2),
342         LOCALE_ENTRY(SMONTHNAME3),
343         LOCALE_ENTRY(SMONTHNAME4),
344         LOCALE_ENTRY(SMONTHNAME5),
345         LOCALE_ENTRY(SMONTHNAME6),
346         LOCALE_ENTRY(SMONTHNAME7),
347         LOCALE_ENTRY(SMONTHNAME8),
348         LOCALE_ENTRY(SMONTHNAME9),
349         LOCALE_ENTRY(SMONTHNAME10),
350         LOCALE_ENTRY(SMONTHNAME11),
351         LOCALE_ENTRY(SMONTHNAME12),
352         LOCALE_ENTRY(SMONTHNAME13),
353         LOCALE_ENTRY(SABBREVMONTHNAME1),
354         LOCALE_ENTRY(SABBREVMONTHNAME2),
355         LOCALE_ENTRY(SABBREVMONTHNAME3),
356         LOCALE_ENTRY(SABBREVMONTHNAME4),
357         LOCALE_ENTRY(SABBREVMONTHNAME5),
358         LOCALE_ENTRY(SABBREVMONTHNAME6),
359         LOCALE_ENTRY(SABBREVMONTHNAME7),
360         LOCALE_ENTRY(SABBREVMONTHNAME8),
361         LOCALE_ENTRY(SABBREVMONTHNAME9),
362         LOCALE_ENTRY(SABBREVMONTHNAME10),
363         LOCALE_ENTRY(SABBREVMONTHNAME11),
364         LOCALE_ENTRY(SABBREVMONTHNAME12),
365         LOCALE_ENTRY(SABBREVMONTHNAME13),
366         LOCALE_ENTRY(SPOSITIVESIGN),
367         LOCALE_ENTRY(SNEGATIVESIGN),
368         LOCALE_ENTRY(IPOSSIGNPOSN),
369         LOCALE_ENTRY(INEGSIGNPOSN),
370         LOCALE_ENTRY(IPOSSYMPRECEDES),
371         LOCALE_ENTRY(IPOSSEPBYSPACE),
372         LOCALE_ENTRY(INEGSYMPRECEDES),
373         LOCALE_ENTRY(INEGSEPBYSPACE),
374         LOCALE_ENTRY(FONTSIGNATURE),
375         LOCALE_ENTRY(SISO639LANGNAME),
376         LOCALE_ENTRY(SISO3166CTRYNAME),
377         {NULL,0},
378 };
379
380 const struct map_lcid2str {
381         LCID            langid;
382         const char      *langname;
383 } languages[]={
384         {0x0401,"Arabic (Saudi Arabia)"},
385         {0x0801,"Arabic (Iraq)"},
386         {0x0c01,"Arabic (Egypt)"},
387         {0x1001,"Arabic (Libya)"},
388         {0x1401,"Arabic (Algeria)"},
389         {0x1801,"Arabic (Morocco)"},
390         {0x1c01,"Arabic (Tunisia)"},
391         {0x2001,"Arabic (Oman)"},
392         {0x2401,"Arabic (Yemen)"},
393         {0x2801,"Arabic (Syria)"},
394         {0x2c01,"Arabic (Jordan)"},
395         {0x3001,"Arabic (Lebanon)"},
396         {0x3401,"Arabic (Kuwait)"},
397         {0x3801,"Arabic (United Arab Emirates)"},
398         {0x3c01,"Arabic (Bahrain)"},
399         {0x4001,"Arabic (Qatar)"},
400         {0x0402,"Bulgarian"},
401         {0x0403,"Catalan"},
402         {0x0404,"Chinese (Taiwan)"},
403         {0x0804,"Chinese (People's Republic of China)"},
404         {0x0c04,"Chinese (Hong Kong)"},
405         {0x1004,"Chinese (Singapore)"},
406         {0x1404,"Chinese (Macau)"},
407         {0x0405,"Czech"},
408         {0x0406,"Danish"},
409         {0x0407,"German (Germany)"},
410         {0x0807,"German (Switzerland)"},
411         {0x0c07,"German (Austria)"},
412         {0x1007,"German (Luxembourg)"},
413         {0x1407,"German (Liechtenstein)"},
414         {0x0408,"Greek"},
415         {0x0409,"English (United States)"},
416         {0x0809,"English (United Kingdom)"},
417         {0x0c09,"English (Australia)"},
418         {0x1009,"English (Canada)"},
419         {0x1409,"English (New Zealand)"},
420         {0x1809,"English (Ireland)"},
421         {0x1c09,"English (South Africa)"},
422         {0x2009,"English (Jamaica)"},
423         {0x2409,"English (Caribbean)"},
424         {0x2809,"English (Belize)"},
425         {0x2c09,"English (Trinidad)"},
426         {0x3009,"English (Zimbabwe)"},
427         {0x3409,"English (Philippines)"},
428         {0x040a,"Spanish (Spain, traditional sorting)"},
429         {0x080a,"Spanish (Mexico)"},
430         {0x0c0a,"Spanish (Spain, international sorting)"},
431         {0x100a,"Spanish (Guatemala)"},
432         {0x140a,"Spanish (Costa Rica)"},
433         {0x180a,"Spanish (Panama)"},
434         {0x1c0a,"Spanish (Dominican Republic)"},
435         {0x200a,"Spanish (Venezuela)"},
436         {0x240a,"Spanish (Colombia)"},
437         {0x280a,"Spanish (Peru)"},
438         {0x2c0a,"Spanish (Argentina)"},
439         {0x300a,"Spanish (Ecuador)"},
440         {0x340a,"Spanish (Chile)"},
441         {0x380a,"Spanish (Uruguay)"},
442         {0x3c0a,"Spanish (Paraguay)"},
443         {0x400a,"Spanish (Bolivia)"},
444         {0x440a,"Spanish (El Salvador)"},
445         {0x480a,"Spanish (Honduras)"},
446         {0x4c0a,"Spanish (Nicaragua)"},
447         {0x500a,"Spanish (Puerto Rico)"},
448         {0x040b,"Finnish"},
449         {0x040c,"French (France)"},
450         {0x080c,"French (Belgium)"},
451         {0x0c0c,"French (Canada)"},
452         {0x100c,"French (Switzerland)"},
453         {0x140c,"French (Luxembourg)"},
454         {0x180c,"French (Monaco)"},
455         {0x040d,"Hebrew"},
456         {0x040e,"Hungarian"},
457         {0x040f,"Icelandic"},
458         {0x0410,"Italian (Italy)"},
459         {0x0810,"Italian (Switzerland)"},
460         {0x0411,"Japanese"},
461         {0x0412,"Korean (Wansung)"},
462         {0x0812,"Korean (Johab)"},
463         {0x0413,"Dutch (Netherlands)"},
464         {0x0813,"Dutch (Belgium)"},
465         {0x0414,"Norwegian (Bokmal)"},
466         {0x0814,"Norwegian (Nynorsk)"},
467         {0x0415,"Polish"},
468         {0x0416,"Portuguese (Brazil)"},
469         {0x0816,"Portuguese (Portugal)"},
470         {0x0417,"Rhaeto Romanic"},
471         {0x0418,"Romanian"},
472         {0x0818,"Moldavian"},
473         {0x0419,"Russian (Russia)"},
474         {0x0819,"Russian (Moldavia)"},
475         {0x041a,"Croatian"},
476         {0x081a,"Serbian (latin)"},
477         {0x0c1a,"Serbian (cyrillic)"},
478         {0x041b,"Slovak"},
479         {0x041c,"Albanian"},
480         {0x041d,"Swedish (Sweden)"},
481         {0x081d,"Swedish (Finland)"},
482         {0x041e,"Thai"},
483         {0x041f,"Turkish"},
484         {0x0420,"Urdu"},
485         {0x0421,"Indonesian"},
486         {0x0422,"Ukrainian"},
487         {0x0423,"Belarusian"},
488         {0x0424,"Slovene"},
489         {0x0425,"Estonian"},
490         {0x0426,"Latvian"},
491         {0x0427,"Lithuanian (modern)"},
492         {0x0827,"Lithuanian (classic)"},
493         {0x0428,"Maori"},
494         {0x0429,"Farsi"},
495         {0x042a,"Vietnamese"},
496         {0x042b,"Armenian"},
497         {0x042c,"Azeri (latin)"},
498         {0x082c,"Azeri (cyrillic)"},
499         {0x042d,"Basque"},
500         {0x042e,"Sorbian"},
501         {0x042f,"Macedonian"},
502         {0x0430,"Sutu"},
503         {0x0431,"Tsonga"},
504         {0x0432,"Tswana"},
505         {0x0433,"Venda"},
506         {0x0434,"Xhosa"},
507         {0x0435,"Zulu"},
508         {0x0436,"Afrikaans"},
509         {0x0437,"Georgian"},
510         {0x0438,"Faeroese"},
511         {0x0439,"Hindi"},
512         {0x043a,"Maltese"},
513         {0x043b,"Saami"},
514         {0x043c,"Irish gaelic"},
515         {0x083c,"Scottish gaelic"},
516         {0x043e,"Malay (Malaysia)"},
517         {0x083e,"Malay (Brunei Darussalam)"},
518         {0x043f,"Kazak"},
519         {0x0441,"Swahili"},
520         {0x0443,"Uzbek (latin)"},
521         {0x0843,"Uzbek (cyrillic)"},
522         {0x0444,"Tatar"},
523         {0x0445,"Bengali"},
524         {0x0446,"Punjabi"},
525         {0x0447,"Gujarati"},
526         {0x0448,"Oriya"},
527         {0x0449,"Tamil"},
528         {0x044a,"Telugu"},
529         {0x044b,"Kannada"},
530         {0x044c,"Malayalam"},
531         {0x044d,"Assamese"},
532         {0x044e,"Marathi"},
533         {0x044f,"Sanskrit"},
534         {0x0457,"Konkani"},
535         {0x048f,"Esperanto"}, /* Non official */
536         {0x0490,"Walon"}, /* Non official */
537         {0x0000,"Unknown"}
538     }, languages_de[]={
539         {0x0401,"Arabic"},
540         {0x0402,"Bulgarisch"},
541         {0x0403,"Katalanisch"},
542         {0x0404,"Traditionales Chinesisch"},
543         {0x0405,"Tschecisch"},
544         {0x0406,"Dänisch"},
545         {0x0407,"Deutsch"},
546         {0x0408,"Griechisch"},
547         {0x0409,"Amerikanisches Englisch"},
548         {0x040A,"Kastilisches Spanisch"},
549         {0x040B,"Finnisch"},
550         {0x040C,"Franzvsisch"},
551         {0x040D,"Hebrdisch"},
552         {0x040E,"Ungarisch"},
553         {0x040F,"Isldndisch"},
554         {0x0410,"Italienisch"},
555         {0x0411,"Japanisch"},
556         {0x0412,"Koreanisch"},
557         {0x0413,"Niederldndisch"},
558         {0x0414,"Norwegisch-Bokmal"},
559         {0x0415,"Polnisch"},
560         {0x0416,"Brasilianisches Portugiesisch"},
561         {0x0417,"Rdtoromanisch"},
562         {0x0418,"Rumdnisch"},
563         {0x0419,"Russisch"},
564         {0x041A,"Kroatoserbisch (lateinisch)"},
565         {0x041B,"Slowenisch"},
566         {0x041C,"Albanisch"},
567         {0x041D,"Schwedisch"},
568         {0x041E,"Thai"},
569         {0x041F,"Türkisch"},
570         {0x0420,"Urdu"},
571         {0x0421,"Bahasa"},
572         {0x0804,"Vereinfachtes Chinesisch"},
573         {0x0807,"Schweizerdeutsch"},
574         {0x0809,"Britisches Englisch"},
575         {0x080A,"Mexikanisches Spanisch"},
576         {0x080C,"Belgisches Franzvsisch"},
577         {0x0810,"Schweizerisches Italienisch"},
578         {0x0813,"Belgisches Niederldndisch"},
579         {0x0814,"Norgwegisch-Nynorsk"},
580         {0x0816,"Portugiesisch"},
581         {0x081A,"Serbokratisch (kyrillisch)"},
582         {0x0C1C,"Kanadisches Franzvsisch"},
583         {0x100C,"Schweizerisches Franzvsisch"},
584         {0x0000,"Unbekannt"},
585 };
586
587 /***********************************************************************
588  *           GetUserDefaultLCID       (OLE2NLS.1)
589  */
590 LCID WINAPI GetUserDefaultLCID()
591 {
592         return MAKELCID( GetUserDefaultLangID() , SORT_DEFAULT );
593 }
594
595 /***********************************************************************
596  *         GetSystemDefaultLCID       (OLE2NLS.2)
597  */
598 LCID WINAPI GetSystemDefaultLCID()
599 {
600         return GetUserDefaultLCID();
601 }
602
603 /***********************************************************************
604  *         GetUserDefaultLangID       (OLE2NLS.3)
605  */
606 LANGID WINAPI GetUserDefaultLangID()
607 {
608         /* caching result, if defined from environment, which should (?) not change during a WINE session */
609         static  LANGID  userLCID = 0;
610         if (Options.language) {
611                 return Languages[Options.language].langid;
612         }
613
614         if (userLCID == 0) {
615                 char *buf=NULL;
616                 char *lang,*country,*charset,*dialect,*next;
617                 int     ret=0;
618                 
619                 buf=getenv("LANGUAGE");
620                 if (!buf) buf=getenv("LANG");
621                 if (!buf) buf=getenv("LC_ALL");
622                 if (!buf) buf=getenv("LC_MESSAGES");
623                 if (!buf) buf=getenv("LC_CTYPE");
624                 if (!buf) return userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT );
625                 
626                 if (!strcmp(buf,"POSIX") || !strcmp(buf,"C")) {
627                         return MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT );
628                 }
629                 
630                 lang=buf;
631                 
632                 do {
633                         next=strchr(lang,':'); if (next) *next++='\0';
634                         dialect=strchr(lang,'@'); if (dialect) *dialect++='\0';
635                         charset=strchr(lang,'.'); if (charset) *charset++='\0';
636                         country=strchr(lang,'_'); if (country) *country++='\0';
637                         
638                         ret=MAIN_GetLanguageID(lang, country, charset, dialect);
639                         
640                         lang=next;
641                         
642                 } while (lang && !ret);
643                 
644                 /* FIXME : are strings returned by getenv() to be free()'ed ? */
645                 userLCID = (LANGID)ret;
646         }
647         return userLCID;
648 }
649
650 /***********************************************************************
651  *         GetSystemDefaultLangID     (OLE2NLS.4)
652  */
653 LANGID WINAPI GetSystemDefaultLangID()
654 {
655         return GetUserDefaultLangID();
656 }
657
658 /******************************************************************************
659  *              GetLocaleInfo16 [OLE2NLS.5]
660  * Is the last parameter really WORD for Win16?
661  */
662 INT16 WINAPI GetLocaleInfo16(LCID lcid,LCTYPE LCType,LPSTR buf,INT16 len)
663 {
664         return GetLocaleInfoA(lcid,LCType,buf,len);
665 }
666 /******************************************************************************
667  * ConvertDefaultLocale32 [KERNEL32.147]
668  */
669 LCID WINAPI ConvertDefaultLocale32 (LCID lcid)
670 {       switch (lcid)
671         {  case LOCALE_SYSTEM_DEFAULT:
672              return GetSystemDefaultLCID();
673            case LOCALE_USER_DEFAULT:
674              return GetUserDefaultLCID();
675            case 0:
676              return MAKELCID (LANG_NEUTRAL, SUBLANG_NEUTRAL);
677         }  
678         return MAKELANGID( PRIMARYLANGID(lcid), SUBLANG_NEUTRAL);
679 }
680 /******************************************************************************
681  * GetLocaleInfo32A [KERNEL32.342]
682  *
683  * NOTES 
684  *  LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
685  *
686  *  MS online documentation states that the string returned is NULL terminated
687  *  except for LOCALE_FONTSIGNATURE  which "will return a non-NULL
688  *  terminated string".
689  */
690 INT WINAPI GetLocaleInfoA(LCID lcid,LCTYPE LCType,LPSTR buf,INT len)
691 {
692   LPCSTR  retString;
693         int     found,i;
694         int     lang=0;
695
696   TRACE("(lcid=0x%lx,lctype=0x%lx,%p,%x)\n",lcid,LCType,buf,len);
697
698   if (len && (! buf) ) {
699     SetLastError(ERROR_INSUFFICIENT_BUFFER);
700                 return 0;
701         }
702
703         if (lcid ==0 || lcid == LANG_SYSTEM_DEFAULT || (LCType & LOCALE_NOUSEROVERRIDE) )       /* 0x00, 0x400 */
704         {
705             lcid = GetSystemDefaultLCID();
706         } 
707         else if (lcid == LANG_USER_DEFAULT) /*0x800*/
708         {
709             lcid = GetUserDefaultLCID();
710         }
711         LCType &= ~(LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP);
712
713         /* As an option, we could obtain the value from win.ini.
714            This would not match the Wine compile-time option.
715            Also, not all identifiers are available from win.ini */
716         retString=0;
717         /* If we are through all of this, retLen should not be zero anymore.
718            If it is, the value is not supported */
719         i=0;
720         while (locale_name2id[i].name!=NULL) {
721                 if (LCType == locale_name2id[i].id) {
722                         retString = locale_name2id[i].name;
723                         break;
724                 }
725                 i++;
726         }
727         if (!retString) {
728       FIXME("Unkown LC type %lX\n",LCType);
729                 return 0;
730         }
731
732     found=0;lang=lcid;
733     for (i=0;(i<3 && !found);i++) {
734       int j;
735
736       for (j=0;j<sizeof(langlocales)/sizeof(langlocales[0]);j++) {
737         if (langlocales[j].lang == lang) {
738           int k;
739
740           for (k=0;k<sizeof(langlocales[j].locvars)/sizeof(langlocales[j].locvars[0]) && (langlocales[j].locvars[k].type);k++) {
741             if (langlocales[j].locvars[k].type == LCType) {
742               found = 1;
743               retString = langlocales[j].locvars[k].val;
744           break;
745             }
746           }
747           if (found)
748             break;
749         }
750       }
751           /* language not found, try without a sublanguage*/
752           if (i==1) lang=MAKELANGID( PRIMARYLANGID(lang), SUBLANG_DEFAULT);
753           /* mask the LC Value */
754           if (i==2) LCType &= 0xfff;
755     }
756
757     if(!found) {
758       ERR("'%s' not supported for your language (%04X).\n",
759                         retString,(WORD)lcid);
760                 SetLastError(ERROR_INVALID_PARAMETER);
761                 return 0;                       
762         }
763     /* a FONTSIGNATURE is not a string, just 6 DWORDs  */
764     if (LCType == LOCALE_FONTSIGNATURE) {
765         if (len)
766             memcpy(buf, retString, (len<=sizeof(FONTSIGNATURE))?len:sizeof(FONTSIGNATURE));
767         return sizeof(FONTSIGNATURE);
768     }
769     /* if len=0 return only the length, don't touch the buffer*/
770     if (len) lstrcpynA(buf,retString,len);
771     return strlen(retString)+1;
772 }
773
774 /******************************************************************************
775  *              GetLocaleInfo32W        [KERNEL32.343]
776  *
777  * NOTES
778  *  MS documentation states that len "specifies the size, in bytes (ANSI version)
779  *  or characters (Unicode version), of" wbuf. Thus the number returned is
780  *  the same between GetLocaleInfo32W and GetLocaleInfo32A.
781  */
782 INT WINAPI GetLocaleInfoW(LCID lcid,LCTYPE LCType,LPWSTR wbuf,INT len)
783 {       WORD wlen;
784         LPSTR abuf;
785         
786         if (len && (! wbuf) )
787         { SetLastError(ERROR_INSUFFICIENT_BUFFER);
788           return 0;
789         }
790
791         abuf = (LPSTR)HeapAlloc(GetProcessHeap(),0,len);
792         wlen = GetLocaleInfoA(lcid, LCType, abuf, len);
793
794         if (wlen && len)        /* if len=0 return only the length*/
795           lstrcpynAtoW(wbuf,abuf,len);
796
797         HeapFree(GetProcessHeap(),0,abuf);
798         return wlen;
799 }
800
801 /******************************************************************************
802  *              SetLocaleInfoA  [KERNEL32.656]
803  */
804 BOOL16 WINAPI SetLocaleInfoA(DWORD lcid, DWORD lctype, LPCSTR data)
805 {
806     FIXME("(%ld,%ld,%s): stub\n",lcid,lctype,data);
807     return TRUE;
808 }
809
810 /******************************************************************************
811  *              IsValidLocale   [KERNEL32.489]
812  */
813 BOOL WINAPI IsValidLocale(LCID lcid,DWORD flags)
814 {
815         /* we support ANY language. Well, at least say that...*/
816         return TRUE;
817 }
818
819 /******************************************************************************
820  *              EnumSystemLocales32W    [KERNEL32.209]
821  */
822 BOOL WINAPI EnumSystemLocalesW( LOCALE_ENUMPROCW lpfnLocaleEnum,
823                                     DWORD flags )
824 {
825         int     i;
826         BOOL    ret;
827         WCHAR   buffer[200];
828         HKEY    xhkey;
829
830         TRACE_(win32)("(%p,%08lx)\n",lpfnLocaleEnum,flags );
831         /* see if we can reuse the Win95 registry entries.... */
832         if (ERROR_SUCCESS==RegOpenKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\control\\Nls\\Locale\\",&xhkey)) {
833                 i=0;
834                 while (1) {
835                         if (ERROR_SUCCESS!=RegEnumKeyW(xhkey,i,buffer,sizeof(buffer)))
836                                 break;
837                         if (!lpfnLocaleEnum(buffer))
838                                 break;
839                         i++;
840                 }
841                 RegCloseKey(xhkey);
842                 return TRUE;
843         }
844
845         i=0;
846         while (languages[i].langid!=0)
847         {
848             LPWSTR cp;
849             char   xbuffer[10];
850         
851             sprintf(xbuffer,"%08lx",(DWORD)languages[i].langid);
852
853             cp = HEAP_strdupAtoW( GetProcessHeap(), 0, xbuffer );
854             ret = lpfnLocaleEnum(cp);
855             HeapFree( GetProcessHeap(), 0, cp );
856             if (!ret) break;
857             i++;
858         }
859         return TRUE;
860 }
861
862 /******************************************************************************
863  *              EnumSystemLocales32A    [KERNEL32.208]
864  */
865 BOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpfnLocaleEnum,
866                                    DWORD flags)
867 {
868         int     i;
869         CHAR    buffer[200];
870         HKEY    xhkey;
871
872         TRACE_(win32)("(%p,%08lx)\n",
873                 lpfnLocaleEnum,flags
874         );
875
876         if ( ERROR_SUCCESS==RegOpenKeyA(HKEY_LOCAL_MACHINE,
877                     "System\\CurrentControlSet\\Control\\Nls\\Locale\\",
878                     &xhkey)) {
879             i=0;
880             while (1) {
881                 DWORD size=sizeof(buffer);
882                 if (ERROR_SUCCESS!=RegEnumValueA(xhkey,i,buffer,&size,NULL,
883                             NULL, NULL,NULL))
884                     break;
885                 if (size && !lpfnLocaleEnum(buffer))
886                     break;
887                 i++;
888             }
889             RegCloseKey(xhkey);
890             return TRUE;
891         }
892         i=0;
893         while (languages[i].langid!=0) {
894                 sprintf(buffer,"%08lx",(DWORD)languages[i].langid);
895                 if (!lpfnLocaleEnum(buffer))
896                         break;
897                 i++;
898         }
899         return TRUE;
900 }
901
902 static const unsigned char CT_CType2_LUT[] = {
903   C2_NOTAPPLICABLE, /*   -   0 */
904   C2_NOTAPPLICABLE, /*   -   1 */
905   C2_NOTAPPLICABLE, /*   -   2 */
906   C2_NOTAPPLICABLE, /*   -   3 */
907   C2_NOTAPPLICABLE, /*   -   4 */
908   C2_NOTAPPLICABLE, /*   -   5 */
909   C2_NOTAPPLICABLE, /*   -   6 */
910   C2_NOTAPPLICABLE, /*   -   7 */
911   C2_NOTAPPLICABLE, /*   -   8 */
912   C2_SEGMENTSEPARATOR, /*   -   9 */
913   C2_NOTAPPLICABLE, /*   -  10 */
914   C2_NOTAPPLICABLE, /*   -  11 */
915   C2_NOTAPPLICABLE, /*   -  12 */
916   C2_NOTAPPLICABLE, /*   -  13 */
917   C2_NOTAPPLICABLE, /*   -  14 */
918   C2_NOTAPPLICABLE, /*   -  15 */
919   C2_NOTAPPLICABLE, /*   -  16 */
920   C2_NOTAPPLICABLE, /*   -  17 */
921   C2_NOTAPPLICABLE, /*   -  18 */
922   C2_NOTAPPLICABLE, /*   -  19 */
923   C2_NOTAPPLICABLE, /*   -  20 */
924   C2_NOTAPPLICABLE, /*   -  21 */
925   C2_NOTAPPLICABLE, /*   -  22 */
926   C2_NOTAPPLICABLE, /*   -  23 */
927   C2_NOTAPPLICABLE, /*   -  24 */
928   C2_NOTAPPLICABLE, /*   -  25 */
929   C2_NOTAPPLICABLE, /*   -  26 */
930   C2_NOTAPPLICABLE, /*   -  27 */
931   C2_NOTAPPLICABLE, /*   -  28 */
932   C2_NOTAPPLICABLE, /*   -  29 */
933   C2_NOTAPPLICABLE, /*   -  30 */
934   C2_NOTAPPLICABLE, /*   -  31 */
935   C2_WHITESPACE, /*   -  32 */
936   C2_OTHERNEUTRAL, /* ! -  33 */
937   C2_OTHERNEUTRAL, /* " -  34 */ /* " */
938   C2_EUROPETERMINATOR, /* # -  35 */
939   C2_EUROPETERMINATOR, /* $ -  36 */
940   C2_EUROPETERMINATOR, /* % -  37 */
941   C2_LEFTTORIGHT, /* & -  38 */
942   C2_OTHERNEUTRAL, /* ' -  39 */
943   C2_OTHERNEUTRAL, /* ( -  40 */
944   C2_OTHERNEUTRAL, /* ) -  41 */
945   C2_OTHERNEUTRAL, /* * -  42 */
946   C2_EUROPETERMINATOR, /* + -  43 */
947   C2_COMMONSEPARATOR, /* , -  44 */
948   C2_EUROPETERMINATOR, /* - -  45 */
949   C2_EUROPESEPARATOR, /* . -  46 */
950   C2_EUROPESEPARATOR, /* / -  47 */
951   C2_EUROPENUMBER, /* 0 -  48 */
952   C2_EUROPENUMBER, /* 1 -  49 */
953   C2_EUROPENUMBER, /* 2 -  50 */
954   C2_EUROPENUMBER, /* 3 -  51 */
955   C2_EUROPENUMBER, /* 4 -  52 */
956   C2_EUROPENUMBER, /* 5 -  53 */
957   C2_EUROPENUMBER, /* 6 -  54 */
958   C2_EUROPENUMBER, /* 7 -  55 */
959   C2_EUROPENUMBER, /* 8 -  56 */
960   C2_EUROPENUMBER, /* 9 -  57 */
961   C2_COMMONSEPARATOR, /* : -  58 */
962   C2_OTHERNEUTRAL, /* ; -  59 */
963   C2_OTHERNEUTRAL, /* < -  60 */
964   C2_OTHERNEUTRAL, /* = -  61 */
965   C2_OTHERNEUTRAL, /* > -  62 */
966   C2_OTHERNEUTRAL, /* ? -  63 */
967   C2_LEFTTORIGHT, /* @ -  64 */
968   C2_LEFTTORIGHT, /* A -  65 */
969   C2_LEFTTORIGHT, /* B -  66 */
970   C2_LEFTTORIGHT, /* C -  67 */
971   C2_LEFTTORIGHT, /* D -  68 */
972   C2_LEFTTORIGHT, /* E -  69 */
973   C2_LEFTTORIGHT, /* F -  70 */
974   C2_LEFTTORIGHT, /* G -  71 */
975   C2_LEFTTORIGHT, /* H -  72 */
976   C2_LEFTTORIGHT, /* I -  73 */
977   C2_LEFTTORIGHT, /* J -  74 */
978   C2_LEFTTORIGHT, /* K -  75 */
979   C2_LEFTTORIGHT, /* L -  76 */
980   C2_LEFTTORIGHT, /* M -  77 */
981   C2_LEFTTORIGHT, /* N -  78 */
982   C2_LEFTTORIGHT, /* O -  79 */
983   C2_LEFTTORIGHT, /* P -  80 */
984   C2_LEFTTORIGHT, /* Q -  81 */
985   C2_LEFTTORIGHT, /* R -  82 */
986   C2_LEFTTORIGHT, /* S -  83 */
987   C2_LEFTTORIGHT, /* T -  84 */
988   C2_LEFTTORIGHT, /* U -  85 */
989   C2_LEFTTORIGHT, /* V -  86 */
990   C2_LEFTTORIGHT, /* W -  87 */
991   C2_LEFTTORIGHT, /* X -  88 */
992   C2_LEFTTORIGHT, /* Y -  89 */
993   C2_LEFTTORIGHT, /* Z -  90 */
994   C2_OTHERNEUTRAL, /* [ -  91 */
995   C2_OTHERNEUTRAL, /* \ -  92 */
996   C2_OTHERNEUTRAL, /* ] -  93 */
997   C2_OTHERNEUTRAL, /* ^ -  94 */
998   C2_OTHERNEUTRAL, /* _ -  95 */
999   C2_OTHERNEUTRAL, /* ` -  96 */
1000   C2_LEFTTORIGHT, /* a -  97 */
1001   C2_LEFTTORIGHT, /* b -  98 */
1002   C2_LEFTTORIGHT, /* c -  99 */
1003   C2_LEFTTORIGHT, /* d - 100 */
1004   C2_LEFTTORIGHT, /* e - 101 */
1005   C2_LEFTTORIGHT, /* f - 102 */
1006   C2_LEFTTORIGHT, /* g - 103 */
1007   C2_LEFTTORIGHT, /* h - 104 */
1008   C2_LEFTTORIGHT, /* i - 105 */
1009   C2_LEFTTORIGHT, /* j - 106 */
1010   C2_LEFTTORIGHT, /* k - 107 */
1011   C2_LEFTTORIGHT, /* l - 108 */
1012   C2_LEFTTORIGHT, /* m - 109 */
1013   C2_LEFTTORIGHT, /* n - 110 */
1014   C2_LEFTTORIGHT, /* o - 111 */
1015   C2_LEFTTORIGHT, /* p - 112 */
1016   C2_LEFTTORIGHT, /* q - 113 */
1017   C2_LEFTTORIGHT, /* r - 114 */
1018   C2_LEFTTORIGHT, /* s - 115 */
1019   C2_LEFTTORIGHT, /* t - 116 */
1020   C2_LEFTTORIGHT, /* u - 117 */
1021   C2_LEFTTORIGHT, /* v - 118 */
1022   C2_LEFTTORIGHT, /* w - 119 */
1023   C2_LEFTTORIGHT, /* x - 120 */
1024   C2_LEFTTORIGHT, /* y - 121 */
1025   C2_LEFTTORIGHT, /* z - 122 */
1026   C2_OTHERNEUTRAL, /* { - 123 */
1027   C2_OTHERNEUTRAL, /* | - 124 */
1028   C2_OTHERNEUTRAL, /* } - 125 */
1029   C2_OTHERNEUTRAL, /* ~ - 126 */
1030   C2_NOTAPPLICABLE, /* \7f - 127 */
1031   C2_NOTAPPLICABLE, /* \80 - 128 */
1032   C2_NOTAPPLICABLE, /* \81 - 129 */
1033   C2_OTHERNEUTRAL, /* \82 - 130 */
1034   C2_LEFTTORIGHT, /* \83 - 131 */
1035   C2_OTHERNEUTRAL, /* \84 - 132 */
1036   C2_OTHERNEUTRAL, /* \85 - 133 */
1037   C2_OTHERNEUTRAL, /* \86 - 134 */
1038   C2_OTHERNEUTRAL, /* \87 - 135 */
1039   C2_LEFTTORIGHT, /* \88 - 136 */
1040   C2_EUROPETERMINATOR, /* \89 - 137 */
1041   C2_LEFTTORIGHT, /* \8a - 138 */
1042   C2_OTHERNEUTRAL, /* \8b - 139 */
1043   C2_LEFTTORIGHT, /* \8c - 140 */
1044   C2_NOTAPPLICABLE, /* \8d - 141 */
1045   C2_NOTAPPLICABLE, /* \8e - 142 */
1046   C2_NOTAPPLICABLE, /* \8f - 143 */
1047   C2_NOTAPPLICABLE, /* \90 - 144 */
1048   C2_OTHERNEUTRAL, /* \91 - 145 */
1049   C2_OTHERNEUTRAL, /* \92 - 146 */
1050   C2_OTHERNEUTRAL, /* \93 - 147 */
1051   C2_OTHERNEUTRAL, /* \94 - 148 */
1052   C2_OTHERNEUTRAL, /* \95 - 149 */
1053   C2_OTHERNEUTRAL, /* \96 - 150 */
1054   C2_OTHERNEUTRAL, /* \97 - 151 */
1055   C2_LEFTTORIGHT, /* \98 - 152 */
1056   C2_OTHERNEUTRAL, /* \99 - 153 */
1057   C2_LEFTTORIGHT, /* \9a - 154 */
1058   C2_OTHERNEUTRAL, /* \9b - 155 */
1059   C2_LEFTTORIGHT, /* \9c - 156 */
1060   C2_NOTAPPLICABLE, /* \9d - 157 */
1061   C2_NOTAPPLICABLE, /* \9e - 158 */
1062   C2_LEFTTORIGHT, /* \9f - 159 */
1063   C2_WHITESPACE, /*   - 160 */
1064   C2_OTHERNEUTRAL, /* ¡ - 161 */
1065   C2_EUROPETERMINATOR, /* ¢ - 162 */
1066   C2_EUROPETERMINATOR, /* £ - 163 */
1067   C2_EUROPETERMINATOR, /* ¤ - 164 */
1068   C2_EUROPETERMINATOR, /* ¥ - 165 */
1069   C2_OTHERNEUTRAL, /* ¦ - 166 */
1070   C2_OTHERNEUTRAL, /* § - 167 */
1071   C2_OTHERNEUTRAL, /* ¨ - 168 */
1072   C2_OTHERNEUTRAL, /* © - 169 */
1073   C2_OTHERNEUTRAL, /* ª - 170 */
1074   C2_OTHERNEUTRAL, /* « - 171 */
1075   C2_OTHERNEUTRAL, /* ¬ - 172 */
1076   C2_OTHERNEUTRAL, /* ­ - 173 */
1077   C2_OTHERNEUTRAL, /* ® - 174 */
1078   C2_OTHERNEUTRAL, /* ¯ - 175 */
1079   C2_EUROPETERMINATOR, /* ° - 176 */
1080   C2_EUROPETERMINATOR, /* ± - 177 */
1081   C2_EUROPENUMBER, /* ² - 178 */
1082   C2_EUROPENUMBER, /* ³ - 179 */
1083   C2_OTHERNEUTRAL, /* ´ - 180 */
1084   C2_OTHERNEUTRAL, /* µ - 181 */
1085   C2_OTHERNEUTRAL, /* ¶ - 182 */
1086   C2_OTHERNEUTRAL, /* · - 183 */
1087   C2_OTHERNEUTRAL, /* ¸ - 184 */
1088   C2_EUROPENUMBER, /* ¹ - 185 */
1089   C2_OTHERNEUTRAL, /* º - 186 */
1090   C2_OTHERNEUTRAL, /* » - 187 */
1091   C2_OTHERNEUTRAL, /* ¼ - 188 */
1092   C2_OTHERNEUTRAL, /* ½ - 189 */
1093   C2_OTHERNEUTRAL, /* ¾ - 190 */
1094   C2_OTHERNEUTRAL, /* ¿ - 191 */
1095   C2_LEFTTORIGHT, /* À - 192 */
1096   C2_LEFTTORIGHT, /* Á - 193 */
1097   C2_LEFTTORIGHT, /* Â - 194 */
1098   C2_LEFTTORIGHT, /* Ã - 195 */
1099   C2_LEFTTORIGHT, /* Ä - 196 */
1100   C2_LEFTTORIGHT, /* Å - 197 */
1101   C2_LEFTTORIGHT, /* Æ - 198 */
1102   C2_LEFTTORIGHT, /* Ç - 199 */
1103   C2_LEFTTORIGHT, /* È - 200 */
1104   C2_LEFTTORIGHT, /* É - 201 */
1105   C2_LEFTTORIGHT, /* Ê - 202 */
1106   C2_LEFTTORIGHT, /* Ë - 203 */
1107   C2_LEFTTORIGHT, /* Ì - 204 */
1108   C2_LEFTTORIGHT, /* Í - 205 */
1109   C2_LEFTTORIGHT, /* Î - 206 */
1110   C2_LEFTTORIGHT, /* Ï - 207 */
1111   C2_LEFTTORIGHT, /* Ð - 208 */
1112   C2_LEFTTORIGHT, /* Ñ - 209 */
1113   C2_LEFTTORIGHT, /* Ò - 210 */
1114   C2_LEFTTORIGHT, /* Ó - 211 */
1115   C2_LEFTTORIGHT, /* Ô - 212 */
1116   C2_LEFTTORIGHT, /* Õ - 213 */
1117   C2_LEFTTORIGHT, /* Ö - 214 */
1118   C2_OTHERNEUTRAL, /* × - 215 */
1119   C2_LEFTTORIGHT, /* Ø - 216 */
1120   C2_LEFTTORIGHT, /* Ù - 217 */
1121   C2_LEFTTORIGHT, /* Ú - 218 */
1122   C2_LEFTTORIGHT, /* Û - 219 */
1123   C2_LEFTTORIGHT, /* Ü - 220 */
1124   C2_LEFTTORIGHT, /* Ý - 221 */
1125   C2_LEFTTORIGHT, /* Þ - 222 */
1126   C2_LEFTTORIGHT, /* ß - 223 */
1127   C2_LEFTTORIGHT, /* à - 224 */
1128   C2_LEFTTORIGHT, /* á - 225 */
1129   C2_LEFTTORIGHT, /* â - 226 */
1130   C2_LEFTTORIGHT, /* ã - 227 */
1131   C2_LEFTTORIGHT, /* ä - 228 */
1132   C2_LEFTTORIGHT, /* å - 229 */
1133   C2_LEFTTORIGHT, /* æ - 230 */
1134   C2_LEFTTORIGHT, /* ç - 231 */
1135   C2_LEFTTORIGHT, /* è - 232 */
1136   C2_LEFTTORIGHT, /* é - 233 */
1137   C2_LEFTTORIGHT, /* ê - 234 */
1138   C2_LEFTTORIGHT, /* ë - 235 */
1139   C2_LEFTTORIGHT, /* ì - 236 */
1140   C2_LEFTTORIGHT, /* í - 237 */
1141   C2_LEFTTORIGHT, /* î - 238 */
1142   C2_LEFTTORIGHT, /* ï - 239 */
1143   C2_LEFTTORIGHT, /* ð - 240 */
1144   C2_LEFTTORIGHT, /* ñ - 241 */
1145   C2_LEFTTORIGHT, /* ò - 242 */
1146   C2_LEFTTORIGHT, /* ó - 243 */
1147   C2_LEFTTORIGHT, /* ô - 244 */
1148   C2_LEFTTORIGHT, /* õ - 245 */
1149   C2_LEFTTORIGHT, /* ö - 246 */
1150   C2_OTHERNEUTRAL, /* ÷ - 247 */
1151   C2_LEFTTORIGHT, /* ø - 248 */
1152   C2_LEFTTORIGHT, /* ù - 249 */
1153   C2_LEFTTORIGHT, /* ú - 250 */
1154   C2_LEFTTORIGHT, /* û - 251 */
1155   C2_LEFTTORIGHT, /* ü - 252 */
1156   C2_LEFTTORIGHT, /* ý - 253 */
1157   C2_LEFTTORIGHT, /* þ - 254 */
1158   C2_LEFTTORIGHT /* ÿ - 255 */
1159 };
1160
1161 const WORD OLE2NLS_CT_CType3_LUT[] = { 
1162   0x0000, /*   -   0 */
1163   0x0000, /*   -   1 */
1164   0x0000, /*   -   2 */
1165   0x0000, /*   -   3 */
1166   0x0000, /*   -   4 */
1167   0x0000, /*   -   5 */
1168   0x0000, /*   -   6 */
1169   0x0000, /*   -   7 */
1170   0x0000, /*   -   8 */
1171   0x0008, /*   -   9 */
1172   0x0008, /*   -  10 */
1173   0x0008, /*   -  11 */
1174   0x0008, /*   -  12 */
1175   0x0008, /*   -  13 */
1176   0x0000, /*   -  14 */
1177   0x0000, /*   -  15 */
1178   0x0000, /*   -  16 */
1179   0x0000, /*   -  17 */
1180   0x0000, /*   -  18 */
1181   0x0000, /*   -  19 */
1182   0x0000, /*   -  20 */
1183   0x0000, /*   -  21 */
1184   0x0000, /*   -  22 */
1185   0x0000, /*   -  23 */
1186   0x0000, /*   -  24 */
1187   0x0000, /*   -  25 */
1188   0x0000, /*   -  26 */
1189   0x0000, /*   -  27 */
1190   0x0000, /*   -  28 */
1191   0x0000, /*   -  29 */
1192   0x0000, /*   -  30 */
1193   0x0000, /*   -  31 */
1194   0x0048, /*   -  32 */
1195   0x0048, /* ! -  33 */
1196   0x0448, /* " -  34 */ /* " */
1197   0x0048, /* # -  35 */
1198   0x0448, /* $ -  36 */
1199   0x0048, /* % -  37 */
1200   0x0048, /* & -  38 */
1201   0x0440, /* ' -  39 */
1202   0x0048, /* ( -  40 */
1203   0x0048, /* ) -  41 */
1204   0x0048, /* * -  42 */
1205   0x0048, /* + -  43 */
1206   0x0048, /* , -  44 */
1207   0x0440, /* - -  45 */
1208   0x0048, /* . -  46 */
1209   0x0448, /* / -  47 */
1210   0x0040, /* 0 -  48 */
1211   0x0040, /* 1 -  49 */
1212   0x0040, /* 2 -  50 */
1213   0x0040, /* 3 -  51 */
1214   0x0040, /* 4 -  52 */
1215   0x0040, /* 5 -  53 */
1216   0x0040, /* 6 -  54 */
1217   0x0040, /* 7 -  55 */
1218   0x0040, /* 8 -  56 */
1219   0x0040, /* 9 -  57 */
1220   0x0048, /* : -  58 */
1221   0x0048, /* ; -  59 */
1222   0x0048, /* < -  60 */
1223   0x0448, /* = -  61 */
1224   0x0048, /* > -  62 */
1225   0x0048, /* ? -  63 */
1226   0x0448, /* @ -  64 */
1227   0x8040, /* A -  65 */
1228   0x8040, /* B -  66 */
1229   0x8040, /* C -  67 */
1230   0x8040, /* D -  68 */
1231   0x8040, /* E -  69 */
1232   0x8040, /* F -  70 */
1233   0x8040, /* G -  71 */
1234   0x8040, /* H -  72 */
1235   0x8040, /* I -  73 */
1236   0x8040, /* J -  74 */
1237   0x8040, /* K -  75 */
1238   0x8040, /* L -  76 */
1239   0x8040, /* M -  77 */
1240   0x8040, /* N -  78 */
1241   0x8040, /* O -  79 */
1242   0x8040, /* P -  80 */
1243   0x8040, /* Q -  81 */
1244   0x8040, /* R -  82 */
1245   0x8040, /* S -  83 */
1246   0x8040, /* T -  84 */
1247   0x8040, /* U -  85 */
1248   0x8040, /* V -  86 */
1249   0x8040, /* W -  87 */
1250   0x8040, /* X -  88 */
1251   0x8040, /* Y -  89 */
1252   0x8040, /* Z -  90 */
1253   0x0048, /* [ -  91 */
1254   0x0448, /* \ -  92 */
1255   0x0048, /* ] -  93 */
1256   0x0448, /* ^ -  94 */
1257   0x0448, /* _ -  95 */
1258   0x0448, /* ` -  96 */
1259   0x8040, /* a -  97 */
1260   0x8040, /* b -  98 */
1261   0x8040, /* c -  99 */
1262   0x8040, /* d - 100 */
1263   0x8040, /* e - 101 */
1264   0x8040, /* f - 102 */
1265   0x8040, /* g - 103 */
1266   0x8040, /* h - 104 */
1267   0x8040, /* i - 105 */
1268   0x8040, /* j - 106 */
1269   0x8040, /* k - 107 */
1270   0x8040, /* l - 108 */
1271   0x8040, /* m - 109 */
1272   0x8040, /* n - 110 */
1273   0x8040, /* o - 111 */
1274   0x8040, /* p - 112 */
1275   0x8040, /* q - 113 */
1276   0x8040, /* r - 114 */
1277   0x8040, /* s - 115 */
1278   0x8040, /* t - 116 */
1279   0x8040, /* u - 117 */
1280   0x8040, /* v - 118 */
1281   0x8040, /* w - 119 */
1282   0x8040, /* x - 120 */
1283   0x8040, /* y - 121 */
1284   0x8040, /* z - 122 */
1285   0x0048, /* { - 123 */
1286   0x0048, /* | - 124 */
1287   0x0048, /* } - 125 */
1288   0x0448, /* ~ - 126 */
1289   0x0000, /* \7f - 127 */
1290   0x0000, /* \80 - 128 */
1291   0x0000, /* \81 - 129 */
1292   0x0008, /* \82 - 130 */
1293   0x8000, /* \83 - 131 */
1294   0x0008, /* \84 - 132 */
1295   0x0008, /* \85 - 133 */
1296   0x0008, /* \86 - 134 */
1297   0x0008, /* \87 - 135 */
1298   0x0001, /* \88 - 136 */
1299   0x0008, /* \89 - 137 */
1300   0x8003, /* \8a - 138 */
1301   0x0008, /* \8b - 139 */
1302   0x8000, /* \8c - 140 */
1303   0x0000, /* \8d - 141 */
1304   0x0000, /* \8e - 142 */
1305   0x0000, /* \8f - 143 */
1306   0x0000, /* \90 - 144 */
1307   0x0088, /* \91 - 145 */
1308   0x0088, /* \92 - 146 */
1309   0x0088, /* \93 - 147 */
1310   0x0088, /* \94 - 148 */
1311   0x0008, /* \95 - 149 */
1312   0x0400, /* \96 - 150 */
1313   0x0400, /* \97 - 151 */
1314   0x0408, /* \98 - 152 */
1315   0x0000, /* \99 - 153 */
1316   0x8003, /* \9a - 154 */
1317   0x0008, /* \9b - 155 */
1318   0x8000, /* \9c - 156 */
1319   0x0000, /* \9d - 157 */
1320   0x0000, /* \9e - 158 */
1321   0x8003, /* \9f - 159 */
1322   0x0008, /*   - 160 */
1323   0x0008, /* ¡ - 161 */
1324   0x0048, /* ¢ - 162 */
1325   0x0048, /* £ - 163 */
1326   0x0008, /* ¤ - 164 */
1327   0x0048, /* ¥ - 165 */
1328   0x0048, /* ¦ - 166 */
1329   0x0008, /* § - 167 */
1330   0x0408, /* ¨ - 168 */
1331   0x0008, /* © - 169 */
1332   0x0400, /* ª - 170 */
1333   0x0008, /* « - 171 */
1334   0x0048, /* ¬ - 172 */
1335   0x0408, /* ­ - 173 */
1336   0x0008, /* ® - 174 */
1337   0x0448, /* ¯ - 175 */
1338   0x0008, /* ° - 176 */
1339   0x0008, /* ± - 177 */
1340   0x0000, /* ² - 178 */
1341   0x0000, /* ³ - 179 */
1342   0x0408, /* ´ - 180 */
1343   0x0008, /* µ - 181 */
1344   0x0008, /* ¶ - 182 */
1345   0x0008, /* · - 183 */
1346   0x0408, /* ¸ - 184 */
1347   0x0000, /* ¹ - 185 */
1348   0x0400, /* º - 186 */
1349   0x0008, /* » - 187 */
1350   0x0000, /* ¼ - 188 */
1351   0x0000, /* ½ - 189 */
1352   0x0000, /* ¾ - 190 */
1353   0x0008, /* ¿ - 191 */
1354   0x8003, /* À - 192 */
1355   0x8003, /* Á - 193 */
1356   0x8003, /* Â - 194 */
1357   0x8003, /* Ã - 195 */
1358   0x8003, /* Ä - 196 */
1359   0x8003, /* Å - 197 */
1360   0x8000, /* Æ - 198 */
1361   0x8003, /* Ç - 199 */
1362   0x8003, /* È - 200 */
1363   0x8003, /* É - 201 */
1364   0x8003, /* Ê - 202 */
1365   0x8003, /* Ë - 203 */
1366   0x8003, /* Ì - 204 */
1367   0x8003, /* Í - 205 */
1368   0x8003, /* Î - 206 */
1369   0x8003, /* Ï - 207 */
1370   0x8000, /* Ð - 208 */
1371   0x8003, /* Ñ - 209 */
1372   0x8003, /* Ò - 210 */
1373   0x8003, /* Ó - 211 */
1374   0x8003, /* Ô - 212 */
1375   0x8003, /* Õ - 213 */
1376   0x8003, /* Ö - 214 */
1377   0x0008, /* × - 215 */
1378   0x8003, /* Ø - 216 */
1379   0x8003, /* Ù - 217 */
1380   0x8003, /* Ú - 218 */
1381   0x8003, /* Û - 219 */
1382   0x8003, /* Ü - 220 */
1383   0x8003, /* Ý - 221 */
1384   0x8000, /* Þ - 222 */
1385   0x8000, /* ß - 223 */
1386   0x8003, /* à - 224 */
1387   0x8003, /* á - 225 */
1388   0x8003, /* â - 226 */
1389   0x8003, /* ã - 227 */
1390   0x8003, /* ä - 228 */
1391   0x8003, /* å - 229 */
1392   0x8000, /* æ - 230 */
1393   0x8003, /* ç - 231 */
1394   0x8003, /* è - 232 */
1395   0x8003, /* é - 233 */
1396   0x8003, /* ê - 234 */
1397   0x8003, /* ë - 235 */
1398   0x8003, /* ì - 236 */
1399   0x8003, /* í - 237 */
1400   0x8003, /* î - 238 */
1401   0x8003, /* ï - 239 */
1402   0x8000, /* ð - 240 */
1403   0x8003, /* ñ - 241 */
1404   0x8003, /* ò - 242 */
1405   0x8003, /* ó - 243 */
1406   0x8003, /* ô - 244 */
1407   0x8003, /* õ - 245 */
1408   0x8003, /* ö - 246 */
1409   0x0008, /* ÷ - 247 */
1410   0x8003, /* ø - 248 */
1411   0x8003, /* ù - 249 */
1412   0x8003, /* ú - 250 */
1413   0x8003, /* û - 251 */
1414   0x8003, /* ü - 252 */
1415   0x8003, /* ý - 253 */
1416   0x8000, /* þ - 254 */
1417   0x8003  /* ÿ - 255 */
1418 };
1419
1420 /******************************************************************************
1421  *              GetStringType16 [OLE2NLS.7]
1422  */
1423 BOOL16 WINAPI GetStringType16(LCID locale,DWORD dwInfoType,LPCSTR src,
1424                               INT16 cchSrc,LPWORD chartype)
1425 {
1426         return GetStringTypeExA(locale,dwInfoType,src,cchSrc,chartype);
1427 }
1428 /******************************************************************************
1429  *              GetStringType32A        [KERNEL32.396]
1430  */
1431 BOOL WINAPI GetStringTypeA(LCID locale,DWORD dwInfoType,LPCSTR src,
1432                                INT cchSrc,LPWORD chartype)
1433 {
1434         return GetStringTypeExA(locale,dwInfoType,src,cchSrc,chartype);
1435 }
1436
1437 /******************************************************************************
1438  *              GetStringTypeEx32A      [KERNEL32.397]
1439  *
1440  * FIXME: Ignores the locale.
1441  */
1442 BOOL WINAPI GetStringTypeExA(LCID locale,DWORD dwInfoType,LPCSTR src,
1443                                  INT cchSrc,LPWORD chartype)
1444 {
1445         int     i;
1446         
1447         if ((src==NULL) || (chartype==NULL) || (src==(LPSTR)chartype))
1448         {
1449           SetLastError(ERROR_INVALID_PARAMETER);
1450           return FALSE;
1451         }
1452
1453         if (cchSrc==-1)
1454           cchSrc=lstrlenA(src)+1;
1455           
1456         switch (dwInfoType) {
1457         case CT_CTYPE1:
1458           for (i=0;i<cchSrc;i++) 
1459           {
1460             chartype[i] = 0;
1461             if (isdigit(src[i])) chartype[i]|=C1_DIGIT;
1462             if (isalpha(src[i])) chartype[i]|=C1_ALPHA;
1463             if (islower(src[i])) chartype[i]|=C1_LOWER;
1464             if (isupper(src[i])) chartype[i]|=C1_UPPER;
1465             if (isspace(src[i])) chartype[i]|=C1_SPACE;
1466             if (ispunct(src[i])) chartype[i]|=C1_PUNCT;
1467             if (iscntrl(src[i])) chartype[i]|=C1_CNTRL;
1468 /* FIXME: isblank() is a GNU extension */
1469 /*              if (isblank(src[i])) chartype[i]|=C1_BLANK; */
1470             if ((src[i] == ' ') || (src[i] == '\t')) chartype[i]|=C1_BLANK;
1471             /* C1_XDIGIT */
1472         }
1473         return TRUE;
1474
1475         case CT_CTYPE2:
1476           for (i=0;i<cchSrc;i++) 
1477           {
1478             chartype[i]=(WORD)CT_CType2_LUT[i];
1479           }
1480           return TRUE;
1481
1482         case CT_CTYPE3:
1483           for (i=0;i<cchSrc;i++) 
1484           {
1485             chartype[i]=OLE2NLS_CT_CType3_LUT[i];
1486           }
1487           return TRUE;
1488
1489         default:
1490           ERR("Unknown dwInfoType:%ld\n",dwInfoType);
1491           return FALSE;
1492         }
1493 }
1494
1495 /******************************************************************************
1496  *              GetStringType32W        [KERNEL32.399]
1497  *
1498  * NOTES
1499  * Yes, this is missing LCID locale. MS fault.
1500  */
1501 BOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR src,INT cchSrc,
1502                                LPWORD chartype)
1503 {
1504         return GetStringTypeExW(0/*defaultlocale*/,dwInfoType,src,cchSrc,chartype);
1505 }
1506
1507 /******************************************************************************
1508  *              GetStringTypeEx32W      [KERNEL32.398]
1509  *
1510  * FIXME: unicode chars are assumed chars
1511  */
1512 BOOL WINAPI GetStringTypeExW(LCID locale,DWORD dwInfoType,LPCWSTR src,
1513                                  INT cchSrc,LPWORD chartype)
1514 {
1515         int     i;
1516
1517
1518         if (cchSrc==-1)
1519           cchSrc=lstrlenW(src)+1;
1520         
1521         switch (dwInfoType) {
1522         case CT_CTYPE2:
1523                 FIXME("CT_CTYPE2 not supported.\n");
1524                 return FALSE;
1525         case CT_CTYPE3:
1526                 FIXME("CT_CTYPE3 not supported.\n");
1527                 return FALSE;
1528         default:break;
1529         }
1530         for (i=0;i<cchSrc;i++) {
1531                 chartype[i] = 0;
1532                 if (isdigit(src[i])) chartype[i]|=C1_DIGIT;
1533                 if (isalpha(src[i])) chartype[i]|=C1_ALPHA;
1534                 if (islower(src[i])) chartype[i]|=C1_LOWER;
1535                 if (isupper(src[i])) chartype[i]|=C1_UPPER;
1536                 if (isspace(src[i])) chartype[i]|=C1_SPACE;
1537                 if (ispunct(src[i])) chartype[i]|=C1_PUNCT;
1538                 if (iscntrl(src[i])) chartype[i]|=C1_CNTRL;
1539 /* FIXME: isblank() is a GNU extension */
1540 /*              if (isblank(src[i])) chartype[i]|=C1_BLANK; */
1541                 if ((src[i] == ' ') || (src[i] == '\t')) chartype[i]|=C1_BLANK;
1542                 /* C1_XDIGIT */
1543         }
1544         return TRUE;
1545 }
1546
1547 /*****************************************************************
1548  * WINE_GetLanguageName   [internal] 
1549  */
1550 static LPCSTR WINE_GetLanguageName( UINT langid )
1551 {
1552     int i;
1553     for ( i = 0; languages[i].langid != 0; i++ )
1554         if ( langid == languages[i].langid )
1555             break;
1556
1557     return languages[i].langname;
1558 }
1559
1560 /***********************************************************************
1561  *           VerLanguageNameA              [KERNEL32.709][VERSION.9]
1562  */
1563 DWORD WINAPI VerLanguageNameA( UINT wLang, LPSTR szLang, UINT nSize )
1564 {
1565     char    buffer[80];
1566     LPCSTR  name;
1567     DWORD   result;
1568
1569     /*
1570      * First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
1571      * from the registry.
1572      */
1573
1574     sprintf( buffer,
1575              "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",
1576              wLang );
1577
1578     result = RegQueryValueA( HKEY_LOCAL_MACHINE, buffer, szLang, (LPDWORD)&nSize );
1579     if ( result == ERROR_SUCCESS || result == ERROR_MORE_DATA )
1580         return nSize;
1581
1582     /*
1583      * If that fails, use the internal table
1584      */
1585
1586     name = WINE_GetLanguageName( wLang );
1587     lstrcpynA( szLang, name, nSize );
1588     return lstrlenA( name );
1589 }
1590
1591 /***********************************************************************
1592  *           VerLanguageNameW              [KERNEL32.710][VERSION.10]
1593  */
1594 DWORD WINAPI VerLanguageNameW( UINT wLang, LPWSTR szLang, UINT nSize )
1595 {
1596     char    buffer[80];
1597     LPWSTR  keyname;
1598     LPCSTR  name;
1599     DWORD   result;
1600
1601     /*
1602      * First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
1603      * from the registry.
1604      */
1605
1606     sprintf( buffer,
1607              "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",
1608              wLang );
1609
1610     keyname = HEAP_strdupAtoW( GetProcessHeap(), 0, buffer );
1611     result = RegQueryValueW( HKEY_LOCAL_MACHINE, keyname, szLang, (LPDWORD)&nSize );
1612     HeapFree( GetProcessHeap(), 0, keyname );
1613
1614     if ( result == ERROR_SUCCESS || result == ERROR_MORE_DATA )
1615         return nSize;
1616
1617     /*
1618      * If that fails, use the internal table
1619      */
1620
1621     name = WINE_GetLanguageName( wLang );
1622     lstrcpynAtoW( szLang, name, nSize );
1623     return lstrlenA( name );
1624 }
1625
1626  
1627 static const unsigned char LCM_Unicode_LUT[] = {
1628   6      ,   3, /*   -   1 */  
1629   6      ,   4, /*   -   2 */  
1630   6      ,   5, /*   -   3 */  
1631   6      ,   6, /*   -   4 */  
1632   6      ,   7, /*   -   5 */  
1633   6      ,   8, /*   -   6 */  
1634   6      ,   9, /*   -   7 */  
1635   6      ,  10, /*   -   8 */  
1636   7      ,   5, /*   -   9 */  
1637   7      ,   6, /*   -  10 */  
1638   7      ,   7, /*   -  11 */  
1639   7      ,   8, /*   -  12 */  
1640   7      ,   9, /*   -  13 */  
1641   6      ,  11, /*   -  14 */  
1642   6      ,  12, /*   -  15 */  
1643   6      ,  13, /*   -  16 */  
1644   6      ,  14, /*   -  17 */  
1645   6      ,  15, /*   -  18 */  
1646   6      ,  16, /*   -  19 */  
1647   6      ,  17, /*   -  20 */  
1648   6      ,  18, /*   -  21 */  
1649   6      ,  19, /*   -  22 */  
1650   6      ,  20, /*   -  23 */  
1651   6      ,  21, /*   -  24 */  
1652   6      ,  22, /*   -  25 */  
1653   6      ,  23, /*   -  26 */  
1654   6      ,  24, /*   -  27 */  
1655   6      ,  25, /*   -  28 */  
1656   6      ,  26, /*   -  29 */  
1657   6      ,  27, /*   -  30 */  
1658   6      ,  28, /*   -  31 */  
1659   7      ,   2, /*   -  32 */
1660   7      ,  28, /* ! -  33 */
1661   7      ,  29, /* " -  34 */ /* " */
1662   7      ,  31, /* # -  35 */
1663   7      ,  33, /* $ -  36 */
1664   7      ,  35, /* % -  37 */
1665   7      ,  37, /* & -  38 */
1666   6      , 128, /* ' -  39 */
1667   7      ,  39, /* ( -  40 */
1668   7      ,  42, /* ) -  41 */
1669   7      ,  45, /* * -  42 */
1670   8      ,   3, /* + -  43 */
1671   7      ,  47, /* , -  44 */
1672   6      , 130, /* - -  45 */
1673   7      ,  51, /* . -  46 */
1674   7      ,  53, /* / -  47 */
1675  12      ,   3, /* 0 -  48 */
1676  12      ,  33, /* 1 -  49 */
1677  12      ,  51, /* 2 -  50 */
1678  12      ,  70, /* 3 -  51 */
1679  12      ,  88, /* 4 -  52 */
1680  12      , 106, /* 5 -  53 */
1681  12      , 125, /* 6 -  54 */
1682  12      , 144, /* 7 -  55 */
1683  12      , 162, /* 8 -  56 */
1684  12      , 180, /* 9 -  57 */
1685   7      ,  55, /* : -  58 */
1686   7      ,  58, /* ; -  59 */
1687   8      ,  14, /* < -  60 */
1688   8      ,  18, /* = -  61 */
1689   8      ,  20, /* > -  62 */
1690   7      ,  60, /* ? -  63 */
1691   7      ,  62, /* @ -  64 */
1692  14      ,   2, /* A -  65 */
1693  14      ,   9, /* B -  66 */
1694  14      ,  10, /* C -  67 */
1695  14      ,  26, /* D -  68 */
1696  14      ,  33, /* E -  69 */
1697  14      ,  35, /* F -  70 */
1698  14      ,  37, /* G -  71 */
1699  14      ,  44, /* H -  72 */
1700  14      ,  50, /* I -  73 */
1701  14      ,  53, /* J -  74 */
1702  14      ,  54, /* K -  75 */
1703  14      ,  72, /* L -  76 */
1704  14      ,  81, /* M -  77 */
1705  14      , 112, /* N -  78 */
1706  14      , 124, /* O -  79 */
1707  14      , 126, /* P -  80 */
1708  14      , 137, /* Q -  81 */
1709  14      , 138, /* R -  82 */
1710  14      , 145, /* S -  83 */
1711  14      , 153, /* T -  84 */
1712  14      , 159, /* U -  85 */
1713  14      , 162, /* V -  86 */
1714  14      , 164, /* W -  87 */
1715  14      , 166, /* X -  88 */
1716  14      , 167, /* Y -  89 */
1717  14      , 169, /* Z -  90 */
1718   7      ,  63, /* [ -  91 */
1719   7      ,  65, /* \ -  92 */
1720   7      ,  66, /* ] -  93 */
1721   7      ,  67, /* ^ -  94 */
1722   7      ,  68, /* _ -  95 */
1723   7      ,  72, /* ` -  96 */
1724  14      ,   2, /* a -  97 */
1725  14      ,   9, /* b -  98 */
1726  14      ,  10, /* c -  99 */
1727  14      ,  26, /* d - 100 */
1728  14      ,  33, /* e - 101 */
1729  14      ,  35, /* f - 102 */
1730  14      ,  37, /* g - 103 */
1731  14      ,  44, /* h - 104 */
1732  14      ,  50, /* i - 105 */
1733  14      ,  53, /* j - 106 */
1734  14      ,  54, /* k - 107 */
1735  14      ,  72, /* l - 108 */
1736  14      ,  81, /* m - 109 */
1737  14      , 112, /* n - 110 */
1738  14      , 124, /* o - 111 */
1739  14      , 126, /* p - 112 */
1740  14      , 137, /* q - 113 */
1741  14      , 138, /* r - 114 */
1742  14      , 145, /* s - 115 */
1743  14      , 153, /* t - 116 */
1744  14      , 159, /* u - 117 */
1745  14      , 162, /* v - 118 */
1746  14      , 164, /* w - 119 */
1747  14      , 166, /* x - 120 */
1748  14      , 167, /* y - 121 */
1749  14      , 169, /* z - 122 */
1750   7      ,  74, /* { - 123 */
1751   7      ,  76, /* | - 124 */
1752   7      ,  78, /* } - 125 */
1753   7      ,  80, /* ~ - 126 */
1754   6      ,  29, /* \7f - 127 */
1755   6      ,  30, /* \80 - 128 */
1756   6      ,  31, /* \81 - 129 */
1757   7      , 123, /* \82 - 130 */
1758  14      ,  35, /* \83 - 131 */
1759   7      , 127, /* \84 - 132 */
1760  10      ,  21, /* \85 - 133 */
1761  10      ,  15, /* \86 - 134 */
1762  10      ,  16, /* \87 - 135 */
1763   7      ,  67, /* \88 - 136 */
1764  10      ,  22, /* \89 - 137 */
1765  14      , 145, /* \8a - 138 */
1766   7      , 136, /* \8b - 139 */
1767  14 + 16 , 124, /* \8c - 140 */
1768   6      ,  43, /* \8d - 141 */
1769   6      ,  44, /* \8e - 142 */
1770   6      ,  45, /* \8f - 143 */
1771   6      ,  46, /* \90 - 144 */
1772   7      , 121, /* \91 - 145 */
1773   7      , 122, /* \92 - 146 */
1774   7      , 125, /* \93 - 147 */
1775   7      , 126, /* \94 - 148 */
1776  10      ,  17, /* \95 - 149 */
1777   6      , 137, /* \96 - 150 */
1778   6      , 139, /* \97 - 151 */
1779   7      ,  93, /* \98 - 152 */
1780  14      , 156, /* \99 - 153 */
1781  14      , 145, /* \9a - 154 */
1782   7      , 137, /* \9b - 155 */
1783  14 + 16 , 124, /* \9c - 156 */
1784   6      ,  59, /* \9d - 157 */
1785   6      ,  60, /* \9e - 158 */
1786  14      , 167, /* \9f - 159 */
1787   7      ,   4, /*   - 160 */
1788   7      ,  81, /* ¡ - 161 */
1789  10      ,   2, /* ¢ - 162 */
1790  10      ,   3, /* £ - 163 */
1791  10      ,   4, /* ¤ - 164 */
1792  10      ,   5, /* ¥ - 165 */
1793   7      ,  82, /* ¦ - 166 */
1794  10      ,   6, /* § - 167 */
1795   7      ,  83, /* ¨ - 168 */
1796  10      ,   7, /* © - 169 */
1797  14      ,   2, /* ª - 170 */
1798   8      ,  24, /* « - 171 */
1799  10      ,   8, /* ¬ - 172 */
1800   6      , 131, /* ­ - 173 */
1801  10      ,   9, /* ® - 174 */
1802   7      ,  84, /* ¯ - 175 */
1803  10      ,  10, /* ° - 176 */
1804   8      ,  23, /* ± - 177 */
1805  12      ,  51, /* ² - 178 */
1806  12      ,  70, /* ³ - 179 */
1807   7      ,  85, /* ´ - 180 */
1808  10      ,  11, /* µ - 181 */
1809  10      ,  12, /* ¶ - 182 */
1810  10      ,  13, /* · - 183 */
1811   7      ,  86, /* ¸ - 184 */
1812  12      ,  33, /* ¹ - 185 */
1813  14      , 124, /* º - 186 */
1814   8      ,  26, /* » - 187 */
1815  12      ,  21, /* ¼ - 188 */
1816  12      ,  25, /* ½ - 189 */
1817  12      ,  29, /* ¾ - 190 */
1818   7      ,  87, /* ¿ - 191 */
1819  14      ,   2, /* À - 192 */
1820  14      ,   2, /* Á - 193 */
1821  14      ,   2, /* Â - 194 */
1822  14      ,   2, /* Ã - 195 */
1823  14      ,   2, /* Ä - 196 */
1824  14      ,   2, /* Å - 197 */
1825  14 + 16 ,   2, /* Æ - 198 */
1826  14      ,  10, /* Ç - 199 */
1827  14      ,  33, /* È - 200 */
1828  14      ,  33, /* É - 201 */
1829  14      ,  33, /* Ê - 202 */
1830  14      ,  33, /* Ë - 203 */
1831  14      ,  50, /* Ì - 204 */
1832  14      ,  50, /* Í - 205 */
1833  14      ,  50, /* Î - 206 */
1834  14      ,  50, /* Ï - 207 */
1835  14      ,  26, /* Ð - 208 */
1836  14      , 112, /* Ñ - 209 */
1837  14      , 124, /* Ò - 210 */
1838  14      , 124, /* Ó - 211 */
1839  14      , 124, /* Ô - 212 */
1840  14      , 124, /* Õ - 213 */
1841  14      , 124, /* Ö - 214 */
1842   8      ,  28, /* × - 215 */
1843  14      , 124, /* Ø - 216 */
1844  14      , 159, /* Ù - 217 */
1845  14      , 159, /* Ú - 218 */
1846  14      , 159, /* Û - 219 */
1847  14      , 159, /* Ü - 220 */
1848  14      , 167, /* Ý - 221 */
1849  14 + 32 , 153, /* Þ - 222 */
1850  14 + 48 , 145, /* ß - 223 */
1851  14      ,   2, /* à - 224 */
1852  14      ,   2, /* á - 225 */
1853  14      ,   2, /* â - 226 */
1854  14      ,   2, /* ã - 227 */
1855  14      ,   2, /* ä - 228 */
1856  14      ,   2, /* å - 229 */
1857  14 + 16 ,   2, /* æ - 230 */
1858  14      ,  10, /* ç - 231 */
1859  14      ,  33, /* è - 232 */
1860  14      ,  33, /* é - 233 */
1861  14      ,  33, /* ê - 234 */
1862  14      ,  33, /* ë - 235 */
1863  14      ,  50, /* ì - 236 */
1864  14      ,  50, /* í - 237 */
1865  14      ,  50, /* î - 238 */
1866  14      ,  50, /* ï - 239 */
1867  14      ,  26, /* ð - 240 */
1868  14      , 112, /* ñ - 241 */
1869  14      , 124, /* ò - 242 */
1870  14      , 124, /* ó - 243 */
1871  14      , 124, /* ô - 244 */
1872  14      , 124, /* õ - 245 */
1873  14      , 124, /* ö - 246 */
1874   8      ,  29, /* ÷ - 247 */
1875  14      , 124, /* ø - 248 */
1876  14      , 159, /* ù - 249 */
1877  14      , 159, /* ú - 250 */
1878  14      , 159, /* û - 251 */
1879  14      , 159, /* ü - 252 */
1880  14      , 167, /* ý - 253 */
1881  14 + 32 , 153, /* þ - 254 */
1882  14      , 167  /* ÿ - 255 */ };
1883
1884 static const unsigned char LCM_Unicode_LUT_2[] = { 33, 44, 145 };
1885
1886 #define LCM_Diacritic_Start 131
1887
1888 static const unsigned char LCM_Diacritic_LUT[] = { 
1889 123,  /* \83 - 131 */
1890   2,  /* \84 - 132 */
1891   2,  /* \85 - 133 */
1892   2,  /* \86 - 134 */
1893   2,  /* \87 - 135 */
1894   3,  /* \88 - 136 */
1895   2,  /* \89 - 137 */
1896  20,  /* \8a - 138 */
1897   2,  /* \8b - 139 */
1898   2,  /* \8c - 140 */
1899   2,  /* \8d - 141 */
1900   2,  /* \8e - 142 */
1901   2,  /* \8f - 143 */
1902   2,  /* \90 - 144 */
1903   2,  /* \91 - 145 */
1904   2,  /* \92 - 146 */
1905   2,  /* \93 - 147 */
1906   2,  /* \94 - 148 */
1907   2,  /* \95 - 149 */
1908   2,  /* \96 - 150 */
1909   2,  /* \97 - 151 */
1910   2,  /* \98 - 152 */
1911   2,  /* \99 - 153 */
1912  20,  /* \9a - 154 */
1913   2,  /* \9b - 155 */
1914   2,  /* \9c - 156 */
1915   2,  /* \9d - 157 */
1916   2,  /* \9e - 158 */
1917  19,  /* \9f - 159 */
1918   2,  /*   - 160 */
1919   2,  /* ¡ - 161 */
1920   2,  /* ¢ - 162 */
1921   2,  /* £ - 163 */
1922   2,  /* ¤ - 164 */
1923   2,  /* ¥ - 165 */
1924   2,  /* ¦ - 166 */
1925   2,  /* § - 167 */
1926   2,  /* ¨ - 168 */
1927   2,  /* © - 169 */
1928   3,  /* ª - 170 */
1929   2,  /* « - 171 */
1930   2,  /* ¬ - 172 */
1931   2,  /* ­ - 173 */
1932   2,  /* ® - 174 */
1933   2,  /* ¯ - 175 */
1934   2,  /* ° - 176 */
1935   2,  /* ± - 177 */
1936   2,  /* ² - 178 */
1937   2,  /* ³ - 179 */
1938   2,  /* ´ - 180 */
1939   2,  /* µ - 181 */
1940   2,  /* ¶ - 182 */
1941   2,  /* · - 183 */
1942   2,  /* ¸ - 184 */
1943   2,  /* ¹ - 185 */
1944   3,  /* º - 186 */
1945   2,  /* » - 187 */
1946   2,  /* ¼ - 188 */
1947   2,  /* ½ - 189 */
1948   2,  /* ¾ - 190 */
1949   2,  /* ¿ - 191 */
1950  15,  /* À - 192 */
1951  14,  /* Á - 193 */
1952  18,  /* Â - 194 */
1953  25,  /* Ã - 195 */
1954  19,  /* Ä - 196 */
1955  26,  /* Å - 197 */
1956   2,  /* Æ - 198 */
1957  28,  /* Ç - 199 */
1958  15,  /* È - 200 */
1959  14,  /* É - 201 */
1960  18,  /* Ê - 202 */
1961  19,  /* Ë - 203 */
1962  15,  /* Ì - 204 */
1963  14,  /* Í - 205 */
1964  18,  /* Î - 206 */
1965  19,  /* Ï - 207 */
1966 104,  /* Ð - 208 */
1967  25,  /* Ñ - 209 */
1968  15,  /* Ò - 210 */
1969  14,  /* Ó - 211 */
1970  18,  /* Ô - 212 */
1971  25,  /* Õ - 213 */
1972  19,  /* Ö - 214 */
1973   2,  /* × - 215 */
1974  33,  /* Ø - 216 */
1975  15,  /* Ù - 217 */
1976  14,  /* Ú - 218 */
1977  18,  /* Û - 219 */
1978  19,  /* Ü - 220 */
1979  14,  /* Ý - 221 */
1980   2,  /* Þ - 222 */
1981   2,  /* ß - 223 */
1982  15,  /* à - 224 */
1983  14,  /* á - 225 */
1984  18,  /* â - 226 */
1985  25,  /* ã - 227 */
1986  19,  /* ä - 228 */
1987  26,  /* å - 229 */
1988   2,  /* æ - 230 */
1989  28,  /* ç - 231 */
1990  15,  /* è - 232 */
1991  14,  /* é - 233 */
1992  18,  /* ê - 234 */
1993  19,  /* ë - 235 */
1994  15,  /* ì - 236 */
1995  14,  /* í - 237 */
1996  18,  /* î - 238 */
1997  19,  /* ï - 239 */
1998 104,  /* ð - 240 */
1999  25,  /* ñ - 241 */
2000  15,  /* ò - 242 */
2001  14,  /* ó - 243 */
2002  18,  /* ô - 244 */
2003  25,  /* õ - 245 */
2004  19,  /* ö - 246 */
2005   2,  /* ÷ - 247 */
2006  33,  /* ø - 248 */
2007  15,  /* ù - 249 */
2008  14,  /* ú - 250 */
2009  18,  /* û - 251 */
2010  19,  /* ü - 252 */
2011  14,  /* ý - 253 */
2012   2,  /* þ - 254 */
2013  19,  /* ÿ - 255 */
2014 } ;
2015
2016 /******************************************************************************
2017  * OLE2NLS_isPunctuation [INTERNAL]
2018  */
2019 static int OLE2NLS_isPunctuation(unsigned char c) 
2020 {
2021   /* "punctuation character" in this context is a character which is 
2022      considered "less important" during word sort comparison.
2023      See LCMapString implementation for the precise definition 
2024      of "less important". */
2025
2026   return (LCM_Unicode_LUT[-2+2*c]==6);
2027 }
2028
2029 /******************************************************************************
2030  * OLE2NLS_isNonSpacing [INTERNAL]
2031  */
2032 static int OLE2NLS_isNonSpacing(unsigned char c) 
2033 {
2034   /* This function is used by LCMapString32A.  Characters 
2035      for which it returns true are ignored when mapping a
2036      string with NORM_IGNORENONSPACE */
2037   return ((c==136) || (c==170) || (c==186));
2038 }
2039
2040 /******************************************************************************
2041  * OLE2NLS_isSymbol [INTERNAL]
2042  */
2043 static int OLE2NLS_isSymbol(unsigned char c) 
2044 {
2045   /* This function is used by LCMapString32A.  Characters 
2046      for which it returns true are ignored when mapping a
2047      string with NORM_IGNORESYMBOLS */
2048   return ( (c!=0) && !IsCharAlphaNumericA(c) );
2049 }
2050
2051 /******************************************************************************
2052  *              identity        [Internal]
2053  */
2054 static int identity(int c)
2055 {
2056   return c;
2057 }
2058
2059 /*************************************************************************
2060  *              LCMapString32A                [KERNEL32.492]
2061  *
2062  * Convert a string, or generate a sort key from it.
2063  *
2064  * If (mapflags & LCMAP_SORTKEY), the function will generate
2065  * a sort key for the source string.  Else, it will convert it
2066  * accordingly to the flags LCMAP_UPPERCASE, LCMAP_LOWERCASE,...
2067  *
2068  * RETURNS
2069  *    Error : 0.
2070  *    Success : length of the result string.
2071  *
2072  * NOTES
2073  *    If called with scrlen = -1, the function will compute the length
2074  *      of the 0-terminated string strsrc by itself.      
2075  * 
2076  *    If called with dstlen = 0, returns the buffer length that 
2077  *      would be required.
2078  *
2079  *    NORM_IGNOREWIDTH means to compare ASCII and wide characters
2080  *    as if they are equal.  
2081  *    In the only code page implemented so far, there may not be
2082  *    wide characters in strings passed to LCMapString32A,
2083  *    so there is nothing to be done for this flag.
2084  */
2085 INT WINAPI LCMapStringA(
2086         LCID lcid /* locale identifier created with MAKELCID; 
2087                      LOCALE_SYSTEM_DEFAULT and LOCALE_USER_DEFAULT are 
2088                      predefined values. */,
2089         DWORD mapflags /* flags */,
2090         LPCSTR srcstr  /* source buffer */,
2091         INT srclen   /* source length */,
2092         LPSTR dststr   /* destination buffer */,
2093         INT dstlen   /* destination buffer length */) 
2094 {
2095   int i;
2096
2097   TRACE_(string)("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
2098         lcid,mapflags,srcstr,srclen,dststr,dstlen);
2099
2100   if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
2101   {
2102     ERR("(src=%s,dest=%s): Invalid NULL string\n", srcstr, dststr);
2103     SetLastError(ERROR_INVALID_PARAMETER);
2104     return 0;
2105   }
2106   if (srclen == -1) 
2107     srclen = lstrlenA(srcstr) + 1 ;    /* (include final '\0') */
2108
2109 #define LCMAPSTRINGA_SUPPORTED_FLAGS (LCMAP_UPPERCASE     | \
2110                                         LCMAP_LOWERCASE     | \
2111                                         LCMAP_SORTKEY       | \
2112                                         NORM_IGNORECASE     | \
2113                                         NORM_IGNORENONSPACE | \
2114                                         SORT_STRINGSORT     | \
2115                                         NORM_IGNOREWIDTH    | \
2116                                         NORM_IGNOREKANATYPE)
2117   /* FIXME: as long as we don't support Kanakana nor Hirigana 
2118    * characters, we can support NORM_IGNOREKANATYPE
2119    */
2120   if (mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS)
2121   {
2122     FIXME_(string)("(0x%04lx,0x%08lx,%p,%d,%p,%d): "
2123           "unimplemented flags: 0x%08lx\n",
2124           lcid,
2125           mapflags,
2126           srcstr,
2127           srclen,
2128           dststr,
2129           dstlen,
2130           mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS
2131      );
2132   }
2133
2134   if ( !(mapflags & LCMAP_SORTKEY) )
2135   {
2136     int i,j;
2137     int (*f)(int) = identity; 
2138     int flag_ignorenonspace = mapflags & NORM_IGNORENONSPACE;
2139     int flag_ignoresymbols = mapflags & NORM_IGNORESYMBOLS;
2140
2141     if (flag_ignorenonspace || flag_ignoresymbols)
2142     {
2143       /* For some values of mapflags, the length of the resulting 
2144          string is not known at this point.  Windows does map the string
2145          and does not SetLastError ERROR_INSUFFICIENT_BUFFER in
2146          these cases. */
2147       if (dstlen==0)
2148       {
2149         /* Compute required length */
2150         for (i=j=0; i < srclen; i++)
2151         {
2152           if ( !(flag_ignorenonspace && OLE2NLS_isNonSpacing(srcstr[i]))
2153                && !(flag_ignoresymbols && OLE2NLS_isSymbol(srcstr[i])) )
2154             j++;
2155         }
2156         return j;
2157       }
2158     }
2159     else
2160     {
2161       if (dstlen==0)
2162         return srclen;  
2163       if (dstlen<srclen) 
2164            {
2165              SetLastError(ERROR_INSUFFICIENT_BUFFER);
2166              return 0;
2167            }
2168     }
2169     if (mapflags & LCMAP_UPPERCASE)
2170       f = toupper;
2171     else if (mapflags & LCMAP_LOWERCASE)
2172       f = tolower;
2173     /* FIXME: NORM_IGNORENONSPACE requires another conversion */
2174     for (i=j=0; (i<srclen) && (j<dstlen) ; i++)
2175     {
2176       if ( !(flag_ignorenonspace && OLE2NLS_isNonSpacing(srcstr[i]))
2177            && !(flag_ignoresymbols && OLE2NLS_isSymbol(srcstr[i])) )
2178       {
2179         dststr[j] = (CHAR) f(srcstr[i]);
2180         j++;
2181       }
2182     }
2183     return j;
2184   }
2185
2186   /* else ... (mapflags & LCMAP_SORTKEY)  */
2187   {
2188     int unicode_len=0;
2189     int case_len=0;
2190     int diacritic_len=0;
2191     int delayed_punctuation_len=0;
2192     char *case_component;
2193     char *diacritic_component;
2194     char *delayed_punctuation_component;
2195     int room,count;
2196     int flag_stringsort = mapflags & SORT_STRINGSORT;
2197
2198     /* compute how much room we will need */
2199     for (i=0;i<srclen;i++)
2200     {
2201       int ofs;
2202       unsigned char source_char = srcstr[i];
2203       if (source_char!='\0') 
2204       {
2205         if (flag_stringsort || !OLE2NLS_isPunctuation(source_char))
2206         {
2207           unicode_len++;
2208           if ( LCM_Unicode_LUT[-2+2*source_char] & ~15 )
2209             unicode_len++;             /* double letter */
2210         }
2211         else
2212         {
2213           delayed_punctuation_len++;
2214         }         
2215       }
2216           
2217       if (isupper(source_char))
2218         case_len=unicode_len; 
2219
2220       ofs = source_char - LCM_Diacritic_Start;
2221       if ((ofs>=0) && (LCM_Diacritic_LUT[ofs]!=2))
2222         diacritic_len=unicode_len;
2223     }
2224
2225     if (mapflags & NORM_IGNORECASE)
2226       case_len=0;                   
2227     if (mapflags & NORM_IGNORENONSPACE)
2228       diacritic_len=0;
2229
2230     room =  2 * unicode_len              /* "unicode" component */
2231       +     diacritic_len                /* "diacritic" component */
2232       +     case_len                     /* "case" component */
2233       +     4 * delayed_punctuation_len  /* punctuation in word sort mode */
2234       +     4                            /* four '\1' separators */
2235       +     1  ;                         /* terminal '\0' */
2236     if (dstlen==0)
2237       return room;      
2238     else if (dstlen<room)
2239     {
2240       SetLastError(ERROR_INSUFFICIENT_BUFFER);
2241       return 0;
2242     }
2243
2244     /*FIXME the Pointercheck should not be nessesary */
2245     if (IsBadWritePtr (dststr,room))
2246     { ERR_(string)("bad destination buffer (dststr) : %p,%d\n",dststr,dstlen);
2247       SetLastError(ERROR_INSUFFICIENT_BUFFER);
2248       return 0;
2249     }
2250
2251     /* locate each component, write separators */
2252     diacritic_component = dststr + 2*unicode_len ;
2253     *diacritic_component++ = '\1'; 
2254     case_component = diacritic_component + diacritic_len ;
2255     *case_component++ = '\1'; 
2256     delayed_punctuation_component = case_component + case_len ;
2257     *delayed_punctuation_component++ = '\1';
2258     *delayed_punctuation_component++ = '\1';
2259
2260     /* read source string char by char, write 
2261        corresponding weight in each component. */
2262     for (i=0,count=0;i<srclen;i++)
2263     {
2264       unsigned char source_char=srcstr[i];
2265       if (source_char!='\0') 
2266       {
2267         int type,longcode;
2268         type = LCM_Unicode_LUT[-2+2*source_char];
2269         longcode = type >> 4;
2270         type &= 15;
2271         if (!flag_stringsort && OLE2NLS_isPunctuation(source_char)) 
2272         {
2273           UINT16 encrypted_location = (1<<15) + 7 + 4*count;
2274           *delayed_punctuation_component++ = (unsigned char) (encrypted_location>>8);
2275           *delayed_punctuation_component++ = (unsigned char) (encrypted_location&255);
2276                      /* big-endian is used here because it lets string comparison be
2277                         compatible with numerical comparison */
2278
2279           *delayed_punctuation_component++ = type;
2280           *delayed_punctuation_component++ = LCM_Unicode_LUT[-1+2*source_char];  
2281                      /* assumption : a punctuation character is never a 
2282                         double or accented letter */
2283         }
2284         else
2285         {
2286           dststr[2*count] = type;
2287           dststr[2*count+1] = LCM_Unicode_LUT[-1+2*source_char];  
2288           if (longcode)
2289           {
2290             if (count<case_len)
2291               case_component[count] = ( isupper(source_char) ? 18 : 2 ) ;
2292             if (count<diacritic_len)
2293               diacritic_component[count] = 2; /* assumption: a double letter
2294                                                  is never accented */
2295             count++;
2296             
2297             dststr[2*count] = type;
2298             dststr[2*count+1] = *(LCM_Unicode_LUT_2 - 1 + longcode); 
2299             /* 16 in the first column of LCM_Unicode_LUT  -->  longcode = 1 
2300                32 in the first column of LCM_Unicode_LUT  -->  longcode = 2 
2301                48 in the first column of LCM_Unicode_LUT  -->  longcode = 3 */
2302           }
2303
2304           if (count<case_len)
2305             case_component[count] = ( isupper(source_char) ? 18 : 2 ) ;
2306           if (count<diacritic_len)
2307           {
2308             int ofs = source_char - LCM_Diacritic_Start;
2309             diacritic_component[count] = (ofs>=0 ? LCM_Diacritic_LUT[ofs] : 2);
2310           }
2311           count++;
2312         }
2313       }
2314     }
2315     dststr[room-1] = '\0';
2316     return room;
2317   }
2318 }
2319                      
2320 /*************************************************************************
2321  *              LCMapString32W                [KERNEL32.493]
2322  *
2323  * Convert a string, or generate a sort key from it.
2324  *
2325  * NOTE
2326  *
2327  * See LCMapString32A for documentation
2328  */
2329 INT WINAPI LCMapStringW(
2330         LCID lcid,DWORD mapflags,LPCWSTR srcstr,INT srclen,LPWSTR dststr,
2331         INT dstlen)
2332 {
2333   int i;
2334  
2335   TRACE_(string)("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n",
2336         lcid,mapflags,srcstr,srclen,dststr,dstlen);
2337
2338   if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
2339   {
2340     ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr, dststr);
2341     SetLastError(ERROR_INVALID_PARAMETER);
2342     return 0;
2343   }
2344   if (srclen==-1) 
2345     srclen = lstrlenW(srcstr)+1;
2346   if (mapflags & LCMAP_SORTKEY) 
2347   {
2348     FIXME_(string)("(0x%04lx,0x%08lx,%p,%d,%p,%d): "
2349           "unimplemented flags: 0x%08lx\n",
2350           lcid,mapflags,srcstr,srclen,dststr,dstlen,mapflags);
2351     return 0;
2352   }
2353   else
2354   {
2355     int (*f)(int)=identity; 
2356
2357     if (dstlen==0)
2358       return srclen;  
2359     if (dstlen<srclen) {
2360       SetLastError(ERROR_INSUFFICIENT_BUFFER);
2361       return 0;
2362     }
2363     if (mapflags & LCMAP_UPPERCASE)
2364       f = toupper;
2365     else if (mapflags & LCMAP_LOWERCASE)
2366       f = tolower;
2367     for (i=0; i < srclen; i++)
2368       dststr[i] = (WCHAR) f(srcstr[i]);
2369     return srclen;
2370   }
2371 }
2372
2373 /***********************************************************************
2374  *           CompareString16       (OLE2NLS.8)
2375  */
2376 UINT16 WINAPI CompareString16(DWORD lcid,DWORD fdwStyle,
2377                               LPCSTR s1,DWORD l1,LPCSTR s2,DWORD l2)
2378 {
2379         return (UINT16)CompareStringA(lcid,fdwStyle,s1,l1,s2,l2);
2380 }
2381
2382 /******************************************************************************
2383  *              CompareString32A        [KERNEL32.143]
2384  * Compares two strings using locale
2385  *
2386  * RETURNS
2387  *
2388  * success: CSTR_LESS_THAN, CSTR_EQUAL, CSTR_GREATER_THAN
2389  * failure: 0
2390  *
2391  * NOTES
2392  *
2393  * Defaults to a word sort, but uses a string sort if
2394  * SORT_STRINGSORT is set.
2395  * Calls SetLastError for ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER.
2396  * 
2397  * BUGS
2398  *
2399  * This implementation ignores the locale
2400  *
2401  * FIXME
2402  * 
2403  * Quite inefficient.
2404  */
2405 UINT WINAPI CompareStringA(
2406     DWORD lcid,     /* locale ID */
2407     DWORD fdwStyle, /* comparison-style options */
2408     LPCSTR s1,      /* first string */
2409     DWORD l1,       /* length of first string */
2410     LPCSTR s2,      /* second string */
2411     DWORD l2)       /* length of second string */
2412 {
2413   int mapstring_flags;
2414   int len1,len2;
2415   int result;
2416   LPSTR sk1,sk2;
2417   TRACE("%s and %s\n",
2418         debugstr_a (s1), debugstr_a (s2));
2419
2420   if ( (s1==NULL) || (s2==NULL) )
2421   {    
2422     ERR("(s1=%s,s2=%s): Invalid NULL string\n", s1, s2);
2423     SetLastError(ERROR_INVALID_PARAMETER);
2424     return 0;
2425   }
2426
2427   if(fdwStyle & NORM_IGNORESYMBOLS)
2428     FIXME("IGNORESYMBOLS not supported\n");
2429         
2430   mapstring_flags = LCMAP_SORTKEY | fdwStyle ;
2431   len1 = LCMapStringA(lcid,mapstring_flags,s1,l1,NULL,0);
2432   len2 = LCMapStringA(lcid,mapstring_flags,s2,l2,NULL,0);
2433
2434   if ((len1==0)||(len2==0))
2435     return 0;     /* something wrong happened */
2436
2437   sk1 = (LPSTR)HeapAlloc(GetProcessHeap(),0,len1);
2438   sk2 = (LPSTR)HeapAlloc(GetProcessHeap(),0,len2);
2439   if ( (!LCMapStringA(lcid,mapstring_flags,s1,l1,sk1,len1))
2440          || (!LCMapStringA(lcid,mapstring_flags,s2,l2,sk2,len2)) )
2441   {
2442     ERR("Bug in LCmapString32A.\n");
2443     result = 0;
2444   }
2445   else
2446   {
2447     /* strcmp doesn't necessarily return -1, 0, or 1 */
2448     result = strcmp(sk1,sk2);
2449   }
2450   HeapFree(GetProcessHeap(),0,sk1);
2451   HeapFree(GetProcessHeap(),0,sk2);
2452
2453   if (result < 0)
2454     return 1;
2455   if (result == 0)
2456     return 2;
2457
2458   /* must be greater, if we reach this point */
2459   return 3;
2460 }
2461
2462 /******************************************************************************
2463  *              CompareString32W        [KERNEL32.144]
2464  * This implementation ignores the locale
2465  * FIXME :  Does only string sort.  Should
2466  * be reimplemented the same way as CompareString32A.
2467  */
2468 UINT WINAPI CompareStringW(DWORD lcid, DWORD fdwStyle, 
2469                                LPCWSTR s1, DWORD l1, LPCWSTR s2,DWORD l2)
2470 {
2471         int len,ret;
2472         if(fdwStyle & NORM_IGNORENONSPACE)
2473                 FIXME("IGNORENONSPACE not supprted\n");
2474         if(fdwStyle & NORM_IGNORESYMBOLS)
2475                 FIXME("IGNORESYMBOLS not supported\n");
2476
2477         /* Is strcmp defaulting to string sort or to word sort?? */
2478         /* FIXME: Handle NORM_STRINGSORT */
2479         l1 = (l1==-1)?lstrlenW(s1):l1;
2480         l2 = (l2==-1)?lstrlenW(s2):l2;
2481         len = l1<l2 ? l1:l2;
2482         ret = (fdwStyle & NORM_IGNORECASE) ?
2483                 CRTDLL__wcsnicmp(s1,s2,len) : CRTDLL_wcsncmp(s1,s2,len);
2484         /* not equal, return 1 or 3 */
2485         if(ret!=0) return ret+2;
2486         /* same len, return 2 */
2487         if(l1==l2) return 2;
2488         /* the longer one is lexically greater */
2489         return (l1<l2)? 1 : 3;
2490 }
2491
2492 /******************************************************************************
2493  *      RegisterNLSInfoChanged  [OLE2NLS.10]
2494  */
2495 BOOL16 WINAPI RegisterNLSInfoChanged16(LPVOID/*FIXME*/ lpNewNLSInfo)
2496 {
2497         FIXME("Fully implemented, but doesn't effect anything.\n");
2498
2499         if (!lpNewNLSInfo)
2500         {
2501                 lpNLSInfo = NULL;
2502                 return TRUE;
2503         }
2504         else
2505         {
2506                 if (!lpNLSInfo)
2507                 {
2508                         lpNLSInfo = lpNewNLSInfo;
2509                         return TRUE;
2510                 }
2511         }
2512
2513         return FALSE; /* ptr not set */
2514
2515
2516 /******************************************************************************
2517  *              OLE_GetFormatA  [Internal]
2518  *
2519  * FIXME
2520  *    If datelen == 0, it should return the reguired string length.
2521  *
2522  This function implements stuff for GetDateFormat() and 
2523  GetTimeFormat().
2524
2525   d    single-digit (no leading zero) day (of month)
2526   dd   two-digit day (of month)
2527   ddd  short day-of-week name
2528   dddd long day-of-week name
2529   M    single-digit month
2530   MM   two-digit month
2531   MMM  short month name
2532   MMMM full month name
2533   y    two-digit year, no leading 0
2534   yy   two-digit year
2535   yyyy four-digit year
2536   gg   era string
2537   h    hours with no leading zero (12-hour)
2538   hh   hours with full two digits
2539   H    hours with no leading zero (24-hour)
2540   HH   hours with full two digits
2541   m    minutes with no leading zero
2542   mm   minutes with full two digits
2543   s    seconds with no leading zero
2544   ss   seconds with full two digits
2545   t    time marker (A or P)
2546   tt   time marker (AM, PM)
2547   ''   used to quote literal characters
2548   ''   (within a quoted string) indicates a literal '
2549
2550  These functions REQUIRE valid locale, date,  and format. 
2551  */
2552 static INT OLE_GetFormatA(LCID locale,
2553                             DWORD flags,
2554                             DWORD tflags,
2555                             LPSYSTEMTIME xtime,
2556                             LPCSTR _format,     /*in*/
2557                             LPSTR date,         /*out*/
2558                             INT datelen)
2559 {
2560    INT inpos, outpos;
2561    int count, type, inquote, Overflow;
2562    char buf[40];
2563    char format[40];
2564    char * pos;
2565    int buflen;
2566
2567    const char * _dgfmt[] = { "%d", "%02d" };
2568    const char ** dgfmt = _dgfmt - 1; 
2569
2570    /* report, for debugging */
2571    TRACE("(0x%lx,0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt=%p \'%s\' , %p, len=%d)\n",
2572          locale, flags, tflags,
2573          xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond,
2574          _format, _format, date, datelen);
2575   
2576    if(datelen == 0) {
2577      FIXME("datelen = 0, returning 255\n");
2578      return 255;
2579    }
2580
2581    /* initalize state variables and output buffer */
2582    inpos = outpos = 0;
2583    count = 0; inquote = 0; Overflow = 0;
2584    type = '\0';
2585    date[0] = buf[0] = '\0';
2586       
2587    strcpy(format,_format);
2588
2589    /* alter the formatstring, while it works for all languages now in wine
2590    its possible that it fails when the time looks like ss:mm:hh as example*/   
2591    if (tflags & (TIME_NOMINUTESORSECONDS))
2592    { if ((pos = strstr ( format, ":mm")))
2593      { memcpy ( pos, pos+3, strlen(format)-(pos-format)-2 );
2594      }
2595    }
2596    if (tflags & (TIME_NOSECONDS))
2597    { if ((pos = strstr ( format, ":ss")))
2598      { memcpy ( pos, pos+3, strlen(format)-(pos-format)-2 );
2599      }
2600    }
2601    
2602    for (inpos = 0;; inpos++) {
2603       /* TRACE(ole, "STATE inpos=%2d outpos=%2d count=%d inquote=%d type=%c buf,date = %c,%c\n", inpos, outpos, count, inquote, type, buf[inpos], date[outpos]); */
2604       if (inquote) {
2605          if (format[inpos] == '\'') {
2606             if (format[inpos+1] == '\'') {
2607                inpos += 1;
2608                date[outpos++] = '\'';
2609             } else {
2610                inquote = 0;
2611                continue; /* we did nothing to the output */
2612             }
2613          } else if (format[inpos] == '\0') {
2614             date[outpos++] = '\0';
2615             if (outpos > datelen) Overflow = 1;
2616             break;
2617          } else {
2618             date[outpos++] = format[inpos];
2619             if (outpos > datelen) {
2620                Overflow = 1;
2621                date[outpos-1] = '\0'; /* this is the last place where
2622                                          it's safe to write */
2623                break;
2624             }
2625          }
2626       } else if (  (count && (format[inpos] != type))
2627                    || count == 4
2628                    || (count == 2 && strchr("ghHmst", type)) )
2629        {
2630             if         (type == 'd') {
2631                if        (count == 4) {
2632                   GetLocaleInfoA(locale,
2633                                    LOCALE_SDAYNAME1
2634                                    + xtime->wDayOfWeek - 1,
2635                                    buf, sizeof(buf));
2636                } else if (count == 3) {
2637                            GetLocaleInfoA(locale, 
2638                                             LOCALE_SABBREVDAYNAME1 
2639                                             + xtime->wDayOfWeek - 1,
2640                                             buf, sizeof(buf));
2641                       } else {
2642                   sprintf(buf, dgfmt[count], xtime->wDay);
2643                }
2644             } else if (type == 'M') {
2645                if (count == 3) {
2646                   GetLocaleInfoA(locale, 
2647                                    LOCALE_SABBREVMONTHNAME1
2648                                    + xtime->wMonth - 1,
2649                                    buf, sizeof(buf));
2650                } else if (count == 4) {
2651                   GetLocaleInfoA(locale,
2652                                    LOCALE_SMONTHNAME1
2653                                    + xtime->wMonth - 1,
2654                                    buf, sizeof(buf));
2655                  } else {
2656                   sprintf(buf, dgfmt[count], xtime->wMonth);
2657                }
2658             } else if (type == 'y') {
2659                if (count == 4) {
2660                       sprintf(buf, "%d", xtime->wYear);
2661                } else if (count == 3) {
2662                   strcpy(buf, "yyy");
2663                   WARN("unknown format, c=%c, n=%d\n",  type, count);
2664                  } else {
2665                   sprintf(buf, dgfmt[count], xtime->wYear % 100);
2666                }
2667             } else if (type == 'g') {
2668                if        (count == 2) {
2669                   FIXME("LOCALE_ICALENDARTYPE unimp.\n");
2670                   strcpy(buf, "AD");
2671             } else {
2672                   strcpy(buf, "g");
2673                   WARN("unknown format, c=%c, n=%d\n", type, count);
2674                }
2675             } else if (type == 'h') {
2676                /* gives us hours 1:00 -- 12:00 */
2677                sprintf(buf, dgfmt[count], (xtime->wHour-1)%12 +1);
2678             } else if (type == 'H') {
2679                /* 24-hour time */
2680                sprintf(buf, dgfmt[count], xtime->wHour);
2681             } else if ( type == 'm') {
2682                sprintf(buf, dgfmt[count], xtime->wMinute);
2683             } else if ( type == 's') {
2684                sprintf(buf, dgfmt[count], xtime->wSecond);
2685             } else if (type == 't') {
2686                if        (count == 1) {
2687                   sprintf(buf, "%c", (xtime->wHour < 12) ? 'A' : 'P');
2688                } else if (count == 2) {
2689                   /* sprintf(buf, "%s", (xtime->wHour < 12) ? "AM" : "PM"); */
2690                   GetLocaleInfoA(locale,
2691                                    (xtime->wHour<12) 
2692                                    ? LOCALE_S1159 : LOCALE_S2359,
2693                                    buf, sizeof(buf));
2694                }
2695             };
2696
2697             /* we need to check the next char in the format string 
2698                again, no matter what happened */
2699             inpos--;
2700             
2701             /* add the contents of buf to the output */
2702             buflen = strlen(buf);
2703             if (outpos + buflen < datelen) {
2704                date[outpos] = '\0'; /* for strcat to hook onto */
2705                  strcat(date, buf);
2706                outpos += buflen;
2707             } else {
2708                date[outpos] = '\0';
2709                strncat(date, buf, datelen - outpos);
2710                  date[datelen - 1] = '\0';
2711                  SetLastError(ERROR_INSUFFICIENT_BUFFER);
2712                WARN("insufficient buffer\n");
2713                  return 0;
2714             }
2715
2716             /* reset the variables we used to keep track of this item */
2717             count = 0;
2718             type = '\0';
2719          } else if (format[inpos] == '\0') {
2720             /* we can't check for this at the loop-head, because
2721                that breaks the printing of the last format-item */
2722             date[outpos] = '\0';
2723             break;
2724          } else if (count) {
2725             /* continuing a code for an item */
2726             count +=1;
2727             continue;
2728          } else if (strchr("hHmstyMdg", format[inpos])) {
2729             type = format[inpos];
2730             count = 1;
2731             continue;
2732          } else if (format[inpos] == '\'') {
2733             inquote = 1;
2734             continue;
2735        } else {
2736             date[outpos++] = format[inpos];
2737          }
2738       /* now deal with a possible buffer overflow */
2739       if (outpos >= datelen) {
2740        date[datelen - 1] = '\0';
2741        SetLastError(ERROR_INSUFFICIENT_BUFFER);
2742        return 0;
2743       }
2744    }
2745    
2746    if (Overflow) {
2747       SetLastError(ERROR_INSUFFICIENT_BUFFER);
2748    };
2749
2750    /* finish it off with a string terminator */
2751    outpos++;
2752    /* sanity check */
2753    if (outpos > datelen-1) outpos = datelen-1;
2754    date[outpos] = '\0';
2755    
2756    TRACE("OLE_GetFormatA returns string '%s', len %d\n",
2757                date, outpos);
2758    return outpos;
2759 }
2760
2761 /******************************************************************************
2762  * OLE_GetFormatW [INTERNAL]
2763  */
2764 static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
2765                             LPSYSTEMTIME xtime,
2766                             LPCWSTR format,
2767                             LPWSTR output, INT outlen)
2768 {
2769    INT   inpos, outpos;
2770    int     count, type=0, inquote;
2771    int     Overflow; /* loop check */
2772    WCHAR   buf[40];
2773    int     buflen=0;
2774    WCHAR   arg0[] = {0}, arg1[] = {'%','d',0};
2775    WCHAR   arg2[] = {'%','0','2','d',0};
2776    WCHAR  *argarr[3];
2777    int     datevars=0, timevars=0;
2778
2779    argarr[0] = arg0;
2780    argarr[1] = arg1;
2781    argarr[2] = arg2;
2782
2783    /* make a debug report */
2784    TRACE("args: 0x%lx, 0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt:%s (at %p), "
2785               "%p with max len %d\n",
2786          locale, flags, tflags,
2787          xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond,
2788          debugstr_w(format), format, output, outlen);
2789    
2790    if(outlen == 0) {
2791      FIXME("outlen = 0, returning 255\n");
2792      return 255;
2793    }
2794
2795    /* initialize state variables */
2796    inpos = outpos = 0;
2797    count = 0;
2798    inquote = Overflow = 0;
2799    /* this is really just a sanity check */
2800    output[0] = buf[0] = 0;
2801    
2802    /* this loop is the core of the function */
2803    for (inpos = 0; /* we have several break points */ ; inpos++) {
2804       if (inquote) {
2805          if (format[inpos] == (WCHAR) '\'') {
2806             if (format[inpos+1] == '\'') {
2807                inpos++;
2808                output[outpos++] = '\'';
2809             } else {
2810                inquote = 0;
2811                continue;
2812             }
2813          } else if (format[inpos] == 0) {
2814             output[outpos++] = 0;
2815             if (outpos > outlen) Overflow = 1;
2816             break;  /*  normal exit (within a quote) */
2817          } else {
2818             output[outpos++] = format[inpos]; /* copy input */
2819             if (outpos > outlen) {
2820                Overflow = 1;
2821                output[outpos-1] = 0; 
2822                break;
2823             }
2824          }
2825       } else if (  (count && (format[inpos] != type))
2826                    || ( (count==4 && type =='y') ||
2827                         (count==4 && type =='M') ||
2828                         (count==4 && type =='d') ||
2829                         (count==2 && type =='g') ||
2830                         (count==2 && type =='h') ||
2831                         (count==2 && type =='H') ||
2832                         (count==2 && type =='m') ||
2833                         (count==2 && type =='s') ||
2834                         (count==2 && type =='t') )  ) {
2835          if        (type == 'd') {
2836             if        (count == 3) {
2837                GetLocaleInfoW(locale,
2838                              LOCALE_SDAYNAME1 + xtime->wDayOfWeek -1,
2839                              buf, sizeof(buf)/sizeof(WCHAR) );
2840             } else if (count == 3) {
2841                GetLocaleInfoW(locale,
2842                                 LOCALE_SABBREVDAYNAME1 +
2843                                 xtime->wDayOfWeek -1,
2844                                 buf, sizeof(buf)/sizeof(WCHAR) );
2845             } else {
2846                wsnprintfW(buf, 5, argarr[count], xtime->wDay );
2847             };
2848          } else if (type == 'M') {
2849             if        (count == 4) {
2850                GetLocaleInfoW(locale,  LOCALE_SMONTHNAME1 +
2851                                 xtime->wMonth -1, buf,
2852                                 sizeof(buf)/sizeof(WCHAR) );
2853             } else if (count == 3) {
2854                GetLocaleInfoW(locale,  LOCALE_SABBREVMONTHNAME1 +
2855                                 xtime->wMonth -1, buf,
2856                                 sizeof(buf)/sizeof(WCHAR) );
2857             } else {
2858                wsnprintfW(buf, 5, argarr[count], xtime->wMonth);
2859             }
2860          } else if (type == 'y') {
2861             if        (count == 4) {
2862                wsnprintfW(buf, 6, argarr[1] /* "%d" */,
2863                          xtime->wYear);
2864             } else if (count == 3) {
2865                lstrcpynAtoW(buf, "yyy", 5);
2866             } else {
2867                wsnprintfW(buf, 6, argarr[count],
2868                             xtime->wYear % 100);
2869             }
2870          } else if (type == 'g') {
2871             if        (count == 2) {
2872                FIXME("LOCALE_ICALENDARTYPE unimplemented\n");
2873                lstrcpynAtoW(buf, "AD", 5);
2874             } else {
2875                /* Win API sez we copy it verbatim */
2876                lstrcpynAtoW(buf, "g", 5);
2877             }
2878          } else if (type == 'h') {
2879             /* hours 1:00-12:00 --- is this right? */
2880             wsnprintfW(buf, 5, argarr[count], 
2881                          (xtime->wHour-1)%12 +1);
2882          } else if (type == 'H') {
2883             wsnprintfW(buf, 5, argarr[count], 
2884                          xtime->wHour);
2885          } else if (type == 'm' ) {
2886             wsnprintfW(buf, 5, argarr[count],
2887                          xtime->wMinute);
2888          } else if (type == 's' ) {
2889             wsnprintfW(buf, 5, argarr[count],
2890                          xtime->wSecond);
2891          } else if (type == 't') {
2892             GetLocaleInfoW(locale, (xtime->wHour < 12) ?
2893                              LOCALE_S1159 : LOCALE_S2359,
2894                              buf, sizeof(buf) );
2895             if        (count == 1) {
2896                buf[1] = 0;
2897             }
2898 }
2899
2900          /* no matter what happened,  we need to check this next 
2901             character the next time we loop through */
2902          inpos--;
2903
2904          /* cat buf onto the output */
2905          outlen = lstrlenW(buf);
2906          if (outpos + buflen < outlen) {
2907             lstrcpyW( output + outpos, buf );
2908             outpos += buflen;
2909          } else {
2910             lstrcpynW( output + outpos, buf, outlen - outpos );
2911             Overflow = 1;
2912             break; /* Abnormal exit */
2913          }
2914
2915          /* reset the variables we used this time */
2916          count = 0;
2917          type = '\0';
2918       } else if (format[inpos] == 0) {
2919          /* we can't check for this at the beginning,  because that 
2920          would keep us from printing a format spec that ended the 
2921          string */
2922          output[outpos] = 0;
2923          break;  /*  NORMAL EXIT  */
2924       } else if (count) {
2925          /* how we keep track of the middle of a format spec */
2926          count++;
2927          continue;
2928       } else if ( (datevars && (format[inpos]=='d' ||
2929                                 format[inpos]=='M' ||
2930                                 format[inpos]=='y' ||
2931                                 format[inpos]=='g')  ) ||
2932                   (timevars && (format[inpos]=='H' ||
2933                                 format[inpos]=='h' ||
2934                                 format[inpos]=='m' ||
2935                                 format[inpos]=='s' ||
2936                                 format[inpos]=='t') )    ) {
2937          type = format[inpos];
2938          count = 1;
2939          continue;
2940       } else if (format[inpos] == '\'') {
2941          inquote = 1;
2942          continue;
2943       } else {
2944          /* unquoted literals */
2945          output[outpos++] = format[inpos];
2946       }
2947    }
2948
2949    if (Overflow) {
2950       SetLastError(ERROR_INSUFFICIENT_BUFFER);
2951       WARN(" buffer overflow\n");
2952    };
2953
2954    /* final string terminator and sanity check */
2955    outpos++;
2956    if (outpos > outlen-1) outpos = outlen-1;
2957    output[outpos] = '0';
2958
2959    TRACE(" returning %s\n", debugstr_w(output));
2960         
2961    return (!Overflow) ? outlen : 0;
2962    
2963 }
2964
2965
2966 /******************************************************************************
2967  *              GetDateFormat32A        [KERNEL32.310]
2968  * Makes an ASCII string of the date
2969  *
2970  * This function uses format to format the date,  or,  if format
2971  * is NULL, uses the default for the locale.  format is a string
2972  * of literal fields and characters as follows:
2973  *
2974  * - d    single-digit (no leading zero) day (of month)
2975  * - dd   two-digit day (of month)
2976  * - ddd  short day-of-week name
2977  * - dddd long day-of-week name
2978  * - M    single-digit month
2979  * - MM   two-digit month
2980  * - MMM  short month name
2981  * - MMMM full month name
2982  * - y    two-digit year, no leading 0
2983  * - yy   two-digit year
2984  * - yyyy four-digit year
2985  * - gg   era string
2986  *
2987  */
2988 INT WINAPI GetDateFormatA(LCID locale,DWORD flags,
2989                               LPSYSTEMTIME xtime,
2990                               LPCSTR format, LPSTR date,INT datelen) 
2991 {
2992    
2993   char format_buf[40];
2994   LPCSTR thisformat;
2995   SYSTEMTIME t;
2996   LPSYSTEMTIME thistime;
2997   LCID thislocale;
2998   INT ret;
2999
3000   TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",
3001               locale,flags,xtime,format,date,datelen);
3002   
3003   if (!locale) {
3004      locale = LOCALE_SYSTEM_DEFAULT;
3005      };
3006   
3007   if (locale == LOCALE_SYSTEM_DEFAULT) {
3008      thislocale = GetSystemDefaultLCID();
3009   } else if (locale == LOCALE_USER_DEFAULT) {
3010      thislocale = GetUserDefaultLCID();
3011   } else {
3012      thislocale = locale;
3013    };
3014
3015   if (xtime == NULL) {
3016      GetSystemTime(&t);
3017      thistime = &t;
3018   } else {
3019      thistime = xtime;
3020   };
3021
3022   if (format == NULL) {
3023      GetLocaleInfoA(thislocale, ((flags&DATE_LONGDATE) 
3024                                    ? LOCALE_SLONGDATE
3025                                    : LOCALE_SSHORTDATE),
3026                       format_buf, sizeof(format_buf));
3027      thisformat = format_buf;
3028   } else {
3029      thisformat = format;
3030   };
3031
3032   
3033   ret = OLE_GetFormatA(thislocale, flags, 0, thistime, thisformat, 
3034                        date, datelen);
3035   
3036
3037    TRACE(
3038                "GetDateFormat32A() returning %d, with data=%s\n",
3039                ret, date);
3040   return ret;
3041 }
3042
3043 /******************************************************************************
3044  *              GetDateFormat32W        [KERNEL32.311]
3045  * Makes a Unicode string of the date
3046  *
3047  * Acts the same as GetDateFormat32A(),  except that it's Unicode.
3048  * Accepts & returns sizes as counts of Unicode characters.
3049  *
3050  */
3051 INT WINAPI GetDateFormatW(LCID locale,DWORD flags,
3052                               LPSYSTEMTIME xtime,
3053                               LPCWSTR format,
3054                               LPWSTR date, INT datelen)
3055 {
3056    unsigned short datearr[] = {'1','9','9','4','-','1','-','1',0};
3057
3058    FIXME("STUB (should call OLE_GetFormatW)\n");   
3059    lstrcpynW(date, datearr, datelen);
3060    return (  datelen < 9) ? datelen : 9;
3061    
3062    
3063 }
3064
3065 /**************************************************************************
3066  *              EnumDateFormats32A      (KERNEL32.198)
3067  */
3068 BOOL WINAPI EnumDateFormatsA(
3069   DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale,  DWORD dwFlags)
3070 {
3071   FIXME("Only US English supported\n");
3072
3073   if(!lpDateFmtEnumProc)
3074     {
3075       SetLastError(ERROR_INVALID_PARAMETER);
3076       return FALSE;
3077     }
3078
3079   switch(dwFlags)
3080     {
3081       case DATE_SHORTDATE:
3082         if(!(*lpDateFmtEnumProc)("M/d/yy")) return TRUE;
3083         if(!(*lpDateFmtEnumProc)("M/d/yyyy")) return TRUE;
3084         if(!(*lpDateFmtEnumProc)("MM/dd/yy")) return TRUE;
3085         if(!(*lpDateFmtEnumProc)("MM/dd/yyyy")) return TRUE;
3086         if(!(*lpDateFmtEnumProc)("yy/MM/dd")) return TRUE;
3087         if(!(*lpDateFmtEnumProc)("dd-MMM-yy")) return TRUE;
3088         return TRUE;
3089       case DATE_LONGDATE:
3090         if(!(*lpDateFmtEnumProc)("dddd, MMMM dd, yyyy")) return TRUE;
3091         if(!(*lpDateFmtEnumProc)("MMMM dd, yyyy")) return TRUE;
3092         if(!(*lpDateFmtEnumProc)("dddd, dd MMMM, yyyy")) return TRUE;
3093         if(!(*lpDateFmtEnumProc)("dd MMMM, yyyy")) return TRUE;
3094         return TRUE;
3095       default:
3096         FIXME("Unknown date format (%ld)\n", dwFlags); 
3097         SetLastError(ERROR_INVALID_PARAMETER);
3098         return FALSE;
3099     }
3100 }
3101
3102 /**************************************************************************
3103  *              EnumDateFormats32W      (KERNEL32.199)
3104  */
3105 BOOL WINAPI EnumDateFormatsW(
3106   DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags)
3107 {
3108   FIXME("(%p, %ld, %ld): stub\n", lpDateFmtEnumProc, Locale, dwFlags);
3109   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3110   return FALSE;
3111 }
3112
3113 /**************************************************************************
3114  *              EnumTimeFormats32A      (KERNEL32.210)
3115  */
3116 BOOL WINAPI EnumTimeFormatsA(
3117   TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags)
3118 {
3119   FIXME("Only US English supported\n");
3120
3121   if(!lpTimeFmtEnumProc)
3122     {
3123       SetLastError(ERROR_INVALID_PARAMETER);
3124       return FALSE;
3125     }
3126
3127   if(dwFlags)
3128     {
3129       FIXME("Unknown time format (%ld)\n", dwFlags); 
3130     }
3131   
3132   if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE;
3133   if(!(*lpTimeFmtEnumProc)("hh:mm:ss tt")) return TRUE;
3134   if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE;
3135   if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE;
3136
3137   return TRUE;
3138 }
3139
3140 /**************************************************************************
3141  *              EnumTimeFormats32W      (KERNEL32.211)
3142  */
3143 BOOL WINAPI EnumTimeFormatsW(
3144   TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags)
3145 {
3146   FIXME("(%p,%ld,%ld): stub\n", lpTimeFmtEnumProc, Locale, dwFlags);
3147   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3148   return FALSE;
3149 }
3150
3151
3152 /**************************************************************************
3153  *              GetNumberFormat32A      (KERNEL32.355)
3154  */
3155 INT WINAPI GetNumberFormatA(LCID locale, DWORD dwflags,
3156                                LPCSTR lpValue,   const NUMBERFMTA * lpFormat,
3157                                LPSTR lpNumberStr, int cchNumber)
3158 {
3159         LCID thislocale;
3160         UINT thisnumdigits;
3161     UINT thisleadingzero;
3162     UINT thisgrouping[8]={ -1 };
3163     LPCSTR thisdecimalsep;
3164     LPCSTR thisthousandsep;
3165     UINT thisnegativeorder;
3166
3167
3168         LPSTR sptr;
3169         LPSTR dptr;
3170         char roundbuffer[24]; /* Should be enough */
3171         char *gptr;
3172         int i,j;
3173         int dotflag=0,negflag=0;
3174         char misc_buf[8], negative_buf[4], decimal_buf[4], thousand_buf[4];
3175         char digits_buf[11];
3176         int intsize=0,decsize=0,totalsize,lastgroup, leadingzeros=0;
3177         int negsignsize,decimalsepsize,thousandsepsize;
3178
3179 /* Default setting stuff - partially borrowed from GetFormatedDate */
3180         if (!locale) {
3181                 locale = LOCALE_SYSTEM_DEFAULT;
3182         }
3183
3184         if (locale == LOCALE_SYSTEM_DEFAULT) {
3185                 thislocale = GetSystemDefaultLCID();
3186         } else if (locale == LOCALE_USER_DEFAULT) {
3187                 thislocale = GetUserDefaultLCID();
3188         } else {
3189                 thislocale = locale;
3190         }
3191 /* Partial implementation: things like native digits are not considered */
3192         if (lpFormat == NULL) {
3193
3194         GetLocaleInfoA(thislocale, LOCALE_IDIGITS,
3195                                         misc_buf, sizeof(misc_buf));
3196         thisnumdigits = atoi(misc_buf);
3197
3198         GetLocaleInfoA(thislocale, LOCALE_ILZERO,
3199                                         misc_buf, sizeof(misc_buf));
3200      thisleadingzero = atoi(misc_buf);
3201
3202      GetLocaleInfoA(thislocale, LOCALE_SGROUPING,
3203                                         misc_buf, sizeof(misc_buf));
3204
3205 /* About grouping mechanism:
3206    I parse the string and pour the group size values along the 
3207    thisgrouping[] array, starting by element 1. Then I convert these
3208    values to indexes for insertion into the integer part.
3209    thisgrouping[0]==-1, therefore I ensure index correctness without
3210    need for range checking and related stuff.
3211    The only drawback is the 7 separators limit, hopefully that means
3212    it will fail with numbers bigger than 10^21 if using groups of three
3213    as usual. */
3214
3215
3216         for (i=1,gptr=misc_buf;*gptr!='\0';i++) {
3217                 /* In control panel, groups up 9 digits long are allowed. If there is any way to use larger groups,
3218                    then the next line must be replaced with the following code:
3219                    thisgrouping[i] = atoi(gptr);
3220                    for (;*gptr!=';' && *gptr!='\0';gptr++) ; */
3221         
3222                 thisgrouping[i] = *(gptr++)-'0';
3223         
3224                 if (*gptr==';')
3225                         gptr++;
3226         }
3227
3228     /* Take care for repeating group size */
3229         if (thisgrouping[i-1]==0) {
3230                 for (j=i-1;j<8;j++)
3231                         thisgrouping[j]=thisgrouping[i-2];
3232                 lastgroup=7;
3233         } else
3234                 lastgroup=i-1;
3235
3236         for (i=2;i<=lastgroup;i++)
3237                 thisgrouping[i]+=thisgrouping[i-1];
3238
3239         GetLocaleInfoA(thislocale, LOCALE_SDECIMAL,
3240                                         decimal_buf, sizeof(decimal_buf));
3241         thisdecimalsep  = decimal_buf;
3242
3243         GetLocaleInfoA(thislocale, LOCALE_STHOUSAND,
3244                                         thousand_buf, sizeof(thousand_buf));
3245         thisthousandsep  = thousand_buf;
3246
3247         GetLocaleInfoA(thislocale, LOCALE_INEGNUMBER,
3248                                         misc_buf, sizeof(misc_buf));
3249         thisnegativeorder = atoi(misc_buf); 
3250
3251         } else {
3252
3253                 thisnumdigits = lpFormat->NumDigits;
3254                 thisleadingzero = lpFormat->LeadingZero;
3255                 
3256                 thisgrouping[1] = lpFormat->Grouping;   
3257                 for (i=2;i<8;i++)
3258                         thisgrouping[i]=thisgrouping[i-1]+lpFormat->Grouping;
3259                 lastgroup=7;
3260                 
3261                 thisdecimalsep = lpFormat->lpDecimalSep;
3262                 thisthousandsep = lpFormat->lpThousandSep;
3263                 thisnegativeorder = lpFormat->NegativeOrder;
3264
3265     }
3266
3267         GetLocaleInfoA(thislocale, LOCALE_SNATIVEDIGITS,
3268                                         digits_buf, sizeof(digits_buf));
3269
3270         GetLocaleInfoA(thislocale, LOCALE_SNEGATIVESIGN,
3271                                         negative_buf, sizeof(negative_buf));
3272
3273         negsignsize=strlen(negative_buf);
3274         decimalsepsize=strlen(thisdecimalsep);
3275         thousandsepsize=strlen(thisthousandsep);
3276
3277         /* Size calculation */
3278         sptr=lpValue;
3279         if (*sptr=='-') {
3280                 negflag=1;
3281                 sptr++;
3282         }
3283         for (; *sptr=='0'; sptr++) leadingzeros++; /* Ignore leading zeros */
3284         for (; *sptr!='\0'; sptr++) {
3285                 if (!dotflag && *sptr=='.') {
3286                         dotflag=1;
3287                 } else if (*sptr<'0' || *sptr>'9') {
3288                         SetLastError(ERROR_INVALID_PARAMETER);
3289                         return 0;
3290                 } else {
3291                         if (dotflag) {
3292                                 decsize++;
3293                         } else {
3294                         intsize++;
3295                         }
3296         }
3297         }
3298
3299
3300 /* Take care of eventual rounding. Only, if I need to do it, then I write
3301    the rounded lpValue copy into roundbuffer, and create the formatted
3302    string from the proper source. This is smarter than copying it always
3303    The buffer includes an extra leading zero, as the number can carry and
3304    get and extra one. If it doesn't, the zero is ignored as any other
3305    useless leading zero
3306 */
3307
3308         if (decsize>0 && decsize>thisnumdigits) {
3309                 sptr-=(decsize-thisnumdigits);
3310                         
3311                 if (*sptr>='5') {
3312                         strcpy(roundbuffer+1,lpValue);
3313                         if (negflag) {
3314                                 *roundbuffer='-';
3315                                 *(roundbuffer+1)='0';
3316                         } else
3317                                 *roundbuffer='0';
3318                                 sptr=roundbuffer+(sptr-lpValue);  // +1-1
3319                                 
3320                                 while ( (++*sptr) > '9') {
3321                                         *(sptr--)='0';
3322                                         if (*sptr=='.') sptr--;
3323                                 }
3324                                 if ((negflag ? *(roundbuffer+leadingzeros+1) : *(roundbuffer+leadingzeros))  == '1')
3325                                         intsize++;      
3326                                         sptr=roundbuffer;
3327                                 } else
3328                                         sptr=lpValue;
3329                         } else
3330                                 sptr=lpValue;
3331
3332         totalsize=intsize;
3333
3334         if (intsize==0 && (decsize==0 || thisleadingzero))
3335                 totalsize++;
3336
3337         if (negflag)
3338                 totalsize+= thisnegativeorder == 1 || thisnegativeorder == 3 ? negsignsize
3339                         : thisnegativeorder == 2 || thisnegativeorder == 4 ? negsignsize+1 : 2 ;
3340
3341         /* Look for the first grouping to be done */
3342         for (j=lastgroup;thisgrouping[j]>=intsize && j>0;j--) ;
3343
3344   
3345         totalsize+=thousandsepsize * j;
3346         if (thisnumdigits>0)
3347                 totalsize+=decimalsepsize+thisnumdigits;
3348
3349         if (cchNumber==0) /* if cchNumber is zero, just return size needed */
3350                 return totalsize+1;
3351         else
3352                 if (cchNumber<totalsize+1)  { /* +1 = Null terminator (right?) */
3353                         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3354                         return 0;
3355                 } else {
3356
3357
3358                         /* Formatting stuff starts here */
3359
3360                         dptr=lpNumberStr;
3361
3362                         if (negflag) {
3363                                 if (thisnegativeorder==0)
3364                                         *dptr++='(';
3365                                 else if (thisnegativeorder<=2) {
3366                                         strcpy(dptr,negative_buf);
3367                                         dptr+=negsignsize;
3368                                         if (thisnegativeorder==2)
3369                                                 *dptr++=' ';
3370                                 }
3371                                 sptr++;
3372                         }
3373
3374                         for (i=1;*sptr=='0' ;i++, sptr++) ; /* Ignore leading zeros from source*/
3375                                 if (intsize==0 && (decsize==0 || thisleadingzero)) // Insert one leading zero into destination if required
3376                                         *(dptr++)=digits_buf[0];
3377                                 for (i=1;i<=intsize;i++) {
3378
3379                                         *(dptr++)=digits_buf[*(sptr++)-'0'];
3380                                         
3381                                         /* Insert a group separator if we just reached the end of a group */
3382                                         if (i==intsize-thisgrouping[j]) {
3383                                                 strcpy(dptr,thisthousandsep);
3384                                                 dptr+=thousandsepsize;
3385                                                 j--;
3386                                         }
3387                                 }
3388
3389                                 if (decsize>0)
3390                                         sptr++;
3391                                 if (thisnumdigits>0) {
3392                                         strcpy(dptr,decimal_buf);
3393                                         dptr+=decimalsepsize;
3394                                         for (i=0;i<thisnumdigits;i++)
3395                                                 *(dptr++)=*sptr !='\0' ? digits_buf[*(sptr++)-'0'] : digits_buf[0];
3396                                 }
3397
3398                                 if (negflag) {
3399                                         if (thisnegativeorder==0)
3400                                                 *dptr++=')';
3401                                         else if (thisnegativeorder>=3) {
3402                                                 if (thisnegativeorder==4)
3403                                                         *dptr++=' ';            
3404                                                         strcpy(dptr,negative_buf);
3405                                                         dptr+=negsignsize;
3406                                                         sptr++;
3407                                         }
3408                                 }
3409
3410                                 *dptr='\0';
3411
3412                 }
3413     return totalsize+1;
3414 }
3415
3416 /**************************************************************************
3417  *              GetNumberFormat32W      (KERNEL32.xxx)
3418  */
3419 INT WINAPI GetNumberFormatW(LCID locale, DWORD dwflags,
3420                                LPCWSTR lpvalue,  const NUMBERFMTW * lpFormat,
3421                                LPWSTR lpNumberStr, int cchNumber)
3422 {
3423  FIXME("%s: stub, no reformating done\n",debugstr_w(lpvalue));
3424
3425  lstrcpynW( lpNumberStr, lpvalue, cchNumber );
3426  return cchNumber? lstrlenW( lpNumberStr ) : 0;
3427 }
3428 /******************************************************************************
3429  *              OLE2NLS_CheckLocale     [intern]
3430  */ 
3431 static LCID OLE2NLS_CheckLocale (LCID locale)
3432 {
3433         if (!locale) 
3434         { locale = LOCALE_SYSTEM_DEFAULT;
3435         }
3436   
3437         if (locale == LOCALE_SYSTEM_DEFAULT) 
3438         { return GetSystemDefaultLCID();
3439         } 
3440         else if (locale == LOCALE_USER_DEFAULT) 
3441         { return GetUserDefaultLCID();
3442         }
3443         else
3444         { return locale;
3445         }
3446 }
3447 /******************************************************************************
3448  *              GetTimeFormat32A        [KERNEL32.422]
3449  * Makes an ASCII string of the time
3450  *
3451  * Formats date according to format,  or locale default if format is
3452  * NULL. The format consists of literal characters and fields as follows:
3453  *
3454  * h  hours with no leading zero (12-hour)
3455  * hh hours with full two digits
3456  * H  hours with no leading zero (24-hour)
3457  * HH hours with full two digits
3458  * m  minutes with no leading zero
3459  * mm minutes with full two digits
3460  * s  seconds with no leading zero
3461  * ss seconds with full two digits
3462  * t  time marker (A or P)
3463  * tt time marker (AM, PM)
3464  *
3465  */
3466 INT WINAPI 
3467 GetTimeFormatA(LCID locale,        /* in  */
3468                  DWORD flags,        /* in  */
3469                  LPSYSTEMTIME xtime, /* in  */ 
3470                  LPCSTR format,      /* in  */
3471                  LPSTR timestr,      /* out */
3472                  INT timelen       /* in  */) 
3473 { char format_buf[40];
3474   LPCSTR thisformat;
3475   SYSTEMTIME t;
3476   LPSYSTEMTIME thistime;
3477   LCID thislocale=0;
3478   DWORD thisflags=LOCALE_STIMEFORMAT; /* standart timeformat */
3479   INT ret;
3480     
3481   TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale,flags,xtime,format,timestr,timelen);
3482
3483   thislocale = OLE2NLS_CheckLocale ( locale );
3484
3485   if ( flags & (TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT ))
3486   { FIXME("TIME_NOTIMEMARKER or TIME_FORCE24HOURFORMAT not implemented\n");
3487   }
3488   
3489   flags &= (TIME_NOSECONDS | TIME_NOMINUTESORSECONDS); /* mask for OLE_GetFormatA*/
3490
3491   if (format == NULL) 
3492   { if (flags & LOCALE_NOUSEROVERRIDE)  /*use system default*/
3493     { thislocale = GetSystemDefaultLCID();
3494     }
3495     GetLocaleInfoA(thislocale, thisflags, format_buf, sizeof(format_buf));
3496     thisformat = format_buf;
3497   }
3498   else 
3499   { thisformat = format;
3500   }
3501   
3502   if (xtime == NULL) /* NULL means use the current local time*/
3503   { GetLocalTime(&t);
3504     thistime = &t;
3505   } 
3506   else
3507   { thistime = xtime;
3508   }
3509   ret = OLE_GetFormatA(thislocale, thisflags, flags, thistime, thisformat,
3510                          timestr, timelen);
3511   return ret;
3512 }
3513
3514
3515 /******************************************************************************
3516  *              GetTimeFormat32W        [KERNEL32.423]
3517  * Makes a Unicode string of the time
3518  */
3519 INT WINAPI 
3520 GetTimeFormatW(LCID locale,        /* in  */
3521                  DWORD flags,        /* in  */
3522                  LPSYSTEMTIME xtime, /* in  */ 
3523                  LPCWSTR format,     /* in  */
3524                  LPWSTR timestr,     /* out */
3525                  INT timelen       /* in  */) 
3526 {       WCHAR format_buf[40];
3527         LPCWSTR thisformat;
3528         SYSTEMTIME t;
3529         LPSYSTEMTIME thistime;
3530         LCID thislocale=0;
3531         DWORD thisflags=LOCALE_STIMEFORMAT; /* standart timeformat */
3532         INT ret;
3533             
3534         TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale,flags,
3535         xtime,debugstr_w(format),timestr,timelen);
3536
3537         thislocale = OLE2NLS_CheckLocale ( locale );
3538
3539         if ( flags & (TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT ))
3540         { FIXME("TIME_NOTIMEMARKER or TIME_FORCE24HOURFORMAT not implemented\n");
3541         }
3542   
3543         flags &= (TIME_NOSECONDS | TIME_NOMINUTESORSECONDS); /* mask for OLE_GetFormatA*/
3544
3545         if (format == NULL) 
3546         { if (flags & LOCALE_NOUSEROVERRIDE)  /*use system default*/
3547           { thislocale = GetSystemDefaultLCID();
3548           }
3549           GetLocaleInfoW(thislocale, thisflags, format_buf, 40);
3550           thisformat = format_buf;
3551         }         
3552         else 
3553         { thisformat = format;
3554         }
3555  
3556         if (xtime == NULL) /* NULL means use the current local time*/
3557         { GetSystemTime(&t);
3558           thistime = &t;
3559         } 
3560         else
3561         { thistime = xtime;
3562         }
3563
3564         ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime, thisformat,
3565                          timestr, timelen);
3566         return ret;
3567 }
3568
3569 /******************************************************************************
3570  *              EnumCalendarInfoA       [KERNEL32.196]
3571  */
3572 BOOL WINAPI EnumCalendarInfoA(
3573         CALINFO_ENUMPROCA calinfoproc,LCID locale,CALID calendar,CALTYPE caltype
3574 ) {
3575         FIXME("(%p,0x%04lx,0x%08lx,0x%08lx),stub!\n",calinfoproc,locale,calendar,caltype);
3576         return FALSE;
3577 }