]> git.buserror.net Git - polintos/scott/priv.git/blob - lib/c++/stlport/c_locale_win32/c_locale_win32.c
Add STLport 5.1.4
[polintos/scott/priv.git] / lib / c++ / stlport / c_locale_win32 / c_locale_win32.c
1 /*
2  * Copyright (c) 1999
3  * Silicon Graphics Computer Systems, Inc.
4  *
5  * Copyright (c) 1999
6  * Boris Fomitchev
7  *
8  * Written 2000
9  * Anton Lapach
10  *
11  * This material is provided "as is", with absolutely no warranty expressed
12  * or implied. Any use is at your own risk.
13  *
14  * Permission to use or copy this software for any purpose is hereby granted
15  * without fee, provided the above notices are retained on all copies.
16  * Permission to modify the code and to distribute modified code is granted,
17  * provided the above notices are retained, and a notice that the code was
18  * modified is included with the above copyright notice.
19  *
20  */
21
22 #include <windows.h>
23 #include <limits.h>
24 #if defined (_STLP_MSVC) || defined (__ICL)
25 #  include <memory.h>
26 #endif
27 #include <string.h>
28 #include <locale.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31
32 #if defined (_STLP_USE_SAFE_STRING_FUNCTIONS)
33 #  define _STLP_STRCPY(D, S) strcpy_s(_STLP_ARRAY_AND_SIZE(D), S)
34 #  define _STLP_STRCPY2(D, DS, S) strcpy_s(D, DS, S)
35 #  define _STLP_RETURN_STRCPY2(D, DS, S) strcpy_s(D, DS, S); return D
36 #  define _STLP_STRNCPY(D, DS, S, C) strncpy_s(D, DS, S, C)
37 #  define _STLP_STRCAT(D, S) strcat_s(_STLP_ARRAY_AND_SIZE(D), S)
38 #  define _STLP_STRCAT2(D, DS, S) strcat_s(D, DS, S)
39 #  if !defined (_STLP_NO_WCHAR_T)
40 #    define _STLP_WCSNCPY(D, DS, S, C) wcsncpy_s(D, DS, S, C)
41 #  endif
42 #else
43 #  define _STLP_STRCPY(D, S) strcpy(D, S)
44 #  define _STLP_STRCPY2(D, DS, S) strcpy(D, S)
45 #  define _STLP_RETURN_STRCPY2(D, DS, S) return strcpy(D, S)
46 #  define _STLP_STRNCPY(D, DS, S, C) strncpy(D, S, C)
47 #  define _STLP_STRCAT(D, S) strcat(D, S)
48 #  define _STLP_STRCAT2(D, DS, S) strcat(D, S)
49 #  if !defined (_STLP_NO_WCHAR_T)
50 #    define _STLP_WCSNCPY(D, DS, S, C) wcsncpy(D, S, C)
51 #  endif
52 #endif
53
54 #if defined (__cplusplus)
55 extern "C" {
56 #endif
57
58 /* Framework functions */
59 /*
60   locale :: "lang[_country[.code_page]]"
61   | ".code_page"
62   | ""
63   | NULL
64
65 */
66
67 #if !defined (_LEADBYTE)
68 /* multibyte leadbyte */
69 #  define _LEADBYTE 0x8000
70 #endif
71
72 typedef struct _LOCALECONV {
73   const char* name;
74   const char* abbrev;
75 } LOCALECONV;
76
77 #define MAX_LANG_LEN        64  /* max language name length */
78 #define MAX_CTRY_LEN        64  /* max country name length */
79 #define MAX_MODIFIER_LEN    0   /* max modifier name length - n/a */
80 #define MAX_LC_LEN          (MAX_LANG_LEN+MAX_CTRY_LEN+MAX_MODIFIER_LEN+3)
81                                 /* max entire locale string length */
82 #define MAX_CP_LEN          5   /* max code page name length */
83
84
85 /* Metrowerks has different define here */
86 #if !defined (LC_MAX)
87 #  if defined (LC_LAST)
88 #    define LC_MAX LC_LAST
89 #  endif
90 #endif
91
92 /*  non-NLS language string table */
93 static LOCALECONV __rg_language[] = {
94   {"american",                    "ENU"},
95   {"american english",            "ENU"},
96   {"american-english",            "ENU"},
97   {"australian",                  "ENA"},
98   {"belgian",                     "NLB"},
99   {"canadian",                    "ENC"},
100   {"chh",                         "ZHH"},
101   {"chi",                         "ZHI"},
102   {"chinese",                     "CHS"},
103   {"chinese-hongkong",            "ZHH"},
104   {"chinese-simplified",          "CHS"},
105   {"chinese-singapore",           "ZHI"},
106   {"chinese-traditional",         "CHT"},
107   {"dutch-belgian",               "NLB"},
108   {"english-american",            "ENU"},
109   {"english-aus",                 "ENA"},
110   {"english-belize",              "ENL"},
111   {"english-can",                 "ENC"},
112   {"english-caribbean",           "ENB"},
113   {"english-ire",                 "ENI"},
114   {"english-jamaica",             "ENJ"},
115   {"english-nz",                  "ENZ"},
116   {"english-south africa",        "ENS"},
117   {"english-trinidad y tobago",   "ENT"},
118   {"english-uk",                  "ENG"},
119   {"english-us",                  "ENU"},
120   {"english-usa",                 "ENU"},
121   {"french-belgian",              "FRB"},
122   {"french-canadian",             "FRC"},
123   {"french-luxembourg",           "FRL"},
124   {"french-swiss",                "FRS"},
125   {"german-austrian",             "DEA"},
126   {"german-lichtenstein",         "DEC"},
127   {"german-luxembourg",           "DEL"},
128   {"german-swiss",                "DES"},
129   {"irish-english",               "ENI"},
130   {"italian-swiss",               "ITS"},
131   {"norwegian",                   "NOR"},
132   {"norwegian-bokmal",            "NOR"},
133   {"norwegian-nynorsk",           "NON"},
134   {"portuguese-brazilian",        "PTB"},
135   {"spanish-argentina",           "ESS"},
136   {"spanish-bolivia",             "ESB"},
137   {"spanish-chile",               "ESL"},
138   {"spanish-colombia",            "ESO"},
139   {"spanish-costa rica",          "ESC"},
140   {"spanish-dominican republic",  "ESD"},
141   {"spanish-ecuador",             "ESF"},
142   {"spanish-el salvador",         "ESE"},
143   {"spanish-guatemala",           "ESG"},
144   {"spanish-honduras",            "ESH"},
145   {"spanish-mexican",             "ESM"},
146   {"spanish-modern",              "ESN"},
147   {"spanish-nicaragua",           "ESI"},
148   {"spanish-panama",              "ESA"},
149   {"spanish-paraguay",            "ESZ"},
150   {"spanish-peru",                "ESR"},
151   {"spanish-puerto rico",         "ESU"},
152   {"spanish-uruguay",             "ESY"},
153   {"spanish-venezuela",           "ESV"},
154   {"swedish-finland",             "SVF"},
155   {"swiss",                       "DES"},
156   {"uk",                          "ENG"},
157   {"us",                          "ENU"},
158   {"usa",                         "ENU"}
159 };
160
161 /*  non-NLS country string table */
162 static LOCALECONV __rg_country[] = {
163   {"america",                     "USA"},
164   {"britain",                     "GBR"},
165   {"china",                       "CHN"},
166   {"czech",                       "CZE"},
167   {"england",                     "GBR"},
168   {"great britain",               "GBR"},
169   {"holland",                     "NLD"},
170   {"hong-kong",                   "HKG"},
171   {"new-zealand",                 "NZL"},
172   {"nz",                          "NZL"},
173   {"pr china",                    "CHN"},
174   {"pr-china",                    "CHN"},
175   {"puerto-rico",                 "PRI"},
176   {"slovak",                      "SVK"},
177   {"south africa",                "ZAF"},
178   {"south korea",                 "KOR"},
179   {"south-africa",                "ZAF"},
180   {"south-korea",                 "KOR"},
181   {"trinidad & tobago",           "TTO"},
182   {"uk",                          "GBR"},
183   {"united-kingdom",              "GBR"},
184   {"united-states",               "USA"},
185   {"us",                          "USA"},
186 };
187
188 typedef struct _Locale_name_hint {
189   LCID id;
190 } _Locale_lcid_t;
191
192 typedef struct _Locale_ctype {
193   _Locale_lcid_t lc;
194   UINT cp;
195   unsigned int ctable[256];
196 } _Locale_ctype_t;
197
198 typedef struct _Locale_numeric {
199   _Locale_lcid_t lc;
200   char cp[MAX_CP_LEN + 1];
201   char decimal_point[4];
202   char thousands_sep[4];
203   char *grouping;
204 } _Locale_numeric_t;
205
206 typedef struct _Locale_time {
207   _Locale_lcid_t lc;
208   char cp[MAX_CP_LEN + 1];
209   char *month[12];
210   char *abbrev_month[12];
211   char *dayofweek[7];
212   char *abbrev_dayofweek[7];
213   char *date_time_format;
214   char *long_date_time_format;
215   char *date_format;
216   char *long_date_format;
217   char *time_format;
218   char am[9];
219   char pm[9];
220 } _Locale_time_t;
221
222 typedef struct _Locale_collate {
223   _Locale_lcid_t lc;
224   char cp[MAX_CP_LEN + 1];
225 } _Locale_collate_t;
226
227 typedef struct _Locale_monetary {
228   _Locale_lcid_t lc;
229   char cp[MAX_CP_LEN + 1];
230   char decimal_point[4];
231   char thousands_sep[4];
232   char *grouping;
233   char int_curr_symbol[5]; /* 3 + 1 + 1 */
234   char curr_symbol[6];
235   char negative_sign[5];
236   char positive_sign[5];
237   int frac_digits;
238   int int_frac_digits;
239 } _Locale_monetary_t;
240
241 typedef struct _Locale_messages {
242   _Locale_lcid_t lc;
243   char cp[MAX_CP_LEN + 1];
244 } _Locale_messages_t;
245
246 /* Internal function */
247 static void __FixGrouping(char *grouping);
248 static const char* __ConvertName(const char* lname, LOCALECONV* ConvTable, int TableSize);
249 static int __ParseLocaleString(const char* lname, char* lang, char* ctry, char* page);
250 static int __GetLCID(const char* lang, const char* ctry, LCID* lcid);
251 static int __GetLCIDFromName(const char* lname, LCID* lcid, char *cp, _Locale_lcid_t *hint);
252 static char const* __GetLocaleName(LCID lcid, const char* cp, char* buf);
253 static char const* __Extract_locale_name(const char* loc, int category, char* buf);
254 static char const* __TranslateToSystem(const char* lname, char* buf, _Locale_lcid_t* hint);
255 static void __GetLocaleInfoUsingACP(LCID lcid, const char* cp, LCTYPE lctype, char* buf, int buf_size);
256 static int __intGetACP(LCID lcid);
257 static int __intGetOCP(LCID lcid);
258 static int __GetDefaultCP(LCID lcid);
259 static char* __ConvertToCP(int from_cp, int to_cp, const char *from, size_t size, size_t *ret_buf_size);
260 static void my_ltoa(long __x, char* buf);
261
262 void my_ltoa(long __x, char* buf) {
263   char rbuf[64];
264   char* ptr = rbuf;
265
266   if (__x == 0)
267     *ptr++ = '0';
268   else {
269     for (; __x != 0; __x /= 10)
270       *ptr++ = (char)(__x % 10) + '0';
271   }
272   while(ptr > rbuf) *buf++ = *--ptr;
273   /* psw */
274   *buf = '\0';
275 }
276
277 #if defined (__cplusplus)
278 _STLP_BEGIN_NAMESPACE
279 extern "C" {
280 #endif
281
282   _Locale_lcid_t* _Locale_get_ctype_hint(_Locale_ctype_t* ltype)
283   { return (ltype != 0) ? &ltype->lc : 0; }
284   _Locale_lcid_t* _Locale_get_numeric_hint(_Locale_numeric_t* lnumeric)
285   { return (lnumeric != 0) ? &lnumeric->lc : 0; }
286   _Locale_lcid_t* _Locale_get_time_hint(_Locale_time_t* ltime)
287   { return (ltime != 0) ? &ltime->lc : 0; }
288   _Locale_lcid_t* _Locale_get_collate_hint(_Locale_collate_t* lcollate)
289   { return (lcollate != 0) ? &lcollate->lc : 0; }
290   _Locale_lcid_t* _Locale_get_monetary_hint(_Locale_monetary_t* lmonetary)
291   { return (lmonetary != 0) ? &lmonetary->lc : 0; }
292   _Locale_lcid_t* _Locale_get_messages_hint(_Locale_messages_t* lmessages)
293   { return (lmessages != 0) ? &lmessages->lc : 0; }
294
295   void* _Locale_ctype_create(const char * name, _Locale_lcid_t* lc_hint) {
296     char cname[_Locale_MAX_SIMPLE_NAME];
297     char cp_name[MAX_CP_LEN + 1];
298     int NativeCP;
299     unsigned char Buffer[256];
300     unsigned char *ptr;
301     unsigned short ctable[256];
302     CPINFO CPInfo;
303     int i;
304     wchar_t *wbuffer;
305     int BufferSize;
306
307     _Locale_ctype_t *ltype = (_Locale_ctype_t*)malloc(sizeof(_Locale_ctype_t));
308     if (!ltype) return ltype;
309     memset(ltype, 0, sizeof(_Locale_ctype_t));
310
311     __Extract_locale_name(name, LC_CTYPE, cname);
312
313     if (__GetLCIDFromName(cname, &ltype->lc.id, cp_name, lc_hint) == -1)
314     { free(ltype); return NULL; }
315
316     ltype->cp = atoi(cp_name);
317
318     NativeCP = __GetDefaultCP(ltype->lc.id);
319
320     /* Make table with all characters. */
321     for (i = 0; i < 256; ++i) Buffer[i] = (unsigned char)i;
322
323     if (!GetCPInfo(NativeCP, &CPInfo)) { free(ltype); return NULL; }
324
325     if (CPInfo.MaxCharSize > 1) {
326       for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr+=2)
327         for (i = *ptr; i <= *(ptr + 1); ++i) Buffer[i] = 0;
328     }
329
330     if ((UINT)NativeCP != ltype->cp) {
331       OSVERSIONINFO ver_info;
332       ver_info.dwOSVersionInfoSize = sizeof(ver_info);
333       GetVersionEx(&ver_info);
334       if (ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
335         /* Convert character sequence to Unicode. */
336         BufferSize = MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, (const char*)Buffer, 256, NULL, 0);
337         wbuffer = (wchar_t*)malloc(BufferSize*sizeof(wchar_t));
338         if (!MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, (const char*)Buffer, 256, wbuffer, BufferSize))
339         { free(wbuffer); free(ltype); return NULL; }
340
341         GetStringTypeW(CT_CTYPE1, wbuffer, 256, ctable);
342
343         for (i = 0; i < 256; ++i)
344           ltype->ctable[i]=(unsigned int)ctable[i];
345
346         if (CPInfo.MaxCharSize > 1) {
347           for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr+=2)
348             for (i = *ptr; i <= *(ptr + 1); i++) ltype->ctable[i] = _LEADBYTE;
349         }
350
351         free(wbuffer);
352       }
353       else {
354         unsigned char TargetBuffer[256];
355         GetStringTypeA(ltype->lc.id, CT_CTYPE1, (const char*)Buffer, 256, ctable);
356
357         /* Convert character sequence to target code page. */
358         BufferSize = MultiByteToWideChar(NativeCP, MB_PRECOMPOSED, (const char*)Buffer, 256, NULL, 0);
359         wbuffer = (wchar_t*)malloc(BufferSize*sizeof(wchar_t));
360         if (!MultiByteToWideChar(NativeCP, MB_PRECOMPOSED, (const char*)Buffer, 256, wbuffer, BufferSize))
361         { free(wbuffer); free(ltype); return NULL; }
362         if (!WideCharToMultiByte(ltype->cp, WC_COMPOSITECHECK | WC_SEPCHARS, wbuffer, BufferSize, (char*)TargetBuffer, 256, NULL, FALSE))
363         { free(wbuffer); free(ltype); return NULL; }
364
365         free(wbuffer);
366
367         /* Translate ctype table. */
368         for (i = 0; i < 256; ++i) {
369           if (!TargetBuffer[i]) continue;
370           ltype->ctable[TargetBuffer[i]] = ctable[i];
371         }
372
373         /* Mark lead byte. */
374         if (!GetCPInfo(ltype->cp, &CPInfo)) { free(ltype); return NULL; }
375
376         if (CPInfo.MaxCharSize > 1) {
377           for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr+=2)
378             for (i = *ptr; i <= *(ptr + 1); ++i) ltype->ctable[i] = _LEADBYTE;
379         }
380       }
381     }
382     else {
383       GetStringTypeA(ltype->lc.id, CT_CTYPE1, (const char*)Buffer, 256, ctable);
384       for (i = 0; i < 256; ++i)
385         ltype->ctable[i]=(unsigned int)ctable[i];
386
387       if (CPInfo.MaxCharSize > 1) {
388         for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr+=2)
389           for (i = *ptr; i <= *(ptr + 1); ++i) ltype->ctable[i] = _LEADBYTE;
390       }
391     }
392     return ltype;
393   }
394
395   void* _Locale_numeric_create(const char * name, _Locale_lcid_t* lc_hint) {
396     char *GroupingBuffer;
397     char cname[_Locale_MAX_SIMPLE_NAME];
398     int BufferSize;
399     _Locale_numeric_t *lnum = (_Locale_numeric_t*)malloc(sizeof(_Locale_numeric_t));
400     if (!lnum) return lnum; /* MS normal behavior for 'new' */
401
402     __Extract_locale_name(name, LC_NUMERIC, cname);
403
404     if (__GetLCIDFromName(cname, &lnum->lc.id, lnum->cp, lc_hint) == -1)
405     { free(lnum); return NULL; }
406
407     __GetLocaleInfoUsingACP(lnum->lc.id, lnum->cp, LOCALE_SDECIMAL, lnum->decimal_point, 4);
408     __GetLocaleInfoUsingACP(lnum->lc.id, lnum->cp, LOCALE_STHOUSAND, lnum->thousands_sep, 4);
409
410     BufferSize = GetLocaleInfoA(lnum->lc.id, LOCALE_SGROUPING, NULL, 0);
411     GroupingBuffer = (char*)malloc(BufferSize);
412     if (!GroupingBuffer) { lnum->grouping = NULL; return lnum; }
413     GetLocaleInfoA(lnum->lc.id, LOCALE_SGROUPING, GroupingBuffer, BufferSize);
414     __FixGrouping(GroupingBuffer);
415     lnum->grouping = GroupingBuffer;
416
417     return lnum;
418   }
419
420 static int __ConvertDate(const char *NTDate, char *buffer, int buf_size) {
421   /* This function will return an incomplete buffer if buffer is not long enough */
422   const char *cur_char;
423   char *cur_output, *end_output;
424
425   /* Correct time format. */
426   cur_char = NTDate;
427   cur_output = buffer;
428   end_output = cur_output + buf_size;
429   buf_size = 0;
430   while (*cur_char) {
431     if (cur_output && (cur_output == end_output)) break;
432     switch (*cur_char) {
433     case 'd':
434     {
435       if (*(cur_char + 1) == 'd') {
436         if (cur_output && (cur_output + 2 > end_output)) {
437           *cur_output = 0;
438           return ++buf_size;
439         }
440         if (*(cur_char + 2) == 'd') {
441           if (*(cur_char + 3) == 'd') {
442             if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'A'; }
443             buf_size += 2;
444             cur_char += 3;
445           }
446           else {
447             if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'a'; }
448             buf_size += 2;
449             cur_char += 2;
450           }
451         }
452         else {
453           if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'd'; }
454           buf_size += 2;
455           cur_char++;
456         }
457       }
458       else {
459         if (cur_output && (cur_output + 3 > end_output)) {
460           *cur_output = 0;
461           return ++buf_size;
462         }
463         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'd'; }
464         buf_size += 3;
465       }
466     }
467     break;
468     case 'M':
469     {
470       if (*(cur_char + 1) == 'M') {
471         if (cur_output && (cur_output + 2 > end_output)) {
472           *cur_output = 0;
473           return ++buf_size;
474         }
475         if (*(cur_char + 2) == 'M') {
476           if (*(cur_char + 3) == 'M') {
477             if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'B'; }
478             buf_size += 2;
479             cur_char += 3;
480           }
481           else {
482             if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'b'; }
483             buf_size += 2;
484             cur_char += 2;
485           }
486         }
487         else {
488           if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'm'; }
489           buf_size += 2;
490           cur_char++;
491         }
492       }
493       else {
494         if (cur_output && (cur_output + 3 > end_output)) {
495           *cur_output = 0;
496           return ++buf_size;
497         }
498         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'm'; }
499         buf_size += 3;
500       }
501     }
502     break;
503     case 'y':
504     {
505       if (*(cur_char + 1) == 'y') {
506         if (cur_output && (cur_output + 2 > end_output)) {
507           *cur_output = 0;
508           return ++buf_size;
509         }
510         if (*(cur_char + 2) == 'y' && *(cur_char + 3) == 'y') {
511           if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'Y'; }
512           buf_size += 2;
513           cur_char += 3;
514         }
515         else {
516           if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'y'; }
517           buf_size += 2;
518           cur_char++;
519         }
520       }
521       else {
522         if (cur_output && (cur_output + 3 > end_output)) {
523           *cur_output = 0;
524           return ++buf_size;
525         }
526         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'y'; }
527         buf_size += 3;
528       }
529     }
530     break;
531     case '%':
532     {
533       if (cur_output && (cur_output + 2 > end_output)) {
534         *cur_output = 0;
535         return ++buf_size;
536       }
537       if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '%'; }
538       buf_size += 2;
539     }
540     break;
541     case '\'':
542     {
543       ++cur_char;
544       while (*cur_char != '\'' && *cur_char != 0 && (cur_output == NULL || cur_output != end_output)) {
545         if (cur_output) { *cur_output++ = *cur_char; }
546         ++cur_char;
547         buf_size += 1;
548       }
549     }
550     break;
551     default:
552     {
553       if (cur_output) { *(cur_output++) = *cur_char; }
554       buf_size += 1;
555     }
556     break;
557     }
558     if (*cur_char == 0) break;
559     ++cur_char;
560   }
561
562   if (!cur_output || cur_output != end_output) {
563     if (cur_output) *cur_output = 0;
564     buf_size += 1;
565   }
566   else {
567     /* We trunc result */
568     *(--cur_output) = 0;
569   }
570
571   return buf_size;
572 }
573
574 static int __ConvertTime(const char *NTTime, char *buffer, int buf_size) {
575   const char *cur_char;
576   char *cur_output, *end_output;
577   cur_char = NTTime;
578   cur_output = buffer;
579   end_output = cur_output + buf_size;
580   buf_size = 0;
581   while (*cur_char) {
582     switch(*cur_char) {
583     case 'h':
584       if (*(cur_char + 1) == 'h') {
585         if (cur_output && (cur_output + 2 > end_output)) {
586           *cur_output = 0;
587           return ++buf_size;
588         }
589         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'I'; }
590         buf_size += 2;
591         ++cur_char;
592       }
593       else {
594         if (cur_output && (cur_output + 3 > end_output)) {
595           *cur_output = 0;
596           return ++buf_size;
597         }
598         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'I'; }
599         buf_size += 3;
600       }
601       break;
602     case 'H':
603       if (*(cur_char + 1) == 'H') {
604         if (cur_output && (cur_output + 2 > end_output)) {
605           *cur_output = 0;
606           return ++buf_size;
607         }
608         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'H'; }
609         buf_size += 2;
610         ++cur_char;
611       }
612       else {
613         if (cur_output && (cur_output + 3 > end_output)) {
614           *cur_output = 0;
615           return ++buf_size;
616         }
617         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'H'; }
618         buf_size += 3;
619       }
620       break;
621     case 'm':
622       if (*(cur_char + 1) == 'm') {
623         if (cur_output && (cur_output + 2 > end_output)) {
624           *cur_output = 0;
625           return ++buf_size;
626         }
627         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'M'; }
628         buf_size += 2;
629         cur_char++;
630       }
631       else {
632         if (cur_output && (cur_output + 3 > end_output)) {
633           *cur_output = 0;
634           return ++buf_size;
635         }
636         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'M'; }
637         buf_size += 3;
638       }
639       break;
640     case 's':
641       if (*(cur_char + 1) == 's') {
642         if (cur_output && (cur_output + 2 > end_output)) {
643           *cur_output = 0;
644           return ++buf_size;
645         }
646         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'S'; }
647         buf_size += 2;
648         ++cur_char;
649       }
650       else {
651         if (cur_output && (cur_output + 3 > end_output)) {
652           *cur_output = 0;
653           return ++buf_size;
654         }
655         if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = '#'; *(cur_output++) = 'S'; }
656         buf_size += 3;
657       }
658       break;
659     case 't':
660       if (*(cur_char + 1) == 't')
661         ++cur_char;
662       if (cur_output && (cur_output + 2 > end_output)) {
663         *cur_output = 0;
664         return ++buf_size;
665       }
666       if (cur_output) { *(cur_output++) = '%'; *(cur_output++) = 'p'; }
667       buf_size += 2;
668       break;
669     case '%':
670       if (cur_output && (cur_output + 2 > end_output)) {
671         *cur_output = 0;
672         return ++buf_size;
673       }
674       if (cur_output) { *(cur_output++)='%'; *(cur_output++)='%'; }
675       buf_size += 2;
676       break;
677     case '\'':
678       ++cur_char;
679       while (*cur_char != '\'' && *cur_char != 0 && (!cur_output || (cur_output != end_output))) {
680         if (cur_output) *cur_output++ = *cur_char;
681         ++cur_char;
682         buf_size += 1;
683       }
684       break;
685     default:
686       if (cur_output) { *(cur_output++) = *cur_char; }
687       buf_size += 1;
688       break;
689     }
690     if (*cur_char == 0) break;
691     ++cur_char;
692   }
693
694   if (!cur_output || cur_output != end_output) {
695     if (cur_output) *cur_output = 0;
696     buf_size += 1;
697   }
698   else {
699     /* We trunc result */
700     *(--cur_output) = 0;
701   }
702
703   return buf_size;
704 }
705
706 void* _Locale_time_create(const char * name, _Locale_lcid_t* lc_hint) {
707     int size, month, dayofweek;
708     size_t length;
709     char fmt80[80];
710     char cname[_Locale_MAX_SIMPLE_NAME];
711
712     _Locale_time_t *ltime=(_Locale_time_t*)malloc(sizeof(_Locale_time_t));
713     if (!ltime) return ltime;
714     memset(ltime, 0, sizeof(_Locale_time_t));
715
716     __Extract_locale_name(name, LC_TIME, cname);
717
718     if (__GetLCIDFromName(cname, &ltime->lc.id, ltime->cp, lc_hint) == -1)
719     { free(ltime); return NULL; }
720
721     for (month = LOCALE_SMONTHNAME1; month <= LOCALE_SMONTHNAME12; ++month) { /* Small hack :-) */
722       size = GetLocaleInfoA(ltime->lc.id, month, NULL, 0);
723       ltime->month[month - LOCALE_SMONTHNAME1] = (char*)malloc(size);
724       if (!ltime->month[month - LOCALE_SMONTHNAME1]) { _Locale_time_destroy(ltime); return NULL; }
725       __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, month, ltime->month[month - LOCALE_SMONTHNAME1], size);
726     }
727
728     for (month = LOCALE_SABBREVMONTHNAME1; month <= LOCALE_SABBREVMONTHNAME12; ++month) {
729       size = GetLocaleInfoA(ltime->lc.id, month, NULL, 0);
730       ltime->abbrev_month[month - LOCALE_SABBREVMONTHNAME1] = (char*)malloc(size);
731       if (!ltime->abbrev_month[month - LOCALE_SABBREVMONTHNAME1]) { _Locale_time_destroy(ltime); return NULL; }
732       __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, month, ltime->abbrev_month[month - LOCALE_SABBREVMONTHNAME1], size);
733     }
734
735   for (dayofweek = LOCALE_SDAYNAME1; dayofweek <= LOCALE_SDAYNAME7; ++dayofweek) {
736       int dayindex = ( dayofweek != LOCALE_SDAYNAME7 ) ? dayofweek - LOCALE_SDAYNAME1 + 1 : 0;
737       size = GetLocaleInfoA(ltime->lc.id, dayofweek, NULL, 0);
738       ltime->dayofweek[dayindex] = (char*)malloc(size);
739       if (!ltime->dayofweek[dayindex]) { _Locale_time_destroy(ltime); return NULL; }
740       __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, dayofweek, ltime->dayofweek[dayindex], size);
741     }
742
743   for (dayofweek = LOCALE_SABBREVDAYNAME1; dayofweek <= LOCALE_SABBREVDAYNAME7; ++dayofweek) {
744       int dayindex = ( dayofweek != LOCALE_SABBREVDAYNAME7 ) ? dayofweek - LOCALE_SABBREVDAYNAME1 + 1 : 0;
745       size = GetLocaleInfoA(ltime->lc.id, dayofweek, NULL, 0);
746       ltime->abbrev_dayofweek[dayindex] = (char*)malloc(size);
747       if (!ltime->abbrev_dayofweek[dayindex]) { _Locale_time_destroy(ltime); return NULL; }
748       __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, dayofweek, ltime->abbrev_dayofweek[dayindex], size);
749     }
750
751     __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, LOCALE_SSHORTDATE, fmt80, 80);
752     size = __ConvertDate(fmt80, NULL, 0);
753     ltime->date_format = (char*)malloc(size);
754     if (!ltime->date_format) { _Locale_time_destroy(ltime); return NULL; }
755     __ConvertDate(fmt80, ltime->date_format, size);
756
757     __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, LOCALE_SLONGDATE, fmt80, 80);
758     size = __ConvertDate(fmt80, NULL, 0);
759     ltime->long_date_format = (char*)malloc(size);
760     if (!ltime->long_date_format) { _Locale_time_destroy(ltime); return NULL; }
761     __ConvertDate(fmt80, ltime->long_date_format, size);
762
763     __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, LOCALE_STIMEFORMAT, fmt80, 80);
764     size = __ConvertTime(fmt80, NULL, 0);
765     ltime->time_format = (char*)malloc(size);
766     if (!ltime->time_format) { _Locale_time_destroy(ltime); return NULL; }
767     __ConvertTime(fmt80, ltime->time_format, size);
768
769     /* NT doesn't provide this information, we must simulate. */
770     length = strlen(ltime->date_format) + strlen(ltime->time_format) + 1 /* space */ + 1 /* trailing 0 */;
771     ltime->date_time_format = (char*)malloc(length);
772     if (!ltime->date_time_format) { _Locale_time_destroy(ltime); return NULL; }
773     _STLP_STRCPY2(ltime->date_time_format, length, ltime->date_format);
774     _STLP_STRCAT2(ltime->date_time_format, length, " ");
775     _STLP_STRCAT2(ltime->date_time_format, length, ltime->time_format);
776
777     /* NT doesn't provide this information, we must simulate. */
778     length = strlen(ltime->long_date_format) + strlen(ltime->time_format) + 1 /* space */ + 1 /* trailing 0 */;
779     ltime->long_date_time_format = (char*)malloc(length);
780     if (!ltime->long_date_time_format) { _Locale_time_destroy(ltime); return NULL; }
781     _STLP_STRCPY2(ltime->long_date_time_format, length, ltime->long_date_format);
782     _STLP_STRCAT2(ltime->long_date_time_format, length, " ");
783     _STLP_STRCAT2(ltime->long_date_time_format, length, ltime->time_format);
784
785     __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, LOCALE_S1159, ltime->am, 9);
786     __GetLocaleInfoUsingACP(ltime->lc.id, ltime->cp, LOCALE_S2359, ltime->pm, 9);
787
788     return ltime;
789   }
790
791   void* _Locale_collate_create(const char * name, _Locale_lcid_t* lc_hint) {
792     char cname[_Locale_MAX_SIMPLE_NAME];
793
794     _Locale_collate_t *lcol=(_Locale_collate_t*)malloc(sizeof(_Locale_collate_t));
795     if (!lcol) return lcol;
796     memset(lcol, 0, sizeof(_Locale_collate_t));
797
798     __Extract_locale_name(name, LC_COLLATE, cname);
799
800     if (__GetLCIDFromName(cname, &lcol->lc.id, lcol->cp, lc_hint) == -1)
801     { free(lcol); return NULL; }
802
803     return lcol;
804   }
805
806   void* _Locale_monetary_create(const char * name, _Locale_lcid_t* lc_hint) {
807     char cname[_Locale_MAX_SIMPLE_NAME];
808     char *GroupingBuffer;
809     int BufferSize;
810     char FracDigits[3];
811
812     _Locale_monetary_t *lmon = (_Locale_monetary_t*)malloc(sizeof(_Locale_monetary_t));
813     if (!lmon) return lmon;
814     memset(lmon, 0, sizeof(_Locale_monetary_t));
815
816     __Extract_locale_name(name, LC_MONETARY, cname);
817
818     if (__GetLCIDFromName(cname, &lmon->lc.id, lmon->cp, lc_hint) == -1)
819     { free(lmon); return NULL; }
820
821     /* Extract information about monetary system */
822     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_SDECIMAL, lmon->decimal_point, 4);
823     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_STHOUSAND, lmon->thousands_sep, 4);
824
825     BufferSize = GetLocaleInfoA(lmon->lc.id, LOCALE_SGROUPING, NULL, 0);
826     GroupingBuffer = (char*)malloc(BufferSize);
827     if (!GroupingBuffer) { lmon->grouping = NULL; return lmon; }
828     GetLocaleInfoA(lmon->lc.id, LOCALE_SGROUPING, GroupingBuffer, BufferSize);
829     __FixGrouping(GroupingBuffer);
830     lmon->grouping=GroupingBuffer;
831
832     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_SCURRENCY, lmon->curr_symbol, 6);
833     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_SNEGATIVESIGN, lmon->negative_sign, 5);
834     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_SPOSITIVESIGN, lmon->positive_sign, 5);
835
836     GetLocaleInfoA(lmon->lc.id, LOCALE_ICURRDIGITS, FracDigits, 3);
837     lmon->frac_digits = atoi(FracDigits);
838
839     GetLocaleInfoA(lmon->lc.id, LOCALE_IINTLCURRDIGITS, FracDigits, 3);
840     lmon->int_frac_digits = atoi(FracDigits);
841
842     __GetLocaleInfoUsingACP(lmon->lc.id, lmon->cp, LOCALE_SINTLSYMBOL, lmon->int_curr_symbol, 5);
843     /* Even if Platform SDK documentation says that the returned symbol should
844      * be a 3 letters symbol followed by a seperation character, experimentation
845      * has shown that no seperation character is ever appended. We are adding it
846      * ourself to conform to the POSIX specification.
847      */
848     if (lmon->int_curr_symbol[3] == 0) {
849       lmon->int_curr_symbol[3] = ' ';
850       lmon->int_curr_symbol[4] = 0;
851     }
852
853     return lmon;
854   }
855
856   void* _Locale_messages_create(const char *name, _Locale_lcid_t* lc_hint) {
857     char cname[_Locale_MAX_SIMPLE_NAME];
858     _Locale_messages_t *lmes=(_Locale_messages_t*)malloc(sizeof(_Locale_messages_t));
859     if (!lmes) return lmes;
860     memset(lmes, 0, sizeof(_Locale_messages_t));
861
862     _Locale_extract_messages_name(name, cname, lc_hint);
863     if (__GetLCIDFromName(cname, &lmes->lc.id, lmes->cp, lc_hint) == -1)
864     { free(lmes); return NULL; }
865
866     return lmes;
867   }
868
869   static const char* _Locale_common_default(char* buf) {
870     char cp[MAX_CP_LEN + 1];
871     int CodePage = __GetDefaultCP(LOCALE_USER_DEFAULT);
872     my_ltoa(CodePage, cp);
873     return __GetLocaleName(LOCALE_USER_DEFAULT, cp, buf);
874   }
875
876   const char* _Locale_ctype_default(char* buf)
877   { return _Locale_common_default(buf); }
878
879   const char* _Locale_numeric_default(char * buf)
880   { return _Locale_common_default(buf); }
881
882   const char* _Locale_time_default(char* buf)
883   { return _Locale_common_default(buf); }
884
885   const char* _Locale_collate_default(char* buf)
886   { return _Locale_common_default(buf); }
887
888   const char* _Locale_monetary_default(char* buf)
889   { return _Locale_common_default(buf); }
890
891   const char* _Locale_messages_default(char* buf)
892   { return _Locale_common_default(buf); }
893
894   char const* _Locale_ctype_name(const void* loc, char* buf) {
895     char cp_buf[MAX_CP_LEN + 1];
896     _Locale_ctype_t* ltype = (_Locale_ctype_t*)loc;
897     my_ltoa(ltype->cp, cp_buf);
898     return __GetLocaleName(ltype->lc.id, cp_buf, buf);
899   }
900
901   char const* _Locale_numeric_name(const void* loc, char* buf) {
902     _Locale_numeric_t* lnum = (_Locale_numeric_t*)loc;
903     return __GetLocaleName(lnum->lc.id, lnum->cp, buf);
904   }
905
906   char const* _Locale_time_name(const void* loc, char* buf) {
907     _Locale_time_t* ltime = (_Locale_time_t*)loc;
908     return __GetLocaleName(ltime->lc.id, ltime->cp, buf);
909   }
910
911   char const* _Locale_collate_name(const void* loc, char* buf) {
912     _Locale_collate_t* lcol = (_Locale_collate_t*)loc;
913     return __GetLocaleName(lcol->lc.id, lcol->cp, buf);
914   }
915
916   char const* _Locale_monetary_name(const void* loc, char* buf) {
917     _Locale_monetary_t* lmon = (_Locale_monetary_t*)loc;
918     return __GetLocaleName(lmon->lc.id, lmon->cp, buf);
919   }
920
921   char const* _Locale_messages_name(const void* loc, char* buf) {
922     _Locale_messages_t* lmes = (_Locale_messages_t*)loc;
923     return __GetLocaleName(lmes->lc.id, lmes->cp, buf);
924   }
925
926   void _Locale_ctype_destroy(void* loc) {
927     _Locale_ctype_t *ltype = (_Locale_ctype_t*)loc;
928     if (!ltype) return;
929     free(ltype);
930   }
931
932   void _Locale_numeric_destroy(void* loc) {
933     _Locale_numeric_t *lnum = (_Locale_numeric_t *)loc;
934     if (!lnum) return;
935
936     if (lnum->grouping) free(lnum->grouping);
937     free(lnum);
938   }
939
940   void _Locale_time_destroy(void* loc) {
941     int i;
942     _Locale_time_t* ltime = (_Locale_time_t*)loc;
943     if (!ltime) return;
944
945   for (i = 0; i < 12; ++i) {
946       if (ltime->month[i]) free(ltime->month[i]);
947       if (ltime->abbrev_month[i]) free(ltime->abbrev_month[i]);
948     }
949
950   for (i = 0; i < 7; ++i) {
951       if (ltime->dayofweek[i]) free(ltime->dayofweek[i]);
952       if (ltime->abbrev_dayofweek[i]) free(ltime->abbrev_dayofweek[i]);
953     }
954
955     if (ltime->date_format) free(ltime->date_format);
956     if (ltime->long_date_format) free(ltime->long_date_format);
957     if (ltime->time_format) free(ltime->time_format);
958     if (ltime->date_time_format) free(ltime->date_time_format);
959     if (ltime->long_date_time_format) free(ltime->long_date_time_format);
960
961     free(ltime);
962   }
963
964   void _Locale_collate_destroy(void* loc) {
965     _Locale_collate_t* lcol=(_Locale_collate_t*)loc;
966     if (!lcol) return;
967
968     free(lcol);
969   }
970
971   void _Locale_monetary_destroy(void* loc) {
972     _Locale_monetary_t *lmon = (_Locale_monetary_t*)loc;
973     if (!lmon) return;
974
975     if (lmon->grouping) free(lmon->grouping);
976     free(lmon);
977   }
978
979   void _Locale_messages_destroy(void* loc) {
980     _Locale_messages_t* lmes = (_Locale_messages_t*)loc;
981     if (!lmes) return;
982
983     free(lmes);
984   }
985
986   static char const* _Locale_extract_category_name(const char* cname, int category, char* buf, _Locale_lcid_t* hint) {
987     char lname[_Locale_MAX_SIMPLE_NAME];
988     __Extract_locale_name(cname, category, lname);
989     if (lname[0] == 'C' && lname[1] == 0) {
990       _STLP_RETURN_STRCPY2(buf, _Locale_MAX_SIMPLE_NAME, lname);
991     }
992     return __TranslateToSystem(lname, buf, hint);
993   }
994
995   char const* _Locale_extract_ctype_name(const char* cname, char* buf, _Locale_lcid_t* hint)
996   { return _Locale_extract_category_name(cname, LC_CTYPE, buf, hint); }
997
998   char const* _Locale_extract_numeric_name(const char* cname, char* buf, _Locale_lcid_t* hint)
999   { return _Locale_extract_category_name(cname, LC_NUMERIC, buf, hint); }
1000
1001   char const* _Locale_extract_time_name(const char* cname, char* buf, _Locale_lcid_t* hint)
1002   { return _Locale_extract_category_name(cname, LC_TIME, buf, hint); }
1003
1004   char const* _Locale_extract_collate_name(const char* cname, char* buf, _Locale_lcid_t* hint)
1005   { return _Locale_extract_category_name(cname, LC_COLLATE, buf, hint); }
1006
1007   char const* _Locale_extract_monetary_name(const char* cname, char* buf, _Locale_lcid_t* hint)
1008   { return _Locale_extract_category_name(cname, LC_MONETARY, buf, hint); }
1009
1010   char const* _Locale_extract_messages_name(const char* cname, char* buf, _Locale_lcid_t* hint) {
1011     if (cname[0] == 'L' && cname[1] == 'C' && cname[2] == '_') {
1012       _STLP_RETURN_STRCPY2(buf, _Locale_MAX_SIMPLE_NAME, "C");
1013     }
1014     if (cname[0] == 'C' && cname[1] == 0) {
1015       _STLP_RETURN_STRCPY2(buf, _Locale_MAX_SIMPLE_NAME, cname);
1016     }
1017     return __TranslateToSystem(cname, buf, hint);
1018   }
1019
1020   char const* _Locale_compose_name(char* buf,
1021                              const char* _ctype, const char* numeric,
1022                              const char* time, const char* _collate,
1023                              const char* monetary, const char* messages,
1024                              const char* default_name) {
1025     (void) default_name;
1026
1027     if (!strcmp(_ctype, numeric) &&
1028        !strcmp(_ctype, time) &&
1029        !strcmp(_ctype, _collate) &&
1030        !strcmp(_ctype, monetary) &&
1031        !strcmp(_ctype, messages)) {
1032       _STLP_RETURN_STRCPY2(buf, _Locale_MAX_COMPOSITE_NAME, _ctype);
1033     }
1034
1035     _STLP_STRCPY2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_CTYPE=");
1036     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, _ctype);
1037     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1038     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_TIME=");
1039     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, time);
1040     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1041     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_NUMERIC=");
1042     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, numeric);
1043     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1044     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_COLLATE=");
1045     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, _collate);
1046     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1047     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_MONETARY=");
1048     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, monetary);
1049     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1050     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, "LC_MESSAGES=");
1051     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, messages);
1052     _STLP_STRCAT2(buf, _Locale_MAX_COMPOSITE_NAME, ";");
1053
1054     return buf;
1055   }
1056
1057   /* ctype */
1058
1059   const _Locale_mask_t* _Locale_ctype_table(_Locale_ctype_t* ltype) {
1060     _STLP_STATIC_ASSERT(sizeof(_Locale_mask_t) == sizeof(unsigned int))
1061     return (const _Locale_mask_t*)ltype->ctable;
1062   }
1063
1064   int _Locale_toupper(_Locale_ctype_t* ltype, int c) {
1065     char buf[2], out_buf[2];
1066     buf[0] = (char)c; buf[1] = 0;
1067     if ((UINT)__GetDefaultCP(ltype->lc.id) == ltype->cp) {
1068       LCMapStringA(ltype->lc.id, LCMAP_LINGUISTIC_CASING | LCMAP_UPPERCASE, buf, 2, out_buf, 2);
1069       return out_buf[0];
1070     }
1071     else {
1072       wchar_t wbuf[2];
1073       MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, buf, 2, wbuf, 2);
1074       WideCharToMultiByte(__GetDefaultCP(ltype->lc.id), WC_COMPOSITECHECK | WC_SEPCHARS, wbuf, 2, buf, 2, NULL, FALSE);
1075
1076       LCMapStringA(ltype->lc.id, LCMAP_LINGUISTIC_CASING | LCMAP_UPPERCASE, buf, 2, out_buf, 2);
1077
1078       MultiByteToWideChar(__GetDefaultCP(ltype->lc.id), MB_PRECOMPOSED, out_buf, 2, wbuf, 2);
1079       WideCharToMultiByte(ltype->cp, WC_COMPOSITECHECK | WC_SEPCHARS, wbuf, 2, out_buf, 2, NULL, FALSE);
1080       return out_buf[0];
1081     }
1082   }
1083
1084   int _Locale_tolower(_Locale_ctype_t* ltype, int c) {
1085     char buf[2], out_buf[2];
1086     buf[0] = (char)c; buf[1] = 0;
1087     if ((UINT)__GetDefaultCP(ltype->lc.id) == ltype->cp) {
1088       LCMapStringA(ltype->lc.id, LCMAP_LINGUISTIC_CASING | LCMAP_LOWERCASE, buf, 2, out_buf, 2);
1089       return out_buf[0];
1090     }
1091     else {
1092       wchar_t wbuf[2];
1093       MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, buf, 2, wbuf, 2);
1094       WideCharToMultiByte(__GetDefaultCP(ltype->lc.id), WC_COMPOSITECHECK | WC_SEPCHARS, wbuf, 2, buf, 2, NULL, FALSE);
1095
1096       LCMapStringA(ltype->lc.id, LCMAP_LINGUISTIC_CASING | LCMAP_LOWERCASE, buf, 2, out_buf, 2);
1097
1098       MultiByteToWideChar(__GetDefaultCP(ltype->lc.id), MB_PRECOMPOSED, out_buf, 2, wbuf, 2);
1099       WideCharToMultiByte(ltype->cp, WC_COMPOSITECHECK | WC_SEPCHARS, wbuf, 2, out_buf, 2, NULL, FALSE);
1100       return out_buf[0];
1101     }
1102   }
1103
1104 #if !defined (_STLP_NO_WCHAR_T)
1105   _Locale_mask_t _Locale_wchar_ctype(_Locale_ctype_t* ltype, wint_t c,
1106                                      _Locale_mask_t which_bits) {
1107     wchar_t buf[2];
1108     WORD out[2];
1109     buf[0] = c; buf[1] = 0;
1110     GetStringTypeW(CT_CTYPE1, buf, -1, out);
1111     (void*)ltype;
1112     return (_Locale_mask_t)out[0] & which_bits;
1113   }
1114
1115   wint_t _Locale_wchar_tolower(_Locale_ctype_t* ltype, wint_t c) {
1116     wchar_t in_c = c;
1117     wchar_t res;
1118
1119     LCMapStringW(ltype->lc.id, LCMAP_LOWERCASE, &in_c, 1, &res, 1);
1120     return res;
1121   }
1122
1123   wint_t _Locale_wchar_toupper(_Locale_ctype_t* ltype, wint_t c) {
1124     wchar_t in_c = c;
1125     wchar_t res;
1126
1127     LCMapStringW(ltype->lc.id, LCMAP_UPPERCASE, &in_c, 1, &res, 1);
1128     return res;
1129   }
1130 #endif
1131
1132 #if !defined (_STLP_NO_MBSTATE_T)
1133
1134   int _Locale_mb_cur_max (_Locale_ctype_t * ltype) {
1135     CPINFO CPInfo;
1136     if (!GetCPInfo(ltype->cp, &CPInfo)) return 0;
1137     return CPInfo.MaxCharSize;
1138   }
1139
1140   int _Locale_mb_cur_min (_Locale_ctype_t *dummy) {
1141     (void*)dummy;
1142     return 1;
1143   }
1144
1145   int _Locale_is_stateless (_Locale_ctype_t * ltype) {
1146     CPINFO CPInfo;
1147     GetCPInfo(ltype->cp, &CPInfo);
1148     return (CPInfo.MaxCharSize == 1) ? 1 : 0;
1149   }
1150
1151 #if defined (__BORLANDC__) && defined (__cplusplus)
1152   /* Weird Borland compiler behavior, even if native wint_t is imported to
1153    * STLport namespace in _cwchar.h, wint_t is still usable when scoped with
1154    * the Standard namespace (std::wint_t). As following WEOF macro is expended
1155    * to (std::wint_t)(0xFFFF) compilation failed. Repeating import avoid this
1156    * problem.*/
1157   using __std_alias::wint_t;
1158 #endif
1159
1160   wint_t _Locale_btowc(_Locale_ctype_t * ltype, int c) {
1161     wchar_t wc;
1162     if (c == EOF) return WEOF;
1163
1164     MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, (char*)&c, 1, &wc, 1);
1165
1166     return (wint_t)wc;
1167   }
1168
1169   int _Locale_wctob(_Locale_ctype_t * ltype, wint_t wc) {
1170     char c;
1171
1172     if (WideCharToMultiByte(ltype->cp, WC_COMPOSITECHECK | WC_DEFAULTCHAR, (wchar_t*)&wc, 1, &c, 1, NULL, NULL) == 0)
1173       return WEOF; /* Not single byte or error conversion. */
1174
1175     return (int)c;
1176   }
1177
1178   static int __isleadbyte(int c, unsigned int *ctable) {
1179     return (ctable[(unsigned char)(c)] & _LEADBYTE);
1180   }
1181
1182   static size_t __mbtowc(_Locale_ctype_t *l, wchar_t *dst, char src, mbstate_t *shift_state) {
1183     int result;
1184
1185     if (*shift_state == 0) {
1186       if (__isleadbyte(src, l->ctable)) {
1187         ((unsigned char*)shift_state)[0] = src;
1188         return (size_t)-2;
1189       }
1190       else {
1191         result = MultiByteToWideChar(l->cp, MB_PRECOMPOSED, &src, 1, dst, 1);
1192         if (result == 0) return (size_t)-1;
1193
1194         return 1;
1195       }
1196     }
1197     else {
1198       ((unsigned char*)shift_state)[1] = src;
1199       result = MultiByteToWideChar(l->cp, MB_PRECOMPOSED, (const char*)shift_state, 2, dst, 1);
1200       *shift_state = 0;
1201       if (result == 0) return (size_t)-1;
1202
1203       return 1;
1204     }
1205   }
1206
1207 #if !defined (_STLP_NO_WCHAR_T)
1208   size_t _Locale_mbtowc(_Locale_ctype_t *ltype, wchar_t *to,
1209                         const char *from, size_t n, mbstate_t *shift_state) {
1210     CPINFO ci;
1211     int result;
1212     (void*)shift_state;
1213     GetCPInfo(ltype->cp, &ci);
1214     if (ci.MaxCharSize == 1) { /* Single byte encoding. */
1215       *shift_state = (mbstate_t)0;
1216       result = MultiByteToWideChar(ltype->cp, MB_PRECOMPOSED, from, 1, to, 1);
1217       if (result == 0) return (size_t)-1;
1218       return result;
1219     }
1220     else { /* Multi byte encoding. */
1221       size_t retval = 0, count = 0;
1222       while(n--) {
1223         retval = __mbtowc(ltype, to, *from, shift_state);
1224         if (retval == -2) { from++; count++; }
1225         else if (retval == -1) return -1;
1226         else return count+retval;
1227       }
1228       if (retval == -2) return (size_t)-2;
1229
1230       return n;
1231     }
1232   }
1233
1234   size_t _Locale_wctomb(_Locale_ctype_t *ltype, char *to, size_t n,
1235                         const wchar_t c, mbstate_t *shift_state) {
1236     int size = \
1237       WideCharToMultiByte(ltype->cp,  WC_COMPOSITECHECK | WC_SEPCHARS, &c, 1, NULL, 0, NULL, NULL);
1238
1239     if ((size_t)size > n) return (size_t)-2;
1240
1241     if (n > INT_MAX)
1242       /* Limiting the output buf size to INT_MAX seems like reasonable to transform a single wchar_t. */
1243       n = INT_MAX;
1244
1245     size = \
1246       WideCharToMultiByte(ltype->cp,  WC_COMPOSITECHECK | WC_SEPCHARS, &c, 1, to, (int)n, NULL, NULL);
1247
1248     if (size == 0) return (size_t)-1;
1249
1250     (void*)shift_state;
1251     return (size_t)size;
1252   }
1253 #endif
1254
1255   size_t _Locale_unshift(_Locale_ctype_t *ltype, mbstate_t *st,
1256                          char *buf, size_t n, char **next) {
1257     (void*)ltype;
1258     if (*st == 0) {
1259       *next = buf;
1260       return 0;
1261     }
1262     else {
1263       if (n < 1) { *next = buf; return (size_t)-2; }
1264
1265       *next = buf + 1;
1266       return 1;
1267     }
1268   }
1269
1270 #endif /*  _STLP_NO_MBSTATE_T */
1271
1272
1273 #ifndef CSTR_EQUAL /* VC5SP3*/
1274 #  define CSTR_EQUAL 2
1275 #endif
1276 #ifndef CSTR_LESS_THAN /* VC5SP3 */
1277 #  define CSTR_LESS_THAN 1
1278 #endif
1279
1280   static DWORD max_DWORD = 0xffffffff;
1281   static DWORD trim_size_t_to_DWORD(size_t n) { return n < (size_t)max_DWORD ? (DWORD)n : max_DWORD; }
1282
1283   /* Collate */
1284   /* This function takes care of the potential size_t DWORD different size. */
1285   static int _Locale_strcmp_auxA(_Locale_collate_t* lcol,
1286                                  const char* s1, size_t n1,
1287                                  const char* s2, size_t n2) {
1288     int result = CSTR_EQUAL;
1289     while (n1 > 0 || n2 > 0) {
1290       DWORD size1 = trim_size_t_to_DWORD(n1);
1291       DWORD size2 = trim_size_t_to_DWORD(n2);
1292       result = CompareStringA(lcol->lc.id, 0, s1, size1, s2, size2);
1293       if (result != CSTR_EQUAL)
1294         break;
1295       n1 -= size1;
1296       n2 -= size2;
1297     }
1298     return result;
1299   }
1300
1301   int _Locale_strcmp(_Locale_collate_t* lcol,
1302                      const char* s1, size_t n1,
1303                      const char* s2, size_t n2) {
1304     int result;
1305     if (__GetDefaultCP(lcol->lc.id) == atoi(lcol->cp)) {
1306       result = _Locale_strcmp_auxA(lcol, s1, n1, s2, n2);
1307     }
1308     else {
1309       char *buf1, *buf2;
1310       size_t size1, size2;
1311       buf1 = __ConvertToCP(atoi(lcol->cp), __GetDefaultCP(lcol->lc.id), s1, n1, &size1);
1312       buf2 = __ConvertToCP(atoi(lcol->cp), __GetDefaultCP(lcol->lc.id), s2, n2, &size2);
1313
1314       result = _Locale_strcmp_auxA(lcol, buf1, size1, buf2, size2);
1315       free(buf1); free(buf2);
1316     }
1317     return (result == CSTR_EQUAL) ? 0 : (result == CSTR_LESS_THAN) ? -1 : 1;
1318   }
1319
1320 #if !defined (_STLP_NO_WCHAR_T)
1321   /* This function takes care of the potential size_t DWORD different size. */
1322   static int _Locale_strcmp_auxW(_Locale_collate_t* lcol,
1323                                  const wchar_t* s1, size_t n1,
1324                                  const wchar_t* s2, size_t n2) {
1325     int result = CSTR_EQUAL;
1326     while (n1 > 0 || n2 > 0) {
1327       DWORD size1 = trim_size_t_to_DWORD(n1);
1328       DWORD size2 = trim_size_t_to_DWORD(n2);
1329       result = CompareStringW(lcol->lc.id, 0, s1, size1, s2, size2);
1330       if (result != CSTR_EQUAL)
1331         break;
1332       n1 -= size1;
1333       n2 -= size2;
1334     }
1335     return result;
1336   }
1337
1338   int _Locale_strwcmp(_Locale_collate_t* lcol,
1339                       const wchar_t* s1, size_t n1,
1340                       const wchar_t* s2, size_t n2) {
1341     int result;
1342     result = _Locale_strcmp_auxW(lcol, s1, n1, s2, n2);
1343     return (result == CSTR_EQUAL) ? 0 : (result == CSTR_LESS_THAN) ? -1 : 1;
1344   }
1345 #endif
1346
1347   size_t _Locale_strxfrm(_Locale_collate_t* lcol,
1348                          char* dst, size_t dst_size,
1349                          const char* src, size_t src_size) {
1350     int result;
1351
1352     /* The Windows API do not support transformation of very long strings (src_size > INT_MAX)
1353      * In this case the result will just be the input string:
1354      */
1355     if (src_size > INT_MAX) {
1356       if (dst != 0) {
1357         _STLP_STRNCPY(dst, dst_size, src, src_size);
1358       }
1359       return src_size;
1360     }
1361     if (dst_size > INT_MAX) {
1362       /* now that we know that src_size <= INT_MAX we can safely decrease dst_size to INT_MAX. */
1363       dst_size = INT_MAX;
1364     }
1365
1366     if (__GetDefaultCP(lcol->lc.id) == atoi(lcol->cp))
1367       result = LCMapStringA(lcol->lc.id, LCMAP_SORTKEY, src, (int)src_size, dst, (int)dst_size);
1368     else {
1369       char *buf;
1370       size_t size;
1371       buf = __ConvertToCP(atoi(lcol->cp), __GetDefaultCP(lcol->lc.id), src, src_size, &size);
1372
1373       result = LCMapStringA(lcol->lc.id, LCMAP_SORTKEY, buf, (int)size, dst, (int)dst_size);
1374       free(buf);
1375     }
1376     return result != 0 ? result - 1 : 0;
1377   }
1378
1379 #if !defined (_STLP_NO_WCHAR_T)
1380   size_t _Locale_strwxfrm(_Locale_collate_t* lcol,
1381                           wchar_t* dst, size_t dst_size,
1382                           const wchar_t* src, size_t src_size) {
1383     int result;
1384
1385     /* see _Locale_strxfrm: */
1386     if (src_size > INT_MAX) {
1387       if (dst != 0) {
1388         _STLP_WCSNCPY(dst, dst_size, src, src_size);
1389       }
1390       return src_size;
1391     }
1392     if (dst_size > INT_MAX) {
1393       dst_size = INT_MAX;
1394     }
1395     result = LCMapStringW(lcol->lc.id, LCMAP_SORTKEY, src, (int)src_size, dst, (int)dst_size);
1396     return result != 0 ? result - 1 : 0;
1397   }
1398 #endif
1399
1400   /* Numeric */
1401
1402   static const char* __true_name = "true";
1403   static const char* __false_name = "false";
1404
1405   char _Locale_decimal_point(_Locale_numeric_t* lnum) {
1406     return lnum->decimal_point[0];
1407   }
1408
1409   char _Locale_thousands_sep(_Locale_numeric_t* lnum) {
1410     return lnum->thousands_sep[0];
1411   }
1412
1413   const char* _Locale_grouping(_Locale_numeric_t * lnum) {
1414     if (!lnum->grouping) return "";
1415     else return lnum->grouping;
1416   }
1417
1418   const char * _Locale_true(_Locale_numeric_t * lnum) {
1419     (void*)lnum;
1420     return __true_name; /* NT does't provide information about this */
1421   }
1422
1423   const char * _Locale_false(_Locale_numeric_t * lnum) {
1424     (void*)lnum;
1425     return __false_name; /* NT does't provide information about this */
1426   }
1427
1428
1429   /* Monetary */
1430   const char* _Locale_int_curr_symbol(_Locale_monetary_t * lmon)
1431   { return lmon->int_curr_symbol; }
1432
1433   const char* _Locale_currency_symbol(_Locale_monetary_t * lmon)
1434   { return lmon->curr_symbol; }
1435
1436   char _Locale_mon_decimal_point(_Locale_monetary_t * lmon)
1437   { return lmon->decimal_point[0]; }
1438
1439   char _Locale_mon_thousands_sep(_Locale_monetary_t * lmon)
1440   { return lmon->thousands_sep[0]; }
1441
1442   const char* _Locale_mon_grouping(_Locale_monetary_t * lmon) {
1443     if (!lmon->grouping) return "";
1444     else return lmon->grouping;
1445   }
1446
1447   const char* _Locale_positive_sign(_Locale_monetary_t * lmon)
1448   { return lmon->positive_sign; }
1449
1450   const char* _Locale_negative_sign(_Locale_monetary_t * lmon)
1451   { return lmon->negative_sign; }
1452
1453   char _Locale_int_frac_digits(_Locale_monetary_t * lmon)
1454   { return (char)lmon->int_frac_digits; }
1455
1456   char _Locale_frac_digits(_Locale_monetary_t * lmon)
1457   { return (char)lmon->frac_digits; }
1458
1459   int _Locale_p_cs_precedes(_Locale_monetary_t * lmon) {
1460     char loc_data[2];
1461     GetLocaleInfoA(lmon->lc.id, LOCALE_IPOSSYMPRECEDES, loc_data, 2);
1462     if (loc_data[0] == '0') return 0;
1463     else if (loc_data[0] == '1') return 1;
1464     else return -1;
1465   }
1466
1467   int _Locale_p_sep_by_space(_Locale_monetary_t * lmon) {
1468     char loc_data[2];
1469     GetLocaleInfoA(lmon->lc.id, LOCALE_IPOSSEPBYSPACE, loc_data, 2);
1470     if (loc_data[0] == '0') return 0;
1471     else if (loc_data[0] == '1') return 1;
1472     else return -1;
1473   }
1474
1475   int _Locale_p_sign_posn(_Locale_monetary_t * lmon) {
1476     char loc_data[2];
1477     GetLocaleInfoA(lmon->lc.id, LOCALE_IPOSSIGNPOSN, loc_data, 2);
1478     return atoi(loc_data);
1479   }
1480
1481   int _Locale_n_cs_precedes(_Locale_monetary_t * lmon) {
1482     char loc_data[2];
1483     GetLocaleInfoA(lmon->lc.id, LOCALE_INEGSYMPRECEDES, loc_data, 2);
1484     if (loc_data[0] == '0') return 0;
1485     else if (loc_data[0] == '1') return 1;
1486     else return -1;
1487   }
1488
1489   int _Locale_n_sep_by_space(_Locale_monetary_t * lmon) {
1490     char loc_data[2];
1491     GetLocaleInfoA(lmon->lc.id, LOCALE_INEGSEPBYSPACE, loc_data, 2);
1492     if (loc_data[0] == '0') return 0;
1493     else if (loc_data[0] == '1') return 1;
1494     else return -1;
1495   }
1496
1497   int _Locale_n_sign_posn(_Locale_monetary_t * lmon) {
1498     char loc_data[2];
1499     GetLocaleInfoA(lmon->lc.id, LOCALE_INEGSIGNPOSN, loc_data, 2);
1500     return atoi(loc_data);
1501   }
1502
1503
1504   /* Time */
1505   const char * _Locale_full_monthname(_Locale_time_t * ltime, int month) {
1506     const char **names = (const char**)ltime->month;
1507     return names[month];
1508   }
1509
1510   const char * _Locale_abbrev_monthname(_Locale_time_t * ltime, int month) {
1511     const char **names = (const char**)ltime->abbrev_month;
1512     return names[month];
1513   }
1514
1515   const char * _Locale_full_dayofweek(_Locale_time_t * ltime, int day) {
1516     const char **names = (const char**)ltime->dayofweek;
1517     return names[day];
1518   }
1519
1520   const char * _Locale_abbrev_dayofweek(_Locale_time_t * ltime, int day) {
1521     const char **names = (const char**)ltime->abbrev_dayofweek;
1522     return names[day];
1523   }
1524
1525 const char* _Locale_d_t_fmt(_Locale_time_t* ltime)
1526 { return ltime->date_time_format; }
1527
1528 const char* _Locale_long_d_t_fmt(_Locale_time_t* ltime)
1529 { return ltime->long_date_time_format; }
1530
1531 const char* _Locale_d_fmt(_Locale_time_t* ltime)
1532 { return ltime->date_format; }
1533
1534 const char* _Locale_long_d_fmt(_Locale_time_t* ltime)
1535 { return ltime->long_date_format; }
1536
1537 const char* _Locale_t_fmt(_Locale_time_t* ltime)
1538 { return ltime->time_format; }
1539
1540 const char* _Locale_am_str(_Locale_time_t* ltime)
1541 { return ltime->am; }
1542
1543 const char* _Locale_pm_str(_Locale_time_t* ltime)
1544 { return ltime->pm; }
1545
1546
1547   /* Messages */
1548
1549   int _Locale_catopen(_Locale_messages_t* __DUMMY_PAR1, const char* __DUMMY_PAR) {
1550     (void*)__DUMMY_PAR1;
1551     (void*)__DUMMY_PAR;
1552     return -1;
1553   }
1554   void _Locale_catclose(_Locale_messages_t* __DUMMY_PAR1, int __DUMMY_PAR) {
1555     (void*)__DUMMY_PAR1;
1556     (void*)&__DUMMY_PAR;
1557   }
1558   const char* _Locale_catgets(_Locale_messages_t* __DUMMY_PAR1, int __DUMMY_PAR2,
1559                               int __DUMMY_PAR3, int __DUMMY_PAR4,
1560                               const char *dfault) {
1561     (void*)__DUMMY_PAR1;
1562     (void*)&__DUMMY_PAR2;
1563     (void*)&__DUMMY_PAR3;
1564     (void*)&__DUMMY_PAR4;
1565     return dfault;
1566   }
1567
1568 #ifdef __cplusplus
1569 } /* extern C */
1570 _STLP_END_NAMESPACE
1571 #endif
1572
1573 void __FixGrouping(char *grouping) {
1574   /* This converts NT version which uses '0' instead of 0, etc ; to ANSI */
1575   while (*grouping) {
1576     if (*grouping >= '0' && *grouping <= '9') {
1577       *grouping = *grouping - '0';
1578       ++grouping;
1579     }
1580     else if (*grouping == ';') {
1581       /* remove ';' */
1582       char *tmp = grouping;
1583       for (; *tmp; ++tmp)
1584         *tmp = *(tmp + 1);
1585     }
1586     else
1587       ++grouping;
1588   }
1589 }
1590
1591 const char* __ConvertName(const char* lname, LOCALECONV* ConvTable, int TableSize) {
1592   int i;
1593   int cmp;
1594   int low = 0;
1595   int high = TableSize - 1;
1596
1597   /*  typical binary search - do until no more to search or match */
1598   while (low <= high) {
1599     i = (low + high) / 2;
1600
1601     if ((cmp = lstrcmpiA(lname, (*(ConvTable + i)).name)) == 0)
1602       return (*(ConvTable + i)).abbrev;
1603     else if (cmp < 0)
1604       high = i - 1;
1605     else
1606       low = i + 1;
1607   }
1608   return lname;
1609 }
1610
1611 int __ParseLocaleString(const char* lname,
1612                         char* lang, char* ctry, char* page) {
1613   int param = 0;
1614   size_t len;
1615   size_t tmpLen;
1616
1617   if (lname[0] == 0)
1618     return 0;
1619
1620   /* We look for the first country separator '_' */
1621   len = strcspn(lname, "_");
1622   if (lname[len] == '_') {
1623     if (len == 0 || len > MAX_LANG_LEN) return -1; /* empty lang is invalid*/
1624     _STLP_STRNCPY(lang, MAX_LANG_LEN + 1, lname, len);
1625     lname += len + 1;
1626     ++param;
1627   }
1628
1629   /* We look for the last code page separator '.' */
1630   len = -1;
1631   tmpLen = strcspn(lname, ".");
1632   while (lname[tmpLen] == '.') {
1633     len = tmpLen; ++tmpLen;
1634     tmpLen += strcspn(lname + tmpLen, ".");
1635   }
1636   if (len != -1) { /* Means that we found a '.' */
1637     if (param == 0) {
1638       /* We have no lang yet so we have to fill it first, no country */
1639       if (len > MAX_LANG_LEN) return -1;
1640       if (len == 0) {
1641         /* No language nor country, only code page */
1642         ++param;
1643       }
1644       else
1645       { _STLP_STRNCPY(lang, MAX_LANG_LEN + 1, lname, len); }
1646       ++param;
1647     }
1648     else {
1649       /* We already have a lang so we are now looking for the country: */
1650       if (len == 0) return -1; /* We forbid locale name with the "_." motif in it */
1651       if (len > MAX_CTRY_LEN) return -1;
1652       _STLP_STRNCPY(ctry, MAX_CTRY_LEN + 1, lname, len);
1653     }
1654     ++param;
1655     lname += len + 1;
1656   }
1657
1658   /* We look for ',' for compatibility with POSIX */
1659   len = strcspn(lname, ",");
1660   switch (param) {
1661     case 0:
1662       if (len > MAX_LANG_LEN) return -1;
1663       _STLP_STRNCPY(lang, MAX_LANG_LEN + 1, lname, len);
1664       break;
1665     case 1:
1666       if (len > MAX_CTRY_LEN) return -1;
1667       _STLP_STRNCPY(ctry, MAX_CTRY_LEN + 1, lname, len);
1668       break;
1669     default:
1670       if (len > MAX_CP_LEN) return -1;
1671       _STLP_STRNCPY(page, MAX_CP_LEN + 1, lname, len);
1672       break;
1673   }
1674
1675   /* ',' POSIX modifier is not used in NT */
1676   return 0;
1677 }
1678
1679 /* Data necessary for find LCID*/
1680 static CRITICAL_SECTION __criticalSection;
1681 static int __FindFlag;
1682 static LCID __FndLCID;
1683 static const char* __FndLang;
1684 static const char* __FndCtry;
1685
1686 void _Locale_init()
1687 { InitializeCriticalSection(&__criticalSection); }
1688
1689 void _Locale_final()
1690 { DeleteCriticalSection(&__criticalSection); }
1691
1692 static LCID LocaleFromHex(const char* locale) {
1693   unsigned long result = 0;
1694   int digit;
1695   while (*locale) {
1696     result <<= 4;
1697     digit = (*locale >= '0' && *locale <= '9') ? *locale - '0':
1698             (*locale >= 'A' && *locale <= 'F') ? (*locale - 'A') + 10
1699                                                : (*locale - 'a') + 10;
1700     result += digit;
1701     ++locale;
1702   }
1703   return (LCID)result;
1704 }
1705
1706 static BOOL CALLBACK EnumLocalesProcA(LPSTR locale) {
1707   LCID lcid = LocaleFromHex(locale);
1708   int LangFlag = 0, CtryFlag = !__FndCtry;
1709   static char Lang[MAX_LANG_LEN], Ctry[MAX_CTRY_LEN];
1710
1711   GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE, Lang, MAX_LANG_LEN);
1712   if (lstrcmpiA(Lang, __FndLang) != 0) {
1713     GetLocaleInfoA(lcid, LOCALE_SABBREVLANGNAME, Lang, MAX_LANG_LEN);
1714     if (lstrcmpiA(Lang, __FndLang) != 0) {
1715       GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, Lang, MAX_LANG_LEN);
1716       if (lstrcmpiA(Lang, __FndLang) == 0) LangFlag = 1;
1717     }
1718     else LangFlag = 1;
1719   }
1720   else LangFlag = 1;
1721
1722   if (__FndCtry) {
1723     GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY, Ctry, MAX_CTRY_LEN);
1724     if (lstrcmpiA(Ctry, __FndCtry) != 0) {
1725       GetLocaleInfoA(lcid, LOCALE_SABBREVCTRYNAME, Ctry, MAX_CTRY_LEN);
1726       if (lstrcmpiA(Ctry, __FndCtry) != 0) {
1727         GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, Ctry, MAX_CTRY_LEN);
1728         if (lstrcmpiA(Ctry, __FndCtry) == 0) CtryFlag = 1;
1729       }
1730       else CtryFlag = 1;
1731     }
1732     else
1733       CtryFlag = 1;
1734   }
1735
1736   if (LangFlag && CtryFlag) {
1737     __FindFlag = 1;
1738     __FndLCID = lcid;
1739     return FALSE;
1740   }
1741
1742   return TRUE;
1743 }
1744
1745 int __GetLCID(const char* lang, const char* ctry, LCID* lcid) {
1746   int ret;
1747   EnterCriticalSection(&__criticalSection);
1748
1749   __FindFlag = 0;
1750   __FndLang = lang;
1751   __FndCtry = ctry;
1752   EnumSystemLocalesA(EnumLocalesProcA, LCID_INSTALLED);
1753
1754   if (__FindFlag != 0) *lcid = __FndLCID;
1755   ret = __FindFlag != 0 ? 0 : -1;
1756
1757   LeaveCriticalSection(&__criticalSection);
1758   return ret;
1759 }
1760
1761 int __GetLCIDFromName(const char* lname, LCID* lcid, char* cp, _Locale_lcid_t *hint) {
1762   char lang[MAX_LANG_LEN + 1], ctry[MAX_CTRY_LEN + 1], page[MAX_CP_LEN + 1];
1763   int result = 0;
1764   if (lname == NULL || lname[0] == 0) {
1765     *lcid = LOCALE_USER_DEFAULT;
1766     return 0;
1767   }
1768
1769   memset(lang, 0, MAX_LANG_LEN + 1);
1770   memset(ctry, 0, MAX_CTRY_LEN + 1);
1771   memset(page, 0, MAX_CP_LEN + 1);
1772   if (__ParseLocaleString(lname, lang, ctry, page) == -1) return -1;
1773
1774   if (hint != 0) {
1775     *lcid = hint->id;
1776   }
1777   else {
1778     if (lang[0] == 0 && ctry[0] == 0)
1779       *lcid = LOCALE_USER_DEFAULT; /* Only code page given. */
1780     else {
1781       if (ctry[0] == 0)
1782         result = __GetLCID(__ConvertName(lang, __rg_language, sizeof(__rg_language) / sizeof(LOCALECONV)), NULL, lcid);
1783       else {
1784         result = __GetLCID(__ConvertName(lang, __rg_language, sizeof(__rg_language) / sizeof(LOCALECONV)),
1785                            __ConvertName(ctry, __rg_country, sizeof(__rg_country) / sizeof(LOCALECONV)),
1786                            lcid);
1787         if (result != 0) {
1788           /* Non NLS mapping might introduce problem with some locales when only one entry is mapped,
1789           * the lang or the country (example: chinese locales like 'chinese_taiwan' gives 'CHS_taiwan'
1790           * that do not exists in system). This is why we are giving this locale an other chance by
1791           * calling __GetLCID without the mapping. */
1792           result = __GetLCID(lang, ctry, lcid);
1793         }
1794       }
1795     }
1796   }
1797
1798   if (result == 0) {
1799     /* Handling code page */
1800     if (lstrcmpiA(page, "ACP") == 0 || page[0] == 0)
1801       my_ltoa(__intGetACP(*lcid), cp);
1802     else if (lstrcmpiA(page, "OCP") == 0)
1803       my_ltoa(__intGetOCP(*lcid), cp);
1804     else
1805       _STLP_STRNCPY(cp, MAX_CP_LEN + 1, page, 5);
1806
1807     /* Code page must be an integer value,
1808      * 0 returned by __intGetACP and 1 returned by __intGetOCP are invalid
1809      * values.
1810      */
1811     if (cp[1] == 0 && (cp[0] == '0' || cp[1] == '1'))
1812       return -1;
1813     else if (atoi(cp) == 0)
1814       return -1;
1815   }
1816
1817   return result;
1818 }
1819
1820 char const* __GetLocaleName(LCID lcid, const char* cp, char* buf) {
1821   char lang[MAX_LANG_LEN + 1], ctry[MAX_CTRY_LEN + 1];
1822   GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE, lang, MAX_LANG_LEN);
1823   GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY, ctry, MAX_CTRY_LEN);
1824   _STLP_STRCPY2(buf, _Locale_MAX_SIMPLE_NAME, lang);
1825   _STLP_STRCAT2(buf, _Locale_MAX_SIMPLE_NAME, "_");
1826   _STLP_STRCAT2(buf, _Locale_MAX_SIMPLE_NAME, ctry);
1827   _STLP_STRCAT2(buf, _Locale_MAX_SIMPLE_NAME, ".");
1828   _STLP_STRCAT2(buf, _Locale_MAX_SIMPLE_NAME, cp);
1829   return buf;
1830 }
1831
1832 static const char* __loc_categories[]= {
1833   "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"
1834 };
1835
1836 char const* __Extract_locale_name(const char* loc, int category, char* buf) {
1837   char *expr;
1838   size_t len_name;
1839   buf[0] = 0;
1840 #if defined (__BORLANDC__)
1841   if (category < LC_MIN || category > LC_MAX) return NULL;
1842   switch (category) {
1843     case 0xFF: category = 0; break;
1844     case 0x01: category = 1; break;
1845     case 0x02: category = 2; break;
1846     case 0x04: category = 3; break;
1847     case 0x10: category = 4; break;
1848     case 0x20: category = 5; break;
1849     default  : category = 0;
1850   }
1851 #else
1852   if (category < LC_ALL || category > LC_MAX) return NULL;
1853 #endif
1854
1855   if (loc[0] == 'L' && loc[1] == 'C' && loc[2] == '_') {
1856     expr = strstr((char*)loc, __loc_categories[category]);
1857     if (expr == NULL) return NULL; /* Category not found. */
1858     expr = strchr(expr, '=');
1859     if (expr == NULL) return NULL;
1860     ++expr;
1861     len_name = strcspn(expr, ";");
1862     len_name = len_name > _Locale_MAX_SIMPLE_NAME ? _Locale_MAX_SIMPLE_NAME
1863                                                   : len_name;
1864     _STLP_STRNCPY(buf, _Locale_MAX_SIMPLE_NAME, expr, len_name); buf[len_name] = 0;
1865     return buf;
1866   }
1867   else {
1868     _STLP_STRNCPY(buf, _Locale_MAX_SIMPLE_NAME, loc, _Locale_MAX_SIMPLE_NAME);
1869     return buf;
1870   }
1871 }
1872
1873 char const* __TranslateToSystem(const char* lname, char* buf, _Locale_lcid_t* hint) {
1874   LCID lcid;
1875   char cp[MAX_CP_LEN + 1];
1876   if (__GetLCIDFromName(lname, &lcid, cp, hint) != 0) return NULL;
1877
1878   return __GetLocaleName(lcid, cp, buf);
1879 }
1880
1881 void __GetLocaleInfoUsingACP(LCID lcid, const char* cp, LCTYPE lctype, char* buf, int buf_size) {
1882   wchar_t *Buffer;
1883   int BufferSize;
1884
1885   GetLocaleInfoA(lcid, lctype, buf, buf_size);
1886
1887   BufferSize = MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0);
1888   Buffer = (wchar_t*)malloc(sizeof(wchar_t) * (BufferSize + 1));
1889   MultiByteToWideChar(CP_ACP, 0, buf, -1, Buffer, BufferSize);
1890   WideCharToMultiByte(atoi(cp), 0, Buffer, -1, buf, buf_size, NULL, NULL);
1891   free(Buffer);
1892 }
1893
1894 /* Return 0 if ANSI code page not used */
1895 int __intGetACP(LCID lcid) {
1896   char cp[6];
1897   GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, cp, 6);
1898   return atoi(cp);
1899 }
1900
1901 /* Return 1 if OEM code page not used */
1902 int __intGetOCP(LCID lcid) {
1903   char cp[6];
1904   GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, cp, 6);
1905   return atoi(cp);
1906 }
1907
1908 int __GetDefaultCP(LCID lcid) {
1909   int cp = __intGetACP(lcid);
1910   if (cp == 0) return __intGetOCP(lcid);
1911   else return cp;
1912 }
1913
1914 static int trim_size_t_to_int(size_t n) { return n < (size_t)INT_MAX ? (int)n : INT_MAX; }
1915
1916 char* __ConvertToCP(int from_cp, int to_cp, const char *from, size_t size, size_t *ret_buf_size) {
1917   size_t wbuffer_size, buffer_size, from_offset, wbuf_offset;
1918   int from_size, to_size, wbuf_size;
1919   wchar_t *wbuffer;
1920   char* buffer;
1921
1922   size_t orig_size = size;
1923
1924   wbuffer_size = 0;
1925   from_offset = 0;
1926   while (size > 0) {
1927     from_size = trim_size_t_to_int(size);
1928     wbuffer_size += MultiByteToWideChar(from_cp, MB_PRECOMPOSED,
1929                                         from + from_offset, from_size, NULL, 0);
1930     from_offset += from_size;
1931     size -= from_size;
1932   }
1933
1934   wbuffer = (wchar_t*)malloc(sizeof(wchar_t)*wbuffer_size);
1935
1936   size = orig_size;
1937   wbuf_offset = 0;
1938   from_offset = 0;
1939   while (size > 0) {
1940     from_size = trim_size_t_to_int(size);
1941     wbuf_size = trim_size_t_to_int(wbuffer_size - wbuf_offset);
1942     wbuf_offset += MultiByteToWideChar(from_cp, MB_PRECOMPOSED,
1943                                        from + from_offset, from_size, wbuffer + wbuf_offset, wbuf_size);
1944     from_offset += from_size;
1945     size -= from_size;
1946   }
1947
1948   buffer_size = 0;
1949   wbuf_offset = 0;
1950   size = wbuffer_size;
1951   while (size > 0) {
1952     wbuf_size = trim_size_t_to_int(size);
1953     buffer_size += WideCharToMultiByte(to_cp, WC_COMPOSITECHECK | WC_SEPCHARS,
1954                                        wbuffer + wbuf_offset, wbuf_size,
1955                                        NULL, 0, NULL, FALSE);
1956     wbuf_offset += wbuf_size;
1957     size -= wbuf_size;
1958   }
1959
1960   buffer = (char*)malloc(buffer_size);
1961   *ret_buf_size = buffer_size;
1962
1963   size = wbuffer_size;
1964   wbuf_offset = 0;
1965   while (size > 0) {
1966     wbuf_size = trim_size_t_to_int(size);
1967     to_size = trim_size_t_to_int(buffer_size);
1968     buffer_size -= WideCharToMultiByte(to_cp, WC_COMPOSITECHECK | WC_SEPCHARS,
1969                                        wbuffer + wbuf_offset, wbuf_size,
1970                                        buffer, to_size, NULL, FALSE);
1971     wbuf_offset += wbuf_size;
1972     size -= wbuf_size;
1973   }
1974
1975   free(wbuffer);
1976   return buffer;
1977 }
1978
1979 #ifdef __cplusplus
1980 }
1981 #endif
1982