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