include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / kernel32 / locale.c
blob235034f61171d0c02d90f8651b77a12afd75b3b5
1 /*
2 * Locale support
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 David Lee Lambert
6 * Copyright 2000 Julio César Gázquez
7 * Copyright 2002 Alexandre Julliard for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <assert.h>
25 #include <locale.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <stdlib.h>
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winternl.h"
37 #include "winnls.h"
38 #include "winerror.h"
39 #include "winver.h"
40 #include "kernel_private.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(nls);
45 extern const NLS_LOCALE_DATA * WINAPI NlsValidateLocale( LCID *lcid, ULONG flags );
47 extern BOOL WINAPI Internal_EnumCalendarInfo( CALINFO_ENUMPROCW proc,
48 const NLS_LOCALE_DATA *locale, CALID id,
49 CALTYPE type, BOOL unicode, BOOL ex,
50 BOOL exex, LPARAM lparam );
51 extern BOOL WINAPI Internal_EnumDateFormats( DATEFMT_ENUMPROCW proc, const NLS_LOCALE_DATA *locale,
52 DWORD flags, BOOL unicode, BOOL ex, BOOL exex, LPARAM lparam );
53 extern BOOL WINAPI Internal_EnumLanguageGroupLocales( LANGGROUPLOCALE_ENUMPROCW proc, LGRPID id,
54 DWORD flags, LONG_PTR param, BOOL unicode );
55 extern BOOL WINAPI Internal_EnumSystemCodePages( CODEPAGE_ENUMPROCW proc, DWORD flags, BOOL unicode );
56 extern BOOL WINAPI Internal_EnumSystemLanguageGroups( LANGUAGEGROUP_ENUMPROCW proc, DWORD flags,
57 LONG_PTR param, BOOL unicode );
58 extern BOOL WINAPI Internal_EnumTimeFormats( TIMEFMT_ENUMPROCW proc, const NLS_LOCALE_DATA *locale,
59 DWORD flags, BOOL unicode, BOOL ex, LPARAM lparam );
60 extern BOOL WINAPI Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW proc, DWORD flags,
61 LONG_PTR param, BOOL unicode );
63 /***********************************************************************
64 * get_lcid_codepage
66 * Retrieve the ANSI codepage for a given locale.
68 static UINT get_lcid_codepage( LCID lcid, UINT flags )
70 UINT ret = 0;
72 if (flags & LOCALE_USE_CP_ACP) return CP_ACP;
73 GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
74 (WCHAR *)&ret, sizeof(ret)/sizeof(WCHAR) );
75 return ret;
79 /******************************************************************************
80 * SetLocaleInfoA [KERNEL32.@]
82 * Set information about an aspect of a locale.
84 * PARAMS
85 * lcid [I] LCID of the locale
86 * lctype [I] LCTYPE_ flags from "winnls.h"
87 * data [I] Information to set
89 * RETURNS
90 * Success: TRUE. The information given will be returned by GetLocaleInfoA()
91 * whenever it is called without LOCALE_NOUSEROVERRIDE.
92 * Failure: FALSE. Use GetLastError() to determine the cause.
94 * NOTES
95 * - Values are only be set for the current user locale; the system locale
96 * settings cannot be changed.
97 * - Any settings changed by this call are lost when the locale is changed by
98 * the control panel (in Wine, this happens every time you change LANG).
99 * - The native implementation of this function does not check that lcid matches
100 * the current user locale, and simply sets the new values. Wine warns you in
101 * this case, but behaves the same.
103 BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
105 UINT codepage = get_lcid_codepage( lcid, lctype );
106 WCHAR *strW;
107 DWORD len;
108 BOOL ret;
110 if (!data)
112 SetLastError( ERROR_INVALID_PARAMETER );
113 return FALSE;
115 len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 );
116 if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
118 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
119 return FALSE;
121 MultiByteToWideChar( codepage, 0, data, -1, strW, len );
122 ret = SetLocaleInfoW( lcid, lctype, strW );
123 HeapFree( GetProcessHeap(), 0, strW );
124 return ret;
128 /******************************************************************************
129 * SetCPGlobal (KERNEL32.@)
131 * Set the current Ansi code page Id for the system.
133 * PARAMS
134 * acp [I] code page ID to be the new ACP.
136 * RETURNS
137 * The previous ACP.
139 UINT WINAPI SetCPGlobal( UINT acp )
141 FIXME( "not supported\n" );
142 return GetACP();
146 /***********************************************************************
147 * GetCPInfoExA (KERNEL32.@)
149 * Get extended information about a code page.
151 * PARAMS
152 * codepage [I] Code page number
153 * dwFlags [I] Reserved, must to 0.
154 * cpinfo [O] Destination for code page information
156 * RETURNS
157 * Success: TRUE. cpinfo is updated with the information about codepage.
158 * Failure: FALSE, if codepage is invalid or cpinfo is NULL.
160 BOOL WINAPI GetCPInfoExA( UINT codepage, DWORD dwFlags, LPCPINFOEXA cpinfo )
162 CPINFOEXW cpinfoW;
164 if (!GetCPInfoExW( codepage, dwFlags, &cpinfoW ))
165 return FALSE;
167 /* the layout is the same except for CodePageName */
168 memcpy(cpinfo, &cpinfoW, sizeof(CPINFOEXA));
169 WideCharToMultiByte(CP_ACP, 0, cpinfoW.CodePageName, -1, cpinfo->CodePageName, sizeof(cpinfo->CodePageName), NULL, NULL);
170 return TRUE;
174 /*********************************************************************
175 * GetDaylightFlag (KERNEL32.@)
177 BOOL WINAPI GetDaylightFlag(void)
179 TIME_ZONE_INFORMATION tzinfo;
180 return GetTimeZoneInformation( &tzinfo) == TIME_ZONE_ID_DAYLIGHT;
184 /***********************************************************************
185 * EnumSystemCodePagesA (KERNEL32.@)
187 BOOL WINAPI EnumSystemCodePagesA( CODEPAGE_ENUMPROCA proc, DWORD flags )
189 return Internal_EnumSystemCodePages( (CODEPAGE_ENUMPROCW)proc, flags, FALSE );
193 /******************************************************************************
194 * GetStringTypeExA (KERNEL32.@)
196 * Get characteristics of the characters making up a string.
198 * PARAMS
199 * locale [I] Locale Id for the string
200 * type [I] CT_CTYPE1 = classification, CT_CTYPE2 = directionality, CT_CTYPE3 = typographic info
201 * src [I] String to analyse
202 * count [I] Length of src in chars, or -1 if src is NUL terminated
203 * chartype [O] Destination for the calculated characteristics
205 * RETURNS
206 * Success: TRUE. chartype is filled with the requested characteristics of each char
207 * in src.
208 * Failure: FALSE. Use GetLastError() to determine the cause.
210 BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype )
212 return GetStringTypeA(locale, type, src, count, chartype);
215 /*************************************************************************
216 * FoldStringA (KERNEL32.@)
218 * Map characters in a string.
220 * PARAMS
221 * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h")
222 * src [I] String to map
223 * srclen [I] Length of src, or -1 if src is NUL terminated
224 * dst [O] Destination for mapped string
225 * dstlen [I] Length of dst, or 0 to find the required length for the mapped string
227 * RETURNS
228 * Success: The length of the string written to dst, including the terminating NUL. If
229 * dstlen is 0, the value returned is the same, but nothing is written to dst,
230 * and dst may be NULL.
231 * Failure: 0. Use GetLastError() to determine the cause.
233 INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen,
234 LPSTR dst, INT dstlen)
236 INT ret = 0, srclenW = 0;
237 WCHAR *srcW = NULL, *dstW = NULL;
239 if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst)
241 SetLastError(ERROR_INVALID_PARAMETER);
242 return 0;
245 srclenW = MultiByteToWideChar(CP_ACP, 0, src, srclen, NULL, 0);
246 srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR));
248 if (!srcW)
250 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
251 goto FoldStringA_exit;
254 MultiByteToWideChar(CP_ACP, 0, src, srclen, srcW, srclenW);
256 ret = FoldStringW(dwFlags, srcW, srclenW, NULL, 0);
257 if (ret && dstlen)
259 dstW = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(WCHAR));
261 if (!dstW)
263 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
264 goto FoldStringA_exit;
267 ret = FoldStringW(dwFlags, srcW, srclenW, dstW, ret);
268 if (!WideCharToMultiByte(CP_ACP, 0, dstW, ret, dst, dstlen, NULL, NULL))
270 ret = 0;
271 SetLastError(ERROR_INSUFFICIENT_BUFFER);
275 HeapFree(GetProcessHeap(), 0, dstW);
277 FoldStringA_exit:
278 HeapFree(GetProcessHeap(), 0, srcW);
279 return ret;
282 /******************************************************************************
283 * EnumSystemLanguageGroupsA (KERNEL32.@)
285 BOOL WINAPI EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA proc, DWORD flags, LONG_PTR param )
287 return Internal_EnumSystemLanguageGroups( (LANGUAGEGROUP_ENUMPROCW)proc, flags, param, FALSE );
290 /******************************************************************************
291 * EnumLanguageGroupLocalesA (KERNEL32.@)
293 BOOL WINAPI EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA proc, LGRPID id,
294 DWORD flags, LONG_PTR param )
296 return Internal_EnumLanguageGroupLocales( (LANGGROUPLOCALE_ENUMPROCW)proc, id, flags, param, FALSE );
299 /******************************************************************************
300 * EnumCalendarInfoA [KERNEL32.@]
302 BOOL WINAPI EnumCalendarInfoA( CALINFO_ENUMPROCA proc, LCID lcid, CALID id, CALTYPE type )
304 return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW)proc, NlsValidateLocale( &lcid, 0 ),
305 id, type, FALSE, FALSE, FALSE, 0 );
308 /******************************************************************************
309 * EnumCalendarInfoExA [KERNEL32.@]
311 BOOL WINAPI EnumCalendarInfoExA( CALINFO_ENUMPROCEXA proc, LCID lcid, CALID id, CALTYPE type )
313 return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW)proc, NlsValidateLocale( &lcid, 0 ),
314 id, type, FALSE, TRUE, FALSE, 0 );
317 /**************************************************************************
318 * EnumDateFormatsExA (KERNEL32.@)
320 * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
321 * LOCALE_NOUSEROVERRIDE here as well?
323 BOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA proc, LCID lcid, DWORD flags)
325 return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW)proc, NlsValidateLocale( &lcid, 0 ),
326 flags, FALSE, TRUE, FALSE, 0 );
329 /**************************************************************************
330 * EnumDateFormatsA (KERNEL32.@)
332 * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
333 * LOCALE_NOUSEROVERRIDE here as well?
335 BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA proc, LCID lcid, DWORD flags)
337 return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW)proc, NlsValidateLocale( &lcid, 0 ),
338 flags, FALSE, FALSE, FALSE, 0 );
341 /**************************************************************************
342 * EnumTimeFormatsA (KERNEL32.@)
344 * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
345 * LOCALE_NOUSEROVERRIDE here as well?
347 BOOL WINAPI EnumTimeFormatsA( TIMEFMT_ENUMPROCA proc, LCID lcid, DWORD flags )
349 /* EnumTimeFormatsA doesn't support flags, EnumTimeFormatsW does. */
350 if (flags & ~LOCALE_USE_CP_ACP)
352 SetLastError(ERROR_INVALID_FLAGS);
353 return FALSE;
355 return Internal_EnumTimeFormats( (TIMEFMT_ENUMPROCW)proc, NlsValidateLocale( &lcid, 0 ),
356 flags, FALSE, FALSE, 0 );
359 /******************************************************************************
360 * InvalidateNLSCache (KERNEL32.@)
362 * Invalidate the cache of NLS values.
364 * PARAMS
365 * None.
367 * RETURNS
368 * Success: TRUE.
369 * Failure: FALSE.
371 BOOL WINAPI InvalidateNLSCache(void)
373 FIXME("() stub\n");
374 return FALSE;
377 /******************************************************************************
378 * EnumUILanguagesA (KERNEL32.@)
380 BOOL WINAPI EnumUILanguagesA( UILANGUAGE_ENUMPROCA proc, DWORD flags, LONG_PTR param )
382 return Internal_EnumUILanguages( (UILANGUAGE_ENUMPROCW)proc, flags, param, FALSE );
386 /*********************************************************************
387 * GetCalendarInfoA (KERNEL32.@)
389 int WINAPI GetCalendarInfoA( LCID lcid, CALID id, CALTYPE type, LPSTR data, int data_len, DWORD *val )
391 WCHAR buffer[256];
393 if (type & CAL_RETURN_NUMBER)
394 return GetCalendarInfoW( lcid, id, type, (WCHAR *)data, data_len, val ) * sizeof(WCHAR);
396 if (!GetCalendarInfoW( lcid, id, type, buffer, ARRAY_SIZE(buffer), val )) return 0;
397 return WideCharToMultiByte( get_lcid_codepage(lcid, type), 0, buffer, -1, data, data_len, NULL, NULL );
401 /*********************************************************************
402 * SetCalendarInfoA (KERNEL32.@)
404 int WINAPI SetCalendarInfoA( LCID lcid, CALID id, CALTYPE type, LPCSTR data )
406 WCHAR buffer[256];
408 if (!MultiByteToWideChar( get_lcid_codepage(lcid, type), 0, data, -1, buffer, ARRAY_SIZE(buffer) ))
409 return 0;
410 return SetCalendarInfoW( lcid, id, type, buffer );
414 /**************************************************************************
415 * GetNumberFormatA (KERNEL32.@)
417 int WINAPI GetNumberFormatA( LCID lcid, DWORD flags, const char *value,
418 const NUMBERFMTA *format, char *buffer, int len )
420 UINT cp = get_lcid_codepage( lcid, flags );
421 WCHAR input[128], output[128];
422 int ret;
424 TRACE( "(0x%04lx,0x%08lx,%s,%p,%p,%d)\n", lcid, flags, debugstr_a(value), format, buffer, len );
426 if (len < 0 || (len && !buffer) || !value)
428 SetLastError( ERROR_INVALID_PARAMETER );
429 return 0;
431 MultiByteToWideChar( cp, 0, value, -1, input, ARRAY_SIZE(input) );
433 if (format)
435 NUMBERFMTW fmt;
436 WCHAR fmt_decimal[4], fmt_thousand[4];
438 if (flags & LOCALE_NOUSEROVERRIDE)
440 SetLastError( ERROR_INVALID_FLAGS );
441 return 0;
443 if (!format->lpDecimalSep || !format->lpThousandSep)
445 SetLastError( ERROR_INVALID_PARAMETER );
446 return 0;
448 MultiByteToWideChar( cp, 0, format->lpDecimalSep, -1, fmt_decimal, ARRAY_SIZE(fmt_decimal) );
449 MultiByteToWideChar( cp, 0, format->lpThousandSep, -1, fmt_thousand, ARRAY_SIZE(fmt_thousand) );
450 fmt.NumDigits = format->NumDigits;
451 fmt.LeadingZero = format->LeadingZero;
452 fmt.Grouping = format->Grouping;
453 fmt.NegativeOrder = format->NegativeOrder;
454 fmt.lpDecimalSep = fmt_decimal;
455 fmt.lpThousandSep = fmt_thousand;
456 ret = GetNumberFormatW( lcid, flags, input, &fmt, output, ARRAY_SIZE(output) );
458 else ret = GetNumberFormatW( lcid, flags, input, NULL, output, ARRAY_SIZE(output) );
460 if (ret) ret = WideCharToMultiByte( cp, 0, output, -1, buffer, len, 0, 0 );
461 return ret;
465 /**************************************************************************
466 * GetCurrencyFormatA (KERNEL32.@)
468 int WINAPI GetCurrencyFormatA( LCID lcid, DWORD flags, const char *value,
469 const CURRENCYFMTA *format, char *buffer, int len )
471 UINT cp = get_lcid_codepage( lcid, flags );
472 WCHAR input[128], output[128];
473 int ret;
475 TRACE( "(0x%04lx,0x%08lx,%s,%p,%p,%d)\n", lcid, flags, debugstr_a(value), format, buffer, len );
477 if (len < 0 || (len && !buffer) || !value)
479 SetLastError( ERROR_INVALID_PARAMETER );
480 return 0;
482 MultiByteToWideChar( cp, 0, value, -1, input, ARRAY_SIZE(input) );
484 if (format)
486 CURRENCYFMTW fmt;
487 WCHAR fmt_decimal[4], fmt_thousand[4], fmt_symbol[13];
489 if (flags & LOCALE_NOUSEROVERRIDE)
491 SetLastError( ERROR_INVALID_FLAGS );
492 return 0;
494 if (!format->lpDecimalSep || !format->lpThousandSep || !format->lpCurrencySymbol)
496 SetLastError( ERROR_INVALID_PARAMETER );
497 return 0;
499 MultiByteToWideChar( cp, 0, format->lpDecimalSep, -1, fmt_decimal, ARRAY_SIZE(fmt_decimal) );
500 MultiByteToWideChar( cp, 0, format->lpThousandSep, -1, fmt_thousand, ARRAY_SIZE(fmt_thousand) );
501 MultiByteToWideChar( cp, 0, format->lpCurrencySymbol, -1, fmt_symbol, ARRAY_SIZE(fmt_symbol) );
502 fmt.NumDigits = format->NumDigits;
503 fmt.LeadingZero = format->LeadingZero;
504 fmt.Grouping = format->Grouping;
505 fmt.NegativeOrder = format->NegativeOrder;
506 fmt.PositiveOrder = format->PositiveOrder;
507 fmt.lpDecimalSep = fmt_decimal;
508 fmt.lpThousandSep = fmt_thousand;
509 fmt.lpCurrencySymbol = fmt_symbol;
510 ret = GetCurrencyFormatW( lcid, flags, input, &fmt, output, ARRAY_SIZE(output) );
512 else ret = GetCurrencyFormatW( lcid, flags, input, NULL, output, ARRAY_SIZE(output) );
514 if (ret) ret = WideCharToMultiByte( cp, 0, output, -1, buffer, len, 0, 0 );
515 return ret;
519 /******************************************************************************
520 * GetGeoInfoA (KERNEL32.@)
522 INT WINAPI GetGeoInfoA(GEOID geoid, GEOTYPE geotype, LPSTR data, int data_len, LANGID lang)
524 WCHAR buffer[256];
526 TRACE("%ld %ld %p %d %d\n", geoid, geotype, data, data_len, lang);
528 if (!GetGeoInfoW( geoid, geotype, buffer, ARRAY_SIZE(buffer), lang )) return 0;
529 return WideCharToMultiByte( CP_ACP, 0, buffer, -1, data, data_len, NULL, NULL );