From 8ea4102a6c6e0ce0fad52e87fdd94530475255f8 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 4 Dec 2009 03:06:58 +0300 Subject: [PATCH] kernel32/lcformat: Add support for genitive month names in GetDateFormat(). --- dlls/kernel32/lcformat.c | 90 +++++++++++++++++++++++++++++++++++++++----- dlls/kernel32/tests/locale.c | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 9 deletions(-) diff --git a/dlls/kernel32/lcformat.c b/dlls/kernel32/lcformat.c index c24ee37cc41..99d1c466533 100644 --- a/dlls/kernel32/lcformat.c +++ b/dlls/kernel32/lcformat.c @@ -52,7 +52,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(nls); * * 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 { @@ -72,14 +72,15 @@ typedef struct _NLS_FORMAT_NODE #define GetLongDate(fmt) fmt->lppszStrings[1] #define GetShortDate(fmt) fmt->lppszStrings[2] #define GetTime(fmt) fmt->lppszStrings[3] -#define GetAM(fmt) fmt->lppszStrings[42] -#define GetPM(fmt) fmt->lppszStrings[43] -#define GetYearMonth(fmt) fmt->lppszStrings[44] +#define GetAM(fmt) fmt->lppszStrings[54] +#define GetPM(fmt) fmt->lppszStrings[55] +#define GetYearMonth(fmt) fmt->lppszStrings[56] -#define GetLongDay(fmt,day) fmt->lppszStrings[4 + day] -#define GetShortDay(fmt,day) fmt->lppszStrings[11 + day] -#define GetLongMonth(fmt,mth) fmt->lppszStrings[18 + mth] -#define GetShortMonth(fmt,mth) fmt->lppszStrings[30 + mth] +#define GetLongDay(fmt,day) fmt->lppszStrings[4 + day] +#define GetShortDay(fmt,day) fmt->lppszStrings[11 + day] +#define GetLongMonth(fmt,mth) fmt->lppszStrings[18 + 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 */ static CRITICAL_SECTION NLS_FormatsCS; @@ -150,7 +151,7 @@ static WCHAR* NLS_GetLocaleString(LCID lcid, DWORD dwFlags) static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags) { /* GetLocaleInfo() identifiers for cached formatting strings */ - static const USHORT NLS_LocaleIndices[] = { + static const LCTYPE NLS_LocaleIndices[] = { LOCALE_SNEGATIVESIGN, LOCALE_SLONGDATE, LOCALE_SSHORTDATE, LOCALE_STIMEFORMAT, @@ -163,6 +164,18 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags) LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, 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_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, @@ -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]); } + /* 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->szShortPM[0] = GetPM(new_node)[0]; new_node->szShortPM[1] = '\0'; @@ -352,6 +375,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, INT cchWritten = 0; INT lastFormatPos = 0; BOOL bSkipping = FALSE; /* Skipping text around marker? */ + BOOL d_dd_formatted = FALSE; /* previous formatted part was for d or dd */ /* Verify our arguments */ if ((cchOut && !lpStr) || !(node = NLS_GetFormats(lcid, dwFlags))) @@ -485,6 +509,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, } buff[0] = '\0'; + if (fmtChar != 'M') d_dd_formatted = FALSE; switch(fmtChar) { case 'd': @@ -496,12 +521,59 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags, { dwVal = lpTime->wDay; szAdd = buff; + d_dd_formatted = TRUE; } break; case 'M': 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); + } else if (count == 3) szAdd = GetShortMonth(node, lpTime->wMonth - 1); else diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 37dc0aada7e..48ab3500635 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "wine/test.h" #include "windef.h" @@ -466,7 +467,9 @@ static void test_GetDateFormatA(void) int ret; SYSTEMTIME curtime; 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 short_day[10], month[10], genitive_month[10]; memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */ STRINGSA("ddd',' MMM dd yy",""); @@ -542,6 +545,72 @@ static void test_GetDateFormatA(void) &curtime, input, buffer, COUNTOF(buffer)); ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "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; } -- 2.11.4.GIT