1c2c66affSColin Finck /*
2c2c66affSColin Finck * Locale-dependent format handling
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 1995 Martin von Loewis
5c2c66affSColin Finck * Copyright 1998 David Lee Lambert
6c2c66affSColin Finck * Copyright 2000 Julio César Gázquez
7c2c66affSColin Finck * Copyright 2003 Jon Griffiths
8c2c66affSColin Finck * Copyright 2005 Dmitry Timoshkov
9c2c66affSColin Finck *
10c2c66affSColin Finck * This library is free software; you can redistribute it and/or
11c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
12c2c66affSColin Finck * License as published by the Free Software Foundation; either
13c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
14c2c66affSColin Finck *
15c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
16c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
17c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18c2c66affSColin Finck * Lesser General Public License for more details.
19c2c66affSColin Finck *
20c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
21c2c66affSColin Finck * License along with this library; if not, write to the Free Software
22c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23c2c66affSColin Finck */
24c2c66affSColin Finck
25cf14b6b2SAmine Khaldi #ifdef __REACTOS__
26cf14b6b2SAmine Khaldi
27c2c66affSColin Finck #include <k32.h>
2815537c3bSKatayama Hirofumi MZ #include "japanese.h" /* Japanese eras */
29c2c66affSColin Finck
30c2c66affSColin Finck #define NDEBUG
31c2c66affSColin Finck #include <debug.h>
32c2c66affSColin Finck DEBUG_CHANNEL(nls);
33c2c66affSColin Finck
34*2549e10cSTimo Kreuzer #undef _WIN32_WINNT
35*2549e10cSTimo Kreuzer #undef WINVER
36*2549e10cSTimo Kreuzer #define _WIN32_WINNT DLL_EXPORT_VERSION
37*2549e10cSTimo Kreuzer #define WINVER DLL_EXPORT_VERSION
38*2549e10cSTimo Kreuzer
39*2549e10cSTimo Kreuzer LCID WINAPI LocaleNameToLCID(_In_ LPCWSTR, _In_ DWORD);
40*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME1 96
41*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME2 97
42*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME3 98
43*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME4 99
44*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME5 100
45*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME6 101
46*2549e10cSTimo Kreuzer #define LOCALE_SSHORTESTDAYNAME7 102
47*2549e10cSTimo Kreuzer
48c2c66affSColin Finck #define CRITICAL_SECTION RTL_CRITICAL_SECTION
49c2c66affSColin Finck #define CRITICAL_SECTION_DEBUG RTL_CRITICAL_SECTION_DEBUG
50c2c66affSColin Finck #define CALINFO_MAX_YEAR 2029
51c2c66affSColin Finck
5215537c3bSKatayama Hirofumi MZ #define IS_LCID_JAPANESE(lcid) PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_JAPANESE
5315537c3bSKatayama Hirofumi MZ
5415537c3bSKatayama Hirofumi MZ #ifndef CAL_SABBREVERASTRING
5515537c3bSKatayama Hirofumi MZ #define CAL_SABBREVERASTRING 0x00000039
5615537c3bSKatayama Hirofumi MZ #endif
5715537c3bSKatayama Hirofumi MZ
58cf14b6b2SAmine Khaldi #else /* __REACTOS__ */
59cf14b6b2SAmine Khaldi
60cf14b6b2SAmine Khaldi #include "config.h"
61cf14b6b2SAmine Khaldi #include "wine/port.h"
62cf14b6b2SAmine Khaldi
63cf14b6b2SAmine Khaldi #include <string.h>
64cf14b6b2SAmine Khaldi #include <stdarg.h>
65cf14b6b2SAmine Khaldi #include <stdio.h>
66cf14b6b2SAmine Khaldi #include <stdlib.h>
67cf14b6b2SAmine Khaldi
68cf14b6b2SAmine Khaldi #include "windef.h"
69cf14b6b2SAmine Khaldi #include "winbase.h"
70cf14b6b2SAmine Khaldi #include "wine/unicode.h"
71cf14b6b2SAmine Khaldi #include "wine/debug.h"
72cf14b6b2SAmine Khaldi #include "winternl.h"
73cf14b6b2SAmine Khaldi
74cf14b6b2SAmine Khaldi #include "kernel_private.h"
75cf14b6b2SAmine Khaldi
76cf14b6b2SAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(nls);
77cf14b6b2SAmine Khaldi
78cf14b6b2SAmine Khaldi #endif /* __REACTOS__ */
79cf14b6b2SAmine Khaldi
80c2c66affSColin Finck #define DATE_DATEVARSONLY 0x0100 /* only date stuff: yMdg */
81c2c66affSColin Finck #define TIME_TIMEVARSONLY 0x0200 /* only time stuff: hHmst */
82c2c66affSColin Finck
83c2c66affSColin Finck /* Since calculating the formatting data for each locale is time-consuming,
84c2c66affSColin Finck * we get the format data for each locale only once and cache it in memory.
85c2c66affSColin Finck * We cache both the system default and user overridden data, after converting
86c2c66affSColin Finck * them into the formats that the functions here expect. Since these functions
87c2c66affSColin Finck * will typically be called with only a small number of the total locales
88c2c66affSColin Finck * installed, the memory overhead is minimal while the speedup is significant.
89c2c66affSColin Finck *
90c2c66affSColin Finck * Our cache takes the form of a singly linked list, whose node is below:
91c2c66affSColin Finck */
92c2c66affSColin Finck #define NLS_NUM_CACHED_STRINGS 57
93c2c66affSColin Finck
94c2c66affSColin Finck typedef struct _NLS_FORMAT_NODE
95c2c66affSColin Finck {
96c2c66affSColin Finck LCID lcid; /* Locale Id */
97c2c66affSColin Finck DWORD dwFlags; /* 0 or LOCALE_NOUSEROVERRIDE */
98c2c66affSColin Finck DWORD dwCodePage; /* Default code page (if LOCALE_USE_ANSI_CP not given) */
99c2c66affSColin Finck NUMBERFMTW fmt; /* Default format for numbers */
100c2c66affSColin Finck CURRENCYFMTW cyfmt; /* Default format for currencies */
101c2c66affSColin Finck LPWSTR lppszStrings[NLS_NUM_CACHED_STRINGS]; /* Default formats,day/month names */
102c2c66affSColin Finck WCHAR szShortAM[2]; /* Short 'AM' marker */
103c2c66affSColin Finck WCHAR szShortPM[2]; /* Short 'PM' marker */
104c2c66affSColin Finck struct _NLS_FORMAT_NODE *next;
105c2c66affSColin Finck } NLS_FORMAT_NODE;
106c2c66affSColin Finck
107c2c66affSColin Finck /* Macros to get particular data strings from a format node */
108c2c66affSColin Finck #define GetNegative(fmt) fmt->lppszStrings[0]
109c2c66affSColin Finck #define GetLongDate(fmt) fmt->lppszStrings[1]
110c2c66affSColin Finck #define GetShortDate(fmt) fmt->lppszStrings[2]
111c2c66affSColin Finck #define GetTime(fmt) fmt->lppszStrings[3]
112c2c66affSColin Finck #define GetAM(fmt) fmt->lppszStrings[54]
113c2c66affSColin Finck #define GetPM(fmt) fmt->lppszStrings[55]
114c2c66affSColin Finck #define GetYearMonth(fmt) fmt->lppszStrings[56]
115c2c66affSColin Finck
116c2c66affSColin Finck #define GetLongDay(fmt,day) fmt->lppszStrings[4 + day]
117c2c66affSColin Finck #define GetShortDay(fmt,day) fmt->lppszStrings[11 + day]
118c2c66affSColin Finck #define GetLongMonth(fmt,mth) fmt->lppszStrings[18 + mth]
119c2c66affSColin Finck #define GetGenitiveMonth(fmt,mth) fmt->lppszStrings[30 + mth]
120c2c66affSColin Finck #define GetShortMonth(fmt,mth) fmt->lppszStrings[42 + mth]
121c2c66affSColin Finck
122c2c66affSColin Finck /* Write access to the cache is protected by this critical section */
123c2c66affSColin Finck static CRITICAL_SECTION NLS_FormatsCS;
124c2c66affSColin Finck static CRITICAL_SECTION_DEBUG NLS_FormatsCS_debug =
125c2c66affSColin Finck {
126c2c66affSColin Finck 0, 0, &NLS_FormatsCS,
127c2c66affSColin Finck { &NLS_FormatsCS_debug.ProcessLocksList,
128c2c66affSColin Finck &NLS_FormatsCS_debug.ProcessLocksList },
129cf14b6b2SAmine Khaldi #ifdef __REACTOS__
130c2c66affSColin Finck 0, 0, 0
131cf14b6b2SAmine Khaldi #else
132cf14b6b2SAmine Khaldi 0, 0, { (DWORD_PTR)(__FILE__ ": NLS_Formats") }
133cf14b6b2SAmine Khaldi #endif
134c2c66affSColin Finck };
135c2c66affSColin Finck static CRITICAL_SECTION NLS_FormatsCS = { &NLS_FormatsCS_debug, -1, 0, 0, 0, 0 };
136c2c66affSColin Finck
137c2c66affSColin Finck /**************************************************************************
138c2c66affSColin Finck * NLS_GetLocaleNumber <internal>
139c2c66affSColin Finck *
140c2c66affSColin Finck * Get a numeric locale format value.
141c2c66affSColin Finck */
NLS_GetLocaleNumber(LCID lcid,DWORD dwFlags)142c2c66affSColin Finck static DWORD NLS_GetLocaleNumber(LCID lcid, DWORD dwFlags)
143c2c66affSColin Finck {
144c2c66affSColin Finck WCHAR szBuff[80];
145c2c66affSColin Finck DWORD dwVal = 0;
146c2c66affSColin Finck
147c2c66affSColin Finck szBuff[0] = '\0';
148655d24d9SDenis Malikov GetLocaleInfoW(lcid, dwFlags, szBuff, ARRAY_SIZE(szBuff));
149c2c66affSColin Finck
150c2c66affSColin Finck if (szBuff[0] && szBuff[1] == ';' && szBuff[2] != '0')
151c2c66affSColin Finck dwVal = (szBuff[0] - '0') * 10 + (szBuff[2] - '0');
152c2c66affSColin Finck else
153c2c66affSColin Finck {
154c2c66affSColin Finck const WCHAR* iter = szBuff;
155c2c66affSColin Finck dwVal = 0;
156c2c66affSColin Finck while(*iter >= '0' && *iter <= '9')
157c2c66affSColin Finck dwVal = dwVal * 10 + (*iter++ - '0');
158c2c66affSColin Finck }
159c2c66affSColin Finck return dwVal;
160c2c66affSColin Finck }
161c2c66affSColin Finck
162c2c66affSColin Finck /**************************************************************************
163c2c66affSColin Finck * NLS_GetLocaleString <internal>
164c2c66affSColin Finck *
165c2c66affSColin Finck * Get a string locale format value.
166c2c66affSColin Finck */
NLS_GetLocaleString(LCID lcid,DWORD dwFlags)167c2c66affSColin Finck static WCHAR* NLS_GetLocaleString(LCID lcid, DWORD dwFlags)
168c2c66affSColin Finck {
169c2c66affSColin Finck WCHAR szBuff[80], *str;
170c2c66affSColin Finck DWORD dwLen;
171c2c66affSColin Finck
172c2c66affSColin Finck szBuff[0] = '\0';
173655d24d9SDenis Malikov GetLocaleInfoW(lcid, dwFlags, szBuff, ARRAY_SIZE(szBuff));
174c2c66affSColin Finck dwLen = strlenW(szBuff) + 1;
175c2c66affSColin Finck str = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
176c2c66affSColin Finck if (str)
177c2c66affSColin Finck memcpy(str, szBuff, dwLen * sizeof(WCHAR));
178c2c66affSColin Finck return str;
179c2c66affSColin Finck }
180c2c66affSColin Finck
181c2c66affSColin Finck #define GET_LOCALE_NUMBER(num, type) num = NLS_GetLocaleNumber(lcid, type|dwFlags); \
182c2c66affSColin Finck TRACE( #type ": %d (%08x)\n", (DWORD)num, (DWORD)num)
183c2c66affSColin Finck
184c2c66affSColin Finck #define GET_LOCALE_STRING(str, type) str = NLS_GetLocaleString(lcid, type|dwFlags); \
185c2c66affSColin Finck TRACE( #type ": %s\n", debugstr_w(str))
186c2c66affSColin Finck
187c2c66affSColin Finck /**************************************************************************
188c2c66affSColin Finck * NLS_GetFormats <internal>
189c2c66affSColin Finck *
190c2c66affSColin Finck * Calculate (and cache) the number formats for a locale.
191c2c66affSColin Finck */
NLS_GetFormats(LCID lcid,DWORD dwFlags)192c2c66affSColin Finck static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
193c2c66affSColin Finck {
194c2c66affSColin Finck /* GetLocaleInfo() identifiers for cached formatting strings */
195c2c66affSColin Finck static const LCTYPE NLS_LocaleIndices[] = {
196c2c66affSColin Finck LOCALE_SNEGATIVESIGN,
197c2c66affSColin Finck LOCALE_SLONGDATE, LOCALE_SSHORTDATE,
198c2c66affSColin Finck LOCALE_STIMEFORMAT,
199c2c66affSColin Finck LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
200c2c66affSColin Finck LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
201c2c66affSColin Finck LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
202c2c66affSColin Finck LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
203c2c66affSColin Finck LOCALE_SABBREVDAYNAME7,
204c2c66affSColin Finck LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
205c2c66affSColin Finck LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
206c2c66affSColin Finck LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
207c2c66affSColin Finck LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
208c2c66affSColin Finck LOCALE_SMONTHNAME1 | LOCALE_RETURN_GENITIVE_NAMES,
209c2c66affSColin Finck LOCALE_SMONTHNAME2 | LOCALE_RETURN_GENITIVE_NAMES,
210c2c66affSColin Finck LOCALE_SMONTHNAME3 | LOCALE_RETURN_GENITIVE_NAMES,
211c2c66affSColin Finck LOCALE_SMONTHNAME4 | LOCALE_RETURN_GENITIVE_NAMES,
212c2c66affSColin Finck LOCALE_SMONTHNAME5 | LOCALE_RETURN_GENITIVE_NAMES,
213c2c66affSColin Finck LOCALE_SMONTHNAME6 | LOCALE_RETURN_GENITIVE_NAMES,
214c2c66affSColin Finck LOCALE_SMONTHNAME7 | LOCALE_RETURN_GENITIVE_NAMES,
215c2c66affSColin Finck LOCALE_SMONTHNAME8 | LOCALE_RETURN_GENITIVE_NAMES,
216c2c66affSColin Finck LOCALE_SMONTHNAME9 | LOCALE_RETURN_GENITIVE_NAMES,
217c2c66affSColin Finck LOCALE_SMONTHNAME10 | LOCALE_RETURN_GENITIVE_NAMES,
218c2c66affSColin Finck LOCALE_SMONTHNAME11 | LOCALE_RETURN_GENITIVE_NAMES,
219c2c66affSColin Finck LOCALE_SMONTHNAME12 | LOCALE_RETURN_GENITIVE_NAMES,
220c2c66affSColin Finck LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
221c2c66affSColin Finck LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
222c2c66affSColin Finck LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
223c2c66affSColin Finck LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
224c2c66affSColin Finck LOCALE_S1159, LOCALE_S2359,
225c2c66affSColin Finck LOCALE_SYEARMONTH
226c2c66affSColin Finck };
227c2c66affSColin Finck static NLS_FORMAT_NODE *NLS_CachedFormats = NULL;
228c2c66affSColin Finck NLS_FORMAT_NODE *node = NLS_CachedFormats;
229c2c66affSColin Finck
230c2c66affSColin Finck dwFlags &= LOCALE_NOUSEROVERRIDE;
231c2c66affSColin Finck
232c2c66affSColin Finck TRACE("(0x%04x,0x%08x)\n", lcid, dwFlags);
233c2c66affSColin Finck
234c2c66affSColin Finck /* See if we have already cached the locales number format */
235c2c66affSColin Finck while (node && (node->lcid != lcid || node->dwFlags != dwFlags) && node->next)
236c2c66affSColin Finck node = node->next;
237c2c66affSColin Finck
238c2c66affSColin Finck if (!node || node->lcid != lcid || node->dwFlags != dwFlags)
239c2c66affSColin Finck {
240c2c66affSColin Finck NLS_FORMAT_NODE *new_node;
241c2c66affSColin Finck DWORD i;
242c2c66affSColin Finck
243c2c66affSColin Finck TRACE("Creating new cache entry\n");
244c2c66affSColin Finck
245c2c66affSColin Finck if (!(new_node = HeapAlloc(GetProcessHeap(), 0, sizeof(NLS_FORMAT_NODE))))
246c2c66affSColin Finck return NULL;
247c2c66affSColin Finck
248c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->dwCodePage, LOCALE_IDEFAULTANSICODEPAGE);
249c2c66affSColin Finck
250c2c66affSColin Finck /* Number Format */
251c2c66affSColin Finck new_node->lcid = lcid;
252c2c66affSColin Finck new_node->dwFlags = dwFlags;
253c2c66affSColin Finck new_node->next = NULL;
254c2c66affSColin Finck
255c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->fmt.NumDigits, LOCALE_IDIGITS);
256c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->fmt.LeadingZero, LOCALE_ILZERO);
257c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->fmt.NegativeOrder, LOCALE_INEGNUMBER);
258c2c66affSColin Finck
259c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->fmt.Grouping, LOCALE_SGROUPING);
260c2c66affSColin Finck if (new_node->fmt.Grouping > 9 && new_node->fmt.Grouping != 32)
261c2c66affSColin Finck {
262c2c66affSColin Finck WARN("LOCALE_SGROUPING (%d) unhandled, please report!\n",
263c2c66affSColin Finck new_node->fmt.Grouping);
264c2c66affSColin Finck new_node->fmt.Grouping = 0;
265c2c66affSColin Finck }
266c2c66affSColin Finck
267c2c66affSColin Finck GET_LOCALE_STRING(new_node->fmt.lpDecimalSep, LOCALE_SDECIMAL);
268c2c66affSColin Finck GET_LOCALE_STRING(new_node->fmt.lpThousandSep, LOCALE_STHOUSAND);
269c2c66affSColin Finck
270c2c66affSColin Finck /* Currency Format */
271c2c66affSColin Finck new_node->cyfmt.NumDigits = new_node->fmt.NumDigits;
272c2c66affSColin Finck new_node->cyfmt.LeadingZero = new_node->fmt.LeadingZero;
273c2c66affSColin Finck
274c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->cyfmt.Grouping, LOCALE_SGROUPING);
275c2c66affSColin Finck
276c2c66affSColin Finck if (new_node->cyfmt.Grouping > 9)
277c2c66affSColin Finck {
278c2c66affSColin Finck WARN("LOCALE_SMONGROUPING (%d) unhandled, please report!\n",
279c2c66affSColin Finck new_node->cyfmt.Grouping);
280c2c66affSColin Finck new_node->cyfmt.Grouping = 0;
281c2c66affSColin Finck }
282c2c66affSColin Finck
283c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->cyfmt.NegativeOrder, LOCALE_INEGCURR);
284c2c66affSColin Finck if (new_node->cyfmt.NegativeOrder > 15)
285c2c66affSColin Finck {
286c2c66affSColin Finck WARN("LOCALE_INEGCURR (%d) unhandled, please report!\n",
287c2c66affSColin Finck new_node->cyfmt.NegativeOrder);
288c2c66affSColin Finck new_node->cyfmt.NegativeOrder = 0;
289c2c66affSColin Finck }
290c2c66affSColin Finck GET_LOCALE_NUMBER(new_node->cyfmt.PositiveOrder, LOCALE_ICURRENCY);
291c2c66affSColin Finck if (new_node->cyfmt.PositiveOrder > 3)
292c2c66affSColin Finck {
293c2c66affSColin Finck WARN("LOCALE_IPOSCURR (%d) unhandled,please report!\n",
294c2c66affSColin Finck new_node->cyfmt.PositiveOrder);
295c2c66affSColin Finck new_node->cyfmt.PositiveOrder = 0;
296c2c66affSColin Finck }
297c2c66affSColin Finck GET_LOCALE_STRING(new_node->cyfmt.lpDecimalSep, LOCALE_SMONDECIMALSEP);
298c2c66affSColin Finck GET_LOCALE_STRING(new_node->cyfmt.lpThousandSep, LOCALE_SMONTHOUSANDSEP);
299c2c66affSColin Finck GET_LOCALE_STRING(new_node->cyfmt.lpCurrencySymbol, LOCALE_SCURRENCY);
300c2c66affSColin Finck
301c2c66affSColin Finck /* Date/Time Format info, negative character, etc */
302655d24d9SDenis Malikov for (i = 0; i < ARRAY_SIZE(NLS_LocaleIndices); i++)
303c2c66affSColin Finck {
304c2c66affSColin Finck GET_LOCALE_STRING(new_node->lppszStrings[i], NLS_LocaleIndices[i]);
305c2c66affSColin Finck }
306c2c66affSColin Finck /* Save some memory if month genitive name is the same or not present */
307c2c66affSColin Finck for (i = 0; i < 12; i++)
308c2c66affSColin Finck {
309c2c66affSColin Finck if (strcmpW(GetLongMonth(new_node, i), GetGenitiveMonth(new_node, i)) == 0)
310c2c66affSColin Finck {
311c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, GetGenitiveMonth(new_node, i));
312c2c66affSColin Finck GetGenitiveMonth(new_node, i) = NULL;
313c2c66affSColin Finck }
314c2c66affSColin Finck }
315c2c66affSColin Finck
316c2c66affSColin Finck new_node->szShortAM[0] = GetAM(new_node)[0]; new_node->szShortAM[1] = '\0';
317c2c66affSColin Finck new_node->szShortPM[0] = GetPM(new_node)[0]; new_node->szShortPM[1] = '\0';
318c2c66affSColin Finck
319c2c66affSColin Finck /* Now add the computed format to the cache */
320c2c66affSColin Finck RtlEnterCriticalSection(&NLS_FormatsCS);
321c2c66affSColin Finck
322c2c66affSColin Finck /* Search again: We may have raced to add the node */
323c2c66affSColin Finck node = NLS_CachedFormats;
324c2c66affSColin Finck while (node && (node->lcid != lcid || node->dwFlags != dwFlags) && node->next)
325c2c66affSColin Finck node = node->next;
326c2c66affSColin Finck
327c2c66affSColin Finck if (!node)
328c2c66affSColin Finck {
329c2c66affSColin Finck node = NLS_CachedFormats = new_node; /* Empty list */
330c2c66affSColin Finck new_node = NULL;
331c2c66affSColin Finck }
332c2c66affSColin Finck else if (node->lcid != lcid || node->dwFlags != dwFlags)
333c2c66affSColin Finck {
334c2c66affSColin Finck node->next = new_node; /* Not in the list, add to end */
335c2c66affSColin Finck node = new_node;
336c2c66affSColin Finck new_node = NULL;
337c2c66affSColin Finck }
338c2c66affSColin Finck
339c2c66affSColin Finck RtlLeaveCriticalSection(&NLS_FormatsCS);
340c2c66affSColin Finck
341c2c66affSColin Finck if (new_node)
342c2c66affSColin Finck {
343c2c66affSColin Finck /* We raced and lost: The node was already added by another thread.
344c2c66affSColin Finck * node points to the currently cached node, so free new_node.
345c2c66affSColin Finck */
346655d24d9SDenis Malikov for (i = 0; i < ARRAY_SIZE(NLS_LocaleIndices); i++)
347c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->lppszStrings[i]);
348c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->fmt.lpDecimalSep);
349c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->fmt.lpThousandSep);
350c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->cyfmt.lpDecimalSep);
351c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->cyfmt.lpThousandSep);
352c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node->cyfmt.lpCurrencySymbol);
353c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, new_node);
354c2c66affSColin Finck }
355c2c66affSColin Finck }
356c2c66affSColin Finck return node;
357c2c66affSColin Finck }
358c2c66affSColin Finck
359c2c66affSColin Finck /**************************************************************************
360c2c66affSColin Finck * NLS_IsUnicodeOnlyLcid <internal>
361c2c66affSColin Finck *
362c2c66affSColin Finck * Determine if a locale is Unicode only, and thus invalid in ASCII calls.
363c2c66affSColin Finck */
NLS_IsUnicodeOnlyLcid(LCID lcid)364c2c66affSColin Finck BOOL NLS_IsUnicodeOnlyLcid(LCID lcid)
365c2c66affSColin Finck {
366c2c66affSColin Finck lcid = ConvertDefaultLocale(lcid);
367c2c66affSColin Finck
368c2c66affSColin Finck switch (PRIMARYLANGID(lcid))
369c2c66affSColin Finck {
370c2c66affSColin Finck case LANG_ARMENIAN:
371c2c66affSColin Finck case LANG_DIVEHI:
372c2c66affSColin Finck case LANG_GEORGIAN:
373c2c66affSColin Finck case LANG_GUJARATI:
374c2c66affSColin Finck case LANG_HINDI:
375c2c66affSColin Finck case LANG_KANNADA:
376c2c66affSColin Finck case LANG_KONKANI:
377c2c66affSColin Finck case LANG_MARATHI:
378c2c66affSColin Finck case LANG_PUNJABI:
379c2c66affSColin Finck case LANG_SANSKRIT:
380c2c66affSColin Finck TRACE("lcid 0x%08x: langid 0x%4x is Unicode Only\n", lcid, PRIMARYLANGID(lcid));
381c2c66affSColin Finck return TRUE;
382c2c66affSColin Finck default:
383c2c66affSColin Finck return FALSE;
384c2c66affSColin Finck }
385c2c66affSColin Finck }
386c2c66affSColin Finck
387c2c66affSColin Finck /*
388c2c66affSColin Finck * Formatting of dates, times, numbers and currencies.
389c2c66affSColin Finck */
390c2c66affSColin Finck
391c2c66affSColin Finck #define IsLiteralMarker(p) (p == '\'')
392c2c66affSColin Finck #define IsDateFmtChar(p) (p == 'd'||p == 'M'||p == 'y'||p == 'g')
393c2c66affSColin Finck #define IsTimeFmtChar(p) (p == 'H'||p == 'h'||p == 'm'||p == 's'||p == 't')
394c2c66affSColin Finck
395c2c66affSColin Finck /* Only the following flags can be given if a date/time format is specified */
39615537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
39715537c3bSKatayama Hirofumi MZ #define DATE_FORMAT_FLAGS (DATE_DATEVARSONLY | DATE_USE_ALT_CALENDAR)
39815537c3bSKatayama Hirofumi MZ #else
399c2c66affSColin Finck #define DATE_FORMAT_FLAGS (DATE_DATEVARSONLY)
40015537c3bSKatayama Hirofumi MZ #endif
401c2c66affSColin Finck #define TIME_FORMAT_FLAGS (TIME_TIMEVARSONLY|TIME_FORCE24HOURFORMAT| \
402c2c66affSColin Finck TIME_NOMINUTESORSECONDS|TIME_NOSECONDS| \
403c2c66affSColin Finck TIME_NOTIMEMARKER)
404c2c66affSColin Finck
405c2c66affSColin Finck /******************************************************************************
406c2c66affSColin Finck * NLS_GetDateTimeFormatW <internal>
407c2c66affSColin Finck *
408c2c66affSColin Finck * Performs the formatting for GetDateFormatW/GetTimeFormatW.
409c2c66affSColin Finck *
410c2c66affSColin Finck * FIXME
411c2c66affSColin Finck * DATE_USE_ALT_CALENDAR - Requires GetCalendarInfo to work first.
412c2c66affSColin Finck * DATE_LTRREADING/DATE_RTLREADING - Not yet implemented.
413c2c66affSColin Finck */
NLS_GetDateTimeFormatW(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCWSTR lpFormat,LPWSTR lpStr,INT cchOut)414c2c66affSColin Finck static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags,
415c2c66affSColin Finck const SYSTEMTIME* lpTime, LPCWSTR lpFormat,
416c2c66affSColin Finck LPWSTR lpStr, INT cchOut)
417c2c66affSColin Finck {
418c2c66affSColin Finck const NLS_FORMAT_NODE *node;
419c2c66affSColin Finck SYSTEMTIME st;
420c2c66affSColin Finck INT cchWritten = 0;
421c2c66affSColin Finck INT lastFormatPos = 0;
422c2c66affSColin Finck BOOL bSkipping = FALSE; /* Skipping text around marker? */
423c2c66affSColin Finck BOOL d_dd_formatted = FALSE; /* previous formatted part was for d or dd */
424c2c66affSColin Finck
425c2c66affSColin Finck /* Verify our arguments */
426c2c66affSColin Finck if ((cchOut && !lpStr) || !(node = NLS_GetFormats(lcid, dwFlags)))
427c2c66affSColin Finck goto invalid_parameter;
428c2c66affSColin Finck
429c2c66affSColin Finck if (dwFlags & ~(DATE_DATEVARSONLY|TIME_TIMEVARSONLY))
430c2c66affSColin Finck {
431c2c66affSColin Finck if (lpFormat &&
432c2c66affSColin Finck ((dwFlags & DATE_DATEVARSONLY && dwFlags & ~DATE_FORMAT_FLAGS) ||
433c2c66affSColin Finck (dwFlags & TIME_TIMEVARSONLY && dwFlags & ~TIME_FORMAT_FLAGS)))
434c2c66affSColin Finck {
435c2c66affSColin Finck goto invalid_flags;
436c2c66affSColin Finck }
437c2c66affSColin Finck
438c2c66affSColin Finck if (dwFlags & DATE_DATEVARSONLY)
439c2c66affSColin Finck {
440c2c66affSColin Finck if ((dwFlags & (DATE_LTRREADING|DATE_RTLREADING)) == (DATE_LTRREADING|DATE_RTLREADING))
441c2c66affSColin Finck goto invalid_flags;
442c2c66affSColin Finck else if (dwFlags & (DATE_LTRREADING|DATE_RTLREADING))
443c2c66affSColin Finck FIXME("Unsupported flags: DATE_LTRREADING/DATE_RTLREADING\n");
444c2c66affSColin Finck
445c2c66affSColin Finck switch (dwFlags & (DATE_SHORTDATE|DATE_LONGDATE|DATE_YEARMONTH))
446c2c66affSColin Finck {
447c2c66affSColin Finck case 0:
448c2c66affSColin Finck break;
449c2c66affSColin Finck case DATE_SHORTDATE:
450c2c66affSColin Finck case DATE_LONGDATE:
451c2c66affSColin Finck case DATE_YEARMONTH:
452c2c66affSColin Finck if (lpFormat)
453c2c66affSColin Finck goto invalid_flags;
454c2c66affSColin Finck break;
455c2c66affSColin Finck default:
456c2c66affSColin Finck goto invalid_flags;
457c2c66affSColin Finck }
458c2c66affSColin Finck }
459c2c66affSColin Finck }
460c2c66affSColin Finck
461c2c66affSColin Finck if (!lpFormat)
462c2c66affSColin Finck {
463c2c66affSColin Finck /* Use the appropriate default format */
464c2c66affSColin Finck if (dwFlags & DATE_DATEVARSONLY)
465c2c66affSColin Finck {
466c2c66affSColin Finck if (dwFlags & DATE_YEARMONTH)
467c2c66affSColin Finck lpFormat = GetYearMonth(node);
468c2c66affSColin Finck else if (dwFlags & DATE_LONGDATE)
469c2c66affSColin Finck lpFormat = GetLongDate(node);
470c2c66affSColin Finck else
471c2c66affSColin Finck lpFormat = GetShortDate(node);
472c2c66affSColin Finck }
473c2c66affSColin Finck else
474c2c66affSColin Finck lpFormat = GetTime(node);
475c2c66affSColin Finck }
476c2c66affSColin Finck
477c2c66affSColin Finck if (!lpTime)
478c2c66affSColin Finck {
479c2c66affSColin Finck GetLocalTime(&st); /* Default to current time */
480c2c66affSColin Finck lpTime = &st;
481c2c66affSColin Finck }
482c2c66affSColin Finck else
483c2c66affSColin Finck {
484c2c66affSColin Finck if (dwFlags & DATE_DATEVARSONLY)
485c2c66affSColin Finck {
486c2c66affSColin Finck FILETIME ftTmp;
487c2c66affSColin Finck
488c2c66affSColin Finck /* Verify the date and correct the D.O.W. if needed */
489c2c66affSColin Finck memset(&st, 0, sizeof(st));
490c2c66affSColin Finck st.wYear = lpTime->wYear;
491c2c66affSColin Finck st.wMonth = lpTime->wMonth;
492c2c66affSColin Finck st.wDay = lpTime->wDay;
493c2c66affSColin Finck
494c2c66affSColin Finck if (st.wDay > 31 || st.wMonth > 12 || !SystemTimeToFileTime(&st, &ftTmp))
495c2c66affSColin Finck goto invalid_parameter;
496c2c66affSColin Finck
497c2c66affSColin Finck FileTimeToSystemTime(&ftTmp, &st);
498c2c66affSColin Finck lpTime = &st;
499c2c66affSColin Finck }
500c2c66affSColin Finck
501c2c66affSColin Finck if (dwFlags & TIME_TIMEVARSONLY)
502c2c66affSColin Finck {
503c2c66affSColin Finck /* Verify the time */
504c2c66affSColin Finck if (lpTime->wHour > 24 || lpTime->wMinute > 59 || lpTime->wSecond > 59)
505c2c66affSColin Finck goto invalid_parameter;
506c2c66affSColin Finck }
507c2c66affSColin Finck }
508c2c66affSColin Finck
509c2c66affSColin Finck /* Format the output */
510c2c66affSColin Finck while (*lpFormat)
511c2c66affSColin Finck {
512c2c66affSColin Finck if (IsLiteralMarker(*lpFormat))
513c2c66affSColin Finck {
514c2c66affSColin Finck /* Start of a literal string */
515c2c66affSColin Finck lpFormat++;
516c2c66affSColin Finck
517c2c66affSColin Finck /* Loop until the end of the literal marker or end of the string */
518c2c66affSColin Finck while (*lpFormat)
519c2c66affSColin Finck {
520c2c66affSColin Finck if (IsLiteralMarker(*lpFormat))
521c2c66affSColin Finck {
522c2c66affSColin Finck lpFormat++;
523c2c66affSColin Finck if (!IsLiteralMarker(*lpFormat))
524c2c66affSColin Finck break; /* Terminating literal marker */
525c2c66affSColin Finck }
526c2c66affSColin Finck
527c2c66affSColin Finck if (!cchOut)
528c2c66affSColin Finck cchWritten++; /* Count size only */
529c2c66affSColin Finck else if (cchWritten >= cchOut)
530c2c66affSColin Finck goto overrun;
531c2c66affSColin Finck else if (!bSkipping)
532c2c66affSColin Finck {
533c2c66affSColin Finck lpStr[cchWritten] = *lpFormat;
534c2c66affSColin Finck cchWritten++;
535c2c66affSColin Finck }
536c2c66affSColin Finck lpFormat++;
537c2c66affSColin Finck }
538c2c66affSColin Finck }
539c2c66affSColin Finck else if ((dwFlags & DATE_DATEVARSONLY && IsDateFmtChar(*lpFormat)) ||
540c2c66affSColin Finck (dwFlags & TIME_TIMEVARSONLY && IsTimeFmtChar(*lpFormat)))
541c2c66affSColin Finck {
542c2c66affSColin Finck WCHAR buff[32], fmtChar;
543c2c66affSColin Finck LPCWSTR szAdd = NULL;
544c2c66affSColin Finck DWORD dwVal = 0;
545c2c66affSColin Finck int count = 0, dwLen;
546c2c66affSColin Finck
547c2c66affSColin Finck bSkipping = FALSE;
548c2c66affSColin Finck
549c2c66affSColin Finck fmtChar = *lpFormat;
550c2c66affSColin Finck while (*lpFormat == fmtChar)
551c2c66affSColin Finck {
552c2c66affSColin Finck count++;
553c2c66affSColin Finck lpFormat++;
554c2c66affSColin Finck }
555c2c66affSColin Finck buff[0] = '\0';
556c2c66affSColin Finck
557c2c66affSColin Finck if (fmtChar != 'M') d_dd_formatted = FALSE;
558c2c66affSColin Finck switch(fmtChar)
559c2c66affSColin Finck {
560c2c66affSColin Finck case 'd':
561c2c66affSColin Finck if (count >= 4)
562c2c66affSColin Finck szAdd = GetLongDay(node, (lpTime->wDayOfWeek + 6) % 7);
563c2c66affSColin Finck else if (count == 3)
564c2c66affSColin Finck szAdd = GetShortDay(node, (lpTime->wDayOfWeek + 6) % 7);
565c2c66affSColin Finck else
566c2c66affSColin Finck {
567c2c66affSColin Finck dwVal = lpTime->wDay;
568c2c66affSColin Finck szAdd = buff;
569c2c66affSColin Finck d_dd_formatted = TRUE;
570c2c66affSColin Finck }
571c2c66affSColin Finck break;
572c2c66affSColin Finck
573c2c66affSColin Finck case 'M':
574c2c66affSColin Finck if (count >= 4)
575c2c66affSColin Finck {
576c2c66affSColin Finck LPCWSTR genitive = GetGenitiveMonth(node, lpTime->wMonth - 1);
577c2c66affSColin Finck if (genitive)
578c2c66affSColin Finck {
579c2c66affSColin Finck if (d_dd_formatted)
580c2c66affSColin Finck {
581c2c66affSColin Finck szAdd = genitive;
582c2c66affSColin Finck break;
583c2c66affSColin Finck }
584c2c66affSColin Finck else
585c2c66affSColin Finck {
586c2c66affSColin Finck LPCWSTR format = lpFormat;
587c2c66affSColin Finck /* Look forward now, if next format pattern is for day genitive
588c2c66affSColin Finck name should be used */
589c2c66affSColin Finck while (*format)
590c2c66affSColin Finck {
591c2c66affSColin Finck /* Skip parts within markers */
592c2c66affSColin Finck if (IsLiteralMarker(*format))
593c2c66affSColin Finck {
594c2c66affSColin Finck ++format;
595c2c66affSColin Finck while (*format)
596c2c66affSColin Finck {
597c2c66affSColin Finck if (IsLiteralMarker(*format))
598c2c66affSColin Finck {
599c2c66affSColin Finck ++format;
600c2c66affSColin Finck if (!IsLiteralMarker(*format)) break;
601c2c66affSColin Finck }
602c2c66affSColin Finck }
603c2c66affSColin Finck }
604c2c66affSColin Finck if (*format != ' ') break;
605c2c66affSColin Finck ++format;
606c2c66affSColin Finck }
607c2c66affSColin Finck /* Only numeric day form matters */
608cf14b6b2SAmine Khaldi if (*format == 'd')
609c2c66affSColin Finck {
610c2c66affSColin Finck INT dcount = 1;
611c2c66affSColin Finck while (*++format == 'd') dcount++;
612c2c66affSColin Finck if (dcount < 3)
613c2c66affSColin Finck {
614c2c66affSColin Finck szAdd = genitive;
615c2c66affSColin Finck break;
616c2c66affSColin Finck }
617c2c66affSColin Finck }
618c2c66affSColin Finck }
619c2c66affSColin Finck }
620c2c66affSColin Finck szAdd = GetLongMonth(node, lpTime->wMonth - 1);
621c2c66affSColin Finck }
622c2c66affSColin Finck else if (count == 3)
623c2c66affSColin Finck szAdd = GetShortMonth(node, lpTime->wMonth - 1);
624c2c66affSColin Finck else
625c2c66affSColin Finck {
626c2c66affSColin Finck dwVal = lpTime->wMonth;
627c2c66affSColin Finck szAdd = buff;
628c2c66affSColin Finck }
629c2c66affSColin Finck break;
630c2c66affSColin Finck
631c2c66affSColin Finck case 'y':
63215537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
63315537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(lcid) && (dwFlags & DATE_USE_ALT_CALENDAR))
63415537c3bSKatayama Hirofumi MZ {
63515537c3bSKatayama Hirofumi MZ PCJAPANESE_ERA pEra = JapaneseEra_Find(lpTime);
63615537c3bSKatayama Hirofumi MZ if (pEra)
63715537c3bSKatayama Hirofumi MZ {
63815537c3bSKatayama Hirofumi MZ if (count >= 2)
63915537c3bSKatayama Hirofumi MZ {
64015537c3bSKatayama Hirofumi MZ count = 2;
64115537c3bSKatayama Hirofumi MZ }
6427e382678SKatayama Hirofumi MZ
64315537c3bSKatayama Hirofumi MZ dwVal = lpTime->wYear - pEra->wYear + 1;
6447e382678SKatayama Hirofumi MZ
6457e382678SKatayama Hirofumi MZ if (dwVal == 1 && JapaneseEra_IsFirstYearGannen())
6467e382678SKatayama Hirofumi MZ {
6477e382678SKatayama Hirofumi MZ // Gan of 'Gannen'
6487e382678SKatayama Hirofumi MZ buff[0] = 0x5143;
6497e382678SKatayama Hirofumi MZ buff[1] = 0;
6507e382678SKatayama Hirofumi MZ }
65115537c3bSKatayama Hirofumi MZ szAdd = buff;
65215537c3bSKatayama Hirofumi MZ break;
65315537c3bSKatayama Hirofumi MZ }
65415537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
65515537c3bSKatayama Hirofumi MZ return 0;
65615537c3bSKatayama Hirofumi MZ }
65715537c3bSKatayama Hirofumi MZ #endif
658c2c66affSColin Finck if (count >= 4)
659c2c66affSColin Finck {
660c2c66affSColin Finck count = 4;
661c2c66affSColin Finck dwVal = lpTime->wYear;
662c2c66affSColin Finck }
663c2c66affSColin Finck else
664c2c66affSColin Finck {
665c2c66affSColin Finck count = count > 2 ? 2 : count;
666c2c66affSColin Finck dwVal = lpTime->wYear % 100;
667c2c66affSColin Finck }
668c2c66affSColin Finck szAdd = buff;
669c2c66affSColin Finck break;
670c2c66affSColin Finck
671c2c66affSColin Finck case 'g':
67215537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
67315537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(lcid))
67415537c3bSKatayama Hirofumi MZ {
67515537c3bSKatayama Hirofumi MZ if (dwFlags & DATE_USE_ALT_CALENDAR)
67615537c3bSKatayama Hirofumi MZ {
67715537c3bSKatayama Hirofumi MZ PCJAPANESE_ERA pEra = JapaneseEra_Find(lpTime);
67815537c3bSKatayama Hirofumi MZ if (pEra)
67915537c3bSKatayama Hirofumi MZ {
68015537c3bSKatayama Hirofumi MZ RtlStringCbCopyW(buff, sizeof(buff), pEra->szEraName);
68115537c3bSKatayama Hirofumi MZ szAdd = buff;
68215537c3bSKatayama Hirofumi MZ break;
68315537c3bSKatayama Hirofumi MZ }
68415537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
68515537c3bSKatayama Hirofumi MZ return 0;
68615537c3bSKatayama Hirofumi MZ }
68715537c3bSKatayama Hirofumi MZ else
68815537c3bSKatayama Hirofumi MZ {
68915537c3bSKatayama Hirofumi MZ /* Seireki */
69015537c3bSKatayama Hirofumi MZ buff[0] = 0x897F;
69115537c3bSKatayama Hirofumi MZ buff[1] = 0x66A6;
69215537c3bSKatayama Hirofumi MZ buff[2] = 0;
69315537c3bSKatayama Hirofumi MZ szAdd = buff;
69415537c3bSKatayama Hirofumi MZ break;
69515537c3bSKatayama Hirofumi MZ }
69615537c3bSKatayama Hirofumi MZ }
69715537c3bSKatayama Hirofumi MZ #endif
698c2c66affSColin Finck if (count == 2)
699c2c66affSColin Finck {
700c2c66affSColin Finck /* FIXME: Our GetCalendarInfo() does not yet support CAL_SERASTRING.
701c2c66affSColin Finck * When it is fixed, this string should be cached in 'node'.
702c2c66affSColin Finck */
703c2c66affSColin Finck FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
704c2c66affSColin Finck buff[0] = 'A'; buff[1] = 'D'; buff[2] = '\0';
705c2c66affSColin Finck }
706c2c66affSColin Finck else
707c2c66affSColin Finck {
708c2c66affSColin Finck buff[0] = 'g'; buff[1] = '\0'; /* Add a literal 'g' */
709c2c66affSColin Finck }
710c2c66affSColin Finck szAdd = buff;
711c2c66affSColin Finck break;
712c2c66affSColin Finck
713c2c66affSColin Finck case 'h':
714c2c66affSColin Finck if (!(dwFlags & TIME_FORCE24HOURFORMAT))
715c2c66affSColin Finck {
716c2c66affSColin Finck count = count > 2 ? 2 : count;
717c2c66affSColin Finck dwVal = lpTime->wHour == 0 ? 12 : (lpTime->wHour - 1) % 12 + 1;
718c2c66affSColin Finck szAdd = buff;
719c2c66affSColin Finck break;
720c2c66affSColin Finck }
721c2c66affSColin Finck /* .. fall through if we are forced to output in 24 hour format */
722c2c66affSColin Finck
723c2c66affSColin Finck case 'H':
724c2c66affSColin Finck count = count > 2 ? 2 : count;
725c2c66affSColin Finck dwVal = lpTime->wHour;
726c2c66affSColin Finck szAdd = buff;
727c2c66affSColin Finck break;
728c2c66affSColin Finck
729c2c66affSColin Finck case 'm':
730c2c66affSColin Finck if (dwFlags & TIME_NOMINUTESORSECONDS)
731c2c66affSColin Finck {
732c2c66affSColin Finck cchWritten = lastFormatPos; /* Skip */
733c2c66affSColin Finck bSkipping = TRUE;
734c2c66affSColin Finck }
735c2c66affSColin Finck else
736c2c66affSColin Finck {
737c2c66affSColin Finck count = count > 2 ? 2 : count;
738c2c66affSColin Finck dwVal = lpTime->wMinute;
739c2c66affSColin Finck szAdd = buff;
740c2c66affSColin Finck }
741c2c66affSColin Finck break;
742c2c66affSColin Finck
743c2c66affSColin Finck case 's':
744c2c66affSColin Finck if (dwFlags & (TIME_NOSECONDS|TIME_NOMINUTESORSECONDS))
745c2c66affSColin Finck {
746c2c66affSColin Finck cchWritten = lastFormatPos; /* Skip */
747c2c66affSColin Finck bSkipping = TRUE;
748c2c66affSColin Finck }
749c2c66affSColin Finck else
750c2c66affSColin Finck {
751c2c66affSColin Finck count = count > 2 ? 2 : count;
752c2c66affSColin Finck dwVal = lpTime->wSecond;
753c2c66affSColin Finck szAdd = buff;
754c2c66affSColin Finck }
755c2c66affSColin Finck break;
756c2c66affSColin Finck
757c2c66affSColin Finck case 't':
758c2c66affSColin Finck if (dwFlags & TIME_NOTIMEMARKER)
759c2c66affSColin Finck {
760c2c66affSColin Finck cchWritten = lastFormatPos; /* Skip */
761c2c66affSColin Finck bSkipping = TRUE;
762c2c66affSColin Finck }
763c2c66affSColin Finck else
764c2c66affSColin Finck {
765c2c66affSColin Finck if (count == 1)
766c2c66affSColin Finck szAdd = lpTime->wHour < 12 ? node->szShortAM : node->szShortPM;
767c2c66affSColin Finck else
768c2c66affSColin Finck szAdd = lpTime->wHour < 12 ? GetAM(node) : GetPM(node);
769c2c66affSColin Finck }
770c2c66affSColin Finck break;
771c2c66affSColin Finck }
772c2c66affSColin Finck
773c2c66affSColin Finck if (szAdd == buff && buff[0] == '\0')
774c2c66affSColin Finck {
775c2c66affSColin Finck static const WCHAR fmtW[] = {'%','.','*','d',0};
776c2c66affSColin Finck /* We have a numeric value to add */
777655d24d9SDenis Malikov snprintfW(buff, ARRAY_SIZE(buff), fmtW, count, dwVal);
778c2c66affSColin Finck }
779c2c66affSColin Finck
780c2c66affSColin Finck dwLen = szAdd ? strlenW(szAdd) : 0;
781c2c66affSColin Finck
782c2c66affSColin Finck if (cchOut && dwLen)
783c2c66affSColin Finck {
784c2c66affSColin Finck if (cchWritten + dwLen < cchOut)
785c2c66affSColin Finck memcpy(lpStr + cchWritten, szAdd, dwLen * sizeof(WCHAR));
786c2c66affSColin Finck else
787c2c66affSColin Finck {
788c2c66affSColin Finck memcpy(lpStr + cchWritten, szAdd, (cchOut - cchWritten) * sizeof(WCHAR));
789c2c66affSColin Finck goto overrun;
790c2c66affSColin Finck }
791c2c66affSColin Finck }
792c2c66affSColin Finck cchWritten += dwLen;
793c2c66affSColin Finck lastFormatPos = cchWritten; /* Save position of last output format text */
794c2c66affSColin Finck }
795c2c66affSColin Finck else
796c2c66affSColin Finck {
797c2c66affSColin Finck /* Literal character */
798c2c66affSColin Finck if (!cchOut)
799c2c66affSColin Finck cchWritten++; /* Count size only */
800c2c66affSColin Finck else if (cchWritten >= cchOut)
801c2c66affSColin Finck goto overrun;
802c2c66affSColin Finck else if (!bSkipping || *lpFormat == ' ')
803c2c66affSColin Finck {
804c2c66affSColin Finck lpStr[cchWritten] = *lpFormat;
805c2c66affSColin Finck cchWritten++;
806c2c66affSColin Finck }
807c2c66affSColin Finck lpFormat++;
808c2c66affSColin Finck }
809c2c66affSColin Finck }
810c2c66affSColin Finck
811c2c66affSColin Finck /* Final string terminator and sanity check */
812c2c66affSColin Finck if (cchOut)
813c2c66affSColin Finck {
814c2c66affSColin Finck if (cchWritten >= cchOut)
815c2c66affSColin Finck goto overrun;
816c2c66affSColin Finck else
817c2c66affSColin Finck lpStr[cchWritten] = '\0';
818c2c66affSColin Finck }
819c2c66affSColin Finck cchWritten++; /* Include terminating NUL */
820c2c66affSColin Finck
821c2c66affSColin Finck TRACE("returning length=%d, output=%s\n", cchWritten, debugstr_w(lpStr));
822c2c66affSColin Finck return cchWritten;
823c2c66affSColin Finck
824c2c66affSColin Finck overrun:
825c2c66affSColin Finck TRACE("returning 0, (ERROR_INSUFFICIENT_BUFFER)\n");
826c2c66affSColin Finck SetLastError(ERROR_INSUFFICIENT_BUFFER);
827c2c66affSColin Finck return 0;
828c2c66affSColin Finck
829c2c66affSColin Finck invalid_parameter:
830c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
831c2c66affSColin Finck return 0;
832c2c66affSColin Finck
833c2c66affSColin Finck invalid_flags:
834c2c66affSColin Finck SetLastError(ERROR_INVALID_FLAGS);
835c2c66affSColin Finck return 0;
836c2c66affSColin Finck }
837c2c66affSColin Finck
838c2c66affSColin Finck /******************************************************************************
839c2c66affSColin Finck * NLS_GetDateTimeFormatA <internal>
840c2c66affSColin Finck *
841c2c66affSColin Finck * ASCII wrapper for GetDateFormatA/GetTimeFormatA.
842c2c66affSColin Finck */
NLS_GetDateTimeFormatA(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCSTR lpFormat,LPSTR lpStr,INT cchOut)843c2c66affSColin Finck static INT NLS_GetDateTimeFormatA(LCID lcid, DWORD dwFlags,
844c2c66affSColin Finck const SYSTEMTIME* lpTime,
845c2c66affSColin Finck LPCSTR lpFormat, LPSTR lpStr, INT cchOut)
846c2c66affSColin Finck {
847c2c66affSColin Finck DWORD cp = CP_ACP;
848c2c66affSColin Finck WCHAR szFormat[128], szOut[128];
849c2c66affSColin Finck INT iRet;
850c2c66affSColin Finck
851c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n", lcid, dwFlags, lpTime,
852c2c66affSColin Finck debugstr_a(lpFormat), lpStr, cchOut);
853c2c66affSColin Finck
854c2c66affSColin Finck if (NLS_IsUnicodeOnlyLcid(lcid))
855c2c66affSColin Finck {
856c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
857c2c66affSColin Finck return 0;
858c2c66affSColin Finck }
859c2c66affSColin Finck
860c2c66affSColin Finck if (!(dwFlags & LOCALE_USE_CP_ACP))
861c2c66affSColin Finck {
862c2c66affSColin Finck const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
863c2c66affSColin Finck if (!node)
864c2c66affSColin Finck {
865c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
866c2c66affSColin Finck return 0;
867c2c66affSColin Finck }
868c2c66affSColin Finck
869c2c66affSColin Finck cp = node->dwCodePage;
870c2c66affSColin Finck }
871c2c66affSColin Finck
872c2c66affSColin Finck if (lpFormat)
873655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat, -1, szFormat, ARRAY_SIZE(szFormat));
874c2c66affSColin Finck
875655d24d9SDenis Malikov if (cchOut > (int) ARRAY_SIZE(szOut))
876655d24d9SDenis Malikov cchOut = ARRAY_SIZE(szOut);
877c2c66affSColin Finck
878c2c66affSColin Finck szOut[0] = '\0';
879c2c66affSColin Finck
880c2c66affSColin Finck iRet = NLS_GetDateTimeFormatW(lcid, dwFlags, lpTime, lpFormat ? szFormat : NULL,
881c2c66affSColin Finck lpStr ? szOut : NULL, cchOut);
882c2c66affSColin Finck
883c2c66affSColin Finck if (lpStr)
884c2c66affSColin Finck {
885c2c66affSColin Finck if (szOut[0])
886c2c66affSColin Finck WideCharToMultiByte(cp, 0, szOut, iRet ? -1 : cchOut, lpStr, cchOut, 0, 0);
887c2c66affSColin Finck else if (cchOut && iRet)
888c2c66affSColin Finck *lpStr = '\0';
889c2c66affSColin Finck }
890c2c66affSColin Finck return iRet;
891c2c66affSColin Finck }
892c2c66affSColin Finck
893c2c66affSColin Finck /******************************************************************************
894c2c66affSColin Finck * GetDateFormatA [KERNEL32.@]
895c2c66affSColin Finck *
896c2c66affSColin Finck * Format a date for a given locale.
897c2c66affSColin Finck *
898c2c66affSColin Finck * PARAMS
899c2c66affSColin Finck * lcid [I] Locale to format for
900c2c66affSColin Finck * dwFlags [I] LOCALE_ and DATE_ flags from "winnls.h"
901c2c66affSColin Finck * lpTime [I] Date to format
902c2c66affSColin Finck * lpFormat [I] Format string, or NULL to use the system defaults
903c2c66affSColin Finck * lpDateStr [O] Destination for formatted string
904c2c66affSColin Finck * cchOut [I] Size of lpDateStr, or 0 to calculate the resulting size
905c2c66affSColin Finck *
906c2c66affSColin Finck * NOTES
907c2c66affSColin Finck * - If lpFormat is NULL, lpDateStr will be formatted according to the format
908c2c66affSColin Finck * details returned by GetLocaleInfoA() and modified by dwFlags.
909c2c66affSColin Finck * - lpFormat is a string of characters and formatting tokens. Any characters
910c2c66affSColin Finck * in the string are copied verbatim to lpDateStr, with tokens being replaced
911c2c66affSColin Finck * by the date values they represent.
912c2c66affSColin Finck * - The following tokens have special meanings in a date format string:
913c2c66affSColin Finck *| Token Meaning
914c2c66affSColin Finck *| ----- -------
915c2c66affSColin Finck *| d Single digit day of the month (no leading 0)
916c2c66affSColin Finck *| dd Double digit day of the month
917c2c66affSColin Finck *| ddd Short name for the day of the week
918c2c66affSColin Finck *| dddd Long name for the day of the week
919c2c66affSColin Finck *| M Single digit month of the year (no leading 0)
920c2c66affSColin Finck *| MM Double digit month of the year
921c2c66affSColin Finck *| MMM Short name for the month of the year
922c2c66affSColin Finck *| MMMM Long name for the month of the year
923c2c66affSColin Finck *| y Double digit year number (no leading 0)
924c2c66affSColin Finck *| yy Double digit year number
925c2c66affSColin Finck *| yyyy Four digit year number
926c2c66affSColin Finck *| gg Era string, for example 'AD'.
927c2c66affSColin Finck * - To output any literal character that could be misidentified as a token,
928c2c66affSColin Finck * enclose it in single quotes.
929c2c66affSColin Finck * - The Ascii version of this function fails if lcid is Unicode only.
930c2c66affSColin Finck *
931c2c66affSColin Finck * RETURNS
932c2c66affSColin Finck * Success: The number of character written to lpDateStr, or that would
933c2c66affSColin Finck * have been written, if cchOut is 0.
934c2c66affSColin Finck * Failure: 0. Use GetLastError() to determine the cause.
935c2c66affSColin Finck */
GetDateFormatA(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCSTR lpFormat,LPSTR lpDateStr,INT cchOut)936c2c66affSColin Finck INT WINAPI GetDateFormatA( LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
937c2c66affSColin Finck LPCSTR lpFormat, LPSTR lpDateStr, INT cchOut)
938c2c66affSColin Finck {
939c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n",lcid, dwFlags, lpTime,
940c2c66affSColin Finck debugstr_a(lpFormat), lpDateStr, cchOut);
941c2c66affSColin Finck
942c2c66affSColin Finck return NLS_GetDateTimeFormatA(lcid, dwFlags | DATE_DATEVARSONLY, lpTime,
943c2c66affSColin Finck lpFormat, lpDateStr, cchOut);
944c2c66affSColin Finck }
945c2c66affSColin Finck
946655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
947cf14b6b2SAmine Khaldi /******************************************************************************
948cf14b6b2SAmine Khaldi * GetDateFormatEx [KERNEL32.@]
949cf14b6b2SAmine Khaldi *
950cf14b6b2SAmine Khaldi * Format a date for a given locale.
951cf14b6b2SAmine Khaldi *
952cf14b6b2SAmine Khaldi * PARAMS
953cf14b6b2SAmine Khaldi * localename [I] Locale to format for
954cf14b6b2SAmine Khaldi * flags [I] LOCALE_ and DATE_ flags from "winnls.h"
955cf14b6b2SAmine Khaldi * date [I] Date to format
956cf14b6b2SAmine Khaldi * format [I] Format string, or NULL to use the locale defaults
957cf14b6b2SAmine Khaldi * outbuf [O] Destination for formatted string
958cf14b6b2SAmine Khaldi * bufsize [I] Size of outbuf, or 0 to calculate the resulting size
959cf14b6b2SAmine Khaldi * calendar [I] Reserved, must be NULL
960cf14b6b2SAmine Khaldi *
961cf14b6b2SAmine Khaldi * See GetDateFormatA for notes.
962cf14b6b2SAmine Khaldi *
963cf14b6b2SAmine Khaldi * RETURNS
964cf14b6b2SAmine Khaldi * Success: The number of characters written to outbuf, or that would have
965cf14b6b2SAmine Khaldi * been written if bufsize is 0.
966cf14b6b2SAmine Khaldi * Failure: 0. Use GetLastError() to determine the cause.
967cf14b6b2SAmine Khaldi */
GetDateFormatEx(LPCWSTR localename,DWORD flags,const SYSTEMTIME * date,LPCWSTR format,LPWSTR outbuf,INT bufsize,LPCWSTR calendar)968cf14b6b2SAmine Khaldi INT WINAPI GetDateFormatEx(LPCWSTR localename, DWORD flags,
969cf14b6b2SAmine Khaldi const SYSTEMTIME* date, LPCWSTR format,
970cf14b6b2SAmine Khaldi LPWSTR outbuf, INT bufsize, LPCWSTR calendar)
971cf14b6b2SAmine Khaldi {
972cf14b6b2SAmine Khaldi TRACE("(%s,0x%08x,%p,%s,%p,%d,%s)\n", debugstr_w(localename), flags,
973cf14b6b2SAmine Khaldi date, debugstr_w(format), outbuf, bufsize, debugstr_w(calendar));
974cf14b6b2SAmine Khaldi
975cf14b6b2SAmine Khaldi /* Parameter is currently reserved and Windows errors if set */
976cf14b6b2SAmine Khaldi if (calendar != NULL)
977cf14b6b2SAmine Khaldi {
978cf14b6b2SAmine Khaldi SetLastError(ERROR_INVALID_PARAMETER);
979cf14b6b2SAmine Khaldi return 0;
980cf14b6b2SAmine Khaldi }
981cf14b6b2SAmine Khaldi
982cf14b6b2SAmine Khaldi return NLS_GetDateTimeFormatW(LocaleNameToLCID(localename, 0),
983cf14b6b2SAmine Khaldi flags | DATE_DATEVARSONLY, date, format,
984cf14b6b2SAmine Khaldi outbuf, bufsize);
985cf14b6b2SAmine Khaldi }
986655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
987c2c66affSColin Finck
988c2c66affSColin Finck /******************************************************************************
989c2c66affSColin Finck * GetDateFormatW [KERNEL32.@]
990c2c66affSColin Finck *
991c2c66affSColin Finck * See GetDateFormatA.
992c2c66affSColin Finck */
GetDateFormatW(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCWSTR lpFormat,LPWSTR lpDateStr,INT cchOut)993c2c66affSColin Finck INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
994c2c66affSColin Finck LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
995c2c66affSColin Finck {
996c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n", lcid, dwFlags, lpTime,
997c2c66affSColin Finck debugstr_w(lpFormat), lpDateStr, cchOut);
998c2c66affSColin Finck
999c2c66affSColin Finck return NLS_GetDateTimeFormatW(lcid, dwFlags|DATE_DATEVARSONLY, lpTime,
1000c2c66affSColin Finck lpFormat, lpDateStr, cchOut);
1001c2c66affSColin Finck }
1002c2c66affSColin Finck
1003c2c66affSColin Finck /******************************************************************************
1004c2c66affSColin Finck * GetTimeFormatA [KERNEL32.@]
1005c2c66affSColin Finck *
1006c2c66affSColin Finck * Format a time for a given locale.
1007c2c66affSColin Finck *
1008c2c66affSColin Finck * PARAMS
1009c2c66affSColin Finck * lcid [I] Locale to format for
1010c2c66affSColin Finck * dwFlags [I] LOCALE_ and TIME_ flags from "winnls.h"
1011c2c66affSColin Finck * lpTime [I] Time to format
1012c2c66affSColin Finck * lpFormat [I] Formatting overrides
1013c2c66affSColin Finck * lpTimeStr [O] Destination for formatted string
1014c2c66affSColin Finck * cchOut [I] Size of lpTimeStr, or 0 to calculate the resulting size
1015c2c66affSColin Finck *
1016c2c66affSColin Finck * NOTES
1017c2c66affSColin Finck * - If lpFormat is NULL, lpszValue will be formatted according to the format
1018c2c66affSColin Finck * details returned by GetLocaleInfoA() and modified by dwFlags.
1019c2c66affSColin Finck * - lpFormat is a string of characters and formatting tokens. Any characters
1020c2c66affSColin Finck * in the string are copied verbatim to lpTimeStr, with tokens being replaced
1021c2c66affSColin Finck * by the time values they represent.
1022c2c66affSColin Finck * - The following tokens have special meanings in a time format string:
1023c2c66affSColin Finck *| Token Meaning
1024c2c66affSColin Finck *| ----- -------
1025c2c66affSColin Finck *| h Hours with no leading zero (12-hour clock)
1026c2c66affSColin Finck *| hh Hours with full two digits (12-hour clock)
1027c2c66affSColin Finck *| H Hours with no leading zero (24-hour clock)
1028c2c66affSColin Finck *| HH Hours with full two digits (24-hour clock)
1029c2c66affSColin Finck *| m Minutes with no leading zero
1030c2c66affSColin Finck *| mm Minutes with full two digits
1031c2c66affSColin Finck *| s Seconds with no leading zero
1032c2c66affSColin Finck *| ss Seconds with full two digits
1033c2c66affSColin Finck *| t Short time marker (e.g. "A" or "P")
1034c2c66affSColin Finck *| tt Long time marker (e.g. "AM", "PM")
1035c2c66affSColin Finck * - To output any literal character that could be misidentified as a token,
1036c2c66affSColin Finck * enclose it in single quotes.
1037c2c66affSColin Finck * - The Ascii version of this function fails if lcid is Unicode only.
1038c2c66affSColin Finck *
1039c2c66affSColin Finck * RETURNS
1040c2c66affSColin Finck * Success: The number of character written to lpTimeStr, or that would
1041c2c66affSColin Finck * have been written, if cchOut is 0.
1042c2c66affSColin Finck * Failure: 0. Use GetLastError() to determine the cause.
1043c2c66affSColin Finck */
GetTimeFormatA(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,INT cchOut)1044c2c66affSColin Finck INT WINAPI GetTimeFormatA(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
1045c2c66affSColin Finck LPCSTR lpFormat, LPSTR lpTimeStr, INT cchOut)
1046c2c66affSColin Finck {
1047c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n",lcid, dwFlags, lpTime,
1048c2c66affSColin Finck debugstr_a(lpFormat), lpTimeStr, cchOut);
1049c2c66affSColin Finck
1050c2c66affSColin Finck return NLS_GetDateTimeFormatA(lcid, dwFlags|TIME_TIMEVARSONLY, lpTime,
1051c2c66affSColin Finck lpFormat, lpTimeStr, cchOut);
1052c2c66affSColin Finck }
1053c2c66affSColin Finck
1054655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
1055cf14b6b2SAmine Khaldi /******************************************************************************
1056cf14b6b2SAmine Khaldi * GetTimeFormatEx [KERNEL32.@]
1057cf14b6b2SAmine Khaldi *
1058cf14b6b2SAmine Khaldi * Format a date for a given locale.
1059cf14b6b2SAmine Khaldi *
1060cf14b6b2SAmine Khaldi * PARAMS
1061cf14b6b2SAmine Khaldi * localename [I] Locale to format for
1062cf14b6b2SAmine Khaldi * flags [I] LOCALE_ and TIME_ flags from "winnls.h"
1063cf14b6b2SAmine Khaldi * time [I] Time to format
1064cf14b6b2SAmine Khaldi * format [I] Formatting overrides
1065cf14b6b2SAmine Khaldi * outbuf [O] Destination for formatted string
1066cf14b6b2SAmine Khaldi * bufsize [I] Size of outbuf, or 0 to calculate the resulting size
1067cf14b6b2SAmine Khaldi *
1068cf14b6b2SAmine Khaldi * See GetTimeFormatA for notes.
1069cf14b6b2SAmine Khaldi *
1070cf14b6b2SAmine Khaldi * RETURNS
1071cf14b6b2SAmine Khaldi * Success: The number of characters written to outbuf, or that would have
1072cf14b6b2SAmine Khaldi * have been written if bufsize is 0.
1073cf14b6b2SAmine Khaldi * Failure: 0. Use GetLastError() to determine the cause.
1074cf14b6b2SAmine Khaldi */
GetTimeFormatEx(LPCWSTR localename,DWORD flags,const SYSTEMTIME * time,LPCWSTR format,LPWSTR outbuf,INT bufsize)1075cf14b6b2SAmine Khaldi INT WINAPI GetTimeFormatEx(LPCWSTR localename, DWORD flags,
1076cf14b6b2SAmine Khaldi const SYSTEMTIME* time, LPCWSTR format,
1077cf14b6b2SAmine Khaldi LPWSTR outbuf, INT bufsize)
1078cf14b6b2SAmine Khaldi {
1079cf14b6b2SAmine Khaldi TRACE("(%s,0x%08x,%p,%s,%p,%d)\n", debugstr_w(localename), flags, time,
1080cf14b6b2SAmine Khaldi debugstr_w(format), outbuf, bufsize);
1081cf14b6b2SAmine Khaldi
1082cf14b6b2SAmine Khaldi return NLS_GetDateTimeFormatW(LocaleNameToLCID(localename, 0),
1083cf14b6b2SAmine Khaldi flags | TIME_TIMEVARSONLY, time, format,
1084cf14b6b2SAmine Khaldi outbuf, bufsize);
1085cf14b6b2SAmine Khaldi }
1086655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
1087cf14b6b2SAmine Khaldi
1088c2c66affSColin Finck /******************************************************************************
1089c2c66affSColin Finck * GetTimeFormatW [KERNEL32.@]
1090c2c66affSColin Finck *
1091c2c66affSColin Finck * See GetTimeFormatA.
1092c2c66affSColin Finck */
GetTimeFormatW(LCID lcid,DWORD dwFlags,const SYSTEMTIME * lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,INT cchOut)1093c2c66affSColin Finck INT WINAPI GetTimeFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
1094c2c66affSColin Finck LPCWSTR lpFormat, LPWSTR lpTimeStr, INT cchOut)
1095c2c66affSColin Finck {
1096c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n",lcid, dwFlags, lpTime,
1097c2c66affSColin Finck debugstr_w(lpFormat), lpTimeStr, cchOut);
1098c2c66affSColin Finck
1099c2c66affSColin Finck return NLS_GetDateTimeFormatW(lcid, dwFlags|TIME_TIMEVARSONLY, lpTime,
1100c2c66affSColin Finck lpFormat, lpTimeStr, cchOut);
1101c2c66affSColin Finck }
1102c2c66affSColin Finck
1103c2c66affSColin Finck /**************************************************************************
1104c2c66affSColin Finck * GetNumberFormatA (KERNEL32.@)
1105c2c66affSColin Finck *
1106c2c66affSColin Finck * Format a number string for a given locale.
1107c2c66affSColin Finck *
1108c2c66affSColin Finck * PARAMS
1109c2c66affSColin Finck * lcid [I] Locale to format for
1110c2c66affSColin Finck * dwFlags [I] LOCALE_ flags from "winnls.h"
1111c2c66affSColin Finck * lpszValue [I] String to format
1112c2c66affSColin Finck * lpFormat [I] Formatting overrides
1113c2c66affSColin Finck * lpNumberStr [O] Destination for formatted string
1114c2c66affSColin Finck * cchOut [I] Size of lpNumberStr, or 0 to calculate the resulting size
1115c2c66affSColin Finck *
1116c2c66affSColin Finck * NOTES
1117c2c66affSColin Finck * - lpszValue can contain only '0' - '9', '-' and '.'.
1118c2c66affSColin Finck * - If lpFormat is non-NULL, dwFlags must be 0. In this case lpszValue will
1119c2c66affSColin Finck * be formatted according to the format details returned by GetLocaleInfoA().
1120c2c66affSColin Finck * - This function rounds the number string if the number of decimals exceeds the
1121c2c66affSColin Finck * locales normal number of decimal places.
1122c2c66affSColin Finck * - If cchOut is 0, this function does not write to lpNumberStr.
1123c2c66affSColin Finck * - The Ascii version of this function fails if lcid is Unicode only.
1124c2c66affSColin Finck *
1125c2c66affSColin Finck * RETURNS
1126c2c66affSColin Finck * Success: The number of character written to lpNumberStr, or that would
1127c2c66affSColin Finck * have been written, if cchOut is 0.
1128c2c66affSColin Finck * Failure: 0. Use GetLastError() to determine the cause.
1129c2c66affSColin Finck */
GetNumberFormatA(LCID lcid,DWORD dwFlags,LPCSTR lpszValue,const NUMBERFMTA * lpFormat,LPSTR lpNumberStr,int cchOut)1130c2c66affSColin Finck INT WINAPI GetNumberFormatA(LCID lcid, DWORD dwFlags,
1131c2c66affSColin Finck LPCSTR lpszValue, const NUMBERFMTA *lpFormat,
1132c2c66affSColin Finck LPSTR lpNumberStr, int cchOut)
1133c2c66affSColin Finck {
1134c2c66affSColin Finck DWORD cp = CP_ACP;
1135c2c66affSColin Finck WCHAR szDec[8], szGrp[8], szIn[128], szOut[128];
1136c2c66affSColin Finck NUMBERFMTW fmt;
1137c2c66affSColin Finck const NUMBERFMTW *pfmt = NULL;
1138c2c66affSColin Finck INT iRet;
1139c2c66affSColin Finck
1140c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%s,%p,%p,%d)\n", lcid, dwFlags, debugstr_a(lpszValue),
1141c2c66affSColin Finck lpFormat, lpNumberStr, cchOut);
1142c2c66affSColin Finck
1143c2c66affSColin Finck if (NLS_IsUnicodeOnlyLcid(lcid))
1144c2c66affSColin Finck {
1145c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1146c2c66affSColin Finck return 0;
1147c2c66affSColin Finck }
1148c2c66affSColin Finck
1149c2c66affSColin Finck if (!(dwFlags & LOCALE_USE_CP_ACP))
1150c2c66affSColin Finck {
1151c2c66affSColin Finck const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
1152c2c66affSColin Finck if (!node)
1153c2c66affSColin Finck {
1154c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1155c2c66affSColin Finck return 0;
1156c2c66affSColin Finck }
1157c2c66affSColin Finck
1158c2c66affSColin Finck cp = node->dwCodePage;
1159c2c66affSColin Finck }
1160c2c66affSColin Finck
1161c2c66affSColin Finck if (lpFormat)
1162c2c66affSColin Finck {
1163c2c66affSColin Finck memcpy(&fmt, lpFormat, sizeof(fmt));
1164c2c66affSColin Finck pfmt = &fmt;
1165c2c66affSColin Finck if (lpFormat->lpDecimalSep)
1166c2c66affSColin Finck {
1167655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, ARRAY_SIZE(szDec));
1168c2c66affSColin Finck fmt.lpDecimalSep = szDec;
1169c2c66affSColin Finck }
1170c2c66affSColin Finck if (lpFormat->lpThousandSep)
1171c2c66affSColin Finck {
1172655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, ARRAY_SIZE(szGrp));
1173c2c66affSColin Finck fmt.lpThousandSep = szGrp;
1174c2c66affSColin Finck }
1175c2c66affSColin Finck }
1176c2c66affSColin Finck
1177c2c66affSColin Finck if (lpszValue)
1178655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, ARRAY_SIZE(szIn));
1179c2c66affSColin Finck
1180655d24d9SDenis Malikov if (cchOut > (int) ARRAY_SIZE(szOut))
1181655d24d9SDenis Malikov cchOut = ARRAY_SIZE(szOut);
1182c2c66affSColin Finck
1183c2c66affSColin Finck szOut[0] = '\0';
1184c2c66affSColin Finck
1185c2c66affSColin Finck iRet = GetNumberFormatW(lcid, dwFlags, lpszValue ? szIn : NULL, pfmt,
1186c2c66affSColin Finck lpNumberStr ? szOut : NULL, cchOut);
1187c2c66affSColin Finck
1188c2c66affSColin Finck if (szOut[0] && lpNumberStr)
1189c2c66affSColin Finck WideCharToMultiByte(cp, 0, szOut, -1, lpNumberStr, cchOut, 0, 0);
1190c2c66affSColin Finck return iRet;
1191c2c66affSColin Finck }
1192c2c66affSColin Finck
1193c2c66affSColin Finck /* Number parsing state flags */
1194c2c66affSColin Finck #define NF_ISNEGATIVE 0x1 /* '-' found */
1195c2c66affSColin Finck #define NF_ISREAL 0x2 /* '.' found */
1196c2c66affSColin Finck #define NF_DIGITS 0x4 /* '0'-'9' found */
1197c2c66affSColin Finck #define NF_DIGITS_OUT 0x8 /* Digits before the '.' found */
1198c2c66affSColin Finck #define NF_ROUND 0x10 /* Number needs to be rounded */
1199c2c66affSColin Finck
1200c2c66affSColin Finck /* Formatting options for Numbers */
1201c2c66affSColin Finck #define NLS_NEG_PARENS 0 /* "(1.1)" */
1202c2c66affSColin Finck #define NLS_NEG_LEFT 1 /* "-1.1" */
1203c2c66affSColin Finck #define NLS_NEG_LEFT_SPACE 2 /* "- 1.1" */
1204c2c66affSColin Finck #define NLS_NEG_RIGHT 3 /* "1.1-" */
1205c2c66affSColin Finck #define NLS_NEG_RIGHT_SPACE 4 /* "1.1 -" */
1206c2c66affSColin Finck
1207c2c66affSColin Finck /**************************************************************************
1208c2c66affSColin Finck * GetNumberFormatW (KERNEL32.@)
1209c2c66affSColin Finck *
1210c2c66affSColin Finck * See GetNumberFormatA.
1211c2c66affSColin Finck */
GetNumberFormatW(LCID lcid,DWORD dwFlags,LPCWSTR lpszValue,const NUMBERFMTW * lpFormat,LPWSTR lpNumberStr,int cchOut)1212c2c66affSColin Finck INT WINAPI GetNumberFormatW(LCID lcid, DWORD dwFlags,
1213c2c66affSColin Finck LPCWSTR lpszValue, const NUMBERFMTW *lpFormat,
1214c2c66affSColin Finck LPWSTR lpNumberStr, int cchOut)
1215c2c66affSColin Finck {
1216655d24d9SDenis Malikov WCHAR szBuff[128], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
1217c2c66affSColin Finck WCHAR szNegBuff[8];
1218c2c66affSColin Finck const WCHAR *lpszNeg = NULL, *lpszNegStart, *szSrc;
1219c2c66affSColin Finck DWORD dwState = 0, dwDecimals = 0, dwGroupCount = 0, dwCurrentGroupCount = 0;
1220c2c66affSColin Finck INT iRet;
1221c2c66affSColin Finck
1222c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%s,%p,%p,%d)\n", lcid, dwFlags, debugstr_w(lpszValue),
1223c2c66affSColin Finck lpFormat, lpNumberStr, cchOut);
1224c2c66affSColin Finck
1225c2c66affSColin Finck if (!lpszValue || cchOut < 0 || (cchOut > 0 && !lpNumberStr) ||
1226c2c66affSColin Finck !IsValidLocale(lcid, 0) ||
1227c2c66affSColin Finck (lpFormat && (dwFlags || !lpFormat->lpDecimalSep || !lpFormat->lpThousandSep)))
1228c2c66affSColin Finck {
1229c2c66affSColin Finck goto error;
1230c2c66affSColin Finck }
1231c2c66affSColin Finck
1232c2c66affSColin Finck if (!lpFormat)
1233c2c66affSColin Finck {
1234c2c66affSColin Finck const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
1235c2c66affSColin Finck
1236c2c66affSColin Finck if (!node)
1237c2c66affSColin Finck goto error;
1238c2c66affSColin Finck lpFormat = &node->fmt;
1239c2c66affSColin Finck lpszNegStart = lpszNeg = GetNegative(node);
1240c2c66affSColin Finck }
1241c2c66affSColin Finck else
1242c2c66affSColin Finck {
1243c2c66affSColin Finck GetLocaleInfoW(lcid, LOCALE_SNEGATIVESIGN|(dwFlags & LOCALE_NOUSEROVERRIDE),
1244655d24d9SDenis Malikov szNegBuff, ARRAY_SIZE(szNegBuff));
1245c2c66affSColin Finck lpszNegStart = lpszNeg = szNegBuff;
1246c2c66affSColin Finck }
1247c2c66affSColin Finck lpszNeg = lpszNeg + strlenW(lpszNeg) - 1;
1248c2c66affSColin Finck
1249c2c66affSColin Finck dwFlags &= (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP);
1250c2c66affSColin Finck
1251c2c66affSColin Finck /* Format the number backwards into a temporary buffer */
1252c2c66affSColin Finck
1253c2c66affSColin Finck szSrc = lpszValue;
1254c2c66affSColin Finck *szOut-- = '\0';
1255c2c66affSColin Finck
1256c2c66affSColin Finck /* Check the number for validity */
1257c2c66affSColin Finck while (*szSrc)
1258c2c66affSColin Finck {
1259c2c66affSColin Finck if (*szSrc >= '0' && *szSrc <= '9')
1260c2c66affSColin Finck {
1261c2c66affSColin Finck dwState |= NF_DIGITS;
1262c2c66affSColin Finck if (dwState & NF_ISREAL)
1263c2c66affSColin Finck dwDecimals++;
1264c2c66affSColin Finck }
1265c2c66affSColin Finck else if (*szSrc == '-')
1266c2c66affSColin Finck {
1267c2c66affSColin Finck if (dwState)
1268c2c66affSColin Finck goto error; /* '-' not first character */
1269c2c66affSColin Finck dwState |= NF_ISNEGATIVE;
1270c2c66affSColin Finck }
1271c2c66affSColin Finck else if (*szSrc == '.')
1272c2c66affSColin Finck {
1273c2c66affSColin Finck if (dwState & NF_ISREAL)
1274c2c66affSColin Finck goto error; /* More than one '.' */
1275c2c66affSColin Finck dwState |= NF_ISREAL;
1276c2c66affSColin Finck }
1277c2c66affSColin Finck else
1278c2c66affSColin Finck goto error; /* Invalid char */
1279c2c66affSColin Finck szSrc++;
1280c2c66affSColin Finck }
1281c2c66affSColin Finck szSrc--; /* Point to last character */
1282c2c66affSColin Finck
1283c2c66affSColin Finck if (!(dwState & NF_DIGITS))
1284c2c66affSColin Finck goto error; /* No digits */
1285c2c66affSColin Finck
1286c2c66affSColin Finck /* Add any trailing negative sign */
1287c2c66affSColin Finck if (dwState & NF_ISNEGATIVE)
1288c2c66affSColin Finck {
1289c2c66affSColin Finck switch (lpFormat->NegativeOrder)
1290c2c66affSColin Finck {
1291c2c66affSColin Finck case NLS_NEG_PARENS:
1292c2c66affSColin Finck *szOut-- = ')';
1293c2c66affSColin Finck break;
1294c2c66affSColin Finck case NLS_NEG_RIGHT:
1295c2c66affSColin Finck case NLS_NEG_RIGHT_SPACE:
1296c2c66affSColin Finck while (lpszNeg >= lpszNegStart)
1297c2c66affSColin Finck *szOut-- = *lpszNeg--;
1298c2c66affSColin Finck if (lpFormat->NegativeOrder == NLS_NEG_RIGHT_SPACE)
1299c2c66affSColin Finck *szOut-- = ' ';
1300c2c66affSColin Finck break;
1301c2c66affSColin Finck }
1302c2c66affSColin Finck }
1303c2c66affSColin Finck
1304c2c66affSColin Finck /* Copy all digits up to the decimal point */
1305c2c66affSColin Finck if (!lpFormat->NumDigits)
1306c2c66affSColin Finck {
1307c2c66affSColin Finck if (dwState & NF_ISREAL)
1308c2c66affSColin Finck {
1309c2c66affSColin Finck while (*szSrc != '.') /* Don't write any decimals or a separator */
1310c2c66affSColin Finck {
1311c2c66affSColin Finck if (*szSrc >= '5' || (*szSrc == '4' && (dwState & NF_ROUND)))
1312c2c66affSColin Finck dwState |= NF_ROUND;
1313c2c66affSColin Finck else
1314c2c66affSColin Finck dwState &= ~NF_ROUND;
1315c2c66affSColin Finck szSrc--;
1316c2c66affSColin Finck }
1317c2c66affSColin Finck szSrc--;
1318c2c66affSColin Finck }
1319c2c66affSColin Finck }
1320c2c66affSColin Finck else
1321c2c66affSColin Finck {
1322c2c66affSColin Finck LPWSTR lpszDec = lpFormat->lpDecimalSep + strlenW(lpFormat->lpDecimalSep) - 1;
1323c2c66affSColin Finck
1324c2c66affSColin Finck if (dwDecimals <= lpFormat->NumDigits)
1325c2c66affSColin Finck {
1326c2c66affSColin Finck dwDecimals = lpFormat->NumDigits - dwDecimals;
1327c2c66affSColin Finck while (dwDecimals--)
1328c2c66affSColin Finck *szOut-- = '0'; /* Pad to correct number of dp */
1329c2c66affSColin Finck }
1330c2c66affSColin Finck else
1331c2c66affSColin Finck {
1332c2c66affSColin Finck dwDecimals -= lpFormat->NumDigits;
1333c2c66affSColin Finck /* Skip excess decimals, and determine if we have to round the number */
1334c2c66affSColin Finck while (dwDecimals--)
1335c2c66affSColin Finck {
1336c2c66affSColin Finck if (*szSrc >= '5' || (*szSrc == '4' && (dwState & NF_ROUND)))
1337c2c66affSColin Finck dwState |= NF_ROUND;
1338c2c66affSColin Finck else
1339c2c66affSColin Finck dwState &= ~NF_ROUND;
1340c2c66affSColin Finck szSrc--;
1341c2c66affSColin Finck }
1342c2c66affSColin Finck }
1343c2c66affSColin Finck
1344c2c66affSColin Finck if (dwState & NF_ISREAL)
1345c2c66affSColin Finck {
1346c2c66affSColin Finck while (*szSrc != '.')
1347c2c66affSColin Finck {
1348c2c66affSColin Finck if (dwState & NF_ROUND)
1349c2c66affSColin Finck {
1350c2c66affSColin Finck if (*szSrc == '9')
1351c2c66affSColin Finck *szOut-- = '0'; /* continue rounding */
1352c2c66affSColin Finck else
1353c2c66affSColin Finck {
1354c2c66affSColin Finck dwState &= ~NF_ROUND;
1355c2c66affSColin Finck *szOut-- = (*szSrc)+1;
1356c2c66affSColin Finck }
1357c2c66affSColin Finck szSrc--;
1358c2c66affSColin Finck }
1359c2c66affSColin Finck else
1360c2c66affSColin Finck *szOut-- = *szSrc--; /* Write existing decimals */
1361c2c66affSColin Finck }
1362c2c66affSColin Finck szSrc--; /* Skip '.' */
1363c2c66affSColin Finck }
1364c2c66affSColin Finck
1365c2c66affSColin Finck while (lpszDec >= lpFormat->lpDecimalSep)
1366c2c66affSColin Finck *szOut-- = *lpszDec--; /* Write decimal separator */
1367c2c66affSColin Finck }
1368c2c66affSColin Finck
1369c2c66affSColin Finck dwGroupCount = lpFormat->Grouping == 32 ? 3 : lpFormat->Grouping;
1370c2c66affSColin Finck
1371c2c66affSColin Finck /* Write the remaining whole number digits, including grouping chars */
1372c2c66affSColin Finck while (szSrc >= lpszValue && *szSrc >= '0' && *szSrc <= '9')
1373c2c66affSColin Finck {
1374c2c66affSColin Finck if (dwState & NF_ROUND)
1375c2c66affSColin Finck {
1376c2c66affSColin Finck if (*szSrc == '9')
1377c2c66affSColin Finck *szOut-- = '0'; /* continue rounding */
1378c2c66affSColin Finck else
1379c2c66affSColin Finck {
1380c2c66affSColin Finck dwState &= ~NF_ROUND;
1381c2c66affSColin Finck *szOut-- = (*szSrc)+1;
1382c2c66affSColin Finck }
1383c2c66affSColin Finck szSrc--;
1384c2c66affSColin Finck }
1385c2c66affSColin Finck else
1386c2c66affSColin Finck *szOut-- = *szSrc--;
1387c2c66affSColin Finck
1388c2c66affSColin Finck dwState |= NF_DIGITS_OUT;
1389c2c66affSColin Finck dwCurrentGroupCount++;
1390c2c66affSColin Finck if (szSrc >= lpszValue && dwCurrentGroupCount == dwGroupCount && *szSrc != '-')
1391c2c66affSColin Finck {
1392c2c66affSColin Finck LPWSTR lpszGrp = lpFormat->lpThousandSep + strlenW(lpFormat->lpThousandSep) - 1;
1393c2c66affSColin Finck
1394c2c66affSColin Finck while (lpszGrp >= lpFormat->lpThousandSep)
1395c2c66affSColin Finck *szOut-- = *lpszGrp--; /* Write grouping char */
1396c2c66affSColin Finck
1397c2c66affSColin Finck dwCurrentGroupCount = 0;
1398c2c66affSColin Finck if (lpFormat->Grouping == 32)
1399c2c66affSColin Finck dwGroupCount = 2; /* Indic grouping: 3 then 2 */
1400c2c66affSColin Finck }
1401c2c66affSColin Finck }
1402c2c66affSColin Finck if (dwState & NF_ROUND)
1403c2c66affSColin Finck {
1404c2c66affSColin Finck *szOut-- = '1'; /* e.g. .6 > 1.0 */
1405c2c66affSColin Finck }
1406c2c66affSColin Finck else if (!(dwState & NF_DIGITS_OUT) && lpFormat->LeadingZero)
1407c2c66affSColin Finck *szOut-- = '0'; /* Add leading 0 if we have no digits before the decimal point */
1408c2c66affSColin Finck
1409c2c66affSColin Finck /* Add any leading negative sign */
1410c2c66affSColin Finck if (dwState & NF_ISNEGATIVE)
1411c2c66affSColin Finck {
1412c2c66affSColin Finck switch (lpFormat->NegativeOrder)
1413c2c66affSColin Finck {
1414c2c66affSColin Finck case NLS_NEG_PARENS:
1415c2c66affSColin Finck *szOut-- = '(';
1416c2c66affSColin Finck break;
1417c2c66affSColin Finck case NLS_NEG_LEFT_SPACE:
1418c2c66affSColin Finck *szOut-- = ' ';
1419c2c66affSColin Finck /* Fall through */
1420c2c66affSColin Finck case NLS_NEG_LEFT:
1421c2c66affSColin Finck while (lpszNeg >= lpszNegStart)
1422c2c66affSColin Finck *szOut-- = *lpszNeg--;
1423c2c66affSColin Finck break;
1424c2c66affSColin Finck }
1425c2c66affSColin Finck }
1426c2c66affSColin Finck szOut++;
1427c2c66affSColin Finck
1428c2c66affSColin Finck iRet = strlenW(szOut) + 1;
1429c2c66affSColin Finck if (cchOut)
1430c2c66affSColin Finck {
1431c2c66affSColin Finck if (iRet <= cchOut)
1432c2c66affSColin Finck memcpy(lpNumberStr, szOut, iRet * sizeof(WCHAR));
1433c2c66affSColin Finck else
1434c2c66affSColin Finck {
1435c2c66affSColin Finck memcpy(lpNumberStr, szOut, cchOut * sizeof(WCHAR));
1436c2c66affSColin Finck lpNumberStr[cchOut - 1] = '\0';
1437c2c66affSColin Finck SetLastError(ERROR_INSUFFICIENT_BUFFER);
1438c2c66affSColin Finck iRet = 0;
1439c2c66affSColin Finck }
1440c2c66affSColin Finck }
1441c2c66affSColin Finck return iRet;
1442c2c66affSColin Finck
1443c2c66affSColin Finck error:
1444c2c66affSColin Finck SetLastError(lpFormat && dwFlags ? ERROR_INVALID_FLAGS : ERROR_INVALID_PARAMETER);
1445c2c66affSColin Finck return 0;
1446c2c66affSColin Finck }
1447c2c66affSColin Finck
1448655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
1449cf14b6b2SAmine Khaldi /**************************************************************************
1450cf14b6b2SAmine Khaldi * GetNumberFormatEx (KERNEL32.@)
1451cf14b6b2SAmine Khaldi */
GetNumberFormatEx(LPCWSTR name,DWORD flags,LPCWSTR value,const NUMBERFMTW * format,LPWSTR number,int numout)1452cf14b6b2SAmine Khaldi INT WINAPI GetNumberFormatEx(LPCWSTR name, DWORD flags,
1453cf14b6b2SAmine Khaldi LPCWSTR value, const NUMBERFMTW *format,
1454cf14b6b2SAmine Khaldi LPWSTR number, int numout)
1455cf14b6b2SAmine Khaldi {
1456cf14b6b2SAmine Khaldi LCID lcid;
1457cf14b6b2SAmine Khaldi
1458cf14b6b2SAmine Khaldi TRACE("(%s,0x%08x,%s,%p,%p,%d)\n", debugstr_w(name), flags,
1459cf14b6b2SAmine Khaldi debugstr_w(value), format, number, numout);
1460cf14b6b2SAmine Khaldi
1461cf14b6b2SAmine Khaldi lcid = LocaleNameToLCID(name, 0);
1462cf14b6b2SAmine Khaldi if (!lcid)
1463cf14b6b2SAmine Khaldi return 0;
1464cf14b6b2SAmine Khaldi
1465cf14b6b2SAmine Khaldi return GetNumberFormatW(lcid, flags, value, format, number, numout);
1466cf14b6b2SAmine Khaldi }
1467655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
1468cf14b6b2SAmine Khaldi
1469c2c66affSColin Finck /**************************************************************************
1470c2c66affSColin Finck * GetCurrencyFormatA (KERNEL32.@)
1471c2c66affSColin Finck *
1472c2c66affSColin Finck * Format a currency string for a given locale.
1473c2c66affSColin Finck *
1474c2c66affSColin Finck * PARAMS
1475c2c66affSColin Finck * lcid [I] Locale to format for
1476c2c66affSColin Finck * dwFlags [I] LOCALE_ flags from "winnls.h"
1477c2c66affSColin Finck * lpszValue [I] String to format
1478c2c66affSColin Finck * lpFormat [I] Formatting overrides
1479c2c66affSColin Finck * lpCurrencyStr [O] Destination for formatted string
1480c2c66affSColin Finck * cchOut [I] Size of lpCurrencyStr, or 0 to calculate the resulting size
1481c2c66affSColin Finck *
1482c2c66affSColin Finck * NOTES
1483c2c66affSColin Finck * - lpszValue can contain only '0' - '9', '-' and '.'.
1484c2c66affSColin Finck * - If lpFormat is non-NULL, dwFlags must be 0. In this case lpszValue will
1485c2c66affSColin Finck * be formatted according to the format details returned by GetLocaleInfoA().
1486c2c66affSColin Finck * - This function rounds the currency if the number of decimals exceeds the
1487c2c66affSColin Finck * locales number of currency decimal places.
1488c2c66affSColin Finck * - If cchOut is 0, this function does not write to lpCurrencyStr.
1489c2c66affSColin Finck * - The Ascii version of this function fails if lcid is Unicode only.
1490c2c66affSColin Finck *
1491c2c66affSColin Finck * RETURNS
1492c2c66affSColin Finck * Success: The number of character written to lpNumberStr, or that would
1493c2c66affSColin Finck * have been written, if cchOut is 0.
1494c2c66affSColin Finck * Failure: 0. Use GetLastError() to determine the cause.
1495c2c66affSColin Finck */
GetCurrencyFormatA(LCID lcid,DWORD dwFlags,LPCSTR lpszValue,const CURRENCYFMTA * lpFormat,LPSTR lpCurrencyStr,int cchOut)1496c2c66affSColin Finck INT WINAPI GetCurrencyFormatA(LCID lcid, DWORD dwFlags,
1497c2c66affSColin Finck LPCSTR lpszValue, const CURRENCYFMTA *lpFormat,
1498c2c66affSColin Finck LPSTR lpCurrencyStr, int cchOut)
1499c2c66affSColin Finck {
1500c2c66affSColin Finck DWORD cp = CP_ACP;
1501c2c66affSColin Finck WCHAR szDec[8], szGrp[8], szCy[8], szIn[128], szOut[128];
1502c2c66affSColin Finck CURRENCYFMTW fmt;
1503c2c66affSColin Finck const CURRENCYFMTW *pfmt = NULL;
1504c2c66affSColin Finck INT iRet;
1505c2c66affSColin Finck
1506c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%s,%p,%p,%d)\n", lcid, dwFlags, debugstr_a(lpszValue),
1507c2c66affSColin Finck lpFormat, lpCurrencyStr, cchOut);
1508c2c66affSColin Finck
1509c2c66affSColin Finck if (NLS_IsUnicodeOnlyLcid(lcid))
1510c2c66affSColin Finck {
1511c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1512c2c66affSColin Finck return 0;
1513c2c66affSColin Finck }
1514c2c66affSColin Finck
1515c2c66affSColin Finck if (!(dwFlags & LOCALE_USE_CP_ACP))
1516c2c66affSColin Finck {
1517c2c66affSColin Finck const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
1518c2c66affSColin Finck if (!node)
1519c2c66affSColin Finck {
1520c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1521c2c66affSColin Finck return 0;
1522c2c66affSColin Finck }
1523c2c66affSColin Finck
1524c2c66affSColin Finck cp = node->dwCodePage;
1525c2c66affSColin Finck }
1526c2c66affSColin Finck
1527c2c66affSColin Finck if (lpFormat)
1528c2c66affSColin Finck {
1529c2c66affSColin Finck memcpy(&fmt, lpFormat, sizeof(fmt));
1530c2c66affSColin Finck pfmt = &fmt;
1531c2c66affSColin Finck if (lpFormat->lpDecimalSep)
1532c2c66affSColin Finck {
1533655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, ARRAY_SIZE(szDec));
1534c2c66affSColin Finck fmt.lpDecimalSep = szDec;
1535c2c66affSColin Finck }
1536c2c66affSColin Finck if (lpFormat->lpThousandSep)
1537c2c66affSColin Finck {
1538655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, ARRAY_SIZE(szGrp));
1539c2c66affSColin Finck fmt.lpThousandSep = szGrp;
1540c2c66affSColin Finck }
1541c2c66affSColin Finck if (lpFormat->lpCurrencySymbol)
1542c2c66affSColin Finck {
1543655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpFormat->lpCurrencySymbol, -1, szCy, ARRAY_SIZE(szCy));
1544c2c66affSColin Finck fmt.lpCurrencySymbol = szCy;
1545c2c66affSColin Finck }
1546c2c66affSColin Finck }
1547c2c66affSColin Finck
1548c2c66affSColin Finck if (lpszValue)
1549655d24d9SDenis Malikov MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, ARRAY_SIZE(szIn));
1550c2c66affSColin Finck
1551655d24d9SDenis Malikov if (cchOut > (int) ARRAY_SIZE(szOut))
1552655d24d9SDenis Malikov cchOut = ARRAY_SIZE(szOut);
1553c2c66affSColin Finck
1554c2c66affSColin Finck szOut[0] = '\0';
1555c2c66affSColin Finck
1556c2c66affSColin Finck iRet = GetCurrencyFormatW(lcid, dwFlags, lpszValue ? szIn : NULL, pfmt,
1557c2c66affSColin Finck lpCurrencyStr ? szOut : NULL, cchOut);
1558c2c66affSColin Finck
1559c2c66affSColin Finck if (szOut[0] && lpCurrencyStr)
1560c2c66affSColin Finck WideCharToMultiByte(cp, 0, szOut, -1, lpCurrencyStr, cchOut, 0, 0);
1561c2c66affSColin Finck return iRet;
1562c2c66affSColin Finck }
1563c2c66affSColin Finck
1564c2c66affSColin Finck /* Formatting states for Currencies. We use flags to avoid code duplication. */
1565c2c66affSColin Finck #define CF_PARENS 0x1 /* Parentheses */
1566c2c66affSColin Finck #define CF_MINUS_LEFT 0x2 /* '-' to the left */
1567c2c66affSColin Finck #define CF_MINUS_RIGHT 0x4 /* '-' to the right */
1568c2c66affSColin Finck #define CF_MINUS_BEFORE 0x8 /* '-' before '$' */
1569c2c66affSColin Finck #define CF_CY_LEFT 0x10 /* '$' to the left */
1570c2c66affSColin Finck #define CF_CY_RIGHT 0x20 /* '$' to the right */
1571c2c66affSColin Finck #define CF_CY_SPACE 0x40 /* ' ' by '$' */
1572c2c66affSColin Finck
1573c2c66affSColin Finck /**************************************************************************
1574c2c66affSColin Finck * GetCurrencyFormatW (KERNEL32.@)
1575c2c66affSColin Finck *
1576c2c66affSColin Finck * See GetCurrencyFormatA.
1577c2c66affSColin Finck */
GetCurrencyFormatW(LCID lcid,DWORD dwFlags,LPCWSTR lpszValue,const CURRENCYFMTW * lpFormat,LPWSTR lpCurrencyStr,int cchOut)1578c2c66affSColin Finck INT WINAPI GetCurrencyFormatW(LCID lcid, DWORD dwFlags,
1579c2c66affSColin Finck LPCWSTR lpszValue, const CURRENCYFMTW *lpFormat,
1580c2c66affSColin Finck LPWSTR lpCurrencyStr, int cchOut)
1581c2c66affSColin Finck {
1582c2c66affSColin Finck static const BYTE NLS_NegCyFormats[16] =
1583c2c66affSColin Finck {
1584c2c66affSColin Finck CF_PARENS|CF_CY_LEFT, /* ($1.1) */
1585c2c66affSColin Finck CF_MINUS_LEFT|CF_MINUS_BEFORE|CF_CY_LEFT, /* -$1.1 */
1586c2c66affSColin Finck CF_MINUS_LEFT|CF_CY_LEFT, /* $-1.1 */
1587c2c66affSColin Finck CF_MINUS_RIGHT|CF_CY_LEFT, /* $1.1- */
1588c2c66affSColin Finck CF_PARENS|CF_CY_RIGHT, /* (1.1$) */
1589c2c66affSColin Finck CF_MINUS_LEFT|CF_CY_RIGHT, /* -1.1$ */
1590c2c66affSColin Finck CF_MINUS_RIGHT|CF_MINUS_BEFORE|CF_CY_RIGHT, /* 1.1-$ */
1591c2c66affSColin Finck CF_MINUS_RIGHT|CF_CY_RIGHT, /* 1.1$- */
1592c2c66affSColin Finck CF_MINUS_LEFT|CF_CY_RIGHT|CF_CY_SPACE, /* -1.1 $ */
1593c2c66affSColin Finck CF_MINUS_LEFT|CF_MINUS_BEFORE|CF_CY_LEFT|CF_CY_SPACE, /* -$ 1.1 */
1594c2c66affSColin Finck CF_MINUS_RIGHT|CF_CY_RIGHT|CF_CY_SPACE, /* 1.1 $- */
1595c2c66affSColin Finck CF_MINUS_RIGHT|CF_CY_LEFT|CF_CY_SPACE, /* $ 1.1- */
1596c2c66affSColin Finck CF_MINUS_LEFT|CF_CY_LEFT|CF_CY_SPACE, /* $ -1.1 */
1597c2c66affSColin Finck CF_MINUS_RIGHT|CF_MINUS_BEFORE|CF_CY_RIGHT|CF_CY_SPACE, /* 1.1- $ */
1598c2c66affSColin Finck CF_PARENS|CF_CY_LEFT|CF_CY_SPACE, /* ($ 1.1) */
1599c2c66affSColin Finck CF_PARENS|CF_CY_RIGHT|CF_CY_SPACE, /* (1.1 $) */
1600c2c66affSColin Finck };
1601c2c66affSColin Finck static const BYTE NLS_PosCyFormats[4] =
1602c2c66affSColin Finck {
1603c2c66affSColin Finck CF_CY_LEFT, /* $1.1 */
1604c2c66affSColin Finck CF_CY_RIGHT, /* 1.1$ */
1605c2c66affSColin Finck CF_CY_LEFT|CF_CY_SPACE, /* $ 1.1 */
1606c2c66affSColin Finck CF_CY_RIGHT|CF_CY_SPACE, /* 1.1 $ */
1607c2c66affSColin Finck };
1608655d24d9SDenis Malikov WCHAR szBuff[128], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
1609c2c66affSColin Finck WCHAR szNegBuff[8];
1610c2c66affSColin Finck const WCHAR *lpszNeg = NULL, *lpszNegStart, *szSrc, *lpszCy, *lpszCyStart;
1611c2c66affSColin Finck DWORD dwState = 0, dwDecimals = 0, dwGroupCount = 0, dwCurrentGroupCount = 0, dwFmt;
1612c2c66affSColin Finck INT iRet;
1613c2c66affSColin Finck
1614c2c66affSColin Finck TRACE("(0x%04x,0x%08x,%s,%p,%p,%d)\n", lcid, dwFlags, debugstr_w(lpszValue),
1615c2c66affSColin Finck lpFormat, lpCurrencyStr, cchOut);
1616c2c66affSColin Finck
1617c2c66affSColin Finck if (!lpszValue || cchOut < 0 || (cchOut > 0 && !lpCurrencyStr) ||
1618c2c66affSColin Finck !IsValidLocale(lcid, 0) ||
1619c2c66affSColin Finck (lpFormat && (dwFlags || !lpFormat->lpDecimalSep || !lpFormat->lpThousandSep ||
1620c2c66affSColin Finck !lpFormat->lpCurrencySymbol || lpFormat->NegativeOrder > 15 ||
1621c2c66affSColin Finck lpFormat->PositiveOrder > 3)))
1622c2c66affSColin Finck {
1623c2c66affSColin Finck goto error;
1624c2c66affSColin Finck }
1625c2c66affSColin Finck
1626c2c66affSColin Finck if (!lpFormat)
1627c2c66affSColin Finck {
1628c2c66affSColin Finck const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
1629c2c66affSColin Finck
1630c2c66affSColin Finck if (!node)
1631c2c66affSColin Finck goto error;
1632c2c66affSColin Finck
1633c2c66affSColin Finck lpFormat = &node->cyfmt;
1634c2c66affSColin Finck lpszNegStart = lpszNeg = GetNegative(node);
1635c2c66affSColin Finck }
1636c2c66affSColin Finck else
1637c2c66affSColin Finck {
1638c2c66affSColin Finck GetLocaleInfoW(lcid, LOCALE_SNEGATIVESIGN|(dwFlags & LOCALE_NOUSEROVERRIDE),
1639655d24d9SDenis Malikov szNegBuff, ARRAY_SIZE(szNegBuff));
1640c2c66affSColin Finck lpszNegStart = lpszNeg = szNegBuff;
1641c2c66affSColin Finck }
1642c2c66affSColin Finck dwFlags &= (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP);
1643c2c66affSColin Finck
1644c2c66affSColin Finck lpszNeg = lpszNeg + strlenW(lpszNeg) - 1;
1645c2c66affSColin Finck lpszCyStart = lpFormat->lpCurrencySymbol;
1646c2c66affSColin Finck lpszCy = lpszCyStart + strlenW(lpszCyStart) - 1;
1647c2c66affSColin Finck
1648c2c66affSColin Finck /* Format the currency backwards into a temporary buffer */
1649c2c66affSColin Finck
1650c2c66affSColin Finck szSrc = lpszValue;
1651c2c66affSColin Finck *szOut-- = '\0';
1652c2c66affSColin Finck
1653c2c66affSColin Finck /* Check the number for validity */
1654c2c66affSColin Finck while (*szSrc)
1655c2c66affSColin Finck {
1656c2c66affSColin Finck if (*szSrc >= '0' && *szSrc <= '9')
1657c2c66affSColin Finck {
1658c2c66affSColin Finck dwState |= NF_DIGITS;
1659c2c66affSColin Finck if (dwState & NF_ISREAL)
1660c2c66affSColin Finck dwDecimals++;
1661c2c66affSColin Finck }
1662c2c66affSColin Finck else if (*szSrc == '-')
1663c2c66affSColin Finck {
1664c2c66affSColin Finck if (dwState)
1665c2c66affSColin Finck goto error; /* '-' not first character */
1666c2c66affSColin Finck dwState |= NF_ISNEGATIVE;
1667c2c66affSColin Finck }
1668c2c66affSColin Finck else if (*szSrc == '.')
1669c2c66affSColin Finck {
1670c2c66affSColin Finck if (dwState & NF_ISREAL)
1671c2c66affSColin Finck goto error; /* More than one '.' */
1672c2c66affSColin Finck dwState |= NF_ISREAL;
1673c2c66affSColin Finck }
1674c2c66affSColin Finck else
1675c2c66affSColin Finck goto error; /* Invalid char */
1676c2c66affSColin Finck szSrc++;
1677c2c66affSColin Finck }
1678c2c66affSColin Finck szSrc--; /* Point to last character */
1679c2c66affSColin Finck
1680c2c66affSColin Finck if (!(dwState & NF_DIGITS))
1681c2c66affSColin Finck goto error; /* No digits */
1682c2c66affSColin Finck
1683c2c66affSColin Finck if (dwState & NF_ISNEGATIVE)
1684c2c66affSColin Finck dwFmt = NLS_NegCyFormats[lpFormat->NegativeOrder];
1685c2c66affSColin Finck else
1686c2c66affSColin Finck dwFmt = NLS_PosCyFormats[lpFormat->PositiveOrder];
1687c2c66affSColin Finck
1688c2c66affSColin Finck /* Add any trailing negative or currency signs */
1689c2c66affSColin Finck if (dwFmt & CF_PARENS)
1690c2c66affSColin Finck *szOut-- = ')';
1691c2c66affSColin Finck
1692c2c66affSColin Finck while (dwFmt & (CF_MINUS_RIGHT|CF_CY_RIGHT))
1693c2c66affSColin Finck {
1694c2c66affSColin Finck switch (dwFmt & (CF_MINUS_RIGHT|CF_MINUS_BEFORE|CF_CY_RIGHT))
1695c2c66affSColin Finck {
1696c2c66affSColin Finck case CF_MINUS_RIGHT:
1697c2c66affSColin Finck case CF_MINUS_RIGHT|CF_CY_RIGHT:
1698c2c66affSColin Finck while (lpszNeg >= lpszNegStart)
1699c2c66affSColin Finck *szOut-- = *lpszNeg--;
1700c2c66affSColin Finck dwFmt &= ~CF_MINUS_RIGHT;
1701c2c66affSColin Finck break;
1702c2c66affSColin Finck
1703c2c66affSColin Finck case CF_CY_RIGHT:
1704c2c66affSColin Finck case CF_MINUS_BEFORE|CF_CY_RIGHT:
1705c2c66affSColin Finck case CF_MINUS_RIGHT|CF_MINUS_BEFORE|CF_CY_RIGHT:
1706c2c66affSColin Finck while (lpszCy >= lpszCyStart)
1707c2c66affSColin Finck *szOut-- = *lpszCy--;
1708c2c66affSColin Finck if (dwFmt & CF_CY_SPACE)
1709c2c66affSColin Finck *szOut-- = ' ';
1710c2c66affSColin Finck dwFmt &= ~(CF_CY_RIGHT|CF_MINUS_BEFORE);
1711c2c66affSColin Finck break;
1712c2c66affSColin Finck }
1713c2c66affSColin Finck }
1714c2c66affSColin Finck
1715c2c66affSColin Finck /* Copy all digits up to the decimal point */
1716c2c66affSColin Finck if (!lpFormat->NumDigits)
1717c2c66affSColin Finck {
1718c2c66affSColin Finck if (dwState & NF_ISREAL)
1719c2c66affSColin Finck {
1720c2c66affSColin Finck while (*szSrc != '.') /* Don't write any decimals or a separator */
1721c2c66affSColin Finck {
1722c2c66affSColin Finck if (*szSrc >= '5' || (*szSrc == '4' && (dwState & NF_ROUND)))
1723c2c66affSColin Finck dwState |= NF_ROUND;
1724c2c66affSColin Finck else
1725c2c66affSColin Finck dwState &= ~NF_ROUND;
1726c2c66affSColin Finck szSrc--;
1727c2c66affSColin Finck }
1728c2c66affSColin Finck szSrc--;
1729c2c66affSColin Finck }
1730c2c66affSColin Finck }
1731c2c66affSColin Finck else
1732c2c66affSColin Finck {
1733c2c66affSColin Finck LPWSTR lpszDec = lpFormat->lpDecimalSep + strlenW(lpFormat->lpDecimalSep) - 1;
1734c2c66affSColin Finck
1735c2c66affSColin Finck if (dwDecimals <= lpFormat->NumDigits)
1736c2c66affSColin Finck {
1737c2c66affSColin Finck dwDecimals = lpFormat->NumDigits - dwDecimals;
1738c2c66affSColin Finck while (dwDecimals--)
1739c2c66affSColin Finck *szOut-- = '0'; /* Pad to correct number of dp */
1740c2c66affSColin Finck }
1741c2c66affSColin Finck else
1742c2c66affSColin Finck {
1743c2c66affSColin Finck dwDecimals -= lpFormat->NumDigits;
1744c2c66affSColin Finck /* Skip excess decimals, and determine if we have to round the number */
1745c2c66affSColin Finck while (dwDecimals--)
1746c2c66affSColin Finck {
1747c2c66affSColin Finck if (*szSrc >= '5' || (*szSrc == '4' && (dwState & NF_ROUND)))
1748c2c66affSColin Finck dwState |= NF_ROUND;
1749c2c66affSColin Finck else
1750c2c66affSColin Finck dwState &= ~NF_ROUND;
1751c2c66affSColin Finck szSrc--;
1752c2c66affSColin Finck }
1753c2c66affSColin Finck }
1754c2c66affSColin Finck
1755c2c66affSColin Finck if (dwState & NF_ISREAL)
1756c2c66affSColin Finck {
1757c2c66affSColin Finck while (*szSrc != '.')
1758c2c66affSColin Finck {
1759c2c66affSColin Finck if (dwState & NF_ROUND)
1760c2c66affSColin Finck {
1761c2c66affSColin Finck if (*szSrc == '9')
1762c2c66affSColin Finck *szOut-- = '0'; /* continue rounding */
1763c2c66affSColin Finck else
1764c2c66affSColin Finck {
1765c2c66affSColin Finck dwState &= ~NF_ROUND;
1766c2c66affSColin Finck *szOut-- = (*szSrc)+1;
1767c2c66affSColin Finck }
1768c2c66affSColin Finck szSrc--;
1769c2c66affSColin Finck }
1770c2c66affSColin Finck else
1771c2c66affSColin Finck *szOut-- = *szSrc--; /* Write existing decimals */
1772c2c66affSColin Finck }
1773c2c66affSColin Finck szSrc--; /* Skip '.' */
1774c2c66affSColin Finck }
1775c2c66affSColin Finck while (lpszDec >= lpFormat->lpDecimalSep)
1776c2c66affSColin Finck *szOut-- = *lpszDec--; /* Write decimal separator */
1777c2c66affSColin Finck }
1778c2c66affSColin Finck
1779c1fad347SKyle Katarn dwGroupCount = lpFormat->Grouping == 32 ? 3 : lpFormat->Grouping;
1780c2c66affSColin Finck
1781c2c66affSColin Finck /* Write the remaining whole number digits, including grouping chars */
1782c2c66affSColin Finck while (szSrc >= lpszValue && *szSrc >= '0' && *szSrc <= '9')
1783c2c66affSColin Finck {
1784c2c66affSColin Finck if (dwState & NF_ROUND)
1785c2c66affSColin Finck {
1786c2c66affSColin Finck if (*szSrc == '9')
1787c2c66affSColin Finck *szOut-- = '0'; /* continue rounding */
1788c2c66affSColin Finck else
1789c2c66affSColin Finck {
1790c2c66affSColin Finck dwState &= ~NF_ROUND;
1791c2c66affSColin Finck *szOut-- = (*szSrc)+1;
1792c2c66affSColin Finck }
1793c2c66affSColin Finck szSrc--;
1794c2c66affSColin Finck }
1795c2c66affSColin Finck else
1796c2c66affSColin Finck *szOut-- = *szSrc--;
1797c2c66affSColin Finck
1798c2c66affSColin Finck dwState |= NF_DIGITS_OUT;
1799c2c66affSColin Finck dwCurrentGroupCount++;
1800c2c66affSColin Finck if (szSrc >= lpszValue && dwCurrentGroupCount == dwGroupCount && *szSrc != '-')
1801c2c66affSColin Finck {
1802c2c66affSColin Finck LPWSTR lpszGrp = lpFormat->lpThousandSep + strlenW(lpFormat->lpThousandSep) - 1;
1803c2c66affSColin Finck
1804c2c66affSColin Finck while (lpszGrp >= lpFormat->lpThousandSep)
1805c2c66affSColin Finck *szOut-- = *lpszGrp--; /* Write grouping char */
1806c2c66affSColin Finck
1807c2c66affSColin Finck dwCurrentGroupCount = 0;
1808c1fad347SKyle Katarn if (lpFormat->Grouping == 32)
1809c1fad347SKyle Katarn dwGroupCount = 2; /* Indic grouping: 3 then 2 */
1810c2c66affSColin Finck }
1811c2c66affSColin Finck }
1812c2c66affSColin Finck if (dwState & NF_ROUND)
1813c2c66affSColin Finck *szOut-- = '1'; /* e.g. .6 > 1.0 */
1814c2c66affSColin Finck else if (!(dwState & NF_DIGITS_OUT) && lpFormat->LeadingZero)
1815c2c66affSColin Finck *szOut-- = '0'; /* Add leading 0 if we have no digits before the decimal point */
1816c2c66affSColin Finck
1817c2c66affSColin Finck /* Add any leading negative or currency sign */
1818c2c66affSColin Finck while (dwFmt & (CF_MINUS_LEFT|CF_CY_LEFT))
1819c2c66affSColin Finck {
1820c2c66affSColin Finck switch (dwFmt & (CF_MINUS_LEFT|CF_MINUS_BEFORE|CF_CY_LEFT))
1821c2c66affSColin Finck {
1822c2c66affSColin Finck case CF_MINUS_LEFT:
1823c2c66affSColin Finck case CF_MINUS_LEFT|CF_CY_LEFT:
1824c2c66affSColin Finck while (lpszNeg >= lpszNegStart)
1825c2c66affSColin Finck *szOut-- = *lpszNeg--;
1826c2c66affSColin Finck dwFmt &= ~CF_MINUS_LEFT;
1827c2c66affSColin Finck break;
1828c2c66affSColin Finck
1829c2c66affSColin Finck case CF_CY_LEFT:
1830c2c66affSColin Finck case CF_CY_LEFT|CF_MINUS_BEFORE:
1831c2c66affSColin Finck case CF_MINUS_LEFT|CF_MINUS_BEFORE|CF_CY_LEFT:
1832c2c66affSColin Finck if (dwFmt & CF_CY_SPACE)
1833c2c66affSColin Finck *szOut-- = ' ';
1834c2c66affSColin Finck while (lpszCy >= lpszCyStart)
1835c2c66affSColin Finck *szOut-- = *lpszCy--;
1836c2c66affSColin Finck dwFmt &= ~(CF_CY_LEFT|CF_MINUS_BEFORE);
1837c2c66affSColin Finck break;
1838c2c66affSColin Finck }
1839c2c66affSColin Finck }
1840c2c66affSColin Finck if (dwFmt & CF_PARENS)
1841c2c66affSColin Finck *szOut-- = '(';
1842c2c66affSColin Finck szOut++;
1843c2c66affSColin Finck
1844c2c66affSColin Finck iRet = strlenW(szOut) + 1;
1845c2c66affSColin Finck if (cchOut)
1846c2c66affSColin Finck {
1847c2c66affSColin Finck if (iRet <= cchOut)
1848c2c66affSColin Finck memcpy(lpCurrencyStr, szOut, iRet * sizeof(WCHAR));
1849c2c66affSColin Finck else
1850c2c66affSColin Finck {
1851c2c66affSColin Finck memcpy(lpCurrencyStr, szOut, cchOut * sizeof(WCHAR));
1852c2c66affSColin Finck lpCurrencyStr[cchOut - 1] = '\0';
1853c2c66affSColin Finck SetLastError(ERROR_INSUFFICIENT_BUFFER);
1854c2c66affSColin Finck iRet = 0;
1855c2c66affSColin Finck }
1856c2c66affSColin Finck }
1857c2c66affSColin Finck return iRet;
1858c2c66affSColin Finck
1859c2c66affSColin Finck error:
1860c2c66affSColin Finck SetLastError(lpFormat && dwFlags ? ERROR_INVALID_FLAGS : ERROR_INVALID_PARAMETER);
1861c2c66affSColin Finck return 0;
1862c2c66affSColin Finck }
1863c2c66affSColin Finck
1864655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
1865655d24d9SDenis Malikov /***********************************************************************
1866655d24d9SDenis Malikov * GetCurrencyFormatEx (KERNEL32.@)
1867655d24d9SDenis Malikov */
GetCurrencyFormatEx(LPCWSTR localename,DWORD flags,LPCWSTR value,const CURRENCYFMTW * format,LPWSTR str,int len)1868655d24d9SDenis Malikov int WINAPI GetCurrencyFormatEx(LPCWSTR localename, DWORD flags, LPCWSTR value,
1869655d24d9SDenis Malikov const CURRENCYFMTW *format, LPWSTR str, int len)
1870655d24d9SDenis Malikov {
1871655d24d9SDenis Malikov TRACE("(%s,0x%08x,%s,%p,%p,%d)\n", debugstr_w(localename), flags,
1872655d24d9SDenis Malikov debugstr_w(value), format, str, len);
1873655d24d9SDenis Malikov
1874655d24d9SDenis Malikov return GetCurrencyFormatW( LocaleNameToLCID(localename, 0), flags, value, format, str, len);
1875655d24d9SDenis Malikov }
1876655d24d9SDenis Malikov #endif
1877655d24d9SDenis Malikov
1878655d24d9SDenis Malikov
1879c2c66affSColin Finck /* FIXME: Everything below here needs to move somewhere else along with the
1880c2c66affSColin Finck * other EnumXXX functions, when a method for storing resources for
1881c2c66affSColin Finck * alternate calendars is determined.
1882c2c66affSColin Finck */
1883c2c66affSColin Finck
1884c2c66affSColin Finck enum enum_callback_type {
1885c2c66affSColin Finck CALLBACK_ENUMPROC,
1886c2c66affSColin Finck CALLBACK_ENUMPROCEX,
1887c2c66affSColin Finck CALLBACK_ENUMPROCEXEX
1888c2c66affSColin Finck };
1889c2c66affSColin Finck
1890c2c66affSColin Finck struct enumdateformats_context {
1891c2c66affSColin Finck enum enum_callback_type type; /* callback kind */
1892c2c66affSColin Finck union {
1893c2c66affSColin Finck DATEFMT_ENUMPROCW callback; /* user callback pointer */
1894c2c66affSColin Finck DATEFMT_ENUMPROCEXW callbackex;
1895c2c66affSColin Finck DATEFMT_ENUMPROCEXEX callbackexex;
1896c2c66affSColin Finck } u;
1897c2c66affSColin Finck LCID lcid; /* locale of interest */
1898c2c66affSColin Finck DWORD flags;
1899c2c66affSColin Finck LPARAM lParam;
1900c2c66affSColin Finck BOOL unicode; /* A vs W callback type, only for regular and Ex callbacks */
1901c2c66affSColin Finck };
1902c2c66affSColin Finck
1903c2c66affSColin Finck /******************************************************************************
1904c2c66affSColin Finck * NLS_EnumDateFormats <internal>
1905c2c66affSColin Finck * Enumerates date formats for a specified locale.
1906c2c66affSColin Finck *
1907c2c66affSColin Finck * PARAMS
1908c2c66affSColin Finck * ctxt [I] enumeration context, see 'struct enumdateformats_context'
1909c2c66affSColin Finck *
1910c2c66affSColin Finck * RETURNS
1911c2c66affSColin Finck * Success: TRUE.
1912c2c66affSColin Finck * Failure: FALSE. Use GetLastError() to determine the cause.
1913c2c66affSColin Finck */
NLS_EnumDateFormats(const struct enumdateformats_context * ctxt)1914c2c66affSColin Finck static BOOL NLS_EnumDateFormats(const struct enumdateformats_context *ctxt)
1915c2c66affSColin Finck {
1916c2c66affSColin Finck WCHAR bufW[256];
1917c2c66affSColin Finck char bufA[256];
1918c2c66affSColin Finck LCTYPE lctype;
1919c2c66affSColin Finck CALID cal_id;
1920c2c66affSColin Finck INT ret;
1921c2c66affSColin Finck
1922c2c66affSColin Finck if (!ctxt->u.callback)
1923c2c66affSColin Finck {
1924c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1925c2c66affSColin Finck return FALSE;
1926c2c66affSColin Finck }
1927c2c66affSColin Finck
1928c2c66affSColin Finck if (!GetLocaleInfoW(ctxt->lcid, LOCALE_ICALENDARTYPE|LOCALE_RETURN_NUMBER, (LPWSTR)&cal_id, sizeof(cal_id)/sizeof(WCHAR)))
1929c2c66affSColin Finck return FALSE;
1930c2c66affSColin Finck
1931c2c66affSColin Finck switch (ctxt->flags & ~LOCALE_USE_CP_ACP)
1932c2c66affSColin Finck {
1933c2c66affSColin Finck case 0:
1934c2c66affSColin Finck case DATE_SHORTDATE:
1935c2c66affSColin Finck lctype = LOCALE_SSHORTDATE;
1936c2c66affSColin Finck break;
1937c2c66affSColin Finck case DATE_LONGDATE:
1938c2c66affSColin Finck lctype = LOCALE_SLONGDATE;
1939c2c66affSColin Finck break;
1940c2c66affSColin Finck case DATE_YEARMONTH:
1941c2c66affSColin Finck lctype = LOCALE_SYEARMONTH;
1942c2c66affSColin Finck break;
1943c2c66affSColin Finck default:
1944c2c66affSColin Finck FIXME("Unknown date format (0x%08x)\n", ctxt->flags);
1945c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
1946c2c66affSColin Finck return FALSE;
1947c2c66affSColin Finck }
1948c2c66affSColin Finck
1949c2c66affSColin Finck lctype |= ctxt->flags & LOCALE_USE_CP_ACP;
1950c2c66affSColin Finck if (ctxt->unicode)
1951655d24d9SDenis Malikov ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, ARRAY_SIZE(bufW));
1952c2c66affSColin Finck else
1953655d24d9SDenis Malikov ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, ARRAY_SIZE(bufA));
1954c2c66affSColin Finck
1955c2c66affSColin Finck if (ret)
1956c2c66affSColin Finck {
1957c2c66affSColin Finck switch (ctxt->type)
1958c2c66affSColin Finck {
1959c2c66affSColin Finck case CALLBACK_ENUMPROC:
1960c2c66affSColin Finck ctxt->u.callback(ctxt->unicode ? bufW : (WCHAR*)bufA);
1961c2c66affSColin Finck break;
1962c2c66affSColin Finck case CALLBACK_ENUMPROCEX:
1963c2c66affSColin Finck ctxt->u.callbackex(ctxt->unicode ? bufW : (WCHAR*)bufA, cal_id);
1964c2c66affSColin Finck break;
1965c2c66affSColin Finck case CALLBACK_ENUMPROCEXEX:
1966c2c66affSColin Finck ctxt->u.callbackexex(bufW, cal_id, ctxt->lParam);
1967c2c66affSColin Finck break;
1968c2c66affSColin Finck default:
1969c2c66affSColin Finck ;
1970c2c66affSColin Finck }
1971c2c66affSColin Finck }
1972c2c66affSColin Finck
1973c2c66affSColin Finck return TRUE;
1974c2c66affSColin Finck }
1975c2c66affSColin Finck
1976c2c66affSColin Finck /**************************************************************************
1977c2c66affSColin Finck * EnumDateFormatsExA (KERNEL32.@)
1978c2c66affSColin Finck *
1979c2c66affSColin Finck * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
1980c2c66affSColin Finck * LOCALE_NOUSEROVERRIDE here as well?
1981c2c66affSColin Finck */
EnumDateFormatsExA(DATEFMT_ENUMPROCEXA proc,LCID lcid,DWORD flags)1982c2c66affSColin Finck BOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA proc, LCID lcid, DWORD flags)
1983c2c66affSColin Finck {
1984c2c66affSColin Finck struct enumdateformats_context ctxt;
1985c2c66affSColin Finck
1986c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROCEX;
1987c2c66affSColin Finck ctxt.u.callbackex = (DATEFMT_ENUMPROCEXW)proc;
1988c2c66affSColin Finck ctxt.lcid = lcid;
1989c2c66affSColin Finck ctxt.flags = flags;
1990c2c66affSColin Finck ctxt.unicode = FALSE;
1991c2c66affSColin Finck
1992c2c66affSColin Finck return NLS_EnumDateFormats(&ctxt);
1993c2c66affSColin Finck }
1994c2c66affSColin Finck
1995c2c66affSColin Finck /**************************************************************************
1996c2c66affSColin Finck * EnumDateFormatsExW (KERNEL32.@)
1997c2c66affSColin Finck */
EnumDateFormatsExW(DATEFMT_ENUMPROCEXW proc,LCID lcid,DWORD flags)1998c2c66affSColin Finck BOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW proc, LCID lcid, DWORD flags)
1999c2c66affSColin Finck {
2000c2c66affSColin Finck struct enumdateformats_context ctxt;
2001c2c66affSColin Finck
2002c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROCEX;
2003c2c66affSColin Finck ctxt.u.callbackex = proc;
2004c2c66affSColin Finck ctxt.lcid = lcid;
2005c2c66affSColin Finck ctxt.flags = flags;
2006c2c66affSColin Finck ctxt.unicode = TRUE;
2007c2c66affSColin Finck
2008c2c66affSColin Finck return NLS_EnumDateFormats(&ctxt);
2009c2c66affSColin Finck }
2010c2c66affSColin Finck
2011c2c66affSColin Finck /**************************************************************************
2012c2c66affSColin Finck * EnumDateFormatsA (KERNEL32.@)
2013c2c66affSColin Finck *
2014c2c66affSColin Finck * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
2015c2c66affSColin Finck * LOCALE_NOUSEROVERRIDE here as well?
2016c2c66affSColin Finck */
EnumDateFormatsA(DATEFMT_ENUMPROCA proc,LCID lcid,DWORD flags)2017c2c66affSColin Finck BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA proc, LCID lcid, DWORD flags)
2018c2c66affSColin Finck {
2019c2c66affSColin Finck struct enumdateformats_context ctxt;
2020c2c66affSColin Finck
2021c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2022c2c66affSColin Finck ctxt.u.callback = (DATEFMT_ENUMPROCW)proc;
2023c2c66affSColin Finck ctxt.lcid = lcid;
2024c2c66affSColin Finck ctxt.flags = flags;
2025c2c66affSColin Finck ctxt.unicode = FALSE;
2026c2c66affSColin Finck
2027c2c66affSColin Finck return NLS_EnumDateFormats(&ctxt);
2028c2c66affSColin Finck }
2029c2c66affSColin Finck
2030c2c66affSColin Finck /**************************************************************************
2031c2c66affSColin Finck * EnumDateFormatsW (KERNEL32.@)
2032c2c66affSColin Finck */
EnumDateFormatsW(DATEFMT_ENUMPROCW proc,LCID lcid,DWORD flags)2033c2c66affSColin Finck BOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW proc, LCID lcid, DWORD flags)
2034c2c66affSColin Finck {
2035c2c66affSColin Finck struct enumdateformats_context ctxt;
2036c2c66affSColin Finck
2037c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2038c2c66affSColin Finck ctxt.u.callback = proc;
2039c2c66affSColin Finck ctxt.lcid = lcid;
2040c2c66affSColin Finck ctxt.flags = flags;
2041c2c66affSColin Finck ctxt.unicode = TRUE;
2042c2c66affSColin Finck
2043c2c66affSColin Finck return NLS_EnumDateFormats(&ctxt);
2044c2c66affSColin Finck }
2045c2c66affSColin Finck
2046655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
2047cf14b6b2SAmine Khaldi /**************************************************************************
2048cf14b6b2SAmine Khaldi * EnumDateFormatsExEx (KERNEL32.@)
2049cf14b6b2SAmine Khaldi */
EnumDateFormatsExEx(DATEFMT_ENUMPROCEXEX proc,const WCHAR * locale,DWORD flags,LPARAM lParam)2050cf14b6b2SAmine Khaldi BOOL WINAPI EnumDateFormatsExEx(DATEFMT_ENUMPROCEXEX proc, const WCHAR *locale, DWORD flags, LPARAM lParam)
2051cf14b6b2SAmine Khaldi {
2052cf14b6b2SAmine Khaldi struct enumdateformats_context ctxt;
2053cf14b6b2SAmine Khaldi
2054cf14b6b2SAmine Khaldi ctxt.type = CALLBACK_ENUMPROCEXEX;
2055cf14b6b2SAmine Khaldi ctxt.u.callbackexex = proc;
2056cf14b6b2SAmine Khaldi ctxt.lcid = LocaleNameToLCID(locale, 0);
2057cf14b6b2SAmine Khaldi ctxt.flags = flags;
2058cf14b6b2SAmine Khaldi ctxt.lParam = lParam;
2059cf14b6b2SAmine Khaldi ctxt.unicode = TRUE;
2060cf14b6b2SAmine Khaldi
2061cf14b6b2SAmine Khaldi return NLS_EnumDateFormats(&ctxt);
2062cf14b6b2SAmine Khaldi }
2063655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
2064cf14b6b2SAmine Khaldi
2065c2c66affSColin Finck struct enumtimeformats_context {
2066c2c66affSColin Finck enum enum_callback_type type; /* callback kind */
2067c2c66affSColin Finck union {
2068c2c66affSColin Finck TIMEFMT_ENUMPROCW callback; /* user callback pointer */
2069c2c66affSColin Finck TIMEFMT_ENUMPROCEX callbackex;
2070c2c66affSColin Finck } u;
2071c2c66affSColin Finck LCID lcid; /* locale of interest */
2072c2c66affSColin Finck DWORD flags;
2073c2c66affSColin Finck LPARAM lParam;
2074c2c66affSColin Finck BOOL unicode; /* A vs W callback type, only for regular and Ex callbacks */
2075c2c66affSColin Finck };
2076c2c66affSColin Finck
NLS_EnumTimeFormats(struct enumtimeformats_context * ctxt)2077c2c66affSColin Finck static BOOL NLS_EnumTimeFormats(struct enumtimeformats_context *ctxt)
2078c2c66affSColin Finck {
2079c2c66affSColin Finck WCHAR bufW[256];
2080c2c66affSColin Finck char bufA[256];
2081c2c66affSColin Finck LCTYPE lctype;
2082c2c66affSColin Finck INT ret;
2083c2c66affSColin Finck
2084c2c66affSColin Finck if (!ctxt->u.callback)
2085c2c66affSColin Finck {
2086c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
2087c2c66affSColin Finck return FALSE;
2088c2c66affSColin Finck }
2089c2c66affSColin Finck
2090c2c66affSColin Finck switch (ctxt->flags & ~LOCALE_USE_CP_ACP)
2091c2c66affSColin Finck {
2092c2c66affSColin Finck case 0:
2093c2c66affSColin Finck lctype = LOCALE_STIMEFORMAT;
2094c2c66affSColin Finck break;
2095c2c66affSColin Finck case TIME_NOSECONDS:
2096c2c66affSColin Finck lctype = LOCALE_SSHORTTIME;
2097c2c66affSColin Finck break;
2098c2c66affSColin Finck default:
2099c2c66affSColin Finck FIXME("Unknown time format (%d)\n", ctxt->flags);
2100c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
2101c2c66affSColin Finck return FALSE;
2102c2c66affSColin Finck }
2103c2c66affSColin Finck
2104c2c66affSColin Finck lctype |= ctxt->flags & LOCALE_USE_CP_ACP;
2105c2c66affSColin Finck if (ctxt->unicode)
2106655d24d9SDenis Malikov ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, ARRAY_SIZE(bufW));
2107c2c66affSColin Finck else
2108655d24d9SDenis Malikov ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, ARRAY_SIZE(bufA));
2109c2c66affSColin Finck
2110c2c66affSColin Finck if (ret)
2111c2c66affSColin Finck {
2112c2c66affSColin Finck switch (ctxt->type)
2113c2c66affSColin Finck {
2114c2c66affSColin Finck case CALLBACK_ENUMPROC:
2115c2c66affSColin Finck ctxt->u.callback(ctxt->unicode ? bufW : (WCHAR*)bufA);
2116c2c66affSColin Finck break;
2117c2c66affSColin Finck case CALLBACK_ENUMPROCEX:
2118c2c66affSColin Finck ctxt->u.callbackex(bufW, ctxt->lParam);
2119c2c66affSColin Finck break;
2120c2c66affSColin Finck default:
2121c2c66affSColin Finck ;
2122c2c66affSColin Finck }
2123c2c66affSColin Finck }
2124c2c66affSColin Finck
2125c2c66affSColin Finck return TRUE;
2126c2c66affSColin Finck }
2127c2c66affSColin Finck
2128c2c66affSColin Finck /**************************************************************************
2129c2c66affSColin Finck * EnumTimeFormatsA (KERNEL32.@)
2130c2c66affSColin Finck *
2131c2c66affSColin Finck * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle
2132c2c66affSColin Finck * LOCALE_NOUSEROVERRIDE here as well?
2133c2c66affSColin Finck */
EnumTimeFormatsA(TIMEFMT_ENUMPROCA proc,LCID lcid,DWORD flags)2134c2c66affSColin Finck BOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA proc, LCID lcid, DWORD flags)
2135c2c66affSColin Finck {
2136c2c66affSColin Finck struct enumtimeformats_context ctxt;
2137c2c66affSColin Finck
2138c2c66affSColin Finck /* EnumTimeFormatsA doesn't support flags, EnumTimeFormatsW does. */
2139c2c66affSColin Finck if (flags & ~LOCALE_USE_CP_ACP)
2140c2c66affSColin Finck {
2141c2c66affSColin Finck SetLastError(ERROR_INVALID_FLAGS);
2142c2c66affSColin Finck return FALSE;
2143c2c66affSColin Finck }
2144c2c66affSColin Finck
2145c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2146c2c66affSColin Finck ctxt.u.callback = (TIMEFMT_ENUMPROCW)proc;
2147c2c66affSColin Finck ctxt.lcid = lcid;
2148c2c66affSColin Finck ctxt.flags = flags;
2149c2c66affSColin Finck ctxt.unicode = FALSE;
2150c2c66affSColin Finck
2151c2c66affSColin Finck return NLS_EnumTimeFormats(&ctxt);
2152c2c66affSColin Finck }
2153c2c66affSColin Finck
2154c2c66affSColin Finck /**************************************************************************
2155c2c66affSColin Finck * EnumTimeFormatsW (KERNEL32.@)
2156c2c66affSColin Finck */
EnumTimeFormatsW(TIMEFMT_ENUMPROCW proc,LCID lcid,DWORD flags)2157c2c66affSColin Finck BOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW proc, LCID lcid, DWORD flags)
2158c2c66affSColin Finck {
2159c2c66affSColin Finck struct enumtimeformats_context ctxt;
2160c2c66affSColin Finck
2161c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2162c2c66affSColin Finck ctxt.u.callback = proc;
2163c2c66affSColin Finck ctxt.lcid = lcid;
2164c2c66affSColin Finck ctxt.flags = flags;
2165c2c66affSColin Finck ctxt.unicode = TRUE;
2166c2c66affSColin Finck
2167c2c66affSColin Finck return NLS_EnumTimeFormats(&ctxt);
2168c2c66affSColin Finck }
2169c2c66affSColin Finck
2170655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
2171cf14b6b2SAmine Khaldi /**************************************************************************
2172cf14b6b2SAmine Khaldi * EnumTimeFormatsEx (KERNEL32.@)
2173cf14b6b2SAmine Khaldi */
EnumTimeFormatsEx(TIMEFMT_ENUMPROCEX proc,const WCHAR * locale,DWORD flags,LPARAM lParam)2174cf14b6b2SAmine Khaldi BOOL WINAPI EnumTimeFormatsEx(TIMEFMT_ENUMPROCEX proc, const WCHAR *locale, DWORD flags, LPARAM lParam)
2175cf14b6b2SAmine Khaldi {
2176cf14b6b2SAmine Khaldi struct enumtimeformats_context ctxt;
2177cf14b6b2SAmine Khaldi
2178cf14b6b2SAmine Khaldi ctxt.type = CALLBACK_ENUMPROCEX;
2179cf14b6b2SAmine Khaldi ctxt.u.callbackex = proc;
2180cf14b6b2SAmine Khaldi ctxt.lcid = LocaleNameToLCID(locale, 0);
2181cf14b6b2SAmine Khaldi ctxt.flags = flags;
2182cf14b6b2SAmine Khaldi ctxt.lParam = lParam;
2183cf14b6b2SAmine Khaldi ctxt.unicode = TRUE;
2184cf14b6b2SAmine Khaldi
2185cf14b6b2SAmine Khaldi return NLS_EnumTimeFormats(&ctxt);
2186cf14b6b2SAmine Khaldi }
2187655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
2188cf14b6b2SAmine Khaldi
2189c2c66affSColin Finck struct enumcalendar_context {
2190c2c66affSColin Finck enum enum_callback_type type; /* callback kind */
2191c2c66affSColin Finck union {
2192c2c66affSColin Finck CALINFO_ENUMPROCW callback; /* user callback pointer */
2193c2c66affSColin Finck CALINFO_ENUMPROCEXW callbackex;
2194c2c66affSColin Finck CALINFO_ENUMPROCEXEX callbackexex;
2195c2c66affSColin Finck } u;
2196c2c66affSColin Finck LCID lcid; /* locale of interest */
2197c2c66affSColin Finck CALID calendar; /* specific calendar or ENUM_ALL_CALENDARS */
2198c2c66affSColin Finck CALTYPE caltype; /* calendar information type */
2199c2c66affSColin Finck LPARAM lParam; /* user input parameter passed to callback, for ExEx case only */
2200c2c66affSColin Finck BOOL unicode; /* A vs W callback type, only for regular and Ex callbacks */
2201c2c66affSColin Finck };
2202c2c66affSColin Finck
2203c2c66affSColin Finck /******************************************************************************
2204c2c66affSColin Finck * NLS_EnumCalendarInfo <internal>
2205c2c66affSColin Finck * Enumerates calendar information for a specified locale.
2206c2c66affSColin Finck *
2207c2c66affSColin Finck * PARAMS
2208c2c66affSColin Finck * ctxt [I] enumeration context, see 'struct enumcalendar_context'
2209c2c66affSColin Finck *
2210c2c66affSColin Finck * RETURNS
2211c2c66affSColin Finck * Success: TRUE.
2212c2c66affSColin Finck * Failure: FALSE. Use GetLastError() to determine the cause.
2213c2c66affSColin Finck *
2214c2c66affSColin Finck * NOTES
2215c2c66affSColin Finck * When the ANSI version of this function is used with a Unicode-only LCID,
2216c2c66affSColin Finck * the call can succeed because the system uses the system code page.
2217c2c66affSColin Finck * However, characters that are undefined in the system code page appear
2218c2c66affSColin Finck * in the string as a question mark (?).
2219c2c66affSColin Finck *
2220c2c66affSColin Finck * TODO
2221c2c66affSColin Finck * The above note should be respected by GetCalendarInfoA.
2222c2c66affSColin Finck */
NLS_EnumCalendarInfo(const struct enumcalendar_context * ctxt)2223c2c66affSColin Finck static BOOL NLS_EnumCalendarInfo(const struct enumcalendar_context *ctxt)
2224c2c66affSColin Finck {
2225c2c66affSColin Finck WCHAR *buf, *opt = NULL, *iter = NULL;
2226c2c66affSColin Finck CALID calendar = ctxt->calendar;
2227c2c66affSColin Finck BOOL ret = FALSE;
2228c2c66affSColin Finck int bufSz = 200; /* the size of the buffer */
2229c2c66affSColin Finck
2230c2c66affSColin Finck if (ctxt->u.callback == NULL)
2231c2c66affSColin Finck {
2232c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
2233c2c66affSColin Finck return FALSE;
2234c2c66affSColin Finck }
2235c2c66affSColin Finck
2236c2c66affSColin Finck buf = HeapAlloc(GetProcessHeap(), 0, bufSz);
2237c2c66affSColin Finck if (buf == NULL)
2238c2c66affSColin Finck {
2239c2c66affSColin Finck SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2240c2c66affSColin Finck return FALSE;
2241c2c66affSColin Finck }
2242c2c66affSColin Finck
2243c2c66affSColin Finck if (calendar == ENUM_ALL_CALENDARS)
2244c2c66affSColin Finck {
2245c2c66affSColin Finck int optSz = GetLocaleInfoW(ctxt->lcid, LOCALE_IOPTIONALCALENDAR, NULL, 0);
2246c2c66affSColin Finck if (optSz > 1)
2247c2c66affSColin Finck {
2248c2c66affSColin Finck opt = HeapAlloc(GetProcessHeap(), 0, optSz * sizeof(WCHAR));
2249c2c66affSColin Finck if (opt == NULL)
2250c2c66affSColin Finck {
2251c2c66affSColin Finck SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2252c2c66affSColin Finck goto cleanup;
2253c2c66affSColin Finck }
2254c2c66affSColin Finck if (GetLocaleInfoW(ctxt->lcid, LOCALE_IOPTIONALCALENDAR, opt, optSz))
2255c2c66affSColin Finck iter = opt;
2256c2c66affSColin Finck }
2257c2c66affSColin Finck calendar = NLS_GetLocaleNumber(ctxt->lcid, LOCALE_ICALENDARTYPE);
2258c2c66affSColin Finck }
2259c2c66affSColin Finck
2260c2c66affSColin Finck while (TRUE) /* loop through calendars */
2261c2c66affSColin Finck {
2262c2c66affSColin Finck do /* loop until there's no error */
2263c2c66affSColin Finck {
2264c2c66affSColin Finck if (ctxt->caltype & CAL_RETURN_NUMBER)
2265c2c66affSColin Finck ret = GetCalendarInfoW(ctxt->lcid, calendar, ctxt->caltype, NULL, bufSz / sizeof(WCHAR), (LPDWORD)buf);
2266c2c66affSColin Finck else if (ctxt->unicode)
2267c2c66affSColin Finck ret = GetCalendarInfoW(ctxt->lcid, calendar, ctxt->caltype, buf, bufSz / sizeof(WCHAR), NULL);
2268c2c66affSColin Finck else ret = GetCalendarInfoA(ctxt->lcid, calendar, ctxt->caltype, (CHAR*)buf, bufSz / sizeof(CHAR), NULL);
2269c2c66affSColin Finck
2270c2c66affSColin Finck if (!ret)
2271c2c66affSColin Finck {
2272c2c66affSColin Finck if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2273c2c66affSColin Finck { /* so resize it */
2274c2c66affSColin Finck int newSz;
2275c2c66affSColin Finck if (ctxt->unicode)
2276c2c66affSColin Finck newSz = GetCalendarInfoW(ctxt->lcid, calendar, ctxt->caltype, NULL, 0, NULL) * sizeof(WCHAR);
2277c2c66affSColin Finck else newSz = GetCalendarInfoA(ctxt->lcid, calendar, ctxt->caltype, NULL, 0, NULL) * sizeof(CHAR);
2278c2c66affSColin Finck if (bufSz >= newSz)
2279c2c66affSColin Finck {
2280c2c66affSColin Finck ERR("Buffer resizing disorder: was %d, requested %d.\n", bufSz, newSz);
2281c2c66affSColin Finck goto cleanup;
2282c2c66affSColin Finck }
2283c2c66affSColin Finck bufSz = newSz;
2284c2c66affSColin Finck WARN("Buffer too small; resizing to %d bytes.\n", bufSz);
2285c2c66affSColin Finck buf = HeapReAlloc(GetProcessHeap(), 0, buf, bufSz);
2286c2c66affSColin Finck if (buf == NULL)
2287c2c66affSColin Finck goto cleanup;
2288c2c66affSColin Finck } else goto cleanup;
2289c2c66affSColin Finck }
2290c2c66affSColin Finck } while (!ret);
2291c2c66affSColin Finck
2292c2c66affSColin Finck /* Here we are. We pass the buffer to the correct version of
2293c2c66affSColin Finck * the callback. Because it's not the same number of params,
2294c2c66affSColin Finck * we must check for Ex, but we don't care about Unicode
2295c2c66affSColin Finck * because the buffer is already in the correct format.
2296c2c66affSColin Finck */
2297c2c66affSColin Finck switch (ctxt->type)
2298c2c66affSColin Finck {
2299c2c66affSColin Finck case CALLBACK_ENUMPROC:
2300c2c66affSColin Finck ret = ctxt->u.callback(buf);
2301c2c66affSColin Finck break;
2302c2c66affSColin Finck case CALLBACK_ENUMPROCEX:
2303c2c66affSColin Finck ret = ctxt->u.callbackex(buf, calendar);
2304c2c66affSColin Finck break;
2305c2c66affSColin Finck case CALLBACK_ENUMPROCEXEX:
2306c2c66affSColin Finck ret = ctxt->u.callbackexex(buf, calendar, NULL, ctxt->lParam);
2307c2c66affSColin Finck break;
2308c2c66affSColin Finck default:
2309c2c66affSColin Finck ;
2310c2c66affSColin Finck }
2311c2c66affSColin Finck
2312c2c66affSColin Finck if (!ret) { /* the callback told to stop */
2313c2c66affSColin Finck ret = TRUE;
2314c2c66affSColin Finck break;
2315c2c66affSColin Finck }
2316c2c66affSColin Finck
2317c2c66affSColin Finck if ((iter == NULL) || (*iter == 0)) /* no more calendars */
2318c2c66affSColin Finck break;
2319c2c66affSColin Finck
2320c2c66affSColin Finck calendar = 0;
2321c2c66affSColin Finck while ((*iter >= '0') && (*iter <= '9'))
2322c2c66affSColin Finck calendar = calendar * 10 + *iter++ - '0';
2323c2c66affSColin Finck
2324c2c66affSColin Finck if (*iter++ != 0)
2325c2c66affSColin Finck {
2326c2c66affSColin Finck SetLastError(ERROR_BADDB);
2327c2c66affSColin Finck ret = FALSE;
2328c2c66affSColin Finck break;
2329c2c66affSColin Finck }
2330c2c66affSColin Finck }
2331c2c66affSColin Finck
2332c2c66affSColin Finck cleanup:
2333c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, opt);
2334c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, buf);
2335c2c66affSColin Finck return ret;
2336c2c66affSColin Finck }
2337c2c66affSColin Finck
2338c2c66affSColin Finck /******************************************************************************
2339c2c66affSColin Finck * EnumCalendarInfoA [KERNEL32.@]
2340c2c66affSColin Finck */
EnumCalendarInfoA(CALINFO_ENUMPROCA calinfoproc,LCID locale,CALID calendar,CALTYPE caltype)2341c2c66affSColin Finck BOOL WINAPI EnumCalendarInfoA( CALINFO_ENUMPROCA calinfoproc,LCID locale,
2342c2c66affSColin Finck CALID calendar,CALTYPE caltype )
2343c2c66affSColin Finck {
2344c2c66affSColin Finck struct enumcalendar_context ctxt;
2345c2c66affSColin Finck
2346c2c66affSColin Finck TRACE("(%p,0x%08x,0x%08x,0x%08x)\n", calinfoproc, locale, calendar, caltype);
2347c2c66affSColin Finck
2348c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2349c2c66affSColin Finck ctxt.u.callback = (CALINFO_ENUMPROCW)calinfoproc;
2350c2c66affSColin Finck ctxt.lcid = locale;
2351c2c66affSColin Finck ctxt.calendar = calendar;
2352c2c66affSColin Finck ctxt.caltype = caltype;
2353c2c66affSColin Finck ctxt.lParam = 0;
2354c2c66affSColin Finck ctxt.unicode = FALSE;
2355c2c66affSColin Finck return NLS_EnumCalendarInfo(&ctxt);
2356c2c66affSColin Finck }
2357c2c66affSColin Finck
2358c2c66affSColin Finck /******************************************************************************
2359c2c66affSColin Finck * EnumCalendarInfoW [KERNEL32.@]
2360c2c66affSColin Finck */
EnumCalendarInfoW(CALINFO_ENUMPROCW calinfoproc,LCID locale,CALID calendar,CALTYPE caltype)2361c2c66affSColin Finck BOOL WINAPI EnumCalendarInfoW( CALINFO_ENUMPROCW calinfoproc,LCID locale,
2362c2c66affSColin Finck CALID calendar,CALTYPE caltype )
2363c2c66affSColin Finck {
2364c2c66affSColin Finck struct enumcalendar_context ctxt;
2365c2c66affSColin Finck
2366c2c66affSColin Finck TRACE("(%p,0x%08x,0x%08x,0x%08x)\n", calinfoproc, locale, calendar, caltype);
2367c2c66affSColin Finck
2368c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROC;
2369c2c66affSColin Finck ctxt.u.callback = calinfoproc;
2370c2c66affSColin Finck ctxt.lcid = locale;
2371c2c66affSColin Finck ctxt.calendar = calendar;
2372c2c66affSColin Finck ctxt.caltype = caltype;
2373c2c66affSColin Finck ctxt.lParam = 0;
2374c2c66affSColin Finck ctxt.unicode = TRUE;
2375c2c66affSColin Finck return NLS_EnumCalendarInfo(&ctxt);
2376c2c66affSColin Finck }
2377c2c66affSColin Finck
2378c2c66affSColin Finck /******************************************************************************
2379c2c66affSColin Finck * EnumCalendarInfoExA [KERNEL32.@]
2380c2c66affSColin Finck */
EnumCalendarInfoExA(CALINFO_ENUMPROCEXA calinfoproc,LCID locale,CALID calendar,CALTYPE caltype)2381c2c66affSColin Finck BOOL WINAPI EnumCalendarInfoExA( CALINFO_ENUMPROCEXA calinfoproc,LCID locale,
2382c2c66affSColin Finck CALID calendar,CALTYPE caltype )
2383c2c66affSColin Finck {
2384c2c66affSColin Finck struct enumcalendar_context ctxt;
2385c2c66affSColin Finck
2386c2c66affSColin Finck TRACE("(%p,0x%08x,0x%08x,0x%08x)\n", calinfoproc, locale, calendar, caltype);
2387c2c66affSColin Finck
2388c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROCEX;
2389c2c66affSColin Finck ctxt.u.callbackex = (CALINFO_ENUMPROCEXW)calinfoproc;
2390c2c66affSColin Finck ctxt.lcid = locale;
2391c2c66affSColin Finck ctxt.calendar = calendar;
2392c2c66affSColin Finck ctxt.caltype = caltype;
2393c2c66affSColin Finck ctxt.lParam = 0;
2394c2c66affSColin Finck ctxt.unicode = FALSE;
2395c2c66affSColin Finck return NLS_EnumCalendarInfo(&ctxt);
2396c2c66affSColin Finck }
2397c2c66affSColin Finck
2398c2c66affSColin Finck /******************************************************************************
2399c2c66affSColin Finck * EnumCalendarInfoExW [KERNEL32.@]
2400c2c66affSColin Finck */
EnumCalendarInfoExW(CALINFO_ENUMPROCEXW calinfoproc,LCID locale,CALID calendar,CALTYPE caltype)2401c2c66affSColin Finck BOOL WINAPI EnumCalendarInfoExW( CALINFO_ENUMPROCEXW calinfoproc,LCID locale,
2402c2c66affSColin Finck CALID calendar,CALTYPE caltype )
2403c2c66affSColin Finck {
2404c2c66affSColin Finck struct enumcalendar_context ctxt;
2405c2c66affSColin Finck
2406c2c66affSColin Finck TRACE("(%p,0x%08x,0x%08x,0x%08x)\n", calinfoproc, locale, calendar, caltype);
2407c2c66affSColin Finck
2408c2c66affSColin Finck ctxt.type = CALLBACK_ENUMPROCEX;
2409c2c66affSColin Finck ctxt.u.callbackex = calinfoproc;
2410c2c66affSColin Finck ctxt.lcid = locale;
2411c2c66affSColin Finck ctxt.calendar = calendar;
2412c2c66affSColin Finck ctxt.caltype = caltype;
2413c2c66affSColin Finck ctxt.lParam = 0;
2414c2c66affSColin Finck ctxt.unicode = TRUE;
2415c2c66affSColin Finck return NLS_EnumCalendarInfo(&ctxt);
2416c2c66affSColin Finck }
2417c2c66affSColin Finck
2418655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
2419cf14b6b2SAmine Khaldi /******************************************************************************
2420cf14b6b2SAmine Khaldi * EnumCalendarInfoExEx [KERNEL32.@]
2421cf14b6b2SAmine Khaldi */
EnumCalendarInfoExEx(CALINFO_ENUMPROCEXEX calinfoproc,LPCWSTR locale,CALID calendar,LPCWSTR reserved,CALTYPE caltype,LPARAM lParam)2422cf14b6b2SAmine Khaldi BOOL WINAPI EnumCalendarInfoExEx( CALINFO_ENUMPROCEXEX calinfoproc, LPCWSTR locale, CALID calendar,
2423cf14b6b2SAmine Khaldi LPCWSTR reserved, CALTYPE caltype, LPARAM lParam)
2424cf14b6b2SAmine Khaldi {
2425cf14b6b2SAmine Khaldi struct enumcalendar_context ctxt;
2426cf14b6b2SAmine Khaldi
2427cf14b6b2SAmine Khaldi TRACE("(%p,%s,0x%08x,%p,0x%08x,0x%ld)\n", calinfoproc, debugstr_w(locale), calendar, reserved, caltype, lParam);
2428cf14b6b2SAmine Khaldi
2429cf14b6b2SAmine Khaldi ctxt.type = CALLBACK_ENUMPROCEXEX;
2430cf14b6b2SAmine Khaldi ctxt.u.callbackexex = calinfoproc;
2431cf14b6b2SAmine Khaldi ctxt.lcid = LocaleNameToLCID(locale, 0);
2432cf14b6b2SAmine Khaldi ctxt.calendar = calendar;
2433cf14b6b2SAmine Khaldi ctxt.caltype = caltype;
2434cf14b6b2SAmine Khaldi ctxt.lParam = lParam;
2435cf14b6b2SAmine Khaldi ctxt.unicode = TRUE;
2436cf14b6b2SAmine Khaldi return NLS_EnumCalendarInfo(&ctxt);
2437cf14b6b2SAmine Khaldi }
2438655d24d9SDenis Malikov #endif /* _WIN32_WINNT >= 0x600 */
2439cf14b6b2SAmine Khaldi
2440c2c66affSColin Finck /*********************************************************************
2441c2c66affSColin Finck * GetCalendarInfoA (KERNEL32.@)
2442c2c66affSColin Finck *
2443c2c66affSColin Finck */
GetCalendarInfoA(LCID lcid,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue)2444c2c66affSColin Finck int WINAPI GetCalendarInfoA(LCID lcid, CALID Calendar, CALTYPE CalType,
2445c2c66affSColin Finck LPSTR lpCalData, int cchData, LPDWORD lpValue)
2446c2c66affSColin Finck {
2447c2c66affSColin Finck int ret, cchDataW = cchData;
2448c2c66affSColin Finck LPWSTR lpCalDataW = NULL;
244915537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
245015537c3bSKatayama Hirofumi MZ DWORD cp = CP_ACP;
245115537c3bSKatayama Hirofumi MZ if (!(CalType & CAL_USE_CP_ACP))
245215537c3bSKatayama Hirofumi MZ {
245315537c3bSKatayama Hirofumi MZ DWORD dwFlags = ((CalType & CAL_NOUSEROVERRIDE) ? LOCALE_NOUSEROVERRIDE : 0);
245415537c3bSKatayama Hirofumi MZ const NLS_FORMAT_NODE *node = NLS_GetFormats(lcid, dwFlags);
245515537c3bSKatayama Hirofumi MZ if (!node)
245615537c3bSKatayama Hirofumi MZ {
245715537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
245815537c3bSKatayama Hirofumi MZ return 0;
245915537c3bSKatayama Hirofumi MZ }
246015537c3bSKatayama Hirofumi MZ cp = node->dwCodePage;
246115537c3bSKatayama Hirofumi MZ }
246215537c3bSKatayama Hirofumi MZ if ((CalType & 0xFFFF) == CAL_SABBREVERASTRING)
246315537c3bSKatayama Hirofumi MZ {
246415537c3bSKatayama Hirofumi MZ /* NOTE: CAL_SABBREVERASTRING is not supported in GetCalendarInfoA */
246515537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
246615537c3bSKatayama Hirofumi MZ return 0;
246715537c3bSKatayama Hirofumi MZ }
246815537c3bSKatayama Hirofumi MZ #endif
2469c2c66affSColin Finck
2470c2c66affSColin Finck if (NLS_IsUnicodeOnlyLcid(lcid))
2471c2c66affSColin Finck {
2472c2c66affSColin Finck SetLastError(ERROR_INVALID_PARAMETER);
2473c2c66affSColin Finck return 0;
2474c2c66affSColin Finck }
2475c2c66affSColin Finck
2476c2c66affSColin Finck if (!cchData && !(CalType & CAL_RETURN_NUMBER))
2477c2c66affSColin Finck cchDataW = GetCalendarInfoW(lcid, Calendar, CalType, NULL, 0, NULL);
2478c2c66affSColin Finck if (!(lpCalDataW = HeapAlloc(GetProcessHeap(), 0, cchDataW*sizeof(WCHAR))))
2479c2c66affSColin Finck return 0;
2480c2c66affSColin Finck
2481c2c66affSColin Finck ret = GetCalendarInfoW(lcid, Calendar, CalType, lpCalDataW, cchDataW, lpValue);
2482c2c66affSColin Finck if(ret && lpCalDataW && lpCalData)
248315537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
248415537c3bSKatayama Hirofumi MZ ret = WideCharToMultiByte(cp, 0, lpCalDataW, -1, lpCalData, cchData, NULL, NULL);
248515537c3bSKatayama Hirofumi MZ #else
2486c2c66affSColin Finck ret = WideCharToMultiByte(CP_ACP, 0, lpCalDataW, -1, lpCalData, cchData, NULL, NULL);
248715537c3bSKatayama Hirofumi MZ #endif
2488c2c66affSColin Finck else if (CalType & CAL_RETURN_NUMBER)
2489c2c66affSColin Finck ret *= sizeof(WCHAR);
2490c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, lpCalDataW);
2491c2c66affSColin Finck
2492c2c66affSColin Finck return ret;
2493c2c66affSColin Finck }
2494c2c66affSColin Finck
2495c2c66affSColin Finck /*********************************************************************
2496c2c66affSColin Finck * GetCalendarInfoW (KERNEL32.@)
2497c2c66affSColin Finck *
2498c2c66affSColin Finck */
GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue)2499c2c66affSColin Finck int WINAPI GetCalendarInfoW(LCID Locale, CALID Calendar, CALTYPE CalType,
2500c2c66affSColin Finck LPWSTR lpCalData, int cchData, LPDWORD lpValue)
2501c2c66affSColin Finck {
2502cf14b6b2SAmine Khaldi static const LCTYPE caltype_lctype_map[] = {
2503cf14b6b2SAmine Khaldi 0, /* not used */
2504cf14b6b2SAmine Khaldi 0, /* CAL_ICALINTVALUE */
2505cf14b6b2SAmine Khaldi 0, /* CAL_SCALNAME */
2506cf14b6b2SAmine Khaldi 0, /* CAL_IYEAROFFSETRANGE */
2507cf14b6b2SAmine Khaldi 0, /* CAL_SERASTRING */
2508cf14b6b2SAmine Khaldi LOCALE_SSHORTDATE,
2509cf14b6b2SAmine Khaldi LOCALE_SLONGDATE,
2510cf14b6b2SAmine Khaldi LOCALE_SDAYNAME1,
2511cf14b6b2SAmine Khaldi LOCALE_SDAYNAME2,
2512cf14b6b2SAmine Khaldi LOCALE_SDAYNAME3,
2513cf14b6b2SAmine Khaldi LOCALE_SDAYNAME4,
2514cf14b6b2SAmine Khaldi LOCALE_SDAYNAME5,
2515cf14b6b2SAmine Khaldi LOCALE_SDAYNAME6,
2516cf14b6b2SAmine Khaldi LOCALE_SDAYNAME7,
2517cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME1,
2518cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME2,
2519cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME3,
2520cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME4,
2521cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME5,
2522cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME6,
2523cf14b6b2SAmine Khaldi LOCALE_SABBREVDAYNAME7,
2524cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME1,
2525cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME2,
2526cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME3,
2527cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME4,
2528cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME5,
2529cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME6,
2530cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME7,
2531cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME8,
2532cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME9,
2533cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME10,
2534cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME11,
2535cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME12,
2536cf14b6b2SAmine Khaldi LOCALE_SMONTHNAME13,
2537cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME1,
2538cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME2,
2539cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME3,
2540cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME4,
2541cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME5,
2542cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME6,
2543cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME7,
2544cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME8,
2545cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME9,
2546cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME10,
2547cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME11,
2548cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME12,
2549cf14b6b2SAmine Khaldi LOCALE_SABBREVMONTHNAME13,
2550cf14b6b2SAmine Khaldi LOCALE_SYEARMONTH,
2551cf14b6b2SAmine Khaldi 0, /* CAL_ITWODIGITYEARMAX */
2552cf14b6b2SAmine Khaldi #if (WINVER >= 0x0600) /* ReactOS */
2553cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME1,
2554cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME2,
2555cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME3,
2556cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME4,
2557cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME5,
2558cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME6,
2559cf14b6b2SAmine Khaldi LOCALE_SSHORTESTDAYNAME7,
2560cf14b6b2SAmine Khaldi #endif
2561cf14b6b2SAmine Khaldi LOCALE_SMONTHDAY,
2562cf14b6b2SAmine Khaldi 0, /* CAL_SABBREVERASTRING */
2563cf14b6b2SAmine Khaldi };
2564cf14b6b2SAmine Khaldi DWORD localeflags = 0;
2565cf14b6b2SAmine Khaldi CALTYPE calinfo;
2566cf14b6b2SAmine Khaldi
2567c2c66affSColin Finck if (CalType & CAL_NOUSEROVERRIDE)
2568c2c66affSColin Finck FIXME("flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
2569c2c66affSColin Finck if (CalType & CAL_USE_CP_ACP)
2570c2c66affSColin Finck FIXME("flag CAL_USE_CP_ACP used, not fully implemented\n");
2571c2c66affSColin Finck
2572c2c66affSColin Finck if (CalType & CAL_RETURN_NUMBER) {
2573c2c66affSColin Finck if (!lpValue)
2574c2c66affSColin Finck {
2575c2c66affSColin Finck SetLastError( ERROR_INVALID_PARAMETER );
2576c2c66affSColin Finck return 0;
2577c2c66affSColin Finck }
2578c2c66affSColin Finck if (lpCalData != NULL)
2579c2c66affSColin Finck WARN("lpCalData not NULL (%p) when it should!\n", lpCalData);
2580c2c66affSColin Finck if (cchData != 0)
2581c2c66affSColin Finck WARN("cchData not 0 (%d) when it should!\n", cchData);
2582c2c66affSColin Finck } else {
2583c2c66affSColin Finck if (lpValue != NULL)
2584c2c66affSColin Finck WARN("lpValue not NULL (%p) when it should!\n", lpValue);
2585c2c66affSColin Finck }
2586c2c66affSColin Finck
2587c2c66affSColin Finck /* FIXME: No verification is made yet wrt Locale
2588c2c66affSColin Finck * for the CALTYPES not requiring GetLocaleInfoA */
2589cf14b6b2SAmine Khaldi
2590cf14b6b2SAmine Khaldi calinfo = CalType & 0xffff;
2591cf14b6b2SAmine Khaldi
2592cf14b6b2SAmine Khaldi #ifdef __REACTOS__
2593cf14b6b2SAmine Khaldi if (CalType & LOCALE_RETURN_GENITIVE_NAMES)
2594cf14b6b2SAmine Khaldi #else
2595cf14b6b2SAmine Khaldi if (CalType & CAL_RETURN_GENITIVE_NAMES)
2596cf14b6b2SAmine Khaldi #endif
2597cf14b6b2SAmine Khaldi localeflags |= LOCALE_RETURN_GENITIVE_NAMES;
2598cf14b6b2SAmine Khaldi
2599cf14b6b2SAmine Khaldi switch (calinfo) {
2600c2c66affSColin Finck case CAL_ICALINTVALUE:
260115537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
260215537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale))
260315537c3bSKatayama Hirofumi MZ {
260415537c3bSKatayama Hirofumi MZ if (CalType & CAL_RETURN_NUMBER)
260515537c3bSKatayama Hirofumi MZ {
260615537c3bSKatayama Hirofumi MZ *lpValue = CAL_JAPAN;
260715537c3bSKatayama Hirofumi MZ return sizeof(DWORD) / sizeof(WCHAR);
260815537c3bSKatayama Hirofumi MZ }
260915537c3bSKatayama Hirofumi MZ else
261015537c3bSKatayama Hirofumi MZ {
261115537c3bSKatayama Hirofumi MZ static const WCHAR fmtW[] = {'%','u',0};
261215537c3bSKatayama Hirofumi MZ WCHAR buffer[10];
261315537c3bSKatayama Hirofumi MZ int ret = snprintfW( buffer, 10, fmtW, CAL_JAPAN ) + 1;
261415537c3bSKatayama Hirofumi MZ if (!lpCalData) return ret;
261515537c3bSKatayama Hirofumi MZ if (ret <= cchData)
261615537c3bSKatayama Hirofumi MZ {
261715537c3bSKatayama Hirofumi MZ strcpyW( lpCalData, buffer );
261815537c3bSKatayama Hirofumi MZ return ret;
261915537c3bSKatayama Hirofumi MZ }
262015537c3bSKatayama Hirofumi MZ SetLastError( ERROR_INSUFFICIENT_BUFFER );
262115537c3bSKatayama Hirofumi MZ return 0;
262215537c3bSKatayama Hirofumi MZ }
262315537c3bSKatayama Hirofumi MZ }
262415537c3bSKatayama Hirofumi MZ #endif
2625c2c66affSColin Finck if (CalType & CAL_RETURN_NUMBER)
2626c2c66affSColin Finck return GetLocaleInfoW(Locale, LOCALE_RETURN_NUMBER | LOCALE_ICALENDARTYPE,
2627c2c66affSColin Finck (LPWSTR)lpValue, 2);
2628c2c66affSColin Finck return GetLocaleInfoW(Locale, LOCALE_ICALENDARTYPE, lpCalData, cchData);
2629c2c66affSColin Finck case CAL_SCALNAME:
263015537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
263115537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale) && Calendar == CAL_JAPAN)
263215537c3bSKatayama Hirofumi MZ {
263315537c3bSKatayama Hirofumi MZ // Wareki
263415537c3bSKatayama Hirofumi MZ lpCalData[0] = 0x548C;
263515537c3bSKatayama Hirofumi MZ lpCalData[1] = 0x66A6;
263615537c3bSKatayama Hirofumi MZ lpCalData[2] = 0;
263715537c3bSKatayama Hirofumi MZ return 3;
263815537c3bSKatayama Hirofumi MZ }
263915537c3bSKatayama Hirofumi MZ #endif
2640cf14b6b2SAmine Khaldi FIXME("Unimplemented caltype %d\n", calinfo);
2641c2c66affSColin Finck if (lpCalData) *lpCalData = 0;
2642c2c66affSColin Finck return 1;
2643c2c66affSColin Finck case CAL_IYEAROFFSETRANGE:
264415537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
264515537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale) && Calendar == CAL_JAPAN)
264615537c3bSKatayama Hirofumi MZ {
264715537c3bSKatayama Hirofumi MZ PCJAPANESE_ERA pEra = JapaneseEra_Find(NULL);
264815537c3bSKatayama Hirofumi MZ if (pEra)
264915537c3bSKatayama Hirofumi MZ {
265015537c3bSKatayama Hirofumi MZ if (CalType & CAL_RETURN_NUMBER)
265115537c3bSKatayama Hirofumi MZ {
265215537c3bSKatayama Hirofumi MZ *lpValue = pEra->wYear;
265315537c3bSKatayama Hirofumi MZ return sizeof(DWORD) / sizeof(WCHAR);
265415537c3bSKatayama Hirofumi MZ }
265515537c3bSKatayama Hirofumi MZ else
265615537c3bSKatayama Hirofumi MZ {
265715537c3bSKatayama Hirofumi MZ static const WCHAR fmtW[] = {'%','u',0};
265815537c3bSKatayama Hirofumi MZ WCHAR buffer[10];
265915537c3bSKatayama Hirofumi MZ int ret = snprintfW( buffer, 10, fmtW, pEra->wYear ) + 1;
266015537c3bSKatayama Hirofumi MZ if (!lpCalData) return ret;
266115537c3bSKatayama Hirofumi MZ if (ret <= cchData)
266215537c3bSKatayama Hirofumi MZ {
266315537c3bSKatayama Hirofumi MZ strcpyW( lpCalData, buffer );
266415537c3bSKatayama Hirofumi MZ return ret;
266515537c3bSKatayama Hirofumi MZ }
266615537c3bSKatayama Hirofumi MZ SetLastError( ERROR_INSUFFICIENT_BUFFER );
266715537c3bSKatayama Hirofumi MZ return 0;
266815537c3bSKatayama Hirofumi MZ }
266915537c3bSKatayama Hirofumi MZ }
267015537c3bSKatayama Hirofumi MZ else
267115537c3bSKatayama Hirofumi MZ {
267215537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
267315537c3bSKatayama Hirofumi MZ return 0;
267415537c3bSKatayama Hirofumi MZ }
267515537c3bSKatayama Hirofumi MZ }
267615537c3bSKatayama Hirofumi MZ #endif
2677cf14b6b2SAmine Khaldi FIXME("Unimplemented caltype %d\n", calinfo);
2678c2c66affSColin Finck return 0;
2679c2c66affSColin Finck case CAL_SERASTRING:
268015537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
268115537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale) && Calendar == CAL_JAPAN)
268215537c3bSKatayama Hirofumi MZ {
268315537c3bSKatayama Hirofumi MZ PCJAPANESE_ERA pEra = JapaneseEra_Find(NULL);
268415537c3bSKatayama Hirofumi MZ if (pEra)
268515537c3bSKatayama Hirofumi MZ {
268615537c3bSKatayama Hirofumi MZ RtlStringCchCopyW(lpCalData, cchData, pEra->szEraName);
268715537c3bSKatayama Hirofumi MZ return strlenW(lpCalData) + 1;
268815537c3bSKatayama Hirofumi MZ }
268915537c3bSKatayama Hirofumi MZ else
269015537c3bSKatayama Hirofumi MZ {
269115537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
269215537c3bSKatayama Hirofumi MZ return 0;
269315537c3bSKatayama Hirofumi MZ }
269415537c3bSKatayama Hirofumi MZ }
269515537c3bSKatayama Hirofumi MZ #endif
2696cf14b6b2SAmine Khaldi FIXME("Unimplemented caltype %d\n", calinfo);
2697c2c66affSColin Finck return 0;
2698c2c66affSColin Finck case CAL_SSHORTDATE:
2699c2c66affSColin Finck case CAL_SLONGDATE:
2700c2c66affSColin Finck case CAL_SDAYNAME1:
2701c2c66affSColin Finck case CAL_SDAYNAME2:
2702c2c66affSColin Finck case CAL_SDAYNAME3:
2703c2c66affSColin Finck case CAL_SDAYNAME4:
2704c2c66affSColin Finck case CAL_SDAYNAME5:
2705c2c66affSColin Finck case CAL_SDAYNAME6:
2706c2c66affSColin Finck case CAL_SDAYNAME7:
2707c2c66affSColin Finck case CAL_SABBREVDAYNAME1:
2708c2c66affSColin Finck case CAL_SABBREVDAYNAME2:
2709c2c66affSColin Finck case CAL_SABBREVDAYNAME3:
2710c2c66affSColin Finck case CAL_SABBREVDAYNAME4:
2711c2c66affSColin Finck case CAL_SABBREVDAYNAME5:
2712c2c66affSColin Finck case CAL_SABBREVDAYNAME6:
2713c2c66affSColin Finck case CAL_SABBREVDAYNAME7:
2714c2c66affSColin Finck case CAL_SMONTHNAME1:
2715c2c66affSColin Finck case CAL_SMONTHNAME2:
2716c2c66affSColin Finck case CAL_SMONTHNAME3:
2717c2c66affSColin Finck case CAL_SMONTHNAME4:
2718c2c66affSColin Finck case CAL_SMONTHNAME5:
2719c2c66affSColin Finck case CAL_SMONTHNAME6:
2720c2c66affSColin Finck case CAL_SMONTHNAME7:
2721c2c66affSColin Finck case CAL_SMONTHNAME8:
2722c2c66affSColin Finck case CAL_SMONTHNAME9:
2723c2c66affSColin Finck case CAL_SMONTHNAME10:
2724c2c66affSColin Finck case CAL_SMONTHNAME11:
2725c2c66affSColin Finck case CAL_SMONTHNAME12:
2726c2c66affSColin Finck case CAL_SMONTHNAME13:
2727c2c66affSColin Finck case CAL_SABBREVMONTHNAME1:
2728c2c66affSColin Finck case CAL_SABBREVMONTHNAME2:
2729c2c66affSColin Finck case CAL_SABBREVMONTHNAME3:
2730c2c66affSColin Finck case CAL_SABBREVMONTHNAME4:
2731c2c66affSColin Finck case CAL_SABBREVMONTHNAME5:
2732c2c66affSColin Finck case CAL_SABBREVMONTHNAME6:
2733c2c66affSColin Finck case CAL_SABBREVMONTHNAME7:
2734c2c66affSColin Finck case CAL_SABBREVMONTHNAME8:
2735c2c66affSColin Finck case CAL_SABBREVMONTHNAME9:
2736c2c66affSColin Finck case CAL_SABBREVMONTHNAME10:
2737c2c66affSColin Finck case CAL_SABBREVMONTHNAME11:
2738c2c66affSColin Finck case CAL_SABBREVMONTHNAME12:
2739c2c66affSColin Finck case CAL_SABBREVMONTHNAME13:
2740c2c66affSColin Finck case CAL_SYEARMONTH:
2741cf14b6b2SAmine Khaldi return GetLocaleInfoW(Locale, caltype_lctype_map[calinfo] | localeflags, lpCalData, cchData);
2742c2c66affSColin Finck case CAL_ITWODIGITYEARMAX:
274315537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
274415537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale) && Calendar == CAL_JAPAN)
274515537c3bSKatayama Hirofumi MZ {
274615537c3bSKatayama Hirofumi MZ if (CalType & CAL_RETURN_NUMBER)
274715537c3bSKatayama Hirofumi MZ {
274815537c3bSKatayama Hirofumi MZ *lpValue = JAPANESE_MAX_TWODIGITYEAR;
274915537c3bSKatayama Hirofumi MZ return sizeof(DWORD) / sizeof(WCHAR);
275015537c3bSKatayama Hirofumi MZ }
275115537c3bSKatayama Hirofumi MZ else
275215537c3bSKatayama Hirofumi MZ {
275315537c3bSKatayama Hirofumi MZ static const WCHAR fmtW[] = {'%','u',0};
275415537c3bSKatayama Hirofumi MZ WCHAR buffer[10];
275515537c3bSKatayama Hirofumi MZ int ret = snprintfW( buffer, 10, fmtW, JAPANESE_MAX_TWODIGITYEAR ) + 1;
275615537c3bSKatayama Hirofumi MZ if (!lpCalData) return ret;
275715537c3bSKatayama Hirofumi MZ if (ret <= cchData)
275815537c3bSKatayama Hirofumi MZ {
275915537c3bSKatayama Hirofumi MZ strcpyW( lpCalData, buffer );
276015537c3bSKatayama Hirofumi MZ return ret;
276115537c3bSKatayama Hirofumi MZ }
276215537c3bSKatayama Hirofumi MZ SetLastError( ERROR_INSUFFICIENT_BUFFER );
276315537c3bSKatayama Hirofumi MZ return 0;
276415537c3bSKatayama Hirofumi MZ }
276515537c3bSKatayama Hirofumi MZ }
276615537c3bSKatayama Hirofumi MZ #endif
2767c2c66affSColin Finck if (CalType & CAL_RETURN_NUMBER)
2768c2c66affSColin Finck {
2769c2c66affSColin Finck *lpValue = CALINFO_MAX_YEAR;
2770c2c66affSColin Finck return sizeof(DWORD) / sizeof(WCHAR);
2771c2c66affSColin Finck }
2772c2c66affSColin Finck else
2773c2c66affSColin Finck {
2774c2c66affSColin Finck static const WCHAR fmtW[] = {'%','u',0};
2775c2c66affSColin Finck WCHAR buffer[10];
2776c2c66affSColin Finck int ret = snprintfW( buffer, 10, fmtW, CALINFO_MAX_YEAR ) + 1;
2777c2c66affSColin Finck if (!lpCalData) return ret;
2778c2c66affSColin Finck if (ret <= cchData)
2779c2c66affSColin Finck {
2780c2c66affSColin Finck strcpyW( lpCalData, buffer );
2781c2c66affSColin Finck return ret;
2782c2c66affSColin Finck }
2783c2c66affSColin Finck SetLastError( ERROR_INSUFFICIENT_BUFFER );
2784c2c66affSColin Finck return 0;
2785c2c66affSColin Finck }
2786c2c66affSColin Finck break;
278715537c3bSKatayama Hirofumi MZ #ifdef __REACTOS__
278815537c3bSKatayama Hirofumi MZ case CAL_SABBREVERASTRING:
278915537c3bSKatayama Hirofumi MZ if (IS_LCID_JAPANESE(Locale) && Calendar == CAL_JAPAN)
279015537c3bSKatayama Hirofumi MZ {
279115537c3bSKatayama Hirofumi MZ PCJAPANESE_ERA pEra = JapaneseEra_Find(NULL);
279215537c3bSKatayama Hirofumi MZ if (pEra)
279315537c3bSKatayama Hirofumi MZ {
279415537c3bSKatayama Hirofumi MZ RtlStringCchCopyW(lpCalData, cchData, pEra->szEraAbbrev);
279515537c3bSKatayama Hirofumi MZ return strlenW(lpCalData) + 1;
279615537c3bSKatayama Hirofumi MZ }
279715537c3bSKatayama Hirofumi MZ }
279815537c3bSKatayama Hirofumi MZ SetLastError(ERROR_INVALID_PARAMETER);
279915537c3bSKatayama Hirofumi MZ return 0;
280015537c3bSKatayama Hirofumi MZ #endif
2801c2c66affSColin Finck default:
2802cf14b6b2SAmine Khaldi FIXME("Unknown caltype %d\n", calinfo);
2803c2c66affSColin Finck SetLastError(ERROR_INVALID_FLAGS);
2804c2c66affSColin Finck return 0;
2805c2c66affSColin Finck }
2806c2c66affSColin Finck return 0;
2807c2c66affSColin Finck }
2808c2c66affSColin Finck
2809655d24d9SDenis Malikov #if _WIN32_WINNT >= 0x600
2810655d24d9SDenis Malikov /*********************************************************************
2811655d24d9SDenis Malikov * GetCalendarInfoEx (KERNEL32.@)
2812655d24d9SDenis Malikov */
GetCalendarInfoEx(LPCWSTR locale,CALID calendar,LPCWSTR lpReserved,CALTYPE caltype,LPWSTR data,int len,DWORD * value)2813655d24d9SDenis Malikov int WINAPI GetCalendarInfoEx(LPCWSTR locale, CALID calendar, LPCWSTR lpReserved, CALTYPE caltype,
2814655d24d9SDenis Malikov LPWSTR data, int len, DWORD *value)
2815655d24d9SDenis Malikov {
2816655d24d9SDenis Malikov static int once;
2817655d24d9SDenis Malikov
2818655d24d9SDenis Malikov LCID lcid = LocaleNameToLCID(locale, 0);
2819655d24d9SDenis Malikov if (!once++)
2820655d24d9SDenis Malikov FIXME("(%s, %d, %p, 0x%08x, %p, %d, %p): semi-stub\n", debugstr_w(locale), calendar, lpReserved, caltype,
2821655d24d9SDenis Malikov data, len, value);
2822655d24d9SDenis Malikov return GetCalendarInfoW(lcid, calendar, caltype, data, len, value);
2823655d24d9SDenis Malikov }
2824655d24d9SDenis Malikov #endif
2825655d24d9SDenis Malikov
2826c2c66affSColin Finck /*********************************************************************
2827c2c66affSColin Finck * SetCalendarInfoA (KERNEL32.@)
2828c2c66affSColin Finck *
2829c2c66affSColin Finck */
SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData)2830c2c66affSColin Finck int WINAPI SetCalendarInfoA(LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData)
2831c2c66affSColin Finck {
2832c2c66affSColin Finck FIXME("(%08x,%08x,%08x,%s): stub\n",
2833c2c66affSColin Finck Locale, Calendar, CalType, debugstr_a(lpCalData));
2834c2c66affSColin Finck return 0;
2835c2c66affSColin Finck }
2836c2c66affSColin Finck
2837c2c66affSColin Finck /*********************************************************************
2838c2c66affSColin Finck * SetCalendarInfoW (KERNEL32.@)
2839c2c66affSColin Finck *
2840c2c66affSColin Finck *
2841c2c66affSColin Finck */
SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData)2842c2c66affSColin Finck int WINAPI SetCalendarInfoW(LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData)
2843c2c66affSColin Finck {
2844c2c66affSColin Finck FIXME("(%08x,%08x,%08x,%s): stub\n",
2845c2c66affSColin Finck Locale, Calendar, CalType, debugstr_w(lpCalData));
2846c2c66affSColin Finck return 0;
2847c2c66affSColin Finck }
2848