[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