4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 David Lee Lambert
6 * Copyright 2000 Julio César Gázquez
23 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(ole
);
28 DECLARE_DEBUG_CHANNEL(string
);
29 DECLARE_DEBUG_CHANNEL(win32
);
31 struct NLS_langlocale
{
33 struct NLS_localevar
{
39 static LPVOID lpNLSInfo
= NULL
;
41 #define LANG_BEGIN(l,s) { MAKELANGID(l,s), {
43 #define LOCVAL(type,value) {type,value},
47 static const struct NLS_langlocale langlocales
[] = {
48 /* add languages in numerical order of main language (last two digits)
49 * it is much easier to find the missing holes that way */
51 LANG_BEGIN (LANG_CATALAN
, SUBLANG_DEFAULT
) /*0x0403*/
52 #include "nls/cat.nls"
55 LANG_BEGIN (LANG_CZECH
, SUBLANG_DEFAULT
) /*0x0405*/
56 #include "nls/cze.nls"
59 LANG_BEGIN (LANG_DANISH
, SUBLANG_DEFAULT
) /*0x0406*/
60 #include "nls/dan.nls"
63 LANG_BEGIN (LANG_GERMAN
, SUBLANG_GERMAN
) /*0x0407*/
64 #include "nls/deu.nls"
66 LANG_BEGIN (LANG_GERMAN
, SUBLANG_GERMAN_SWISS
) /*0x0807*/
67 #include "nls/des.nls"
69 LANG_BEGIN (LANG_GERMAN
, SUBLANG_GERMAN_AUSTRIAN
) /*0x0C07*/
70 #include "nls/dea.nls"
72 LANG_BEGIN (LANG_GERMAN
, SUBLANG_GERMAN_LUXEMBOURG
) /*0x1007*/
73 #include "nls/del.nls"
75 LANG_BEGIN (LANG_GERMAN
, SUBLANG_GERMAN_LIECHTENSTEIN
) /*0x1407*/
76 #include "nls/dec.nls"
79 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_US
) /*0x0409*/
80 #include "nls/enu.nls"
82 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_UK
) /*0x0809*/
83 #include "nls/eng.nls"
85 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_AUS
) /*0x0C09*/
86 #include "nls/ena.nls"
88 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_CAN
) /*0x1009*/
89 #include "nls/enc.nls"
91 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_NZ
) /*0x1409*/
92 #include "nls/enz.nls"
94 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_EIRE
) /*0x1809*/
95 #include "nls/irl.nls"
97 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_SAFRICA
) /*0x1C09*/
98 #include "nls/ens.nls"
100 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_JAMAICA
) /*0x2009*/
101 #include "nls/enj.nls"
103 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_CARRIBEAN
) /*0x2409*/
104 #include "nls/enb.nls"
106 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_BELIZE
) /*0x2809*/
107 #include "nls/enl.nls"
109 LANG_BEGIN (LANG_ENGLISH
, SUBLANG_ENGLISH_TRINIDAD
) /*0x2C09*/
110 #include "nls/ent.nls"
113 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH
) /*0x040a*/
114 #include "nls/esp.nls"
116 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_MEXICAN
) /*0x080a*/
117 #include "nls/esm.nls"
119 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_MODERN
) /*0x0C0a*/
120 #include "nls/esn.nls"
122 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_GUATEMALA
) /*0x100a*/
123 #include "nls/esg.nls"
125 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_COSTARICA
) /*0x140a*/
126 #include "nls/esc.nls"
128 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_PANAMA
) /*0x180a*/
129 #include "nls/esa.nls"
131 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_DOMINICAN
) /*0x1C0A*/
132 #include "nls/esd.nls"
134 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_VENEZUELA
) /*0x200a*/
135 #include "nls/esv.nls"
137 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_COLOMBIA
) /*0x240a*/
138 #include "nls/eso.nls"
140 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_PERU
) /*0x280a*/
141 #include "nls/esr.nls"
143 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_ARGENTINA
) /*0x2c0a*/
144 #include "nls/ess.nls"
146 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_ECUADOR
) /*0x300a*/
147 #include "nls/esf.nls"
149 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_CHILE
) /*0x340a*/
150 #include "nls/esl.nls"
152 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_URUGUAY
) /*0x380a*/
153 #include "nls/esy.nls"
155 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_PARAGUAY
) /*0x3c0a*/
156 #include "nls/esz.nls"
158 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_BOLIVIA
) /*0x400a*/
159 #include "nls/esb.nls"
161 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_EL_SALVADOR
) /*0x440a*/
162 #include "nls/ese.nls"
164 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_HONDURAS
) /*0x480a*/
165 #include "nls/esh.nls"
167 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_NICARAGUA
) /*0x4c0a*/
168 #include "nls/esi.nls"
170 LANG_BEGIN (LANG_SPANISH
, SUBLANG_SPANISH_PUERTO_RICO
) /*0x500a*/
171 #include "nls/esu.nls"
174 LANG_BEGIN (LANG_FINNISH
, SUBLANG_DEFAULT
) /*0x040B*/
175 #include "nls/fin.nls"
178 LANG_BEGIN (LANG_FRENCH
, SUBLANG_FRENCH
) /*0x040C*/
179 #include "nls/fra.nls"
181 LANG_BEGIN (LANG_FRENCH
, SUBLANG_FRENCH_BELGIAN
) /*0x080C*/
182 #include "nls/frb.nls"
184 LANG_BEGIN (LANG_FRENCH
, SUBLANG_FRENCH_CANADIAN
) /*0x0C0C*/
185 #include "nls/frc.nls"
187 LANG_BEGIN (LANG_FRENCH
, SUBLANG_FRENCH_SWISS
) /*0x100C*/
188 #include "nls/frs.nls"
190 LANG_BEGIN (LANG_FRENCH
, SUBLANG_FRENCH_LUXEMBOURG
) /*0x140C*/
191 #include "nls/frl.nls"
194 LANG_BEGIN (LANG_HUNGARIAN
, SUBLANG_DEFAULT
) /*0x040e*/
195 #include "nls/hun.nls"
198 LANG_BEGIN (LANG_ITALIAN
, SUBLANG_ITALIAN
) /*0x0410*/
199 #include "nls/ita.nls"
201 LANG_BEGIN (LANG_ITALIAN
, SUBLANG_ITALIAN_SWISS
) /*0x0810*/
202 #include "nls/its.nls"
205 LANG_BEGIN (LANG_JAPANESE
, SUBLANG_DEFAULT
) /*0x0411*/
206 #include "nls/jpn.nls"
209 LANG_BEGIN (LANG_KOREAN
, SUBLANG_KOREAN
) /*0x0412*/
210 #include "nls/kor.nls"
213 LANG_BEGIN (LANG_DUTCH
, SUBLANG_DUTCH
) /*0x0413*/
214 #include "nls/nld.nls"
216 LANG_BEGIN (LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
) /*0x0813*/
217 #include "nls/nlb.nls"
219 LANG_BEGIN (LANG_DUTCH
, SUBLANG_DUTCH_SURINAM
) /*0x0C13*/
220 #include "nls/nls.nls"
223 LANG_BEGIN (LANG_NORWEGIAN
, SUBLANG_NORWEGIAN_BOKMAL
) /*0x0414*/
224 #include "nls/nor.nls"
226 LANG_BEGIN (LANG_NORWEGIAN
, SUBLANG_NORWEGIAN_NYNORSK
) /*0x0814*/
227 #include "nls/non.nls"
230 LANG_BEGIN (LANG_POLISH
, SUBLANG_DEFAULT
) /*0x0415*/
231 #include "nls/plk.nls"
234 LANG_BEGIN (LANG_PORTUGUESE
,SUBLANG_PORTUGUESE_BRAZILIAN
) /*0x0416*/
235 #include "nls/ptb.nls"
237 LANG_BEGIN (LANG_PORTUGUESE
,SUBLANG_PORTUGUESE
) /*0x0816*/
238 #include "nls/ptg.nls"
241 LANG_BEGIN (LANG_RUSSIAN
, SUBLANG_DEFAULT
) /*0x419*/
242 #include "nls/rus.nls"
245 LANG_BEGIN (LANG_SLOVAK
, SUBLANG_DEFAULT
) /*0x041b*/
246 #include "nls/sky.nls"
249 LANG_BEGIN (LANG_SWEDISH
, SUBLANG_SWEDISH
) /*0x041d*/
250 #include "nls/sve.nls"
252 LANG_BEGIN (LANG_SWEDISH
, SUBLANG_SWEDISH_FINLAND
) /*0x081d*/
253 #include "nls/svf.nls"
256 LANG_BEGIN (LANG_THAI
, SUBLANG_DEFAULT
) /*0x41e*/
257 #include "nls/tha.nls"
259 LANG_BEGIN (LANG_GAELIC
, SUBLANG_DEFAULT
) /* 0x043c */
260 #include "nls/gae.nls"
263 LANG_BEGIN (LANG_GAELIC
, SUBLANG_GAELIC_SCOTTISH
)
264 #include "nls/gdh.nls"
267 LANG_BEGIN (LANG_GAELIC
, SUBLANG_GAELIC_MANX
)
268 #include "nls/gdv.nls"
271 LANG_BEGIN (LANG_ESPERANTO
, SUBLANG_DEFAULT
) /*0x048f*/
272 #include "nls/esperanto.nls"
275 LANG_BEGIN (LANG_WALON
, SUBLANG_DEFAULT
) /*0x0490*/
276 #include "nls/wal.nls"
279 LANG_BEGIN (LANG_CORNISH
, SUBLANG_DEFAULT
) /* 0x0491 */
280 #include "nls/cor.nls"
283 LANG_BEGIN (LANG_WELSH
, SUBLANG_DEFAULT
) /* 0x0492 */
284 #include "nls/cym.nls"
287 LANG_BEGIN (LANG_BRETON
, SUBLANG_DEFAULT
) /* 0x0x93 */
288 #include "nls/brf.nls"
294 /* Locale name to id map. used by EnumSystemLocales, GetLocaleInfoA
295 * MUST contain all #defines from winnls.h
296 * last entry has NULL name, 0 id.
298 #define LOCALE_ENTRY(x) {#x,LOCALE_##x}
299 static const struct tagLOCALE_NAME2ID
{
302 } locale_name2id
[]= {
303 LOCALE_ENTRY(ILANGUAGE
),
304 LOCALE_ENTRY(SLANGUAGE
),
305 LOCALE_ENTRY(SENGLANGUAGE
),
306 LOCALE_ENTRY(SABBREVLANGNAME
),
307 LOCALE_ENTRY(SNATIVELANGNAME
),
308 LOCALE_ENTRY(ICOUNTRY
),
309 LOCALE_ENTRY(SCOUNTRY
),
310 LOCALE_ENTRY(SENGCOUNTRY
),
311 LOCALE_ENTRY(SABBREVCTRYNAME
),
312 LOCALE_ENTRY(SNATIVECTRYNAME
),
313 LOCALE_ENTRY(IDEFAULTLANGUAGE
),
314 LOCALE_ENTRY(IDEFAULTCOUNTRY
),
315 LOCALE_ENTRY(IDEFAULTCODEPAGE
),
316 LOCALE_ENTRY(IDEFAULTANSICODEPAGE
),
317 LOCALE_ENTRY(IDEFAULTMACCODEPAGE
),
319 LOCALE_ENTRY(IMEASURE
),
320 LOCALE_ENTRY(SDECIMAL
),
321 LOCALE_ENTRY(STHOUSAND
),
322 LOCALE_ENTRY(SGROUPING
),
323 LOCALE_ENTRY(IDIGITS
),
324 LOCALE_ENTRY(ILZERO
),
325 LOCALE_ENTRY(INEGNUMBER
),
326 LOCALE_ENTRY(SNATIVEDIGITS
),
327 LOCALE_ENTRY(SCURRENCY
),
328 LOCALE_ENTRY(SINTLSYMBOL
),
329 LOCALE_ENTRY(SMONDECIMALSEP
),
330 LOCALE_ENTRY(SMONTHOUSANDSEP
),
331 LOCALE_ENTRY(SMONGROUPING
),
332 LOCALE_ENTRY(ICURRDIGITS
),
333 LOCALE_ENTRY(IINTLCURRDIGITS
),
334 LOCALE_ENTRY(ICURRENCY
),
335 LOCALE_ENTRY(INEGCURR
),
338 LOCALE_ENTRY(SSHORTDATE
),
339 LOCALE_ENTRY(SLONGDATE
),
340 LOCALE_ENTRY(STIMEFORMAT
),
342 LOCALE_ENTRY(ILDATE
),
344 LOCALE_ENTRY(ITIMEMARKPOSN
),
345 LOCALE_ENTRY(ICENTURY
),
346 LOCALE_ENTRY(ITLZERO
),
347 LOCALE_ENTRY(IDAYLZERO
),
348 LOCALE_ENTRY(IMONLZERO
),
351 LOCALE_ENTRY(ICALENDARTYPE
),
352 LOCALE_ENTRY(IOPTIONALCALENDAR
),
353 LOCALE_ENTRY(IFIRSTDAYOFWEEK
),
354 LOCALE_ENTRY(IFIRSTWEEKOFYEAR
),
355 LOCALE_ENTRY(SDAYNAME1
),
356 LOCALE_ENTRY(SDAYNAME2
),
357 LOCALE_ENTRY(SDAYNAME3
),
358 LOCALE_ENTRY(SDAYNAME4
),
359 LOCALE_ENTRY(SDAYNAME5
),
360 LOCALE_ENTRY(SDAYNAME6
),
361 LOCALE_ENTRY(SDAYNAME7
),
362 LOCALE_ENTRY(SABBREVDAYNAME1
),
363 LOCALE_ENTRY(SABBREVDAYNAME2
),
364 LOCALE_ENTRY(SABBREVDAYNAME3
),
365 LOCALE_ENTRY(SABBREVDAYNAME4
),
366 LOCALE_ENTRY(SABBREVDAYNAME5
),
367 LOCALE_ENTRY(SABBREVDAYNAME6
),
368 LOCALE_ENTRY(SABBREVDAYNAME7
),
369 LOCALE_ENTRY(SMONTHNAME1
),
370 LOCALE_ENTRY(SMONTHNAME2
),
371 LOCALE_ENTRY(SMONTHNAME3
),
372 LOCALE_ENTRY(SMONTHNAME4
),
373 LOCALE_ENTRY(SMONTHNAME5
),
374 LOCALE_ENTRY(SMONTHNAME6
),
375 LOCALE_ENTRY(SMONTHNAME7
),
376 LOCALE_ENTRY(SMONTHNAME8
),
377 LOCALE_ENTRY(SMONTHNAME9
),
378 LOCALE_ENTRY(SMONTHNAME10
),
379 LOCALE_ENTRY(SMONTHNAME11
),
380 LOCALE_ENTRY(SMONTHNAME12
),
381 LOCALE_ENTRY(SMONTHNAME13
),
382 LOCALE_ENTRY(SABBREVMONTHNAME1
),
383 LOCALE_ENTRY(SABBREVMONTHNAME2
),
384 LOCALE_ENTRY(SABBREVMONTHNAME3
),
385 LOCALE_ENTRY(SABBREVMONTHNAME4
),
386 LOCALE_ENTRY(SABBREVMONTHNAME5
),
387 LOCALE_ENTRY(SABBREVMONTHNAME6
),
388 LOCALE_ENTRY(SABBREVMONTHNAME7
),
389 LOCALE_ENTRY(SABBREVMONTHNAME8
),
390 LOCALE_ENTRY(SABBREVMONTHNAME9
),
391 LOCALE_ENTRY(SABBREVMONTHNAME10
),
392 LOCALE_ENTRY(SABBREVMONTHNAME11
),
393 LOCALE_ENTRY(SABBREVMONTHNAME12
),
394 LOCALE_ENTRY(SABBREVMONTHNAME13
),
395 LOCALE_ENTRY(SPOSITIVESIGN
),
396 LOCALE_ENTRY(SNEGATIVESIGN
),
397 LOCALE_ENTRY(IPOSSIGNPOSN
),
398 LOCALE_ENTRY(INEGSIGNPOSN
),
399 LOCALE_ENTRY(IPOSSYMPRECEDES
),
400 LOCALE_ENTRY(IPOSSEPBYSPACE
),
401 LOCALE_ENTRY(INEGSYMPRECEDES
),
402 LOCALE_ENTRY(INEGSEPBYSPACE
),
403 LOCALE_ENTRY(FONTSIGNATURE
),
404 LOCALE_ENTRY(SISO639LANGNAME
),
405 LOCALE_ENTRY(SISO3166CTRYNAME
),
409 const struct map_lcid2str
{
411 const char *langname
;
413 {0x0401,"Arabic (Saudi Arabia)"},
414 {0x0801,"Arabic (Iraq)"},
415 {0x0c01,"Arabic (Egypt)"},
416 {0x1001,"Arabic (Libya)"},
417 {0x1401,"Arabic (Algeria)"},
418 {0x1801,"Arabic (Morocco)"},
419 {0x1c01,"Arabic (Tunisia)"},
420 {0x2001,"Arabic (Oman)"},
421 {0x2401,"Arabic (Yemen)"},
422 {0x2801,"Arabic (Syria)"},
423 {0x2c01,"Arabic (Jordan)"},
424 {0x3001,"Arabic (Lebanon)"},
425 {0x3401,"Arabic (Kuwait)"},
426 {0x3801,"Arabic (United Arab Emirates)"},
427 {0x3c01,"Arabic (Bahrain)"},
428 {0x4001,"Arabic (Qatar)"},
429 {0x0402,"Bulgarian"},
431 {0x0404,"Chinese (Taiwan)"},
432 {0x0804,"Chinese (People's Republic of China)"},
433 {0x0c04,"Chinese (Hong Kong)"},
434 {0x1004,"Chinese (Singapore)"},
435 {0x1404,"Chinese (Macau)"},
438 {0x0407,"German (Germany)"},
439 {0x0807,"German (Switzerland)"},
440 {0x0c07,"German (Austria)"},
441 {0x1007,"German (Luxembourg)"},
442 {0x1407,"German (Liechtenstein)"},
444 {0x0409,"English (United States)"},
445 {0x0809,"English (United Kingdom)"},
446 {0x0c09,"English (Australia)"},
447 {0x1009,"English (Canada)"},
448 {0x1409,"English (New Zealand)"},
449 {0x1809,"English (Ireland)"},
450 {0x1c09,"English (South Africa)"},
451 {0x2009,"English (Jamaica)"},
452 {0x2409,"English (Caribbean)"},
453 {0x2809,"English (Belize)"},
454 {0x2c09,"English (Trinidad)"},
455 {0x3009,"English (Zimbabwe)"},
456 {0x3409,"English (Philippines)"},
457 {0x040a,"Spanish (Spain, traditional sorting)"},
458 {0x080a,"Spanish (Mexico)"},
459 {0x0c0a,"Spanish (Spain, international sorting)"},
460 {0x100a,"Spanish (Guatemala)"},
461 {0x140a,"Spanish (Costa Rica)"},
462 {0x180a,"Spanish (Panama)"},
463 {0x1c0a,"Spanish (Dominican Republic)"},
464 {0x200a,"Spanish (Venezuela)"},
465 {0x240a,"Spanish (Colombia)"},
466 {0x280a,"Spanish (Peru)"},
467 {0x2c0a,"Spanish (Argentina)"},
468 {0x300a,"Spanish (Ecuador)"},
469 {0x340a,"Spanish (Chile)"},
470 {0x380a,"Spanish (Uruguay)"},
471 {0x3c0a,"Spanish (Paraguay)"},
472 {0x400a,"Spanish (Bolivia)"},
473 {0x440a,"Spanish (El Salvador)"},
474 {0x480a,"Spanish (Honduras)"},
475 {0x4c0a,"Spanish (Nicaragua)"},
476 {0x500a,"Spanish (Puerto Rico)"},
478 {0x040c,"French (France)"},
479 {0x080c,"French (Belgium)"},
480 {0x0c0c,"French (Canada)"},
481 {0x100c,"French (Switzerland)"},
482 {0x140c,"French (Luxembourg)"},
483 {0x180c,"French (Monaco)"},
485 {0x040e,"Hungarian"},
486 {0x040f,"Icelandic"},
487 {0x0410,"Italian (Italy)"},
488 {0x0810,"Italian (Switzerland)"},
490 {0x0412,"Korean (Wansung)"},
491 {0x0812,"Korean (Johab)"},
492 {0x0413,"Dutch (Netherlands)"},
493 {0x0813,"Dutch (Belgium)"},
494 {0x0414,"Norwegian (Bokmal)"},
495 {0x0814,"Norwegian (Nynorsk)"},
497 {0x0416,"Portuguese (Brazil)"},
498 {0x0816,"Portuguese (Portugal)"},
499 {0x0417,"Rhaeto Romanic"},
501 {0x0818,"Moldavian"},
502 {0x0419,"Russian (Russia)"},
503 {0x0819,"Russian (Moldavia)"},
505 {0x081a,"Serbian (latin)"},
506 {0x0c1a,"Serbian (cyrillic)"},
509 {0x041d,"Swedish (Sweden)"},
510 {0x081d,"Swedish (Finland)"},
514 {0x0421,"Indonesian"},
515 {0x0422,"Ukrainian"},
516 {0x0423,"Belarusian"},
520 {0x0427,"Lithuanian (modern)"},
521 {0x0827,"Lithuanian (classic)"},
524 {0x042a,"Vietnamese"},
526 {0x042c,"Azeri (latin)"},
527 {0x082c,"Azeri (cyrillic)"},
530 {0x042f,"Macedonian"},
537 {0x0436,"Afrikaans"},
543 {0x043c,"Irish gaelic"},
544 {0x083c,"Scottish gaelic"},
545 {0x0c3c,"Manx Gaelic"},
546 {0x043e,"Malay (Malaysia)"},
547 {0x083e,"Malay (Brunei Darussalam)"},
550 {0x0443,"Uzbek (latin)"},
551 {0x0843,"Uzbek (cyrillic)"},
560 {0x044c,"Malayalam"},
565 {0x048f,"Esperanto"}, /* Non official */
566 {0x0490,"Walon"}, /* Non official */
567 {0x0491,"Cornish"}, /* Not official */
568 {0x0492,"Welsh"}, /* Not official */
569 {0x0493,"Breton"}, /* Not official */
573 {0x0402,"Bulgarisch"},
574 {0x0403,"Katalanisch"},
575 {0x0404,"Traditionales Chinesisch"},
576 {0x0405,"Tschecisch"},
579 {0x0408,"Griechisch"},
580 {0x0409,"Amerikanisches Englisch"},
581 {0x040A,"Kastilisches Spanisch"},
583 {0x040C,"Franzvsisch"},
584 {0x040D,"Hebrdisch"},
585 {0x040E,"Ungarisch"},
586 {0x040F,"Isldndisch"},
587 {0x0410,"Italienisch"},
588 {0x0411,"Japanisch"},
589 {0x0412,"Koreanisch"},
590 {0x0413,"Niederldndisch"},
591 {0x0414,"Norwegisch-Bokmal"},
593 {0x0416,"Brasilianisches Portugiesisch"},
594 {0x0417,"Rdtoromanisch"},
595 {0x0418,"Rumdnisch"},
597 {0x041A,"Kroatoserbisch (lateinisch)"},
598 {0x041B,"Slowenisch"},
599 {0x041C,"Albanisch"},
600 {0x041D,"Schwedisch"},
605 {0x0804,"Vereinfachtes Chinesisch"},
606 {0x0807,"Schweizerdeutsch"},
607 {0x0809,"Britisches Englisch"},
608 {0x080A,"Mexikanisches Spanisch"},
609 {0x080C,"Belgisches Franzvsisch"},
610 {0x0810,"Schweizerisches Italienisch"},
611 {0x0813,"Belgisches Niederldndisch"},
612 {0x0814,"Norgwegisch-Nynorsk"},
613 {0x0816,"Portugiesisch"},
614 {0x081A,"Serbokratisch (kyrillisch)"},
615 {0x0C1C,"Kanadisches Franzvsisch"},
616 {0x100C,"Schweizerisches Franzvsisch"},
617 {0x0000,"Unbekannt"},
620 /***********************************************************************
621 * GetUserDefaultLCID (OLE2NLS.1)
623 LCID WINAPI
GetUserDefaultLCID()
625 return MAKELCID( GetUserDefaultLangID() , SORT_DEFAULT
);
628 /***********************************************************************
629 * GetSystemDefaultLCID (OLE2NLS.2)
631 LCID WINAPI
GetSystemDefaultLCID()
633 return GetUserDefaultLCID();
636 /***********************************************************************
637 * GetUserDefaultLangID (OLE2NLS.3)
639 LANGID WINAPI
GetUserDefaultLangID()
641 /* caching result, if defined from environment, which should (?) not change during a WINE session */
642 static LANGID userLCID
= 0;
643 if (Options
.language
) {
644 return Languages
[Options
.language
].langid
;
649 char *lang
,*country
,*charset
,*dialect
,*next
;
652 buf
=getenv("LANGUAGE");
653 if (!buf
) buf
=getenv("LANG");
654 if (!buf
) buf
=getenv("LC_ALL");
655 if (!buf
) buf
=getenv("LC_MESSAGES");
656 if (!buf
) buf
=getenv("LC_CTYPE");
657 if (!buf
) return userLCID
= MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
);
659 if (!strcmp(buf
,"POSIX") || !strcmp(buf
,"C")) {
660 return MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
);
666 next
=strchr(lang
,':'); if (next
) *next
++='\0';
667 dialect
=strchr(lang
,'@'); if (dialect
) *dialect
++='\0';
668 charset
=strchr(lang
,'.'); if (charset
) *charset
++='\0';
669 country
=strchr(lang
,'_'); if (country
) *country
++='\0';
671 ret
=MAIN_GetLanguageID(lang
, country
, charset
, dialect
);
675 } while (lang
&& !ret
);
677 /* FIXME : are strings returned by getenv() to be free()'ed ? */
678 userLCID
= (LANGID
)ret
;
683 /***********************************************************************
684 * GetSystemDefaultLangID (OLE2NLS.4)
686 LANGID WINAPI
GetSystemDefaultLangID()
688 return GetUserDefaultLangID();
691 /******************************************************************************
692 * GetLocaleInfo16 [OLE2NLS.5]
693 * Is the last parameter really WORD for Win16?
695 INT16 WINAPI
GetLocaleInfo16(LCID lcid
,LCTYPE LCType
,LPSTR buf
,INT16 len
)
697 return GetLocaleInfoA(lcid
,LCType
,buf
,len
);
699 /******************************************************************************
700 * ConvertDefaultLocale32 [KERNEL32.147]
702 LCID WINAPI
ConvertDefaultLocale32 (LCID lcid
)
704 { case LOCALE_SYSTEM_DEFAULT
:
705 return GetSystemDefaultLCID();
706 case LOCALE_USER_DEFAULT
:
707 return GetUserDefaultLCID();
709 return MAKELCID (LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
711 return MAKELANGID( PRIMARYLANGID(lcid
), SUBLANG_NEUTRAL
);
713 /******************************************************************************
714 * GetLocaleInfo32A [KERNEL32.342]
717 * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
719 * MS online documentation states that the string returned is NULL terminated
720 * except for LOCALE_FONTSIGNATURE which "will return a non-NULL
721 * terminated string".
723 INT WINAPI
GetLocaleInfoA(LCID lcid
,LCTYPE LCType
,LPSTR buf
,INT len
)
729 TRACE("(lcid=0x%lx,lctype=0x%lx,%p,%x)\n",lcid
,LCType
,buf
,len
);
731 if (len
&& (! buf
) ) {
732 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
736 if (lcid
==0 || lcid
== LANG_SYSTEM_DEFAULT
|| (LCType
& LOCALE_NOUSEROVERRIDE
) ) /* 0x00, 0x400 */
738 lcid
= GetSystemDefaultLCID();
740 else if (lcid
== LANG_USER_DEFAULT
) /*0x800*/
742 lcid
= GetUserDefaultLCID();
744 LCType
&= ~(LOCALE_NOUSEROVERRIDE
|LOCALE_USE_CP_ACP
);
746 /* As an option, we could obtain the value from win.ini.
747 This would not match the Wine compile-time option.
748 Also, not all identifiers are available from win.ini */
750 /* If we are through all of this, retLen should not be zero anymore.
751 If it is, the value is not supported */
753 while (locale_name2id
[i
].name
!=NULL
) {
754 if (LCType
== locale_name2id
[i
].id
) {
755 retString
= locale_name2id
[i
].name
;
761 FIXME("Unkown LC type %lX\n",LCType
);
766 for (i
=0;(i
<3 && !found
);i
++) {
769 for (j
=0;j
<sizeof(langlocales
)/sizeof(langlocales
[0]);j
++) {
770 if (langlocales
[j
].lang
== lang
) {
773 for (k
=0;k
<sizeof(langlocales
[j
].locvars
)/sizeof(langlocales
[j
].locvars
[0]) && (langlocales
[j
].locvars
[k
].type
);k
++) {
774 if (langlocales
[j
].locvars
[k
].type
== LCType
) {
776 retString
= langlocales
[j
].locvars
[k
].val
;
784 /* language not found, try without a sublanguage*/
785 if (i
==1) lang
=MAKELANGID( PRIMARYLANGID(lang
), SUBLANG_DEFAULT
);
786 /* mask the LC Value */
787 if (i
==2) LCType
&= 0xfff;
791 ERR("'%s' not supported for your language (%04X).\n",
792 retString
,(WORD
)lcid
);
793 SetLastError(ERROR_INVALID_PARAMETER
);
796 /* a FONTSIGNATURE is not a string, just 6 DWORDs */
797 if (LCType
== LOCALE_FONTSIGNATURE
) {
799 memcpy(buf
, retString
, (len
<=sizeof(FONTSIGNATURE
))?len
:sizeof(FONTSIGNATURE
));
800 return sizeof(FONTSIGNATURE
);
802 /* if len=0 return only the length, don't touch the buffer*/
803 if (len
) lstrcpynA(buf
,retString
,len
);
804 return strlen(retString
)+1;
807 /******************************************************************************
808 * GetLocaleInfo32W [KERNEL32.343]
811 * MS documentation states that len "specifies the size, in bytes (ANSI version)
812 * or characters (Unicode version), of" wbuf. Thus the number returned is
813 * the same between GetLocaleInfo32W and GetLocaleInfo32A.
815 INT WINAPI
GetLocaleInfoW(LCID lcid
,LCTYPE LCType
,LPWSTR wbuf
,INT len
)
819 if (len
&& (! wbuf
) )
820 { SetLastError(ERROR_INSUFFICIENT_BUFFER
);
824 abuf
= (LPSTR
)HeapAlloc(GetProcessHeap(),0,len
);
825 wlen
= GetLocaleInfoA(lcid
, LCType
, abuf
, len
);
827 if (wlen
&& len
) /* if len=0 return only the length*/
828 lstrcpynAtoW(wbuf
,abuf
,len
);
830 HeapFree(GetProcessHeap(),0,abuf
);
834 /******************************************************************************
835 * SetLocaleInfoA [KERNEL32.656]
837 BOOL16 WINAPI
SetLocaleInfoA(DWORD lcid
, DWORD lctype
, LPCSTR data
)
839 FIXME("(%ld,%ld,%s): stub\n",lcid
,lctype
,data
);
843 /******************************************************************************
844 * IsValidLocale [KERNEL32.489]
846 BOOL WINAPI
IsValidLocale(LCID lcid
,DWORD flags
)
848 /* we support ANY language. Well, at least say that...*/
852 /******************************************************************************
853 * EnumSystemLocales32W [KERNEL32.209]
855 BOOL WINAPI
EnumSystemLocalesW( LOCALE_ENUMPROCW lpfnLocaleEnum
,
863 TRACE_(win32
)("(%p,%08lx)\n",lpfnLocaleEnum
,flags
);
864 /* see if we can reuse the Win95 registry entries.... */
865 if (ERROR_SUCCESS
==RegOpenKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\control\\Nls\\Locale\\",&xhkey
)) {
868 if (ERROR_SUCCESS
!=RegEnumKeyW(xhkey
,i
,buffer
,sizeof(buffer
)))
870 if (!lpfnLocaleEnum(buffer
))
879 while (languages
[i
].langid
!=0)
884 sprintf(xbuffer
,"%08lx",(DWORD
)languages
[i
].langid
);
886 cp
= HEAP_strdupAtoW( GetProcessHeap(), 0, xbuffer
);
887 ret
= lpfnLocaleEnum(cp
);
888 HeapFree( GetProcessHeap(), 0, cp
);
895 /******************************************************************************
896 * EnumSystemLocales32A [KERNEL32.208]
898 BOOL WINAPI
EnumSystemLocalesA(LOCALE_ENUMPROCA lpfnLocaleEnum
,
905 TRACE_(win32
)("(%p,%08lx)\n",
909 if ( ERROR_SUCCESS
==RegOpenKeyA(HKEY_LOCAL_MACHINE
,
910 "System\\CurrentControlSet\\Control\\Nls\\Locale\\",
914 DWORD size
=sizeof(buffer
);
915 if (ERROR_SUCCESS
!=RegEnumValueA(xhkey
,i
,buffer
,&size
,NULL
,
918 if (size
&& !lpfnLocaleEnum(buffer
))
926 while (languages
[i
].langid
!=0) {
927 sprintf(buffer
,"%08lx",(DWORD
)languages
[i
].langid
);
928 if (!lpfnLocaleEnum(buffer
))
935 static const unsigned char CT_CType2_LUT
[] = {
936 C2_NOTAPPLICABLE
, /* - 0 */
937 C2_NOTAPPLICABLE
, /* - 1 */
938 C2_NOTAPPLICABLE
, /* - 2 */
939 C2_NOTAPPLICABLE
, /* - 3 */
940 C2_NOTAPPLICABLE
, /* - 4 */
941 C2_NOTAPPLICABLE
, /* - 5 */
942 C2_NOTAPPLICABLE
, /* - 6 */
943 C2_NOTAPPLICABLE
, /* - 7 */
944 C2_NOTAPPLICABLE
, /* - 8 */
945 C2_SEGMENTSEPARATOR
, /* - 9 */
946 C2_NOTAPPLICABLE
, /* - 10 */
947 C2_NOTAPPLICABLE
, /* - 11 */
948 C2_NOTAPPLICABLE
, /* - 12 */
949 C2_NOTAPPLICABLE
, /* - 13 */
950 C2_NOTAPPLICABLE
, /* - 14 */
951 C2_NOTAPPLICABLE
, /* - 15 */
952 C2_NOTAPPLICABLE
, /* - 16 */
953 C2_NOTAPPLICABLE
, /* - 17 */
954 C2_NOTAPPLICABLE
, /* - 18 */
955 C2_NOTAPPLICABLE
, /* - 19 */
956 C2_NOTAPPLICABLE
, /* - 20 */
957 C2_NOTAPPLICABLE
, /* - 21 */
958 C2_NOTAPPLICABLE
, /* - 22 */
959 C2_NOTAPPLICABLE
, /* - 23 */
960 C2_NOTAPPLICABLE
, /* - 24 */
961 C2_NOTAPPLICABLE
, /* - 25 */
962 C2_NOTAPPLICABLE
, /* - 26 */
963 C2_NOTAPPLICABLE
, /* - 27 */
964 C2_NOTAPPLICABLE
, /* - 28 */
965 C2_NOTAPPLICABLE
, /* - 29 */
966 C2_NOTAPPLICABLE
, /* - 30 */
967 C2_NOTAPPLICABLE
, /* - 31 */
968 C2_WHITESPACE
, /* - 32 */
969 C2_OTHERNEUTRAL
, /* ! - 33 */
970 C2_OTHERNEUTRAL
, /* " - 34 */ /* " */
971 C2_EUROPETERMINATOR
, /* # - 35 */
972 C2_EUROPETERMINATOR
, /* $ - 36 */
973 C2_EUROPETERMINATOR
, /* % - 37 */
974 C2_LEFTTORIGHT
, /* & - 38 */
975 C2_OTHERNEUTRAL
, /* ' - 39 */
976 C2_OTHERNEUTRAL
, /* ( - 40 */
977 C2_OTHERNEUTRAL
, /* ) - 41 */
978 C2_OTHERNEUTRAL
, /* * - 42 */
979 C2_EUROPETERMINATOR
, /* + - 43 */
980 C2_COMMONSEPARATOR
, /* , - 44 */
981 C2_EUROPETERMINATOR
, /* - - 45 */
982 C2_EUROPESEPARATOR
, /* . - 46 */
983 C2_EUROPESEPARATOR
, /* / - 47 */
984 C2_EUROPENUMBER
, /* 0 - 48 */
985 C2_EUROPENUMBER
, /* 1 - 49 */
986 C2_EUROPENUMBER
, /* 2 - 50 */
987 C2_EUROPENUMBER
, /* 3 - 51 */
988 C2_EUROPENUMBER
, /* 4 - 52 */
989 C2_EUROPENUMBER
, /* 5 - 53 */
990 C2_EUROPENUMBER
, /* 6 - 54 */
991 C2_EUROPENUMBER
, /* 7 - 55 */
992 C2_EUROPENUMBER
, /* 8 - 56 */
993 C2_EUROPENUMBER
, /* 9 - 57 */
994 C2_COMMONSEPARATOR
, /* : - 58 */
995 C2_OTHERNEUTRAL
, /* ; - 59 */
996 C2_OTHERNEUTRAL
, /* < - 60 */
997 C2_OTHERNEUTRAL
, /* = - 61 */
998 C2_OTHERNEUTRAL
, /* > - 62 */
999 C2_OTHERNEUTRAL
, /* ? - 63 */
1000 C2_LEFTTORIGHT
, /* @ - 64 */
1001 C2_LEFTTORIGHT
, /* A - 65 */
1002 C2_LEFTTORIGHT
, /* B - 66 */
1003 C2_LEFTTORIGHT
, /* C - 67 */
1004 C2_LEFTTORIGHT
, /* D - 68 */
1005 C2_LEFTTORIGHT
, /* E - 69 */
1006 C2_LEFTTORIGHT
, /* F - 70 */
1007 C2_LEFTTORIGHT
, /* G - 71 */
1008 C2_LEFTTORIGHT
, /* H - 72 */
1009 C2_LEFTTORIGHT
, /* I - 73 */
1010 C2_LEFTTORIGHT
, /* J - 74 */
1011 C2_LEFTTORIGHT
, /* K - 75 */
1012 C2_LEFTTORIGHT
, /* L - 76 */
1013 C2_LEFTTORIGHT
, /* M - 77 */
1014 C2_LEFTTORIGHT
, /* N - 78 */
1015 C2_LEFTTORIGHT
, /* O - 79 */
1016 C2_LEFTTORIGHT
, /* P - 80 */
1017 C2_LEFTTORIGHT
, /* Q - 81 */
1018 C2_LEFTTORIGHT
, /* R - 82 */
1019 C2_LEFTTORIGHT
, /* S - 83 */
1020 C2_LEFTTORIGHT
, /* T - 84 */
1021 C2_LEFTTORIGHT
, /* U - 85 */
1022 C2_LEFTTORIGHT
, /* V - 86 */
1023 C2_LEFTTORIGHT
, /* W - 87 */
1024 C2_LEFTTORIGHT
, /* X - 88 */
1025 C2_LEFTTORIGHT
, /* Y - 89 */
1026 C2_LEFTTORIGHT
, /* Z - 90 */
1027 C2_OTHERNEUTRAL
, /* [ - 91 */
1028 C2_OTHERNEUTRAL
, /* \ - 92 */
1029 C2_OTHERNEUTRAL
, /* ] - 93 */
1030 C2_OTHERNEUTRAL
, /* ^ - 94 */
1031 C2_OTHERNEUTRAL
, /* _ - 95 */
1032 C2_OTHERNEUTRAL
, /* ` - 96 */
1033 C2_LEFTTORIGHT
, /* a - 97 */
1034 C2_LEFTTORIGHT
, /* b - 98 */
1035 C2_LEFTTORIGHT
, /* c - 99 */
1036 C2_LEFTTORIGHT
, /* d - 100 */
1037 C2_LEFTTORIGHT
, /* e - 101 */
1038 C2_LEFTTORIGHT
, /* f - 102 */
1039 C2_LEFTTORIGHT
, /* g - 103 */
1040 C2_LEFTTORIGHT
, /* h - 104 */
1041 C2_LEFTTORIGHT
, /* i - 105 */
1042 C2_LEFTTORIGHT
, /* j - 106 */
1043 C2_LEFTTORIGHT
, /* k - 107 */
1044 C2_LEFTTORIGHT
, /* l - 108 */
1045 C2_LEFTTORIGHT
, /* m - 109 */
1046 C2_LEFTTORIGHT
, /* n - 110 */
1047 C2_LEFTTORIGHT
, /* o - 111 */
1048 C2_LEFTTORIGHT
, /* p - 112 */
1049 C2_LEFTTORIGHT
, /* q - 113 */
1050 C2_LEFTTORIGHT
, /* r - 114 */
1051 C2_LEFTTORIGHT
, /* s - 115 */
1052 C2_LEFTTORIGHT
, /* t - 116 */
1053 C2_LEFTTORIGHT
, /* u - 117 */
1054 C2_LEFTTORIGHT
, /* v - 118 */
1055 C2_LEFTTORIGHT
, /* w - 119 */
1056 C2_LEFTTORIGHT
, /* x - 120 */
1057 C2_LEFTTORIGHT
, /* y - 121 */
1058 C2_LEFTTORIGHT
, /* z - 122 */
1059 C2_OTHERNEUTRAL
, /* { - 123 */
1060 C2_OTHERNEUTRAL
, /* | - 124 */
1061 C2_OTHERNEUTRAL
, /* } - 125 */
1062 C2_OTHERNEUTRAL
, /* ~ - 126 */
1063 C2_NOTAPPLICABLE
, /* \x7f - 127 */
1064 C2_NOTAPPLICABLE
, /* € - 128 */
1065 C2_NOTAPPLICABLE
, /* � - 129 */
1066 C2_OTHERNEUTRAL
, /* ‚ - 130 */
1067 C2_LEFTTORIGHT
, /* ƒ - 131 */
1068 C2_OTHERNEUTRAL
, /* „ - 132 */
1069 C2_OTHERNEUTRAL
, /* … - 133 */
1070 C2_OTHERNEUTRAL
, /* † - 134 */
1071 C2_OTHERNEUTRAL
, /* ‡ - 135 */
1072 C2_LEFTTORIGHT
, /* ˆ - 136 */
1073 C2_EUROPETERMINATOR
, /* ‰ - 137 */
1074 C2_LEFTTORIGHT
, /* Š - 138 */
1075 C2_OTHERNEUTRAL
, /* ‹ - 139 */
1076 C2_LEFTTORIGHT
, /* Œ - 140 */
1077 C2_NOTAPPLICABLE
, /* � - 141 */
1078 C2_NOTAPPLICABLE
, /* Ž - 142 */
1079 C2_NOTAPPLICABLE
, /* � - 143 */
1080 C2_NOTAPPLICABLE
, /* � - 144 */
1081 C2_OTHERNEUTRAL
, /* ‘ - 145 */
1082 C2_OTHERNEUTRAL
, /* ’ - 146 */
1083 C2_OTHERNEUTRAL
, /* “ - 147 */
1084 C2_OTHERNEUTRAL
, /* ” - 148 */
1085 C2_OTHERNEUTRAL
, /* • - 149 */
1086 C2_OTHERNEUTRAL
, /* – - 150 */
1087 C2_OTHERNEUTRAL
, /* — - 151 */
1088 C2_LEFTTORIGHT
, /* ˜ - 152 */
1089 C2_OTHERNEUTRAL
, /* ™ - 153 */
1090 C2_LEFTTORIGHT
, /* š - 154 */
1091 C2_OTHERNEUTRAL
, /* › - 155 */
1092 C2_LEFTTORIGHT
, /* œ - 156 */
1093 C2_NOTAPPLICABLE
, /* � - 157 */
1094 C2_NOTAPPLICABLE
, /* ž - 158 */
1095 C2_LEFTTORIGHT
, /* Ÿ - 159 */
1096 C2_WHITESPACE
, /* - 160 */
1097 C2_OTHERNEUTRAL
, /* ¡ - 161 */
1098 C2_EUROPETERMINATOR
, /* ¢ - 162 */
1099 C2_EUROPETERMINATOR
, /* £ - 163 */
1100 C2_EUROPETERMINATOR
, /* ¤ - 164 */
1101 C2_EUROPETERMINATOR
, /* ¥ - 165 */
1102 C2_OTHERNEUTRAL
, /* ¦ - 166 */
1103 C2_OTHERNEUTRAL
, /* § - 167 */
1104 C2_OTHERNEUTRAL
, /* ¨ - 168 */
1105 C2_OTHERNEUTRAL
, /* © - 169 */
1106 C2_OTHERNEUTRAL
, /* ª - 170 */
1107 C2_OTHERNEUTRAL
, /* « - 171 */
1108 C2_OTHERNEUTRAL
, /* ¬ - 172 */
1109 C2_OTHERNEUTRAL
, /* - 173 */
1110 C2_OTHERNEUTRAL
, /* ® - 174 */
1111 C2_OTHERNEUTRAL
, /* ¯ - 175 */
1112 C2_EUROPETERMINATOR
, /* ° - 176 */
1113 C2_EUROPETERMINATOR
, /* ± - 177 */
1114 C2_EUROPENUMBER
, /* ² - 178 */
1115 C2_EUROPENUMBER
, /* ³ - 179 */
1116 C2_OTHERNEUTRAL
, /* ´ - 180 */
1117 C2_OTHERNEUTRAL
, /* µ - 181 */
1118 C2_OTHERNEUTRAL
, /* ¶ - 182 */
1119 C2_OTHERNEUTRAL
, /* · - 183 */
1120 C2_OTHERNEUTRAL
, /* ¸ - 184 */
1121 C2_EUROPENUMBER
, /* ¹ - 185 */
1122 C2_OTHERNEUTRAL
, /* º - 186 */
1123 C2_OTHERNEUTRAL
, /* » - 187 */
1124 C2_OTHERNEUTRAL
, /* ¼ - 188 */
1125 C2_OTHERNEUTRAL
, /* ½ - 189 */
1126 C2_OTHERNEUTRAL
, /* ¾ - 190 */
1127 C2_OTHERNEUTRAL
, /* ¿ - 191 */
1128 C2_LEFTTORIGHT
, /* À - 192 */
1129 C2_LEFTTORIGHT
, /* Á - 193 */
1130 C2_LEFTTORIGHT
, /* Â - 194 */
1131 C2_LEFTTORIGHT
, /* Ã - 195 */
1132 C2_LEFTTORIGHT
, /* Ä - 196 */
1133 C2_LEFTTORIGHT
, /* Å - 197 */
1134 C2_LEFTTORIGHT
, /* Æ - 198 */
1135 C2_LEFTTORIGHT
, /* Ç - 199 */
1136 C2_LEFTTORIGHT
, /* È - 200 */
1137 C2_LEFTTORIGHT
, /* É - 201 */
1138 C2_LEFTTORIGHT
, /* Ê - 202 */
1139 C2_LEFTTORIGHT
, /* Ë - 203 */
1140 C2_LEFTTORIGHT
, /* Ì - 204 */
1141 C2_LEFTTORIGHT
, /* Í - 205 */
1142 C2_LEFTTORIGHT
, /* Î - 206 */
1143 C2_LEFTTORIGHT
, /* Ï - 207 */
1144 C2_LEFTTORIGHT
, /* Ð - 208 */
1145 C2_LEFTTORIGHT
, /* Ñ - 209 */
1146 C2_LEFTTORIGHT
, /* Ò - 210 */
1147 C2_LEFTTORIGHT
, /* Ó - 211 */
1148 C2_LEFTTORIGHT
, /* Ô - 212 */
1149 C2_LEFTTORIGHT
, /* Õ - 213 */
1150 C2_LEFTTORIGHT
, /* Ö - 214 */
1151 C2_OTHERNEUTRAL
, /* × - 215 */
1152 C2_LEFTTORIGHT
, /* Ø - 216 */
1153 C2_LEFTTORIGHT
, /* Ù - 217 */
1154 C2_LEFTTORIGHT
, /* Ú - 218 */
1155 C2_LEFTTORIGHT
, /* Û - 219 */
1156 C2_LEFTTORIGHT
, /* Ü - 220 */
1157 C2_LEFTTORIGHT
, /* Ý - 221 */
1158 C2_LEFTTORIGHT
, /* Þ - 222 */
1159 C2_LEFTTORIGHT
, /* ß - 223 */
1160 C2_LEFTTORIGHT
, /* à - 224 */
1161 C2_LEFTTORIGHT
, /* á - 225 */
1162 C2_LEFTTORIGHT
, /* â - 226 */
1163 C2_LEFTTORIGHT
, /* ã - 227 */
1164 C2_LEFTTORIGHT
, /* ä - 228 */
1165 C2_LEFTTORIGHT
, /* å - 229 */
1166 C2_LEFTTORIGHT
, /* æ - 230 */
1167 C2_LEFTTORIGHT
, /* ç - 231 */
1168 C2_LEFTTORIGHT
, /* è - 232 */
1169 C2_LEFTTORIGHT
, /* é - 233 */
1170 C2_LEFTTORIGHT
, /* ê - 234 */
1171 C2_LEFTTORIGHT
, /* ë - 235 */
1172 C2_LEFTTORIGHT
, /* ì - 236 */
1173 C2_LEFTTORIGHT
, /* í - 237 */
1174 C2_LEFTTORIGHT
, /* î - 238 */
1175 C2_LEFTTORIGHT
, /* ï - 239 */
1176 C2_LEFTTORIGHT
, /* ð - 240 */
1177 C2_LEFTTORIGHT
, /* ñ - 241 */
1178 C2_LEFTTORIGHT
, /* ò - 242 */
1179 C2_LEFTTORIGHT
, /* ó - 243 */
1180 C2_LEFTTORIGHT
, /* ô - 244 */
1181 C2_LEFTTORIGHT
, /* õ - 245 */
1182 C2_LEFTTORIGHT
, /* ö - 246 */
1183 C2_OTHERNEUTRAL
, /* ÷ - 247 */
1184 C2_LEFTTORIGHT
, /* ø - 248 */
1185 C2_LEFTTORIGHT
, /* ù - 249 */
1186 C2_LEFTTORIGHT
, /* ú - 250 */
1187 C2_LEFTTORIGHT
, /* û - 251 */
1188 C2_LEFTTORIGHT
, /* ü - 252 */
1189 C2_LEFTTORIGHT
, /* ý - 253 */
1190 C2_LEFTTORIGHT
, /* þ - 254 */
1191 C2_LEFTTORIGHT
/* ÿ - 255 */
1194 const WORD OLE2NLS_CT_CType3_LUT
[] = {
1228 0x0048, /* ! - 33 */
1229 0x0448, /* " - 34 */ /* " */
1230 0x0048, /* # - 35 */
1231 0x0448, /* $ - 36 */
1232 0x0048, /* % - 37 */
1233 0x0048, /* & - 38 */
1234 0x0440, /* ' - 39 */
1235 0x0048, /* ( - 40 */
1236 0x0048, /* ) - 41 */
1237 0x0048, /* * - 42 */
1238 0x0048, /* + - 43 */
1239 0x0048, /* , - 44 */
1240 0x0440, /* - - 45 */
1241 0x0048, /* . - 46 */
1242 0x0448, /* / - 47 */
1243 0x0040, /* 0 - 48 */
1244 0x0040, /* 1 - 49 */
1245 0x0040, /* 2 - 50 */
1246 0x0040, /* 3 - 51 */
1247 0x0040, /* 4 - 52 */
1248 0x0040, /* 5 - 53 */
1249 0x0040, /* 6 - 54 */
1250 0x0040, /* 7 - 55 */
1251 0x0040, /* 8 - 56 */
1252 0x0040, /* 9 - 57 */
1253 0x0048, /* : - 58 */
1254 0x0048, /* ; - 59 */
1255 0x0048, /* < - 60 */
1256 0x0448, /* = - 61 */
1257 0x0048, /* > - 62 */
1258 0x0048, /* ? - 63 */
1259 0x0448, /* @ - 64 */
1260 0x8040, /* A - 65 */
1261 0x8040, /* B - 66 */
1262 0x8040, /* C - 67 */
1263 0x8040, /* D - 68 */
1264 0x8040, /* E - 69 */
1265 0x8040, /* F - 70 */
1266 0x8040, /* G - 71 */
1267 0x8040, /* H - 72 */
1268 0x8040, /* I - 73 */
1269 0x8040, /* J - 74 */
1270 0x8040, /* K - 75 */
1271 0x8040, /* L - 76 */
1272 0x8040, /* M - 77 */
1273 0x8040, /* N - 78 */
1274 0x8040, /* O - 79 */
1275 0x8040, /* P - 80 */
1276 0x8040, /* Q - 81 */
1277 0x8040, /* R - 82 */
1278 0x8040, /* S - 83 */
1279 0x8040, /* T - 84 */
1280 0x8040, /* U - 85 */
1281 0x8040, /* V - 86 */
1282 0x8040, /* W - 87 */
1283 0x8040, /* X - 88 */
1284 0x8040, /* Y - 89 */
1285 0x8040, /* Z - 90 */
1286 0x0048, /* [ - 91 */
1287 0x0448, /* \ - 92 */
1288 0x0048, /* ] - 93 */
1289 0x0448, /* ^ - 94 */
1290 0x0448, /* _ - 95 */
1291 0x0448, /* ` - 96 */
1292 0x8040, /* a - 97 */
1293 0x8040, /* b - 98 */
1294 0x8040, /* c - 99 */
1295 0x8040, /* d - 100 */
1296 0x8040, /* e - 101 */
1297 0x8040, /* f - 102 */
1298 0x8040, /* g - 103 */
1299 0x8040, /* h - 104 */
1300 0x8040, /* i - 105 */
1301 0x8040, /* j - 106 */
1302 0x8040, /* k - 107 */
1303 0x8040, /* l - 108 */
1304 0x8040, /* m - 109 */
1305 0x8040, /* n - 110 */
1306 0x8040, /* o - 111 */
1307 0x8040, /* p - 112 */
1308 0x8040, /* q - 113 */
1309 0x8040, /* r - 114 */
1310 0x8040, /* s - 115 */
1311 0x8040, /* t - 116 */
1312 0x8040, /* u - 117 */
1313 0x8040, /* v - 118 */
1314 0x8040, /* w - 119 */
1315 0x8040, /* x - 120 */
1316 0x8040, /* y - 121 */
1317 0x8040, /* z - 122 */
1318 0x0048, /* { - 123 */
1319 0x0048, /* | - 124 */
1320 0x0048, /* } - 125 */
1321 0x0448, /* ~ - 126 */
1322 0x0000, /* \x7f - 127 */
1323 0x0000, /* € - 128 */
1324 0x0000, /* � - 129 */
1325 0x0008, /* ‚ - 130 */
1326 0x8000, /* ƒ - 131 */
1327 0x0008, /* „ - 132 */
1328 0x0008, /* … - 133 */
1329 0x0008, /* † - 134 */
1330 0x0008, /* ‡ - 135 */
1331 0x0001, /* ˆ - 136 */
1332 0x0008, /* ‰ - 137 */
1333 0x8003, /* Š - 138 */
1334 0x0008, /* ‹ - 139 */
1335 0x8000, /* Œ - 140 */
1336 0x0000, /* � - 141 */
1337 0x0000, /* Ž - 142 */
1338 0x0000, /* � - 143 */
1339 0x0000, /* � - 144 */
1340 0x0088, /* ‘ - 145 */
1341 0x0088, /* ’ - 146 */
1342 0x0088, /* “ - 147 */
1343 0x0088, /* ” - 148 */
1344 0x0008, /* • - 149 */
1345 0x0400, /* – - 150 */
1346 0x0400, /* — - 151 */
1347 0x0408, /* ˜ - 152 */
1348 0x0000, /* ™ - 153 */
1349 0x8003, /* š - 154 */
1350 0x0008, /* › - 155 */
1351 0x8000, /* œ - 156 */
1352 0x0000, /* � - 157 */
1353 0x0000, /* ž - 158 */
1354 0x8003, /* Ÿ - 159 */
1356 0x0008, /* ¡ - 161 */
1357 0x0048, /* ¢ - 162 */
1358 0x0048, /* £ - 163 */
1359 0x0008, /* ¤ - 164 */
1360 0x0048, /* ¥ - 165 */
1361 0x0048, /* ¦ - 166 */
1362 0x0008, /* § - 167 */
1363 0x0408, /* ¨ - 168 */
1364 0x0008, /* © - 169 */
1365 0x0400, /* ª - 170 */
1366 0x0008, /* « - 171 */
1367 0x0048, /* ¬ - 172 */
1368 0x0408, /* - 173 */
1369 0x0008, /* ® - 174 */
1370 0x0448, /* ¯ - 175 */
1371 0x0008, /* ° - 176 */
1372 0x0008, /* ± - 177 */
1373 0x0000, /* ² - 178 */
1374 0x0000, /* ³ - 179 */
1375 0x0408, /* ´ - 180 */
1376 0x0008, /* µ - 181 */
1377 0x0008, /* ¶ - 182 */
1378 0x0008, /* · - 183 */
1379 0x0408, /* ¸ - 184 */
1380 0x0000, /* ¹ - 185 */
1381 0x0400, /* º - 186 */
1382 0x0008, /* » - 187 */
1383 0x0000, /* ¼ - 188 */
1384 0x0000, /* ½ - 189 */
1385 0x0000, /* ¾ - 190 */
1386 0x0008, /* ¿ - 191 */
1387 0x8003, /* À - 192 */
1388 0x8003, /* Á - 193 */
1389 0x8003, /* Â - 194 */
1390 0x8003, /* Ã - 195 */
1391 0x8003, /* Ä - 196 */
1392 0x8003, /* Å - 197 */
1393 0x8000, /* Æ - 198 */
1394 0x8003, /* Ç - 199 */
1395 0x8003, /* È - 200 */
1396 0x8003, /* É - 201 */
1397 0x8003, /* Ê - 202 */
1398 0x8003, /* Ë - 203 */
1399 0x8003, /* Ì - 204 */
1400 0x8003, /* Í - 205 */
1401 0x8003, /* Î - 206 */
1402 0x8003, /* Ï - 207 */
1403 0x8000, /* Ð - 208 */
1404 0x8003, /* Ñ - 209 */
1405 0x8003, /* Ò - 210 */
1406 0x8003, /* Ó - 211 */
1407 0x8003, /* Ô - 212 */
1408 0x8003, /* Õ - 213 */
1409 0x8003, /* Ö - 214 */
1410 0x0008, /* × - 215 */
1411 0x8003, /* Ø - 216 */
1412 0x8003, /* Ù - 217 */
1413 0x8003, /* Ú - 218 */
1414 0x8003, /* Û - 219 */
1415 0x8003, /* Ü - 220 */
1416 0x8003, /* Ý - 221 */
1417 0x8000, /* Þ - 222 */
1418 0x8000, /* ß - 223 */
1419 0x8003, /* à - 224 */
1420 0x8003, /* á - 225 */
1421 0x8003, /* â - 226 */
1422 0x8003, /* ã - 227 */
1423 0x8003, /* ä - 228 */
1424 0x8003, /* å - 229 */
1425 0x8000, /* æ - 230 */
1426 0x8003, /* ç - 231 */
1427 0x8003, /* è - 232 */
1428 0x8003, /* é - 233 */
1429 0x8003, /* ê - 234 */
1430 0x8003, /* ë - 235 */
1431 0x8003, /* ì - 236 */
1432 0x8003, /* í - 237 */
1433 0x8003, /* î - 238 */
1434 0x8003, /* ï - 239 */
1435 0x8000, /* ð - 240 */
1436 0x8003, /* ñ - 241 */
1437 0x8003, /* ò - 242 */
1438 0x8003, /* ó - 243 */
1439 0x8003, /* ô - 244 */
1440 0x8003, /* õ - 245 */
1441 0x8003, /* ö - 246 */
1442 0x0008, /* ÷ - 247 */
1443 0x8003, /* ø - 248 */
1444 0x8003, /* ù - 249 */
1445 0x8003, /* ú - 250 */
1446 0x8003, /* û - 251 */
1447 0x8003, /* ü - 252 */
1448 0x8003, /* ý - 253 */
1449 0x8000, /* þ - 254 */
1450 0x8003 /* ÿ - 255 */
1453 /******************************************************************************
1454 * GetStringType16 [OLE2NLS.7]
1456 BOOL16 WINAPI
GetStringType16(LCID locale
,DWORD dwInfoType
,LPCSTR src
,
1457 INT16 cchSrc
,LPWORD chartype
)
1459 return GetStringTypeExA(locale
,dwInfoType
,src
,cchSrc
,chartype
);
1461 /******************************************************************************
1462 * GetStringType32A [KERNEL32.396]
1464 BOOL WINAPI
GetStringTypeA(LCID locale
,DWORD dwInfoType
,LPCSTR src
,
1465 INT cchSrc
,LPWORD chartype
)
1467 return GetStringTypeExA(locale
,dwInfoType
,src
,cchSrc
,chartype
);
1470 /******************************************************************************
1471 * GetStringTypeEx32A [KERNEL32.397]
1473 * FIXME: Ignores the locale.
1475 BOOL WINAPI
GetStringTypeExA(LCID locale
,DWORD dwInfoType
,LPCSTR src
,
1476 INT cchSrc
,LPWORD chartype
)
1480 if ((src
==NULL
) || (chartype
==NULL
) || (src
==(LPSTR
)chartype
))
1482 SetLastError(ERROR_INVALID_PARAMETER
);
1487 cchSrc
=lstrlenA(src
)+1;
1489 switch (dwInfoType
) {
1491 for (i
=0;i
<cchSrc
;i
++)
1494 if (isdigit(src
[i
])) chartype
[i
]|=C1_DIGIT
;
1495 if (isalpha(src
[i
])) chartype
[i
]|=C1_ALPHA
;
1496 if (islower(src
[i
])) chartype
[i
]|=C1_LOWER
;
1497 if (isupper(src
[i
])) chartype
[i
]|=C1_UPPER
;
1498 if (isspace(src
[i
])) chartype
[i
]|=C1_SPACE
;
1499 if (ispunct(src
[i
])) chartype
[i
]|=C1_PUNCT
;
1500 if (iscntrl(src
[i
])) chartype
[i
]|=C1_CNTRL
;
1501 /* FIXME: isblank() is a GNU extension */
1502 /* if (isblank(src[i])) chartype[i]|=C1_BLANK; */
1503 if ((src
[i
] == ' ') || (src
[i
] == '\t')) chartype
[i
]|=C1_BLANK
;
1509 for (i
=0;i
<cchSrc
;i
++)
1511 chartype
[i
]=(WORD
)CT_CType2_LUT
[i
];
1516 for (i
=0;i
<cchSrc
;i
++)
1518 chartype
[i
]=OLE2NLS_CT_CType3_LUT
[i
];
1523 ERR("Unknown dwInfoType:%ld\n",dwInfoType
);
1528 /******************************************************************************
1529 * GetStringType32W [KERNEL32.399]
1532 * Yes, this is missing LCID locale. MS fault.
1534 BOOL WINAPI
GetStringTypeW(DWORD dwInfoType
,LPCWSTR src
,INT cchSrc
,
1537 return GetStringTypeExW(0/*defaultlocale*/,dwInfoType
,src
,cchSrc
,chartype
);
1540 /******************************************************************************
1541 * GetStringTypeEx32W [KERNEL32.398]
1543 * FIXME: unicode chars are assumed chars
1545 BOOL WINAPI
GetStringTypeExW(LCID locale
,DWORD dwInfoType
,LPCWSTR src
,
1546 INT cchSrc
,LPWORD chartype
)
1552 cchSrc
=lstrlenW(src
)+1;
1554 switch (dwInfoType
) {
1556 FIXME("CT_CTYPE2 not supported.\n");
1559 FIXME("CT_CTYPE3 not supported.\n");
1563 for (i
=0;i
<cchSrc
;i
++) {
1565 if (isdigit(src
[i
])) chartype
[i
]|=C1_DIGIT
;
1566 if (isalpha(src
[i
])) chartype
[i
]|=C1_ALPHA
;
1567 if (islower(src
[i
])) chartype
[i
]|=C1_LOWER
;
1568 if (isupper(src
[i
])) chartype
[i
]|=C1_UPPER
;
1569 if (isspace(src
[i
])) chartype
[i
]|=C1_SPACE
;
1570 if (ispunct(src
[i
])) chartype
[i
]|=C1_PUNCT
;
1571 if (iscntrl(src
[i
])) chartype
[i
]|=C1_CNTRL
;
1572 /* FIXME: isblank() is a GNU extension */
1573 /* if (isblank(src[i])) chartype[i]|=C1_BLANK; */
1574 if ((src
[i
] == ' ') || (src
[i
] == '\t')) chartype
[i
]|=C1_BLANK
;
1580 /*****************************************************************
1581 * WINE_GetLanguageName [internal]
1583 static LPCSTR
WINE_GetLanguageName( UINT langid
)
1586 for ( i
= 0; languages
[i
].langid
!= 0; i
++ )
1587 if ( langid
== languages
[i
].langid
)
1590 return languages
[i
].langname
;
1593 /***********************************************************************
1594 * VerLanguageNameA [KERNEL32.709][VERSION.9]
1596 DWORD WINAPI
VerLanguageNameA( UINT wLang
, LPSTR szLang
, UINT nSize
)
1603 * First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
1604 * from the registry.
1608 "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",
1611 result
= RegQueryValueA( HKEY_LOCAL_MACHINE
, buffer
, szLang
, (LPDWORD
)&nSize
);
1612 if ( result
== ERROR_SUCCESS
|| result
== ERROR_MORE_DATA
)
1616 * If that fails, use the internal table
1619 name
= WINE_GetLanguageName( wLang
);
1620 lstrcpynA( szLang
, name
, nSize
);
1621 return lstrlenA( name
);
1624 /***********************************************************************
1625 * VerLanguageNameW [KERNEL32.710][VERSION.10]
1627 DWORD WINAPI
VerLanguageNameW( UINT wLang
, LPWSTR szLang
, UINT nSize
)
1635 * First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
1636 * from the registry.
1640 "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",
1643 keyname
= HEAP_strdupAtoW( GetProcessHeap(), 0, buffer
);
1644 result
= RegQueryValueW( HKEY_LOCAL_MACHINE
, keyname
, szLang
, (LPDWORD
)&nSize
);
1645 HeapFree( GetProcessHeap(), 0, keyname
);
1647 if ( result
== ERROR_SUCCESS
|| result
== ERROR_MORE_DATA
)
1651 * If that fails, use the internal table
1654 name
= WINE_GetLanguageName( wLang
);
1655 lstrcpynAtoW( szLang
, name
, nSize
);
1656 return lstrlenA( name
);
1660 static const unsigned char LCM_Unicode_LUT
[] = {
1693 7 , 28, /* ! - 33 */
1694 7 , 29, /* " - 34 */ /* " */
1695 7 , 31, /* # - 35 */
1696 7 , 33, /* $ - 36 */
1697 7 , 35, /* % - 37 */
1698 7 , 37, /* & - 38 */
1699 6 , 128, /* ' - 39 */
1700 7 , 39, /* ( - 40 */
1701 7 , 42, /* ) - 41 */
1702 7 , 45, /* * - 42 */
1704 7 , 47, /* , - 44 */
1705 6 , 130, /* - - 45 */
1706 7 , 51, /* . - 46 */
1707 7 , 53, /* / - 47 */
1708 12 , 3, /* 0 - 48 */
1709 12 , 33, /* 1 - 49 */
1710 12 , 51, /* 2 - 50 */
1711 12 , 70, /* 3 - 51 */
1712 12 , 88, /* 4 - 52 */
1713 12 , 106, /* 5 - 53 */
1714 12 , 125, /* 6 - 54 */
1715 12 , 144, /* 7 - 55 */
1716 12 , 162, /* 8 - 56 */
1717 12 , 180, /* 9 - 57 */
1718 7 , 55, /* : - 58 */
1719 7 , 58, /* ; - 59 */
1720 8 , 14, /* < - 60 */
1721 8 , 18, /* = - 61 */
1722 8 , 20, /* > - 62 */
1723 7 , 60, /* ? - 63 */
1724 7 , 62, /* @ - 64 */
1725 14 , 2, /* A - 65 */
1726 14 , 9, /* B - 66 */
1727 14 , 10, /* C - 67 */
1728 14 , 26, /* D - 68 */
1729 14 , 33, /* E - 69 */
1730 14 , 35, /* F - 70 */
1731 14 , 37, /* G - 71 */
1732 14 , 44, /* H - 72 */
1733 14 , 50, /* I - 73 */
1734 14 , 53, /* J - 74 */
1735 14 , 54, /* K - 75 */
1736 14 , 72, /* L - 76 */
1737 14 , 81, /* M - 77 */
1738 14 , 112, /* N - 78 */
1739 14 , 124, /* O - 79 */
1740 14 , 126, /* P - 80 */
1741 14 , 137, /* Q - 81 */
1742 14 , 138, /* R - 82 */
1743 14 , 145, /* S - 83 */
1744 14 , 153, /* T - 84 */
1745 14 , 159, /* U - 85 */
1746 14 , 162, /* V - 86 */
1747 14 , 164, /* W - 87 */
1748 14 , 166, /* X - 88 */
1749 14 , 167, /* Y - 89 */
1750 14 , 169, /* Z - 90 */
1751 7 , 63, /* [ - 91 */
1752 7 , 65, /* \ - 92 */
1753 7 , 66, /* ] - 93 */
1754 7 , 67, /* ^ - 94 */
1755 7 , 68, /* _ - 95 */
1756 7 , 72, /* ` - 96 */
1757 14 , 2, /* a - 97 */
1758 14 , 9, /* b - 98 */
1759 14 , 10, /* c - 99 */
1760 14 , 26, /* d - 100 */
1761 14 , 33, /* e - 101 */
1762 14 , 35, /* f - 102 */
1763 14 , 37, /* g - 103 */
1764 14 , 44, /* h - 104 */
1765 14 , 50, /* i - 105 */
1766 14 , 53, /* j - 106 */
1767 14 , 54, /* k - 107 */
1768 14 , 72, /* l - 108 */
1769 14 , 81, /* m - 109 */
1770 14 , 112, /* n - 110 */
1771 14 , 124, /* o - 111 */
1772 14 , 126, /* p - 112 */
1773 14 , 137, /* q - 113 */
1774 14 , 138, /* r - 114 */
1775 14 , 145, /* s - 115 */
1776 14 , 153, /* t - 116 */
1777 14 , 159, /* u - 117 */
1778 14 , 162, /* v - 118 */
1779 14 , 164, /* w - 119 */
1780 14 , 166, /* x - 120 */
1781 14 , 167, /* y - 121 */
1782 14 , 169, /* z - 122 */
1783 7 , 74, /* { - 123 */
1784 7 , 76, /* | - 124 */
1785 7 , 78, /* } - 125 */
1786 7 , 80, /* ~ - 126 */
1787 6 , 29, /* \x7f - 127 */
1788 6 , 30, /* € - 128 */
1789 6 , 31, /* � - 129 */
1790 7 , 123, /* ‚ - 130 */
1791 14 , 35, /* ƒ - 131 */
1792 7 , 127, /* „ - 132 */
1793 10 , 21, /* … - 133 */
1794 10 , 15, /* † - 134 */
1795 10 , 16, /* ‡ - 135 */
1796 7 , 67, /* ˆ - 136 */
1797 10 , 22, /* ‰ - 137 */
1798 14 , 145, /* Š - 138 */
1799 7 , 136, /* ‹ - 139 */
1800 14 + 16 , 124, /* Œ - 140 */
1801 6 , 43, /* � - 141 */
1802 6 , 44, /* Ž - 142 */
1803 6 , 45, /* � - 143 */
1804 6 , 46, /* � - 144 */
1805 7 , 121, /* ‘ - 145 */
1806 7 , 122, /* ’ - 146 */
1807 7 , 125, /* “ - 147 */
1808 7 , 126, /* ” - 148 */
1809 10 , 17, /* • - 149 */
1810 6 , 137, /* – - 150 */
1811 6 , 139, /* — - 151 */
1812 7 , 93, /* ˜ - 152 */
1813 14 , 156, /* ™ - 153 */
1814 14 , 145, /* š - 154 */
1815 7 , 137, /* › - 155 */
1816 14 + 16 , 124, /* œ - 156 */
1817 6 , 59, /* � - 157 */
1818 6 , 60, /* ž - 158 */
1819 14 , 167, /* Ÿ - 159 */
1821 7 , 81, /* ¡ - 161 */
1822 10 , 2, /* ¢ - 162 */
1823 10 , 3, /* £ - 163 */
1824 10 , 4, /* ¤ - 164 */
1825 10 , 5, /* ¥ - 165 */
1826 7 , 82, /* ¦ - 166 */
1827 10 , 6, /* § - 167 */
1828 7 , 83, /* ¨ - 168 */
1829 10 , 7, /* © - 169 */
1830 14 , 2, /* ª - 170 */
1831 8 , 24, /* « - 171 */
1832 10 , 8, /* ¬ - 172 */
1833 6 , 131, /* - 173 */
1834 10 , 9, /* ® - 174 */
1835 7 , 84, /* ¯ - 175 */
1836 10 , 10, /* ° - 176 */
1837 8 , 23, /* ± - 177 */
1838 12 , 51, /* ² - 178 */
1839 12 , 70, /* ³ - 179 */
1840 7 , 85, /* ´ - 180 */
1841 10 , 11, /* µ - 181 */
1842 10 , 12, /* ¶ - 182 */
1843 10 , 13, /* · - 183 */
1844 7 , 86, /* ¸ - 184 */
1845 12 , 33, /* ¹ - 185 */
1846 14 , 124, /* º - 186 */
1847 8 , 26, /* » - 187 */
1848 12 , 21, /* ¼ - 188 */
1849 12 , 25, /* ½ - 189 */
1850 12 , 29, /* ¾ - 190 */
1851 7 , 87, /* ¿ - 191 */
1852 14 , 2, /* À - 192 */
1853 14 , 2, /* Á - 193 */
1854 14 , 2, /* Â - 194 */
1855 14 , 2, /* Ã - 195 */
1856 14 , 2, /* Ä - 196 */
1857 14 , 2, /* Å - 197 */
1858 14 + 16 , 2, /* Æ - 198 */
1859 14 , 10, /* Ç - 199 */
1860 14 , 33, /* È - 200 */
1861 14 , 33, /* É - 201 */
1862 14 , 33, /* Ê - 202 */
1863 14 , 33, /* Ë - 203 */
1864 14 , 50, /* Ì - 204 */
1865 14 , 50, /* Í - 205 */
1866 14 , 50, /* Î - 206 */
1867 14 , 50, /* Ï - 207 */
1868 14 , 26, /* Ð - 208 */
1869 14 , 112, /* Ñ - 209 */
1870 14 , 124, /* Ò - 210 */
1871 14 , 124, /* Ó - 211 */
1872 14 , 124, /* Ô - 212 */
1873 14 , 124, /* Õ - 213 */
1874 14 , 124, /* Ö - 214 */
1875 8 , 28, /* × - 215 */
1876 14 , 124, /* Ø - 216 */
1877 14 , 159, /* Ù - 217 */
1878 14 , 159, /* Ú - 218 */
1879 14 , 159, /* Û - 219 */
1880 14 , 159, /* Ü - 220 */
1881 14 , 167, /* Ý - 221 */
1882 14 + 32 , 153, /* Þ - 222 */
1883 14 + 48 , 145, /* ß - 223 */
1884 14 , 2, /* à - 224 */
1885 14 , 2, /* á - 225 */
1886 14 , 2, /* â - 226 */
1887 14 , 2, /* ã - 227 */
1888 14 , 2, /* ä - 228 */
1889 14 , 2, /* å - 229 */
1890 14 + 16 , 2, /* æ - 230 */
1891 14 , 10, /* ç - 231 */
1892 14 , 33, /* è - 232 */
1893 14 , 33, /* é - 233 */
1894 14 , 33, /* ê - 234 */
1895 14 , 33, /* ë - 235 */
1896 14 , 50, /* ì - 236 */
1897 14 , 50, /* í - 237 */
1898 14 , 50, /* î - 238 */
1899 14 , 50, /* ï - 239 */
1900 14 , 26, /* ð - 240 */
1901 14 , 112, /* ñ - 241 */
1902 14 , 124, /* ò - 242 */
1903 14 , 124, /* ó - 243 */
1904 14 , 124, /* ô - 244 */
1905 14 , 124, /* õ - 245 */
1906 14 , 124, /* ö - 246 */
1907 8 , 29, /* ÷ - 247 */
1908 14 , 124, /* ø - 248 */
1909 14 , 159, /* ù - 249 */
1910 14 , 159, /* ú - 250 */
1911 14 , 159, /* û - 251 */
1912 14 , 159, /* ü - 252 */
1913 14 , 167, /* ý - 253 */
1914 14 + 32 , 153, /* þ - 254 */
1915 14 , 167 /* ÿ - 255 */ };
1917 static const unsigned char LCM_Unicode_LUT_2
[] = { 33, 44, 145 };
1919 #define LCM_Diacritic_Start 131
1921 static const unsigned char LCM_Diacritic_LUT
[] = {
2049 /******************************************************************************
2050 * OLE2NLS_isPunctuation [INTERNAL]
2052 static int OLE2NLS_isPunctuation(unsigned char c
)
2054 /* "punctuation character" in this context is a character which is
2055 considered "less important" during word sort comparison.
2056 See LCMapString implementation for the precise definition
2057 of "less important". */
2059 return (LCM_Unicode_LUT
[-2+2*c
]==6);
2062 /******************************************************************************
2063 * OLE2NLS_isNonSpacing [INTERNAL]
2065 static int OLE2NLS_isNonSpacing(unsigned char c
)
2067 /* This function is used by LCMapString32A. Characters
2068 for which it returns true are ignored when mapping a
2069 string with NORM_IGNORENONSPACE */
2070 return ((c
==136) || (c
==170) || (c
==186));
2073 /******************************************************************************
2074 * OLE2NLS_isSymbol [INTERNAL]
2076 static int OLE2NLS_isSymbol(unsigned char c
)
2078 /* This function is used by LCMapString32A. Characters
2079 for which it returns true are ignored when mapping a
2080 string with NORM_IGNORESYMBOLS */
2081 return ( (c
!=0) && !IsCharAlphaNumericA(c
) );
2084 /******************************************************************************
2085 * identity [Internal]
2087 static int identity(int c
)
2092 /*************************************************************************
2093 * LCMapString32A [KERNEL32.492]
2095 * Convert a string, or generate a sort key from it.
2097 * If (mapflags & LCMAP_SORTKEY), the function will generate
2098 * a sort key for the source string. Else, it will convert it
2099 * accordingly to the flags LCMAP_UPPERCASE, LCMAP_LOWERCASE,...
2103 * Success : length of the result string.
2106 * If called with scrlen = -1, the function will compute the length
2107 * of the 0-terminated string strsrc by itself.
2109 * If called with dstlen = 0, returns the buffer length that
2110 * would be required.
2112 * NORM_IGNOREWIDTH means to compare ASCII and wide characters
2113 * as if they are equal.
2114 * In the only code page implemented so far, there may not be
2115 * wide characters in strings passed to LCMapString32A,
2116 * so there is nothing to be done for this flag.
2118 INT WINAPI
LCMapStringA(
2119 LCID lcid
/* locale identifier created with MAKELCID;
2120 LOCALE_SYSTEM_DEFAULT and LOCALE_USER_DEFAULT are
2121 predefined values. */,
2122 DWORD mapflags
/* flags */,
2123 LPCSTR srcstr
/* source buffer */,
2124 INT srclen
/* source length */,
2125 LPSTR dststr
/* destination buffer */,
2126 INT dstlen
/* destination buffer length */)
2130 TRACE_(string
)("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
2131 lcid
,mapflags
,srcstr
,srclen
,dststr
,dstlen
);
2133 if ( ((dstlen
!=0) && (dststr
==NULL
)) || (srcstr
==NULL
) )
2135 ERR("(src=%s,dest=%s): Invalid NULL string\n", srcstr
, dststr
);
2136 SetLastError(ERROR_INVALID_PARAMETER
);
2140 srclen
= lstrlenA(srcstr
) + 1 ; /* (include final '\0') */
2142 #define LCMAPSTRINGA_SUPPORTED_FLAGS (LCMAP_UPPERCASE | \
2146 NORM_IGNORENONSPACE | \
2148 NORM_IGNOREWIDTH | \
2149 NORM_IGNOREKANATYPE)
2150 /* FIXME: as long as we don't support Kanakana nor Hirigana
2151 * characters, we can support NORM_IGNOREKANATYPE
2153 if (mapflags
& ~LCMAPSTRINGA_SUPPORTED_FLAGS
)
2155 FIXME_(string
)("(0x%04lx,0x%08lx,%p,%d,%p,%d): "
2156 "unimplemented flags: 0x%08lx\n",
2163 mapflags
& ~LCMAPSTRINGA_SUPPORTED_FLAGS
2167 if ( !(mapflags
& LCMAP_SORTKEY
) )
2170 int (*f
)(int) = identity
;
2171 int flag_ignorenonspace
= mapflags
& NORM_IGNORENONSPACE
;
2172 int flag_ignoresymbols
= mapflags
& NORM_IGNORESYMBOLS
;
2174 if (flag_ignorenonspace
|| flag_ignoresymbols
)
2176 /* For some values of mapflags, the length of the resulting
2177 string is not known at this point. Windows does map the string
2178 and does not SetLastError ERROR_INSUFFICIENT_BUFFER in
2182 /* Compute required length */
2183 for (i
=j
=0; i
< srclen
; i
++)
2185 if ( !(flag_ignorenonspace
&& OLE2NLS_isNonSpacing(srcstr
[i
]))
2186 && !(flag_ignoresymbols
&& OLE2NLS_isSymbol(srcstr
[i
])) )
2198 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2202 if (mapflags
& LCMAP_UPPERCASE
)
2204 else if (mapflags
& LCMAP_LOWERCASE
)
2206 /* FIXME: NORM_IGNORENONSPACE requires another conversion */
2207 for (i
=j
=0; (i
<srclen
) && (j
<dstlen
) ; i
++)
2209 if ( !(flag_ignorenonspace
&& OLE2NLS_isNonSpacing(srcstr
[i
]))
2210 && !(flag_ignoresymbols
&& OLE2NLS_isSymbol(srcstr
[i
])) )
2212 dststr
[j
] = (CHAR
) f(srcstr
[i
]);
2219 /* FIXME: This function completely ignores the "lcid" parameter. */
2220 /* else ... (mapflags & LCMAP_SORTKEY) */
2224 int diacritic_len
=0;
2225 int delayed_punctuation_len
=0;
2226 char *case_component
;
2227 char *diacritic_component
;
2228 char *delayed_punctuation_component
;
2230 int flag_stringsort
= mapflags
& SORT_STRINGSORT
;
2232 /* compute how much room we will need */
2233 for (i
=0;i
<srclen
;i
++)
2236 unsigned char source_char
= srcstr
[i
];
2237 if (source_char
!='\0')
2239 if (flag_stringsort
|| !OLE2NLS_isPunctuation(source_char
))
2242 if ( LCM_Unicode_LUT
[-2+2*source_char
] & ~15 )
2243 unicode_len
++; /* double letter */
2247 delayed_punctuation_len
++;
2251 if (isupper(source_char
))
2252 case_len
=unicode_len
;
2254 ofs
= source_char
- LCM_Diacritic_Start
;
2255 if ((ofs
>=0) && (LCM_Diacritic_LUT
[ofs
]!=2))
2256 diacritic_len
=unicode_len
;
2259 if (mapflags
& NORM_IGNORECASE
)
2261 if (mapflags
& NORM_IGNORENONSPACE
)
2264 room
= 2 * unicode_len
/* "unicode" component */
2265 + diacritic_len
/* "diacritic" component */
2266 + case_len
/* "case" component */
2267 + 4 * delayed_punctuation_len
/* punctuation in word sort mode */
2268 + 4 /* four '\1' separators */
2269 + 1 ; /* terminal '\0' */
2272 else if (dstlen
<room
)
2274 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2278 /*FIXME the Pointercheck should not be nessesary */
2279 if (IsBadWritePtr (dststr
,room
))
2280 { ERR_(string
)("bad destination buffer (dststr) : %p,%d\n",dststr
,dstlen
);
2281 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2285 /* locate each component, write separators */
2286 diacritic_component
= dststr
+ 2*unicode_len
;
2287 *diacritic_component
++ = '\1';
2288 case_component
= diacritic_component
+ diacritic_len
;
2289 *case_component
++ = '\1';
2290 delayed_punctuation_component
= case_component
+ case_len
;
2291 *delayed_punctuation_component
++ = '\1';
2292 *delayed_punctuation_component
++ = '\1';
2294 /* read source string char by char, write
2295 corresponding weight in each component. */
2296 for (i
=0,count
=0;i
<srclen
;i
++)
2298 unsigned char source_char
=srcstr
[i
];
2299 if (source_char
!='\0')
2302 type
= LCM_Unicode_LUT
[-2+2*source_char
];
2303 longcode
= type
>> 4;
2305 if (!flag_stringsort
&& OLE2NLS_isPunctuation(source_char
))
2307 UINT16 encrypted_location
= (1<<15) + 7 + 4*count
;
2308 *delayed_punctuation_component
++ = (unsigned char) (encrypted_location
>>8);
2309 *delayed_punctuation_component
++ = (unsigned char) (encrypted_location
&255);
2310 /* big-endian is used here because it lets string comparison be
2311 compatible with numerical comparison */
2313 *delayed_punctuation_component
++ = type
;
2314 *delayed_punctuation_component
++ = LCM_Unicode_LUT
[-1+2*source_char
];
2315 /* assumption : a punctuation character is never a
2316 double or accented letter */
2320 dststr
[2*count
] = type
;
2321 dststr
[2*count
+1] = LCM_Unicode_LUT
[-1+2*source_char
];
2325 case_component
[count
] = ( isupper(source_char
) ? 18 : 2 ) ;
2326 if (count
<diacritic_len
)
2327 diacritic_component
[count
] = 2; /* assumption: a double letter
2328 is never accented */
2331 dststr
[2*count
] = type
;
2332 dststr
[2*count
+1] = *(LCM_Unicode_LUT_2
- 1 + longcode
);
2333 /* 16 in the first column of LCM_Unicode_LUT --> longcode = 1
2334 32 in the first column of LCM_Unicode_LUT --> longcode = 2
2335 48 in the first column of LCM_Unicode_LUT --> longcode = 3 */
2339 case_component
[count
] = ( isupper(source_char
) ? 18 : 2 ) ;
2340 if (count
<diacritic_len
)
2342 int ofs
= source_char
- LCM_Diacritic_Start
;
2343 diacritic_component
[count
] = (ofs
>=0 ? LCM_Diacritic_LUT
[ofs
] : 2);
2349 dststr
[room
-1] = '\0';
2354 /*************************************************************************
2355 * LCMapString32W [KERNEL32.493]
2357 * Convert a string, or generate a sort key from it.
2361 * See LCMapString32A for documentation
2363 INT WINAPI
LCMapStringW(
2364 LCID lcid
,DWORD mapflags
,LPCWSTR srcstr
,INT srclen
,LPWSTR dststr
,
2369 TRACE_(string
)("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n",
2370 lcid
, mapflags
, srcstr
, srclen
, dststr
, dstlen
);
2372 if ( ((dstlen
!=0) && (dststr
==NULL
)) || (srcstr
==NULL
) )
2374 ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr
, dststr
);
2375 SetLastError(ERROR_INVALID_PARAMETER
);
2379 srclen
= lstrlenW(srcstr
)+1;
2381 /* FIXME: Both this function and it's companion LCMapStringA()
2382 * completely ignore the "lcid" parameter. In place of the "lcid"
2383 * parameter the application must set the "LC_COLLATE" or "LC_ALL"
2384 * environment variable prior to invoking this function. */
2385 if (mapflags
& LCMAP_SORTKEY
)
2387 /* Possible values of LC_COLLATE. */
2388 char *lc_collate_default
= 0; /* value prior to this function */
2389 char *lc_collate_env
= 0; /* value retrieved from the environment */
2391 /* General purpose index into strings of any type. */
2394 /* Lengths of various strings where the length is measured in
2395 * wide characters for wide character strings and in bytes for
2396 * native strings. The lengths include the NULL terminator. */
2397 size_t returned_len
= 0;
2398 size_t src_native_len
= 0;
2399 size_t dst_native_len
= 0;
2400 size_t dststr_libc_len
= 0;
2402 /* Native (character set determined by locale) versions of the
2403 * strings source and destination strings. */
2404 LPSTR src_native
= 0;
2405 LPSTR dst_native
= 0;
2407 /* Version of the source and destination strings using the
2408 * "wchar_t" Unicode data type needed by various libc functions. */
2409 wchar_t *srcstr_libc
= 0;
2410 wchar_t *dststr_libc
= 0;
2412 if(!(srcstr_libc
= (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
2413 srclen
* sizeof(wchar_t))))
2415 ERR("Unable to allocate %d bytes for srcstr_libc\n",
2416 srclen
* sizeof(wchar_t));
2417 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2421 /* Convert source string to a libc Unicode string. */
2422 for(str_idx
= 0; str_idx
< srclen
; str_idx
++)
2424 srcstr_libc
[str_idx
] = srcstr
[str_idx
];
2427 /* src_native should contain at most 3 bytes for each
2428 * multibyte characters in the original srcstr string. */
2429 src_native_len
= 3 * srclen
;
2430 if(!(src_native
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0,
2433 ERR("Unable to allocate %d bytes for src_native\n", src_native_len
);
2434 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2435 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2439 /* FIXME: Prior to to setting the LC_COLLATE locale category the
2440 * current value is backed up so it can be restored after the
2441 * last LC_COLLATE sensitive function returns.
2443 * Even though the locale is adjusted for a minimum amount of
2444 * time a race condition exists where other threads may be
2445 * affected if they invoke LC_COLLATE sensitive functions. One
2446 * possible solution is to wrap all LC_COLLATE sensitive Wine
2447 * functions, like LCMapStringW(), in a mutex.
2449 * Another enhancement to the following would be to set the
2450 * LC_COLLATE locale category as a function of the "lcid"
2451 * parameter instead of the "LC_COLLATE" environment variable. */
2452 if(!(lc_collate_default
= setlocale(LC_COLLATE
, NULL
)))
2454 ERR("Unable to query the LC_COLLATE catagory\n");
2455 SetLastError(ERROR_INVALID_PARAMETER
);
2456 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2457 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2461 if(!(lc_collate_env
= setlocale(LC_COLLATE
, "")))
2463 ERR("Unable to inherit the LC_COLLATE locale category from the "
2464 "environment. The \"LC_COLLATE\" environment variable is "
2465 "\"%s\".\n", getenv("LC_COLLATE") ?
2466 getenv("LC_COLLATE") : "<unset>");
2467 SetLastError(ERROR_INVALID_PARAMETER
);
2468 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2469 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2473 TRACE_(string
)("lc_collate_default = %s\n", lc_collate_default
);
2474 TRACE_(string
)("lc_collate_env = %s\n", lc_collate_env
);
2476 /* Convert the libc Unicode string to a native multibyte character
2478 returned_len
= wcstombs(src_native
, srcstr_libc
, src_native_len
) + 1;
2479 if(returned_len
== 0)
2481 LPSTR srcstr_ascii
= (LPSTR
)HEAP_strdupWtoA(GetProcessHeap(),
2483 ERR("wcstombs failed. The string specified (%s) may contains an "
2484 "invalid character.\n", srcstr_ascii
);
2485 SetLastError(ERROR_INVALID_PARAMETER
);
2486 if(srcstr_ascii
) HeapFree(GetProcessHeap(), 0, srcstr_ascii
);
2487 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2488 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2489 setlocale(LC_COLLATE
, lc_collate_default
);
2492 else if(returned_len
> src_native_len
)
2494 src_native
[src_native_len
- 1] = 0;
2495 ERR("wcstombs returned a string (%s) that was longer (%d bytes) "
2496 "than expected (%d bytes).\n", src_native
, returned_len
,
2499 /* Since this is an internal error I'm not sure what the correct
2501 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2503 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2504 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2505 setlocale(LC_COLLATE
, lc_collate_default
);
2508 src_native_len
= returned_len
;
2510 TRACE_(string
)("src_native = %s src_native_len = %d\n",
2511 src_native
, src_native_len
);
2513 /* dst_native seems to contain at most 4 bytes for each byte in
2514 * the original src_native string. Change if need be since this
2515 * isn't documented by the strxfrm() man page. */
2516 dst_native_len
= 4 * src_native_len
;
2517 if(!(dst_native
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0, dst_native_len
)))
2519 ERR("Unable to allocate %d bytes for dst_native\n", dst_native_len
);
2520 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2521 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2522 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2523 setlocale(LC_COLLATE
, lc_collate_default
);
2527 /* The actual translation is done by the following call to
2528 * strxfrm(). The surrounding code could have been simplified
2529 * by calling wcsxfrm() instead except that wcsxfrm() is not
2530 * available on older Linux systems (RedHat 4.1 with
2533 * Also, it is possible that the translation could be done by
2534 * various tables as it is done in LCMapStringA(). However, I'm
2535 * not sure what those tables are. */
2536 returned_len
= strxfrm(dst_native
, src_native
, dst_native_len
) + 1;
2538 if(returned_len
> dst_native_len
)
2540 dst_native
[dst_native_len
- 1] = 0;
2541 ERR("strxfrm returned a string (%s) that was longer (%d bytes) "
2542 "than expected (%d bytes).\n", dst_native
, returned_len
,
2545 /* Since this is an internal error I'm not sure what the correct
2547 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2549 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2550 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2551 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
2552 setlocale(LC_COLLATE
, lc_collate_default
);
2555 dst_native_len
= returned_len
;
2557 TRACE_(string
)("dst_native = %s dst_native_len = %d\n",
2558 dst_native
, dst_native_len
);
2560 dststr_libc_len
= dst_native_len
;
2561 if(!(dststr_libc
= (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
2562 dststr_libc_len
* sizeof(wchar_t))))
2564 ERR("Unable to allocate %d bytes for dststr_libc\n",
2565 dststr_libc_len
* sizeof(wchar_t));
2566 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2567 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2568 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2569 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
2570 setlocale(LC_COLLATE
, lc_collate_default
);
2574 /* Convert the native multibyte string to a libc Unicode string. */
2575 returned_len
= mbstowcs(dststr_libc
, dst_native
, dst_native_len
) + 1;
2577 /* Restore LC_COLLATE now that the last LC_COLLATE sensitive
2578 * function has returned. */
2579 setlocale(LC_COLLATE
, lc_collate_default
);
2581 if(returned_len
== 0)
2583 ERR("mbstowcs failed. The native version of the translated string "
2584 "(%s) may contain an invalid character.\n", dst_native
);
2585 SetLastError(ERROR_INVALID_PARAMETER
);
2586 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2587 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2588 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
2589 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
2594 if(returned_len
> dstlen
)
2596 ERR("mbstowcs returned a string that was longer (%d chars) "
2597 "than the buffer provided (%d chars).\n", returned_len
,
2599 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2600 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2601 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2602 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
2603 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
2606 dstlen
= returned_len
;
2608 /* Convert a libc Unicode string to the destination string. */
2609 for(str_idx
= 0; str_idx
< dstlen
; str_idx
++)
2611 dststr
[str_idx
] = dststr_libc
[str_idx
];
2613 TRACE_(string
)("1st 4 int sized chunks of dststr = %x %x %x %x\n",
2614 *(((int *)dststr
) + 0),
2615 *(((int *)dststr
) + 1),
2616 *(((int *)dststr
) + 2),
2617 *(((int *)dststr
) + 3));
2621 dstlen
= returned_len
;
2623 TRACE_(string
)("dstlen (return) = %d\n", dstlen
);
2624 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
2625 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
2626 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
2627 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
2632 int (*f
)(int)=identity
;
2638 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2642 if (mapflags
& LCMAP_UPPERCASE
)
2644 else if (mapflags
& LCMAP_LOWERCASE
)
2646 for (i
=0; i
< srclen
; i
++)
2647 dststr
[i
] = (WCHAR
) f(srcstr
[i
]);
2652 /***********************************************************************
2653 * CompareString16 (OLE2NLS.8)
2655 UINT16 WINAPI
CompareString16(DWORD lcid
,DWORD fdwStyle
,
2656 LPCSTR s1
,DWORD l1
,LPCSTR s2
,DWORD l2
)
2658 return (UINT16
)CompareStringA(lcid
,fdwStyle
,s1
,l1
,s2
,l2
);
2661 /***********************************************************************
2662 * OLE2NLS_EstimateMappingLength
2664 * Estimates the number of characters required to hold the string
2665 * computed by LCMapStringA.
2667 * The size is always over-estimated, with a fixed limit on the
2668 * amount of estimation error.
2670 * Note that len == -1 is not permitted.
2672 static inline int OLE2NLS_EstimateMappingLength(LCID lcid
, DWORD dwMapFlags
,
2673 LPCSTR str
, DWORD len
)
2675 /* Estimate only for small strings to keep the estimation error from
2676 * becoming too large. */
2677 if (len
< 128) return len
* 8 + 5;
2678 else return LCMapStringA(lcid
, dwMapFlags
, str
, len
, NULL
, 0);
2681 /******************************************************************************
2682 * CompareString32A [KERNEL32.143]
2683 * Compares two strings using locale
2687 * success: CSTR_LESS_THAN, CSTR_EQUAL, CSTR_GREATER_THAN
2692 * Defaults to a word sort, but uses a string sort if
2693 * SORT_STRINGSORT is set.
2694 * Calls SetLastError for ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER.
2698 * This implementation ignores the locale
2702 * Quite inefficient.
2704 UINT WINAPI
CompareStringA(
2705 DWORD lcid
, /* locale ID */
2706 DWORD fdwStyle
, /* comparison-style options */
2707 LPCSTR s1
, /* first string */
2708 DWORD l1
, /* length of first string */
2709 LPCSTR s2
, /* second string */
2710 DWORD l2
) /* length of second string */
2712 int mapstring_flags
;
2716 TRACE("%s and %s\n",
2717 debugstr_a (s1
), debugstr_a (s2
));
2719 if ( (s1
==NULL
) || (s2
==NULL
) )
2721 ERR("(s1=%s,s2=%s): Invalid NULL string\n", s1
, s2
);
2722 SetLastError(ERROR_INVALID_PARAMETER
);
2726 if(fdwStyle
& NORM_IGNORESYMBOLS
)
2727 FIXME("IGNORESYMBOLS not supported\n");
2729 if (l1
== -1) l1
= lstrlenA(s1
);
2730 if (l2
== -1) l2
= lstrlenA(s2
);
2732 mapstring_flags
= LCMAP_SORTKEY
| fdwStyle
;
2733 len1
= OLE2NLS_EstimateMappingLength(lcid
, mapstring_flags
, s1
, l1
);
2734 len2
= OLE2NLS_EstimateMappingLength(lcid
, mapstring_flags
, s2
, l2
);
2736 if ((len1
==0)||(len2
==0))
2737 return 0; /* something wrong happened */
2739 sk1
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0, len1
+ len2
);
2741 if ( (!LCMapStringA(lcid
,mapstring_flags
,s1
,l1
,sk1
,len1
))
2742 || (!LCMapStringA(lcid
,mapstring_flags
,s2
,l2
,sk2
,len2
)) )
2744 ERR("Bug in LCmapString32A.\n");
2749 /* strcmp doesn't necessarily return -1, 0, or 1 */
2750 result
= strcmp(sk1
,sk2
);
2752 HeapFree(GetProcessHeap(),0,sk1
);
2759 /* must be greater, if we reach this point */
2763 /******************************************************************************
2764 * CompareString32W [KERNEL32.144]
2765 * This implementation ignores the locale
2766 * FIXME : Does only string sort. Should
2767 * be reimplemented the same way as CompareString32A.
2769 UINT WINAPI
CompareStringW(DWORD lcid
, DWORD fdwStyle
,
2770 LPCWSTR s1
, DWORD l1
, LPCWSTR s2
,DWORD l2
)
2773 if(fdwStyle
& NORM_IGNORENONSPACE
)
2774 FIXME("IGNORENONSPACE not supprted\n");
2775 if(fdwStyle
& NORM_IGNORESYMBOLS
)
2776 FIXME("IGNORESYMBOLS not supported\n");
2778 /* Is strcmp defaulting to string sort or to word sort?? */
2779 /* FIXME: Handle NORM_STRINGSORT */
2780 l1
= (l1
==-1)?lstrlenW(s1
):l1
;
2781 l2
= (l2
==-1)?lstrlenW(s2
):l2
;
2782 len
= l1
<l2
? l1
:l2
;
2783 ret
= (fdwStyle
& NORM_IGNORECASE
) ?
2784 CRTDLL__wcsnicmp(s1
,s2
,len
) : CRTDLL_wcsncmp(s1
,s2
,len
);
2785 /* not equal, return 1 or 3 */
2786 if(ret
!=0) return ret
+2;
2787 /* same len, return 2 */
2788 if(l1
==l2
) return 2;
2789 /* the longer one is lexically greater */
2790 return (l1
<l2
)? 1 : 3;
2793 /******************************************************************************
2794 * RegisterNLSInfoChanged [OLE2NLS.10]
2796 BOOL16 WINAPI
RegisterNLSInfoChanged16(LPVOID
/*FIXME*/ lpNewNLSInfo
)
2798 FIXME("Fully implemented, but doesn't effect anything.\n");
2809 lpNLSInfo
= lpNewNLSInfo
;
2814 return FALSE
; /* ptr not set */
2817 /******************************************************************************
2818 * OLE_GetFormatA [Internal]
2821 * If datelen == 0, it should return the reguired string length.
2823 This function implements stuff for GetDateFormat() and
2826 d single-digit (no leading zero) day (of month)
2827 dd two-digit day (of month)
2828 ddd short day-of-week name
2829 dddd long day-of-week name
2830 M single-digit month
2832 MMM short month name
2833 MMMM full month name
2834 y two-digit year, no leading 0
2836 yyyy four-digit year
2838 h hours with no leading zero (12-hour)
2839 hh hours with full two digits
2840 H hours with no leading zero (24-hour)
2841 HH hours with full two digits
2842 m minutes with no leading zero
2843 mm minutes with full two digits
2844 s seconds with no leading zero
2845 ss seconds with full two digits
2846 t time marker (A or P)
2847 tt time marker (AM, PM)
2848 '' used to quote literal characters
2849 '' (within a quoted string) indicates a literal '
2851 These functions REQUIRE valid locale, date, and format.
2853 static INT
OLE_GetFormatA(LCID locale
,
2857 LPCSTR _format
, /*in*/
2862 int count
, type
, inquote
, Overflow
;
2868 const char * _dgfmt
[] = { "%d", "%02d" };
2869 const char ** dgfmt
= _dgfmt
- 1;
2871 /* report, for debugging */
2872 TRACE("(0x%lx,0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt=%p \'%s\' , %p, len=%d)\n",
2873 locale
, flags
, tflags
,
2874 xtime
->wDay
, xtime
->wHour
, xtime
->wMinute
, xtime
->wSecond
,
2875 _format
, _format
, date
, datelen
);
2878 FIXME("datelen = 0, returning 255\n");
2882 /* initalize state variables and output buffer */
2884 count
= 0; inquote
= 0; Overflow
= 0;
2886 date
[0] = buf
[0] = '\0';
2888 strcpy(format
,_format
);
2890 /* alter the formatstring, while it works for all languages now in wine
2891 its possible that it fails when the time looks like ss:mm:hh as example*/
2892 if (tflags
& (TIME_NOMINUTESORSECONDS
))
2893 { if ((pos
= strstr ( format
, ":mm")))
2894 { memcpy ( pos
, pos
+3, strlen(format
)-(pos
-format
)-2 );
2897 if (tflags
& (TIME_NOSECONDS
))
2898 { if ((pos
= strstr ( format
, ":ss")))
2899 { memcpy ( pos
, pos
+3, strlen(format
)-(pos
-format
)-2 );
2903 for (inpos
= 0;; inpos
++) {
2904 /* 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]); */
2906 if (format
[inpos
] == '\'') {
2907 if (format
[inpos
+1] == '\'') {
2909 date
[outpos
++] = '\'';
2912 continue; /* we did nothing to the output */
2914 } else if (format
[inpos
] == '\0') {
2915 date
[outpos
++] = '\0';
2916 if (outpos
> datelen
) Overflow
= 1;
2919 date
[outpos
++] = format
[inpos
];
2920 if (outpos
> datelen
) {
2922 date
[outpos
-1] = '\0'; /* this is the last place where
2923 it's safe to write */
2927 } else if ( (count
&& (format
[inpos
] != type
))
2929 || (count
== 2 && strchr("ghHmst", type
)) )
2933 GetLocaleInfoA(locale
,
2935 + xtime
->wDayOfWeek
- 1,
2937 } else if (count
== 3) {
2938 GetLocaleInfoA(locale
,
2939 LOCALE_SABBREVDAYNAME1
2940 + xtime
->wDayOfWeek
- 1,
2943 sprintf(buf
, dgfmt
[count
], xtime
->wDay
);
2945 } else if (type
== 'M') {
2947 GetLocaleInfoA(locale
,
2948 LOCALE_SABBREVMONTHNAME1
2949 + xtime
->wMonth
- 1,
2951 } else if (count
== 4) {
2952 GetLocaleInfoA(locale
,
2954 + xtime
->wMonth
- 1,
2957 sprintf(buf
, dgfmt
[count
], xtime
->wMonth
);
2959 } else if (type
== 'y') {
2961 sprintf(buf
, "%d", xtime
->wYear
);
2962 } else if (count
== 3) {
2964 WARN("unknown format, c=%c, n=%d\n", type
, count
);
2966 sprintf(buf
, dgfmt
[count
], xtime
->wYear
% 100);
2968 } else if (type
== 'g') {
2970 FIXME("LOCALE_ICALENDARTYPE unimp.\n");
2974 WARN("unknown format, c=%c, n=%d\n", type
, count
);
2976 } else if (type
== 'h') {
2977 /* gives us hours 1:00 -- 12:00 */
2978 sprintf(buf
, dgfmt
[count
], (xtime
->wHour
-1)%12 +1);
2979 } else if (type
== 'H') {
2981 sprintf(buf
, dgfmt
[count
], xtime
->wHour
);
2982 } else if ( type
== 'm') {
2983 sprintf(buf
, dgfmt
[count
], xtime
->wMinute
);
2984 } else if ( type
== 's') {
2985 sprintf(buf
, dgfmt
[count
], xtime
->wSecond
);
2986 } else if (type
== 't') {
2988 sprintf(buf
, "%c", (xtime
->wHour
< 12) ? 'A' : 'P');
2989 } else if (count
== 2) {
2990 /* sprintf(buf, "%s", (xtime->wHour < 12) ? "AM" : "PM"); */
2991 GetLocaleInfoA(locale
,
2993 ? LOCALE_S1159
: LOCALE_S2359
,
2998 /* we need to check the next char in the format string
2999 again, no matter what happened */
3002 /* add the contents of buf to the output */
3003 buflen
= strlen(buf
);
3004 if (outpos
+ buflen
< datelen
) {
3005 date
[outpos
] = '\0'; /* for strcat to hook onto */
3009 date
[outpos
] = '\0';
3010 strncat(date
, buf
, datelen
- outpos
);
3011 date
[datelen
- 1] = '\0';
3012 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3013 WARN("insufficient buffer\n");
3017 /* reset the variables we used to keep track of this item */
3020 } else if (format
[inpos
] == '\0') {
3021 /* we can't check for this at the loop-head, because
3022 that breaks the printing of the last format-item */
3023 date
[outpos
] = '\0';
3026 /* continuing a code for an item */
3029 } else if (strchr("hHmstyMdg", format
[inpos
])) {
3030 type
= format
[inpos
];
3033 } else if (format
[inpos
] == '\'') {
3037 date
[outpos
++] = format
[inpos
];
3039 /* now deal with a possible buffer overflow */
3040 if (outpos
>= datelen
) {
3041 date
[datelen
- 1] = '\0';
3042 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3048 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3051 /* finish it off with a string terminator */
3054 if (outpos
> datelen
-1) outpos
= datelen
-1;
3055 date
[outpos
] = '\0';
3057 TRACE("OLE_GetFormatA returns string '%s', len %d\n",
3062 /******************************************************************************
3063 * OLE_GetFormatW [INTERNAL]
3065 static INT
OLE_GetFormatW(LCID locale
, DWORD flags
, DWORD tflags
,
3068 LPWSTR output
, INT outlen
)
3071 int count
, type
=0, inquote
;
3072 int Overflow
; /* loop check */
3075 WCHAR arg0
[] = {0}, arg1
[] = {'%','d',0};
3076 WCHAR arg2
[] = {'%','0','2','d',0};
3078 int datevars
=0, timevars
=0;
3084 /* make a debug report */
3085 TRACE("args: 0x%lx, 0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt:%s (at %p), "
3086 "%p with max len %d\n",
3087 locale
, flags
, tflags
,
3088 xtime
->wDay
, xtime
->wHour
, xtime
->wMinute
, xtime
->wSecond
,
3089 debugstr_w(format
), format
, output
, outlen
);
3092 FIXME("outlen = 0, returning 255\n");
3096 /* initialize state variables */
3099 inquote
= Overflow
= 0;
3100 /* this is really just a sanity check */
3101 output
[0] = buf
[0] = 0;
3103 /* this loop is the core of the function */
3104 for (inpos
= 0; /* we have several break points */ ; inpos
++) {
3106 if (format
[inpos
] == (WCHAR
) '\'') {
3107 if (format
[inpos
+1] == '\'') {
3109 output
[outpos
++] = '\'';
3114 } else if (format
[inpos
] == 0) {
3115 output
[outpos
++] = 0;
3116 if (outpos
> outlen
) Overflow
= 1;
3117 break; /* normal exit (within a quote) */
3119 output
[outpos
++] = format
[inpos
]; /* copy input */
3120 if (outpos
> outlen
) {
3122 output
[outpos
-1] = 0;
3126 } else if ( (count
&& (format
[inpos
] != type
))
3127 || ( (count
==4 && type
=='y') ||
3128 (count
==4 && type
=='M') ||
3129 (count
==4 && type
=='d') ||
3130 (count
==2 && type
=='g') ||
3131 (count
==2 && type
=='h') ||
3132 (count
==2 && type
=='H') ||
3133 (count
==2 && type
=='m') ||
3134 (count
==2 && type
=='s') ||
3135 (count
==2 && type
=='t') ) ) {
3138 GetLocaleInfoW(locale
,
3139 LOCALE_SDAYNAME1
+ xtime
->wDayOfWeek
-1,
3140 buf
, sizeof(buf
)/sizeof(WCHAR
) );
3141 } else if (count
== 3) {
3142 GetLocaleInfoW(locale
,
3143 LOCALE_SABBREVDAYNAME1
+
3144 xtime
->wDayOfWeek
-1,
3145 buf
, sizeof(buf
)/sizeof(WCHAR
) );
3147 wsnprintfW(buf
, 5, argarr
[count
], xtime
->wDay
);
3149 } else if (type
== 'M') {
3151 GetLocaleInfoW(locale
, LOCALE_SMONTHNAME1
+
3152 xtime
->wMonth
-1, buf
,
3153 sizeof(buf
)/sizeof(WCHAR
) );
3154 } else if (count
== 3) {
3155 GetLocaleInfoW(locale
, LOCALE_SABBREVMONTHNAME1
+
3156 xtime
->wMonth
-1, buf
,
3157 sizeof(buf
)/sizeof(WCHAR
) );
3159 wsnprintfW(buf
, 5, argarr
[count
], xtime
->wMonth
);
3161 } else if (type
== 'y') {
3163 wsnprintfW(buf
, 6, argarr
[1] /* "%d" */,
3165 } else if (count
== 3) {
3166 lstrcpynAtoW(buf
, "yyy", 5);
3168 wsnprintfW(buf
, 6, argarr
[count
],
3169 xtime
->wYear
% 100);
3171 } else if (type
== 'g') {
3173 FIXME("LOCALE_ICALENDARTYPE unimplemented\n");
3174 lstrcpynAtoW(buf
, "AD", 5);
3176 /* Win API sez we copy it verbatim */
3177 lstrcpynAtoW(buf
, "g", 5);
3179 } else if (type
== 'h') {
3180 /* hours 1:00-12:00 --- is this right? */
3181 wsnprintfW(buf
, 5, argarr
[count
],
3182 (xtime
->wHour
-1)%12 +1);
3183 } else if (type
== 'H') {
3184 wsnprintfW(buf
, 5, argarr
[count
],
3186 } else if (type
== 'm' ) {
3187 wsnprintfW(buf
, 5, argarr
[count
],
3189 } else if (type
== 's' ) {
3190 wsnprintfW(buf
, 5, argarr
[count
],
3192 } else if (type
== 't') {
3193 GetLocaleInfoW(locale
, (xtime
->wHour
< 12) ?
3194 LOCALE_S1159
: LOCALE_S2359
,
3201 /* no matter what happened, we need to check this next
3202 character the next time we loop through */
3205 /* cat buf onto the output */
3206 outlen
= lstrlenW(buf
);
3207 if (outpos
+ buflen
< outlen
) {
3208 lstrcpyW( output
+ outpos
, buf
);
3211 lstrcpynW( output
+ outpos
, buf
, outlen
- outpos
);
3213 break; /* Abnormal exit */
3216 /* reset the variables we used this time */
3219 } else if (format
[inpos
] == 0) {
3220 /* we can't check for this at the beginning, because that
3221 would keep us from printing a format spec that ended the
3224 break; /* NORMAL EXIT */
3226 /* how we keep track of the middle of a format spec */
3229 } else if ( (datevars
&& (format
[inpos
]=='d' ||
3230 format
[inpos
]=='M' ||
3231 format
[inpos
]=='y' ||
3232 format
[inpos
]=='g') ) ||
3233 (timevars
&& (format
[inpos
]=='H' ||
3234 format
[inpos
]=='h' ||
3235 format
[inpos
]=='m' ||
3236 format
[inpos
]=='s' ||
3237 format
[inpos
]=='t') ) ) {
3238 type
= format
[inpos
];
3241 } else if (format
[inpos
] == '\'') {
3245 /* unquoted literals */
3246 output
[outpos
++] = format
[inpos
];
3251 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3252 WARN(" buffer overflow\n");
3255 /* final string terminator and sanity check */
3257 if (outpos
> outlen
-1) outpos
= outlen
-1;
3258 output
[outpos
] = '0';
3260 TRACE(" returning %s\n", debugstr_w(output
));
3262 return (!Overflow
) ? outlen
: 0;
3267 /******************************************************************************
3268 * GetDateFormat32A [KERNEL32.310]
3269 * Makes an ASCII string of the date
3271 * This function uses format to format the date, or, if format
3272 * is NULL, uses the default for the locale. format is a string
3273 * of literal fields and characters as follows:
3275 * - d single-digit (no leading zero) day (of month)
3276 * - dd two-digit day (of month)
3277 * - ddd short day-of-week name
3278 * - dddd long day-of-week name
3279 * - M single-digit month
3280 * - MM two-digit month
3281 * - MMM short month name
3282 * - MMMM full month name
3283 * - y two-digit year, no leading 0
3284 * - yy two-digit year
3285 * - yyyy four-digit year
3289 INT WINAPI
GetDateFormatA(LCID locale
,DWORD flags
,
3291 LPCSTR format
, LPSTR date
,INT datelen
)
3294 char format_buf
[40];
3297 LPSYSTEMTIME thistime
;
3301 TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",
3302 locale
,flags
,xtime
,format
,date
,datelen
);
3305 locale
= LOCALE_SYSTEM_DEFAULT
;
3308 if (locale
== LOCALE_SYSTEM_DEFAULT
) {
3309 thislocale
= GetSystemDefaultLCID();
3310 } else if (locale
== LOCALE_USER_DEFAULT
) {
3311 thislocale
= GetUserDefaultLCID();
3313 thislocale
= locale
;
3316 if (xtime
== NULL
) {
3323 if (format
== NULL
) {
3324 GetLocaleInfoA(thislocale
, ((flags
&DATE_LONGDATE
)
3326 : LOCALE_SSHORTDATE
),
3327 format_buf
, sizeof(format_buf
));
3328 thisformat
= format_buf
;
3330 thisformat
= format
;
3334 ret
= OLE_GetFormatA(thislocale
, flags
, 0, thistime
, thisformat
,
3339 "GetDateFormat32A() returning %d, with data=%s\n",
3344 /******************************************************************************
3345 * GetDateFormat32W [KERNEL32.311]
3346 * Makes a Unicode string of the date
3348 * Acts the same as GetDateFormat32A(), except that it's Unicode.
3349 * Accepts & returns sizes as counts of Unicode characters.
3352 INT WINAPI
GetDateFormatW(LCID locale
,DWORD flags
,
3355 LPWSTR date
, INT datelen
)
3357 unsigned short datearr
[] = {'1','9','9','4','-','1','-','1',0};
3359 FIXME("STUB (should call OLE_GetFormatW)\n");
3360 lstrcpynW(date
, datearr
, datelen
);
3361 return ( datelen
< 9) ? datelen
: 9;
3366 /**************************************************************************
3367 * EnumDateFormats32A (KERNEL32.198)
3369 BOOL WINAPI
EnumDateFormatsA(
3370 DATEFMT_ENUMPROCA lpDateFmtEnumProc
, LCID Locale
, DWORD dwFlags
)
3372 FIXME("Only US English supported\n");
3374 if(!lpDateFmtEnumProc
)
3376 SetLastError(ERROR_INVALID_PARAMETER
);
3382 case DATE_SHORTDATE
:
3383 if(!(*lpDateFmtEnumProc
)("M/d/yy")) return TRUE
;
3384 if(!(*lpDateFmtEnumProc
)("M/d/yyyy")) return TRUE
;
3385 if(!(*lpDateFmtEnumProc
)("MM/dd/yy")) return TRUE
;
3386 if(!(*lpDateFmtEnumProc
)("MM/dd/yyyy")) return TRUE
;
3387 if(!(*lpDateFmtEnumProc
)("yy/MM/dd")) return TRUE
;
3388 if(!(*lpDateFmtEnumProc
)("dd-MMM-yy")) return TRUE
;
3391 if(!(*lpDateFmtEnumProc
)("dddd, MMMM dd, yyyy")) return TRUE
;
3392 if(!(*lpDateFmtEnumProc
)("MMMM dd, yyyy")) return TRUE
;
3393 if(!(*lpDateFmtEnumProc
)("dddd, dd MMMM, yyyy")) return TRUE
;
3394 if(!(*lpDateFmtEnumProc
)("dd MMMM, yyyy")) return TRUE
;
3397 FIXME("Unknown date format (%ld)\n", dwFlags
);
3398 SetLastError(ERROR_INVALID_PARAMETER
);
3403 /**************************************************************************
3404 * EnumDateFormats32W (KERNEL32.199)
3406 BOOL WINAPI
EnumDateFormatsW(
3407 DATEFMT_ENUMPROCW lpDateFmtEnumProc
, LCID Locale
, DWORD dwFlags
)
3409 FIXME("(%p, %ld, %ld): stub\n", lpDateFmtEnumProc
, Locale
, dwFlags
);
3410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3414 /**************************************************************************
3415 * EnumTimeFormats32A (KERNEL32.210)
3417 BOOL WINAPI
EnumTimeFormatsA(
3418 TIMEFMT_ENUMPROCA lpTimeFmtEnumProc
, LCID Locale
, DWORD dwFlags
)
3420 FIXME("Only US English supported\n");
3422 if(!lpTimeFmtEnumProc
)
3424 SetLastError(ERROR_INVALID_PARAMETER
);
3430 FIXME("Unknown time format (%ld)\n", dwFlags
);
3433 if(!(*lpTimeFmtEnumProc
)("h:mm:ss tt")) return TRUE
;
3434 if(!(*lpTimeFmtEnumProc
)("hh:mm:ss tt")) return TRUE
;
3435 if(!(*lpTimeFmtEnumProc
)("H:mm:ss")) return TRUE
;
3436 if(!(*lpTimeFmtEnumProc
)("HH:mm:ss")) return TRUE
;
3441 /**************************************************************************
3442 * EnumTimeFormats32W (KERNEL32.211)
3444 BOOL WINAPI
EnumTimeFormatsW(
3445 TIMEFMT_ENUMPROCW lpTimeFmtEnumProc
, LCID Locale
, DWORD dwFlags
)
3447 FIXME("(%p,%ld,%ld): stub\n", lpTimeFmtEnumProc
, Locale
, dwFlags
);
3448 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3453 /**************************************************************************
3454 * GetNumberFormat32A (KERNEL32.355)
3456 INT WINAPI
GetNumberFormatA(LCID locale
, DWORD dwflags
,
3457 LPCSTR lpValue
, const NUMBERFMTA
* lpFormat
,
3458 LPSTR lpNumberStr
, int cchNumber
)
3462 UINT thisleadingzero
;
3463 UINT thisgrouping
[8]={ -1 };
3464 LPCSTR thisdecimalsep
;
3465 LPCSTR thisthousandsep
;
3466 UINT thisnegativeorder
;
3471 char roundbuffer
[24]; /* Should be enough */
3474 int dotflag
=0,negflag
=0;
3475 char misc_buf
[8], negative_buf
[4], decimal_buf
[4], thousand_buf
[4];
3476 char digits_buf
[11];
3477 int intsize
=0,decsize
=0,totalsize
,lastgroup
, leadingzeros
=0;
3478 int negsignsize
,decimalsepsize
,thousandsepsize
;
3480 /* Default setting stuff - partially borrowed from GetFormatedDate */
3482 locale
= LOCALE_SYSTEM_DEFAULT
;
3485 if (locale
== LOCALE_SYSTEM_DEFAULT
) {
3486 thislocale
= GetSystemDefaultLCID();
3487 } else if (locale
== LOCALE_USER_DEFAULT
) {
3488 thislocale
= GetUserDefaultLCID();
3490 thislocale
= locale
;
3492 /* Partial implementation: things like native digits are not considered */
3493 if (lpFormat
== NULL
) {
3495 GetLocaleInfoA(thislocale
, LOCALE_IDIGITS
,
3496 misc_buf
, sizeof(misc_buf
));
3497 thisnumdigits
= atoi(misc_buf
);
3499 GetLocaleInfoA(thislocale
, LOCALE_ILZERO
,
3500 misc_buf
, sizeof(misc_buf
));
3501 thisleadingzero
= atoi(misc_buf
);
3503 GetLocaleInfoA(thislocale
, LOCALE_SGROUPING
,
3504 misc_buf
, sizeof(misc_buf
));
3506 /* About grouping mechanism:
3507 I parse the string and pour the group size values along the
3508 thisgrouping[] array, starting by element 1. Then I convert these
3509 values to indexes for insertion into the integer part.
3510 thisgrouping[0]==-1, therefore I ensure index correctness without
3511 need for range checking and related stuff.
3512 The only drawback is the 7 separators limit, hopefully that means
3513 it will fail with numbers bigger than 10^21 if using groups of three
3517 for (i
=1,gptr
=misc_buf
;*gptr
!='\0';i
++) {
3518 /* In control panel, groups up 9 digits long are allowed. If there is any way to use larger groups,
3519 then the next line must be replaced with the following code:
3520 thisgrouping[i] = atoi(gptr);
3521 for (;*gptr!=';' && *gptr!='\0';gptr++) ; */
3523 thisgrouping
[i
] = *(gptr
++)-'0';
3529 /* Take care for repeating group size */
3530 if (thisgrouping
[i
-1]==0) {
3532 thisgrouping
[j
]=thisgrouping
[i
-2];
3537 for (i
=2;i
<=lastgroup
;i
++)
3538 thisgrouping
[i
]+=thisgrouping
[i
-1];
3540 GetLocaleInfoA(thislocale
, LOCALE_SDECIMAL
,
3541 decimal_buf
, sizeof(decimal_buf
));
3542 thisdecimalsep
= decimal_buf
;
3544 GetLocaleInfoA(thislocale
, LOCALE_STHOUSAND
,
3545 thousand_buf
, sizeof(thousand_buf
));
3546 thisthousandsep
= thousand_buf
;
3548 GetLocaleInfoA(thislocale
, LOCALE_INEGNUMBER
,
3549 misc_buf
, sizeof(misc_buf
));
3550 thisnegativeorder
= atoi(misc_buf
);
3554 thisnumdigits
= lpFormat
->NumDigits
;
3555 thisleadingzero
= lpFormat
->LeadingZero
;
3557 thisgrouping
[1] = lpFormat
->Grouping
;
3559 thisgrouping
[i
]=thisgrouping
[i
-1]+lpFormat
->Grouping
;
3562 thisdecimalsep
= lpFormat
->lpDecimalSep
;
3563 thisthousandsep
= lpFormat
->lpThousandSep
;
3564 thisnegativeorder
= lpFormat
->NegativeOrder
;
3568 GetLocaleInfoA(thislocale
, LOCALE_SNATIVEDIGITS
,
3569 digits_buf
, sizeof(digits_buf
));
3571 GetLocaleInfoA(thislocale
, LOCALE_SNEGATIVESIGN
,
3572 negative_buf
, sizeof(negative_buf
));
3574 negsignsize
=strlen(negative_buf
);
3575 decimalsepsize
=strlen(thisdecimalsep
);
3576 thousandsepsize
=strlen(thisthousandsep
);
3578 /* Size calculation */
3584 for (; *sptr
=='0'; sptr
++) leadingzeros
++; /* Ignore leading zeros */
3585 for (; *sptr
!='\0'; sptr
++) {
3586 if (!dotflag
&& *sptr
=='.') {
3588 } else if (*sptr
<'0' || *sptr
>'9') {
3589 SetLastError(ERROR_INVALID_PARAMETER
);
3601 /* Take care of eventual rounding. Only, if I need to do it, then I write
3602 the rounded lpValue copy into roundbuffer, and create the formatted
3603 string from the proper source. This is smarter than copying it always
3604 The buffer includes an extra leading zero, as the number can carry and
3605 get and extra one. If it doesn't, the zero is ignored as any other
3606 useless leading zero
3609 if (decsize
>0 && decsize
>thisnumdigits
) {
3610 sptr
-=(decsize
-thisnumdigits
);
3613 strcpy(roundbuffer
+1,lpValue
);
3616 *(roundbuffer
+1)='0';
3619 dptr
=roundbuffer
+(sptr
-lpValue
); /* +1-1 */
3621 while ( (++*dptr
) > '9') {
3623 if (*dptr
=='.') dptr
--;
3625 if ((negflag
? *(roundbuffer
+leadingzeros
+1) : *(roundbuffer
+leadingzeros
)) == '1')
3635 if (intsize
==0 && (decsize
==0 || thisleadingzero
))
3639 totalsize
+= thisnegativeorder
== 1 || thisnegativeorder
== 3 ? negsignsize
3640 : thisnegativeorder
== 2 || thisnegativeorder
== 4 ? negsignsize
+1 : 2 ;
3642 /* Look for the first grouping to be done */
3643 for (j
=lastgroup
;thisgrouping
[j
]>=intsize
&& j
>0;j
--) ;
3646 totalsize
+=thousandsepsize
* j
;
3647 if (thisnumdigits
>0)
3648 totalsize
+=decimalsepsize
+thisnumdigits
;
3650 if (cchNumber
==0) /* if cchNumber is zero, just return size needed */
3653 if (cchNumber
<totalsize
+1) { /* +1 = Null terminator (right?) */
3654 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3659 /* Formatting stuff starts here */
3664 if (thisnegativeorder
==0)
3666 else if (thisnegativeorder
<=2) {
3667 strcpy(dptr
,negative_buf
);
3669 if (thisnegativeorder
==2)
3675 for (i
=1;*sptr
=='0' ;i
++, sptr
++) ; /* Ignore leading zeros from source*/
3676 if (intsize
==0 && (decsize
==0 || thisleadingzero
)) /* Insert one leading zero into destination if required */
3677 *(dptr
++)=digits_buf
[0];
3678 for (i
=1;i
<=intsize
;i
++) {
3680 *(dptr
++)=digits_buf
[*(sptr
++)-'0'];
3682 /* Insert a group separator if we just reached the end of a group */
3683 if (i
==intsize
-thisgrouping
[j
]) {
3684 strcpy(dptr
,thisthousandsep
);
3685 dptr
+=thousandsepsize
;
3692 if (thisnumdigits
>0) {
3693 strcpy(dptr
,decimal_buf
);
3694 dptr
+=decimalsepsize
;
3695 for (i
=0;i
<thisnumdigits
;i
++)
3696 *(dptr
++)=*sptr
!='\0' ? digits_buf
[*(sptr
++)-'0'] : digits_buf
[0];
3700 if (thisnegativeorder
==0)
3702 else if (thisnegativeorder
>=3) {
3703 if (thisnegativeorder
==4)
3705 strcpy(dptr
,negative_buf
);
3717 /**************************************************************************
3718 * GetNumberFormat32W (KERNEL32.xxx)
3720 INT WINAPI
GetNumberFormatW(LCID locale
, DWORD dwflags
,
3721 LPCWSTR lpvalue
, const NUMBERFMTW
* lpFormat
,
3722 LPWSTR lpNumberStr
, int cchNumber
)
3724 FIXME("%s: stub, no reformating done\n",debugstr_w(lpvalue
));
3726 lstrcpynW( lpNumberStr
, lpvalue
, cchNumber
);
3727 return cchNumber
? lstrlenW( lpNumberStr
) : 0;
3729 /******************************************************************************
3730 * OLE2NLS_CheckLocale [intern]
3732 static LCID
OLE2NLS_CheckLocale (LCID locale
)
3735 { locale
= LOCALE_SYSTEM_DEFAULT
;
3738 if (locale
== LOCALE_SYSTEM_DEFAULT
)
3739 { return GetSystemDefaultLCID();
3741 else if (locale
== LOCALE_USER_DEFAULT
)
3742 { return GetUserDefaultLCID();
3748 /******************************************************************************
3749 * GetTimeFormat32A [KERNEL32.422]
3750 * Makes an ASCII string of the time
3752 * Formats date according to format, or locale default if format is
3753 * NULL. The format consists of literal characters and fields as follows:
3755 * h hours with no leading zero (12-hour)
3756 * hh hours with full two digits
3757 * H hours with no leading zero (24-hour)
3758 * HH hours with full two digits
3759 * m minutes with no leading zero
3760 * mm minutes with full two digits
3761 * s seconds with no leading zero
3762 * ss seconds with full two digits
3763 * t time marker (A or P)
3764 * tt time marker (AM, PM)
3768 GetTimeFormatA(LCID locale
, /* in */
3769 DWORD flags
, /* in */
3770 LPSYSTEMTIME xtime
, /* in */
3771 LPCSTR format
, /* in */
3772 LPSTR timestr
, /* out */
3773 INT timelen
/* in */)
3774 { char format_buf
[40];
3777 LPSYSTEMTIME thistime
;
3779 DWORD thisflags
=LOCALE_STIMEFORMAT
; /* standart timeformat */
3782 TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale
,flags
,xtime
,format
,timestr
,timelen
);
3784 thislocale
= OLE2NLS_CheckLocale ( locale
);
3786 if ( flags
& (TIME_NOTIMEMARKER
| TIME_FORCE24HOURFORMAT
))
3787 { FIXME("TIME_NOTIMEMARKER or TIME_FORCE24HOURFORMAT not implemented\n");
3790 flags
&= (TIME_NOSECONDS
| TIME_NOMINUTESORSECONDS
); /* mask for OLE_GetFormatA*/
3793 { if (flags
& LOCALE_NOUSEROVERRIDE
) /*use system default*/
3794 { thislocale
= GetSystemDefaultLCID();
3796 GetLocaleInfoA(thislocale
, thisflags
, format_buf
, sizeof(format_buf
));
3797 thisformat
= format_buf
;
3800 { thisformat
= format
;
3803 if (xtime
== NULL
) /* NULL means use the current local time*/
3810 ret
= OLE_GetFormatA(thislocale
, thisflags
, flags
, thistime
, thisformat
,
3816 /******************************************************************************
3817 * GetTimeFormat32W [KERNEL32.423]
3818 * Makes a Unicode string of the time
3821 GetTimeFormatW(LCID locale
, /* in */
3822 DWORD flags
, /* in */
3823 LPSYSTEMTIME xtime
, /* in */
3824 LPCWSTR format
, /* in */
3825 LPWSTR timestr
, /* out */
3826 INT timelen
/* in */)
3827 { WCHAR format_buf
[40];
3830 LPSYSTEMTIME thistime
;
3832 DWORD thisflags
=LOCALE_STIMEFORMAT
; /* standart timeformat */
3835 TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale
,flags
,
3836 xtime
,debugstr_w(format
),timestr
,timelen
);
3838 thislocale
= OLE2NLS_CheckLocale ( locale
);
3840 if ( flags
& (TIME_NOTIMEMARKER
| TIME_FORCE24HOURFORMAT
))
3841 { FIXME("TIME_NOTIMEMARKER or TIME_FORCE24HOURFORMAT not implemented\n");
3844 flags
&= (TIME_NOSECONDS
| TIME_NOMINUTESORSECONDS
); /* mask for OLE_GetFormatA*/
3847 { if (flags
& LOCALE_NOUSEROVERRIDE
) /*use system default*/
3848 { thislocale
= GetSystemDefaultLCID();
3850 GetLocaleInfoW(thislocale
, thisflags
, format_buf
, 40);
3851 thisformat
= format_buf
;
3854 { thisformat
= format
;
3857 if (xtime
== NULL
) /* NULL means use the current local time*/
3858 { GetSystemTime(&t
);
3865 ret
= OLE_GetFormatW(thislocale
, thisflags
, flags
, thistime
, thisformat
,
3870 /******************************************************************************
3871 * EnumCalendarInfoA [KERNEL32.196]
3873 BOOL WINAPI
EnumCalendarInfoA(
3874 CALINFO_ENUMPROCA calinfoproc
,LCID locale
,CALID calendar
,CALTYPE caltype
3876 FIXME("(%p,0x%04lx,0x%08lx,0x%08lx),stub!\n",calinfoproc
,locale
,calendar
,caltype
);