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