[PATCH 3/3] Add support for genitive month names in GetDateFormat()
Nikolay Sivov
bunglehead at gmail.com
Thu Dec 3 18:06:58 CST 2009
---
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 c24ee37..08d5431 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 37dc0aa..bc63e2a 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stdio.h>
#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;
}
--
1.5.6.5
--=-3KYnsHt2UmD2cPJm71y/--
More information about the wine-patches
mailing list