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