kernelbase: Reimplement GetDateFormatW/Ex() using get_locale_info().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2022-05-04 08:44:20 +02:00
parent 2cfcdc6462
commit 6ccdd7f8f5
4 changed files with 188 additions and 59 deletions

View File

@ -641,8 +641,8 @@
@ stdcall -import GetCurrentThreadStackLimits(ptr ptr)
@ stdcall -arch=x86_64 GetCurrentUmsThread()
@ stdcall GetDateFormatA(long long ptr str ptr long)
@ stdcall GetDateFormatEx(wstr long ptr wstr ptr long wstr)
@ stdcall GetDateFormatW(long long ptr wstr ptr long)
@ stdcall -import GetDateFormatEx(wstr long ptr wstr ptr long wstr)
@ stdcall -import GetDateFormatW(long long ptr wstr ptr long)
@ stdcall GetDaylightFlag()
@ stdcall GetDefaultCommConfigA(str ptr ptr)
@ stdcall GetDefaultCommConfigW(wstr ptr ptr)

View File

@ -780,61 +780,6 @@ INT WINAPI GetDateFormatA( LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
lpFormat, lpDateStr, cchOut);
}
/******************************************************************************
* GetDateFormatEx [KERNEL32.@]
*
* Format a date for a given locale.
*
* PARAMS
* localename [I] Locale to format for
* flags [I] LOCALE_ and DATE_ flags from "winnls.h"
* date [I] Date to format
* format [I] Format string, or NULL to use the locale defaults
* outbuf [O] Destination for formatted string
* bufsize [I] Size of outbuf, or 0 to calculate the resulting size
* calendar [I] Reserved, must be NULL
*
* See GetDateFormatA for notes.
*
* RETURNS
* Success: The number of characters written to outbuf, or that would have
* been written if bufsize is 0.
* Failure: 0. Use GetLastError() to determine the cause.
*/
INT WINAPI GetDateFormatEx(LPCWSTR localename, DWORD flags,
const SYSTEMTIME* date, LPCWSTR format,
LPWSTR outbuf, INT bufsize, LPCWSTR calendar)
{
TRACE("(%s,0x%08lx,%p,%s,%p,%d,%s)\n", debugstr_w(localename), flags,
date, debugstr_w(format), outbuf, bufsize, debugstr_w(calendar));
/* Parameter is currently reserved and Windows errors if set */
if (calendar != NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
return NLS_GetDateTimeFormatW(LocaleNameToLCID(localename, 0),
flags | DATE_DATEVARSONLY, date, format,
outbuf, bufsize);
}
/******************************************************************************
* GetDateFormatW [KERNEL32.@]
*
* See GetDateFormatA.
*/
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
{
TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n", lcid, dwFlags, lpTime,
debugstr_w(lpFormat), lpDateStr, cchOut);
return NLS_GetDateTimeFormatW(lcid, dwFlags|DATE_DATEVARSONLY, lpTime,
lpFormat, lpDateStr, cchOut);
}
/******************************************************************************
* GetTimeFormatA [KERNEL32.@]
*

View File

@ -500,8 +500,8 @@
@ stdcall -norelay GetCurrentThreadId() kernelbase_GetCurrentThreadId
@ stdcall GetCurrentThreadStackLimits(ptr ptr)
@ stdcall GetDateFormatA(long long ptr str ptr long) kernel32.GetDateFormatA
@ stdcall GetDateFormatEx(wstr long ptr wstr ptr long wstr) kernel32.GetDateFormatEx
@ stdcall GetDateFormatW(long long ptr wstr ptr long) kernel32.GetDateFormatW
@ stdcall GetDateFormatEx(wstr long ptr wstr ptr long wstr)
@ stdcall GetDateFormatW(long long ptr wstr ptr long)
@ stdcall GetDeviceDriverBaseNameA(ptr ptr long)
@ stdcall GetDeviceDriverBaseNameW(ptr ptr long)
@ stdcall GetDeviceDriverFileNameA(ptr ptr long)

View File

@ -6821,6 +6821,151 @@ static int get_currency_format( const NLS_LOCALE_DATA *locale, DWORD flags, cons
}
/* get the length of a date/time formatting pattern */
static int get_pattern_len( const WCHAR *pattern, const WCHAR *accept )
{
int i;
if (*pattern == '\'')
{
for (i = 1; pattern[i]; i++)
{
if (pattern[i] != '\'') continue;
if (pattern[++i] != '\'') return i;
}
return i;
}
if (!wcschr( accept, *pattern )) return 1;
for (i = 1; pattern[i]; i++) if (pattern[i] != pattern[0]) break;
return i;
}
static int get_date_format( const NLS_LOCALE_DATA *locale, DWORD flags, const SYSTEMTIME *systime,
const WCHAR *format, WCHAR *buffer, int len )
{
DWORD override = flags & LOCALE_NOUSEROVERRIDE;
DWORD genitive = 0;
WCHAR *p, fmt[80], output[256];
SYSTEMTIME time;
int ret, val, count, i;
if (!format)
{
if (flags & DATE_USE_ALT_CALENDAR) FIXME( "alt calendar not supported\n" );
switch (flags & (DATE_SHORTDATE | DATE_LONGDATE | DATE_YEARMONTH | DATE_MONTHDAY))
{
case 0:
case DATE_SHORTDATE:
get_locale_info( locale, 0, LOCALE_SSHORTDATE | override, fmt, ARRAY_SIZE(fmt) );
break;
case DATE_LONGDATE:
get_locale_info( locale, 0, LOCALE_SLONGDATE | override, fmt, ARRAY_SIZE(fmt) );
break;
case DATE_YEARMONTH:
get_locale_info( locale, 0, LOCALE_SYEARMONTH | override, fmt, ARRAY_SIZE(fmt) );
break;
case DATE_MONTHDAY:
get_locale_info( locale, 0, LOCALE_SMONTHDAY | override, fmt, ARRAY_SIZE(fmt) );
break;
default:
SetLastError( ERROR_INVALID_FLAGS );
return 0;
}
format = fmt;
}
else if (override || (flags & (DATE_SHORTDATE | DATE_LONGDATE | DATE_YEARMONTH | DATE_MONTHDAY)))
{
SetLastError( ERROR_INVALID_FLAGS );
return 0;
}
if (systime)
{
FILETIME ft;
time = *systime;
time.wHour = time.wMinute = time.wSecond = time.wMilliseconds = 0;
if (!SystemTimeToFileTime( &time, &ft ) || !FileTimeToSystemTime( &ft, &time )) return 0;
}
else GetLocalTime( &time );
for (p = output; *format; format += count)
{
count = get_pattern_len( format, L"yMd" );
switch (*format)
{
case '\'':
for (i = 1; i < count; i++)
{
if (format[i] == '\'') i++;
if (i < count) *p++ = format[i];
}
break;
case 'y':
p += swprintf( p, output + ARRAY_SIZE(output) - p, L"%02u",
(count <= 2) ? time.wYear % 100 : time.wYear );
break;
case 'M':
if (count <= 2)
{
p += swprintf( p, output + ARRAY_SIZE(output) - p, L"%.*u", count, time.wMonth );
break;
}
val = (count == 3 ? LOCALE_SABBREVMONTHNAME1 : LOCALE_SMONTHNAME1) + time.wMonth - 1;
if (!genitive)
{
for (i = count; format[i]; i += get_pattern_len( format, L"yMd" ))
{
if (format[i] != 'd') continue;
if (format[i + 1] != 'd' || format[i + 2] != 'd')
genitive = LOCALE_RETURN_GENITIVE_NAMES;
break;
}
}
p += get_locale_info( locale, 0, val | override | genitive,
p, output + ARRAY_SIZE(output) - p ) - 1;
break;
case 'd':
if (count <= 2)
{
genitive = LOCALE_RETURN_GENITIVE_NAMES;
p += swprintf( p, output + ARRAY_SIZE(output) - p, L"%.*u", count, time.wDay );
break;
}
genitive = 0;
val = (count == 3 ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1) + (time.wDayOfWeek + 6) % 7;
p += get_locale_info( locale, 0, val | override, p, output + ARRAY_SIZE(output) - p ) - 1;
break;
case 'g':
p += locale_return_string( count >= 2 ? locale->serastring : locale->sabbreverastring,
override, p, output + ARRAY_SIZE(output) - p ) - 1;
break;
default:
*p++ = *format;
break;
}
}
*p++ = 0;
ret = p - output;
if (!len) return ret;
lstrcpynW( buffer, output, len );
if (ret > len)
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return 0;
}
return ret;
}
/**************************************************************************
* GetNumberFormatW (kernelbase.@)
*/
@ -6897,3 +7042,42 @@ int WINAPI GetCurrencyFormatEx( const WCHAR *name, DWORD flags, const WCHAR *val
TRACE( "(%s,%lx,%s,%p,%p,%d)\n", debugstr_w(name), flags, debugstr_w(value), format, buffer, len );
return get_currency_format( locale, flags, value, format, buffer, len );
}
/***********************************************************************
* GetDateFormatW (kernelbase.@)
*/
int WINAPI GetDateFormatW( LCID lcid, DWORD flags, const SYSTEMTIME *systime,
const WCHAR *format, WCHAR *buffer, int len )
{
const NLS_LOCALE_DATA *locale = NlsValidateLocale( &lcid, 0 );
if (len < 0 || (len && !buffer) || !locale)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
TRACE( "(%04lx,%lx,%p,%s,%p,%d)\n", lcid, flags, systime, debugstr_w(format), buffer, len );
return get_date_format( locale, flags, systime, format, buffer, len );
}
/***********************************************************************
* GetDateFormatEx (kernelbase.@)
*/
int WINAPI GetDateFormatEx( const WCHAR *name, DWORD flags, const SYSTEMTIME *systime,
const WCHAR *format, WCHAR *buffer, int len, const WCHAR *calendar )
{
LCID lcid;
const NLS_LOCALE_DATA *locale = get_locale_by_name( name, &lcid );
if (len < 0 || (len && !buffer) || !locale || calendar)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
TRACE( "(%s,%lx,%p,%s,%p,%d)\n", debugstr_w(name), flags, systime, debugstr_w(format), buffer, len );
return get_date_format( locale, flags, systime, format, buffer, len );
}