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
33 #define WIN32_NO_STATUS
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 /***********************************************************************
66 * Retrieve the ANSI codepage for a given locale.
68 static UINT
get_lcid_codepage( LCID lcid
, UINT flags
)
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
) );
79 /******************************************************************************
80 * SetLocaleInfoA [KERNEL32.@]
82 * Set information about an aspect of a locale.
85 * lcid [I] LCID of the locale
86 * lctype [I] LCTYPE_ flags from "winnls.h"
87 * data [I] Information to set
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.
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
);
112 SetLastError( ERROR_INVALID_PARAMETER
);
115 len
= MultiByteToWideChar( codepage
, 0, data
, -1, NULL
, 0 );
116 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
118 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
121 MultiByteToWideChar( codepage
, 0, data
, -1, strW
, len
);
122 ret
= SetLocaleInfoW( lcid
, lctype
, strW
);
123 HeapFree( GetProcessHeap(), 0, strW
);
128 /******************************************************************************
129 * SetCPGlobal (KERNEL32.@)
131 * Set the current Ansi code page Id for the system.
134 * acp [I] code page ID to be the new ACP.
139 UINT WINAPI
SetCPGlobal( UINT acp
)
141 FIXME( "not supported\n" );
146 /***********************************************************************
147 * GetCPInfoExA (KERNEL32.@)
149 * Get extended information about a code page.
152 * codepage [I] Code page number
153 * dwFlags [I] Reserved, must to 0.
154 * cpinfo [O] Destination for code page information
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
)
164 if (!GetCPInfoExW( codepage
, dwFlags
, &cpinfoW
))
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
);
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.
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
206 * Success: TRUE. chartype is filled with the requested characteristics of each char
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.
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
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
);
245 srclenW
= MultiByteToWideChar(CP_ACP
, 0, src
, srclen
, NULL
, 0);
246 srcW
= HeapAlloc(GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
));
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);
259 dstW
= HeapAlloc(GetProcessHeap(), 0, ret
* sizeof(WCHAR
));
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
))
271 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
275 HeapFree(GetProcessHeap(), 0, dstW
);
278 HeapFree(GetProcessHeap(), 0, srcW
);
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
);
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.
371 BOOL WINAPI
InvalidateNLSCache(void)
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
)
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
)
408 if (!MultiByteToWideChar( get_lcid_codepage(lcid
, type
), 0, data
, -1, buffer
, ARRAY_SIZE(buffer
) ))
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];
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
);
431 MultiByteToWideChar( cp
, 0, value
, -1, input
, ARRAY_SIZE(input
) );
436 WCHAR fmt_decimal
[4], fmt_thousand
[4];
438 if (flags
& LOCALE_NOUSEROVERRIDE
)
440 SetLastError( ERROR_INVALID_FLAGS
);
443 if (!format
->lpDecimalSep
|| !format
->lpThousandSep
)
445 SetLastError( ERROR_INVALID_PARAMETER
);
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 );
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];
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
);
482 MultiByteToWideChar( cp
, 0, value
, -1, input
, ARRAY_SIZE(input
) );
487 WCHAR fmt_decimal
[4], fmt_thousand
[4], fmt_symbol
[13];
489 if (flags
& LOCALE_NOUSEROVERRIDE
)
491 SetLastError( ERROR_INVALID_FLAGS
);
494 if (!format
->lpDecimalSep
|| !format
->lpThousandSep
|| !format
->lpCurrencySymbol
)
496 SetLastError( ERROR_INVALID_PARAMETER
);
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 );
519 /******************************************************************************
520 * GetGeoInfoA (KERNEL32.@)
522 INT WINAPI
GetGeoInfoA(GEOID geoid
, GEOTYPE geotype
, LPSTR data
, int data_len
, LANGID lang
)
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
);