Commit 8ea4102a authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

kernel32/lcformat: Add support for genitive month names in GetDateFormat().

parent 8e4f283e
...@@ -52,7 +52,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(nls); ...@@ -52,7 +52,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(nls);
* *
* Our cache takes the form of a singly linked list, whose node is below: * Our cache takes the form of a singly linked list, whose node is below:
*/ */
#define NLS_NUM_CACHED_STRINGS 45 #define NLS_NUM_CACHED_STRINGS 57
typedef struct _NLS_FORMAT_NODE typedef struct _NLS_FORMAT_NODE
{ {
...@@ -72,14 +72,15 @@ typedef struct _NLS_FORMAT_NODE ...@@ -72,14 +72,15 @@ typedef struct _NLS_FORMAT_NODE
#define GetLongDate(fmt) fmt->lppszStrings[1] #define GetLongDate(fmt) fmt->lppszStrings[1]
#define GetShortDate(fmt) fmt->lppszStrings[2] #define GetShortDate(fmt) fmt->lppszStrings[2]
#define GetTime(fmt) fmt->lppszStrings[3] #define GetTime(fmt) fmt->lppszStrings[3]
#define GetAM(fmt) fmt->lppszStrings[42] #define GetAM(fmt) fmt->lppszStrings[54]
#define GetPM(fmt) fmt->lppszStrings[43] #define GetPM(fmt) fmt->lppszStrings[55]
#define GetYearMonth(fmt) fmt->lppszStrings[44] #define GetYearMonth(fmt) fmt->lppszStrings[56]
#define GetLongDay(fmt,day) fmt->lppszStrings[4 + day] #define GetLongDay(fmt,day) fmt->lppszStrings[4 + day]
#define GetShortDay(fmt,day) fmt->lppszStrings[11 + day] #define GetShortDay(fmt,day) fmt->lppszStrings[11 + day]
#define GetLongMonth(fmt,mth) fmt->lppszStrings[18 + mth] #define GetLongMonth(fmt,mth) fmt->lppszStrings[18 + mth]
#define GetShortMonth(fmt,mth) fmt->lppszStrings[30 + mth] #define GetGenitiveMonth(fmt,mth) fmt->lppszStrings[30 + mth]
#define GetShortMonth(fmt,mth) fmt->lppszStrings[42 + mth]
/* Write access to the cache is protected by this critical section */ /* Write access to the cache is protected by this critical section */
static CRITICAL_SECTION NLS_FormatsCS; static CRITICAL_SECTION NLS_FormatsCS;
...@@ -150,7 +151,7 @@ static WCHAR* NLS_GetLocaleString(LCID lcid, DWORD dwFlags) ...@@ -150,7 +151,7 @@ static WCHAR* NLS_GetLocaleString(LCID lcid, DWORD dwFlags)
static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags) static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
{ {
/* GetLocaleInfo() identifiers for cached formatting strings */ /* GetLocaleInfo() identifiers for cached formatting strings */
static const USHORT NLS_LocaleIndices[] = { static const LCTYPE NLS_LocaleIndices[] = {
LOCALE_SNEGATIVESIGN, LOCALE_SNEGATIVESIGN,
LOCALE_SLONGDATE, LOCALE_SSHORTDATE, LOCALE_SLONGDATE, LOCALE_SSHORTDATE,
LOCALE_STIMEFORMAT, LOCALE_STIMEFORMAT,
...@@ -163,6 +164,18 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags) ...@@ -163,6 +164,18 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
LOCALE_SMONTHNAME1 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME2 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME3 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME4 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME5 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME6 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME7 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME8 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME9 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME10 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME11 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SMONTHNAME12 | LOCALE_RETURN_GENITIVE_NAMES,
LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
...@@ -249,6 +262,16 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags) ...@@ -249,6 +262,16 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
{ {
GET_LOCALE_STRING(new_node->lppszStrings[i], NLS_LocaleIndices[i]); GET_LOCALE_STRING(new_node->lppszStrings[i], NLS_LocaleIndices[i]);
} }
/* Save some memory if month genitive name is the same or not present */
for (i = 0; i < 12; i++)
{
if (strcmpW(GetLongMonth(new_node, i), GetGenitiveMonth(new_node, i)) == 0)
{
HeapFree(GetProcessHeap(), 0, GetGenitiveMonth(new_node, i));
GetGenitiveMonth(new_node, i) = NULL;
}
}
new_node->szShortAM[0] = GetAM(new_node)[0]; new_node->szShortAM[1] = '\0'; new_node->szShortAM[0] = GetAM(new_node)[0]; new_node->szShortAM[1] = '\0';
new_node->szShortPM[0] = GetPM(new_node)[0]; new_node->szShortPM[1] = '\0'; new_node->szShortPM[0] = GetPM(new_node)[0]; new_node->szShortPM[1] = '\0';
...@@ -352,6 +375,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, ...@@ -352,6 +375,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags,
INT cchWritten = 0; INT cchWritten = 0;
INT lastFormatPos = 0; INT lastFormatPos = 0;
BOOL bSkipping = FALSE; /* Skipping text around marker? */ BOOL bSkipping = FALSE; /* Skipping text around marker? */
BOOL d_dd_formatted = FALSE; /* previous formatted part was for d or dd */
/* Verify our arguments */ /* Verify our arguments */
if ((cchOut && !lpStr) || !(node = NLS_GetFormats(lcid, dwFlags))) if ((cchOut && !lpStr) || !(node = NLS_GetFormats(lcid, dwFlags)))
...@@ -485,6 +509,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, ...@@ -485,6 +509,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags,
} }
buff[0] = '\0'; buff[0] = '\0';
if (fmtChar != 'M') d_dd_formatted = FALSE;
switch(fmtChar) switch(fmtChar)
{ {
case 'd': case 'd':
...@@ -496,12 +521,59 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, ...@@ -496,12 +521,59 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags,
{ {
dwVal = lpTime->wDay; dwVal = lpTime->wDay;
szAdd = buff; szAdd = buff;
d_dd_formatted = TRUE;
} }
break; break;
case 'M': case 'M':
if (count >= 4) if (count >= 4)
{
LPCWSTR genitive = GetGenitiveMonth(node, lpTime->wMonth - 1);
if (genitive)
{
if (d_dd_formatted)
{
szAdd = genitive;
break;
}
else
{
LPCWSTR format = lpFormat;
/* Look forward now, if next format pattern is for day genitive
name should be used */
while (*format)
{
/* Skip parts within markers */
if (IsLiteralMarker(*format))
{
++format;
while (*format)
{
if (IsLiteralMarker(*format))
{
++format;
if (!IsLiteralMarker(*format)) break;
}
}
}
if (*format != ' ') break;
++format;
}
/* Only numeric day form matters */
if (*format && *format == 'd')
{
INT dcount = 1;
while (*++format == 'd') dcount++;
if (dcount < 3)
{
szAdd = genitive;
break;
}
}
}
}
szAdd = GetLongMonth(node, lpTime->wMonth - 1); szAdd = GetLongMonth(node, lpTime->wMonth - 1);
}
else if (count == 3) else if (count == 3)
szAdd = GetShortMonth(node, lpTime->wMonth - 1); szAdd = GetShortMonth(node, lpTime->wMonth - 1);
else else
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include "wine/test.h" #include "wine/test.h"
#include "windef.h" #include "windef.h"
...@@ -466,7 +467,9 @@ static void test_GetDateFormatA(void) ...@@ -466,7 +467,9 @@ static void test_GetDateFormatA(void)
int ret; int ret;
SYSTEMTIME curtime; SYSTEMTIME curtime;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
char short_day[10], month[10], genitive_month[10];
memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */ memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
STRINGSA("ddd',' MMM dd yy",""); STRINGSA("ddd',' MMM dd yy","");
...@@ -542,6 +545,72 @@ static void test_GetDateFormatA(void) ...@@ -542,6 +545,72 @@ static void test_GetDateFormatA(void)
&curtime, input, buffer, COUNTOF(buffer)); &curtime, input, buffer, COUNTOF(buffer));
ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
"Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
if (!ret)
{
win_skip("LANG_RUSSIAN locale data unavailable\n");
return;
}
/* month part should be in genitive form */
strcpy(genitive_month, buffer + 2);
ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
strcpy(month, buffer);
ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
strcpy(short_day, buffer);
STRINGSA("dd MMMMddd dd", "");
sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("MMMMddd dd", "");
sprintf(Expected, "%s%s 04", month, short_day);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("MMMMddd", "");
sprintf(Expected, "%s%s", month, short_day);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("MMMMdd", "");
sprintf(Expected, "%s04", genitive_month);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("MMMMdd ddd", "");
sprintf(Expected, "%s04 %s", genitive_month, short_day);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("dd dddMMMM", "");
sprintf(Expected, "04 %s%s", short_day, month);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
STRINGSA("dd dddMMMM ddd MMMMdd", "");
sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA;
/* with literal part */
STRINGSA("ddd',' MMMM dd", "");
sprintf(Expected, "%s, %s 04", short_day, genitive_month);
ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
EXPECT_EQA; EXPECT_EQA;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment