[KERNEL32] make some NLS and Format functions work. Wine-sync with latest version
authorDenis Malikov <filedem@gmail.com>
Sun, 18 Nov 2018 14:32:13 +0000 (21:32 +0700)
committerMark Jansen <mark.jansen@reactos.org>
Sat, 5 Jan 2019 18:01:30 +0000 (19:01 +0100)
base/shell/cmd/config.h
dll/win32/kernel32/include/kernel32.h
dll/win32/kernel32/kernel32.spec
dll/win32/kernel32/winnls/string/lang.c
dll/win32/kernel32/winnls/string/lcformat.c
dll/win32/kernel32/winnls/string/nls.c
media/doc/README.WINE
sdk/include/psdk/winnls.h

index e89e1ea..bdeeaa0 100644 (file)
@@ -42,7 +42,7 @@
 /* Define one of these to select the used locale. */
 /*  (date and time formats etc.) used in DATE, TIME, */
 /*  DIR, PROMPT etc. */
-#define LOCALE_WINDOWS   /* System locale */
+/* #define LOCALE_WINDOWS */   /* System locale */
 /* #define LOCALE_GERMAN */    /* German locale */
 /* #define LOCALE_DEFAULT */   /* United States locale */
 
index d5839bf..005b5d0 100644 (file)
@@ -50,6 +50,8 @@
 #define ROUND_UP(n, align) \
     ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
 #define __TRY _SEH2_TRY
 #define __EXCEPT_PAGE_FAULT _SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_ACCESS_VIOLATION)
 #define __ENDTRY _SEH2_END
index aea5d2f..f3ee418 100644 (file)
 @ stdcall EnterCriticalSection(ptr) ntdll.RtlEnterCriticalSection
 @ stdcall EnumCalendarInfoA(ptr long long long)
 @ stdcall EnumCalendarInfoExA(ptr long long long)
-@ stub -version=0x600+ EnumCalendarInfoExEx
+@ stdcall -version=0x600+ EnumCalendarInfoExEx(ptr wstr long wstr long long)
 @ stdcall EnumCalendarInfoExW(ptr long long long)
 @ stdcall EnumCalendarInfoW(ptr long long long)
 @ stdcall EnumDateFormatsA(ptr long long)
 @ stdcall EnumDateFormatsExA(ptr long long)
-@ stub -version=0x600+ EnumDateFormatsExEx
+@ stdcall -version=0x600+ EnumDateFormatsExEx(ptr wstr long long)
 @ stdcall EnumDateFormatsExW(ptr long long)
 @ stdcall EnumDateFormatsW(ptr long long)
 @ stdcall EnumLanguageGroupLocalesA(ptr long long ptr)
 @ stdcall EnumSystemLanguageGroupsA(ptr long ptr)
 @ stdcall EnumSystemLanguageGroupsW(ptr long ptr)
 @ stdcall EnumSystemLocalesA(ptr long)
-@ stub -version=0x600+ EnumSystemLocalesEx
+@ stdcall -version=0x600+ EnumSystemLocalesEx(ptr long long ptr)
 @ stdcall EnumSystemLocalesW(ptr long)
 @ stdcall EnumTimeFormatsA(ptr long long)
-@ stub -version=0x600+ EnumTimeFormatsEx
+@ stdcall -version=0x600+ EnumTimeFormatsEx(ptr wstr long long)
 @ stdcall EnumTimeFormatsW(ptr long long)
 @ stdcall EnumUILanguagesA(ptr long long)
 @ stdcall EnumUILanguagesW(ptr long long)
 @ stub -version=0x600+ GetCalendarDaysInMonth
 @ stub -version=0x600+ GetCalendarDifferenceInDays
 @ stdcall GetCalendarInfoA(long long long ptr long ptr)
-@ stub -version=0x600+ GetCalendarInfoEx
+@ stdcall -version=0x600+ GetCalendarInfoEx(wstr, long, wstr, long, wstr, long, ptr)
 @ stdcall GetCalendarInfoW(long long long ptr long ptr)
 @ stub -version=0x600+ GetCalendarMonthsInYear
 @ stub -version=0x600+ GetCalendarSupportedDateRange
 @ stdcall -norelay GetCurrentThread()
 @ stdcall -norelay GetCurrentThreadId()
 @ stdcall GetDateFormatA(long long ptr str ptr long)
-@ stub -version=0x600+ GetDateFormatEx
+@ stdcall -version=0x600+ GetDateFormatEx(wstr long ptr wstr wstr long wstr)
 @ stdcall GetDateFormatW(long long ptr wstr ptr long)
 @ stdcall GetDefaultCommConfigA(str ptr long)
 @ stdcall GetDefaultCommConfigW(wstr ptr long)
 @ stdcall -version=0x500-0x502 GetLinguistLangSize(ptr)
 @ stdcall GetLocalTime(ptr)
 @ stdcall GetLocaleInfoA(long long ptr long)
-@ stub -version=0x600+ GetLocaleInfoEx
+@ stdcall -version=0x600+ GetLocaleInfoEx(wstr long ptr long)
 @ stdcall GetLocaleInfoW(long long ptr long)
+@ stdcall -version=0x600+ IsValidLocaleName(wstr)
 @ stdcall GetLogicalDriveStringsA(long ptr)
 @ stdcall GetLogicalDriveStringsW(long ptr)
 @ stdcall GetLogicalDrives()
 @ stdcall GetModuleHandleExW(long ptr ptr)
 @ stdcall GetModuleHandleW(wstr)
 @ stdcall GetNLSVersion(long long ptr)
-@ stub -version=0x600+ GetNLSVersionEx
+@ stdcall GetNLSVersionEx(long wstr ptr)
 @ stub -version=0x600+ GetNamedPipeAttribute
 @ stub -version=0x600+ GetNamedPipeClientComputerNameA
 @ stub -version=0x600+ GetNamedPipeClientComputerNameW
 @ stdcall GetNumaProcessorNode(long ptr)
 @ stub -version=0x600+ GetNumaProximityNode
 @ stdcall GetNumberFormatA(long long str ptr ptr long)
-@ stub -version=0x600+ GetNumberFormatEx
+@ stdcall -version=0x600+ GetNumberFormatEx(wstr long wstr ptr wstr long)
 @ stdcall GetNumberFormatW(long long wstr ptr ptr long)
 @ stdcall GetNumberOfConsoleFonts()
 @ stdcall GetNumberOfConsoleInputEvents(long ptr)
 @ stdcall GetTickCount()
 @ stub -version=0x600+ GetTickCount64
 @ stdcall GetTimeFormatA(long long ptr str ptr long)
-@ stub -version=0x600+ GetTimeFormatEx
+@ stdcall -version=0x600+ GetTimeFormatEx(wstr long ptr wstr wstr long)
 @ stdcall GetTimeFormatW(long long ptr wstr ptr long)
 @ stdcall GetTimeZoneInformation(ptr)
 @ stub -version=0x600+ GetTimeZoneInformationForYear
 @ stub -version=0x600+ GetUILanguageInfo
 @ stdcall GetUserDefaultLCID()
 @ stdcall GetUserDefaultLangID()
-@ stub -version=0x600+ GetUserDefaultLocaleName
+@ stdcall -version=0x600+ GetUserDefaultLocaleName(wstr long)
 @ stdcall GetUserDefaultUILanguage()
 @ stdcall GetUserGeoID(long)
 @ stub -version=0x600+ GetUserPreferredUILanguages
 @ stdcall IsWow64Process(ptr ptr)
 @ stub -version=0x600+ LCIDToLocaleName
 @ stdcall LCMapStringA(long long str long ptr long)
-@ stub -version=0x600+ LCMapStringEx
+@ stdcall -version=0x600+ LCMapStringEx(long long wstr long ptr long ptr ptr long)
 @ stdcall LCMapStringW(long long wstr long ptr long)
 @ stdcall LZClose(long)
 @ stdcall LZCloseFile(long)
index 5bd9ec4..42c57d1 100644 (file)
@@ -56,7 +56,7 @@ static const WCHAR szLangGroupsKeyName[] = {
     'L','a','n','g','u','a','g','e',' ','G','r','o','u','p','s',0
 };
 
-#ifndef __REACTOS__
+#if (WINVER >= 0x0600)
 /* Charset to codepage map, sorted by name. */
 static const struct charset_entry
 {
@@ -262,6 +262,248 @@ static inline UINT get_lcid_codepage( LCID lcid )
     return ret;
 }
 
+#if (WINVER >= 0x0600)
+/***********************************************************************
+ *              charset_cmp (internal)
+ */
+static int charset_cmp( const void *name, const void *entry )
+{
+    const struct charset_entry *charset = entry;
+    return strcasecmp( name, charset->charset_name );
+}
+
+/***********************************************************************
+ *             find_charset
+ */
+static UINT find_charset( const WCHAR *name )
+{
+    const struct charset_entry *entry;
+    char charset_name[16];
+    size_t i, j;
+
+    /* remove punctuation characters from charset name */
+    for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++)
+        if (isalnum((unsigned char)name[i])) charset_name[j++] = name[i];
+    charset_name[j] = 0;
+
+    entry = bsearch( charset_name, charset_names, ARRAY_SIZE( charset_names ),
+                     sizeof(charset_names[0]), charset_cmp );
+    if (entry) return entry->codepage;
+    return 0;
+}
+
+static LANGID get_default_sublang( LANGID lang )
+{
+    switch (lang)
+    {
+    case MAKELANGID( LANG_SPANISH, SUBLANG_NEUTRAL ):
+        return MAKELANGID( LANG_SPANISH, SUBLANG_SPANISH_MODERN );
+    case MAKELANGID( LANG_CHINESE, SUBLANG_NEUTRAL ):
+        return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
+    case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE ):
+        return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
+    case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL ):
+    case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_MACAU ):
+        return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG );
+    }
+    if (SUBLANGID( lang ) == SUBLANG_NEUTRAL) lang = MAKELANGID( PRIMARYLANGID(lang), SUBLANG_DEFAULT );
+    return lang;
+}
+
+/***********************************************************************
+ *           find_locale_id_callback
+ */
+static BOOL CALLBACK find_locale_id_callback( HMODULE hModule, LPCWSTR type,
+                                              LPCWSTR name, LANGID lang, LPARAM lParam )
+{
+    struct locale_name *data = (struct locale_name *)lParam;
+    WCHAR buffer[128];
+    int matches = 0;
+    LCID lcid = MAKELCID( lang, SORT_DEFAULT );  /* FIXME: handle sort order */
+
+    if (PRIMARYLANGID(lang) == LANG_NEUTRAL) return TRUE; /* continue search */
+
+    /* first check exact name */
+    if (data->win_name[0] &&
+        GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, buffer, ARRAY_SIZE( buffer )))
+    {
+        if (!strcmpiW( data->win_name, buffer ))
+        {
+            matches = 4;  /* everything matches */
+            goto done;
+        }
+    }
+
+    if (!GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE,
+                         buffer, ARRAY_SIZE( buffer )))
+        return TRUE;
+    if (strcmpiW( buffer, data->lang )) return TRUE;
+    matches++;  /* language name matched */
+
+    if (data->script)
+    {
+        if (GetLocaleInfoW( lcid, LOCALE_SSCRIPTS | LOCALE_NOUSEROVERRIDE,
+                            buffer, ARRAY_SIZE( buffer )))
+        {
+            const WCHAR *p = buffer;
+            unsigned int len = strlenW( data->script );
+            while (*p)
+            {
+                if (!strncmpiW( p, data->script, len ) && (!p[len] || p[len] == ';')) break;
+                if (!(p = strchrW( p, ';'))) goto done;
+                p++;
+            }
+            if (!*p) goto done;
+            matches++;  /* script matched */
+        }
+    }
+
+    if (data->country)
+    {
+        if (GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE,
+                            buffer, ARRAY_SIZE( buffer )))
+        {
+            if (strcmpiW( buffer, data->country )) goto done;
+            matches++;  /* country name matched */
+        }
+    }
+    else  /* match default language */
+    {
+        LANGID def_lang = data->script ? lang : MAKELANGID( PRIMARYLANGID(lang), LANG_NEUTRAL );
+        if (lang == get_default_sublang( def_lang )) matches++;
+    }
+
+    if (data->codepage)
+    {
+        UINT unix_cp;
+        if (GetLocaleInfoW( lcid, LOCALE_IDEFAULTUNIXCODEPAGE | LOCALE_RETURN_NUMBER,
+                            (LPWSTR)&unix_cp, sizeof(unix_cp)/sizeof(WCHAR) ))
+        {
+            if (unix_cp == data->codepage) matches++;
+        }
+    }
+
+    /* FIXME: check sort order */
+
+done:
+    if (matches > data->matches)
+    {
+        data->lcid = lcid;
+        data->matches = matches;
+    }
+    return (data->matches < 4);  /* no need to continue for perfect match */
+}
+
+
+/***********************************************************************
+ *             parse_locale_name
+ *
+ * Parse a locale name into a struct locale_name, handling both Windows and Unix formats.
+ * Unix format is: lang[_country][.charset][@modifier]
+ * Windows format is: lang[-script][-country][_modifier]
+ */
+static void parse_locale_name( const WCHAR *str, struct locale_name *name )
+{
+    static const WCHAR sepW[] = {'-','_','.','@',0};
+    static const WCHAR winsepW[] = {'-','_',0};
+    static const WCHAR posixW[] = {'P','O','S','I','X',0};
+    static const WCHAR cW[] = {'C',0};
+    static const WCHAR latinW[] = {'l','a','t','i','n',0};
+    static const WCHAR latnW[] = {'-','L','a','t','n',0};
+    WCHAR *p;
+
+    TRACE("%s\n", debugstr_w(str));
+
+    name->country = name->charset = name->script = name->modifier = NULL;
+    name->lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
+    name->matches = 0;
+    name->codepage = 0;
+    name->win_name[0] = 0;
+    lstrcpynW( name->lang, str, ARRAY_SIZE( name->lang ));
+
+    if (!*name->lang)
+    {
+        name->lcid = LOCALE_INVARIANT;
+        name->matches = 4;
+        return;
+    }
+
+    if (!(p = strpbrkW( name->lang, sepW )))
+    {
+        if (!strcmpW( name->lang, posixW ) || !strcmpW( name->lang, cW ))
+        {
+            name->matches = 4;  /* perfect match for default English lcid */
+            return;
+        }
+        strcpyW( name->win_name, name->lang );
+    }
+    else if (*p == '-')  /* Windows format */
+    {
+        strcpyW( name->win_name, name->lang );
+        *p++ = 0;
+        name->country = p;
+        if ((p = strpbrkW( p, winsepW )) && *p == '-')
+        {
+            *p++ = 0;
+            name->script = name->country;
+            name->country = p;
+            p = strpbrkW( p, winsepW );
+        }
+        if (p)
+        {
+            *p++ = 0;
+            name->modifier = p;
+        }
+        /* second value can be script or country, check length to resolve the ambiguity */
+        if (!name->script && strlenW( name->country ) == 4)
+        {
+            name->script = name->country;
+            name->country = NULL;
+        }
+    }
+    else  /* Unix format */
+    {
+        if (*p == '_')
+        {
+            *p++ = 0;
+            name->country = p;
+            p = strpbrkW( p, sepW + 2 );
+        }
+        if (p && *p == '.')
+        {
+            *p++ = 0;
+            name->charset = p;
+            p = strchrW( p, '@' );
+        }
+        if (p)
+        {
+            *p++ = 0;
+            name->modifier = p;
+        }
+
+        if (name->charset)
+            name->codepage = find_charset( name->charset );
+
+        /* rebuild a Windows name if possible */
+
+        if (name->charset) goto done;  /* can't specify charset in Windows format */
+        if (name->modifier && strcmpW( name->modifier, latinW ))
+            goto done;  /* only Latn script supported for now */
+        strcpyW( name->win_name, name->lang );
+        if (name->modifier) strcatW( name->win_name, latnW );
+        if (name->country)
+        {
+            p = name->win_name + strlenW(name->win_name);
+            *p++ = '-';
+            strcpyW( p, name->country );
+        }
+    }
+done:
+    EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE,
+                            find_locale_id_callback, (LPARAM)name );
+}
+#endif
+
 /***********************************************************************
  *           convert_default_lcid
  *
@@ -585,6 +827,52 @@ LANGID WINAPI GetSystemDefaultUILanguage(void)
     return lang;
 }
 
+#if (WINVER >= 0x0600)
+/***********************************************************************
+ *           LocaleNameToLCID  (KERNEL32.@)
+ */
+LCID WINAPI LocaleNameToLCID( LPCWSTR name, DWORD flags )
+{
+    struct locale_name locale_name;
+    static int once;
+
+    if (flags && !once++)
+        FIXME( "unsupported flags %x\n", flags );
+
+    if (name == LOCALE_NAME_USER_DEFAULT)
+        return GetUserDefaultLCID();
+
+    /* string parsing */
+    parse_locale_name( name, &locale_name );
+
+    TRACE( "found lcid %x for %s, matches %d\n",
+           locale_name.lcid, debugstr_w(name), locale_name.matches );
+
+    if (!locale_name.matches)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    if (locale_name.matches == 1)
+        WARN( "locale %s not recognized, defaulting to %s\n",
+              debugstr_w(name), debugstr_w(locale_name.lang) );
+
+    return locale_name.lcid;
+}
+
+
+/***********************************************************************
+ *           LCIDToLocaleName  (KERNEL32.@)
+ */
+INT WINAPI LCIDToLocaleName( LCID lcid, LPWSTR name, INT count, DWORD flags )
+{
+    static int once;
+    if (flags && !once++) FIXME( "unsupported flags %x\n", flags );
+
+    return GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, name, count );
+}
+#endif
 
 /******************************************************************************
  *             get_registry_locale_info
@@ -965,6 +1253,41 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
     return ret;
 }
 
+#if (WINVER >= 0x0600)
+WINBASEAPI
+int
+WINAPI
+GetLocaleInfoEx(
+  _In_opt_ LPCWSTR lpLocaleName,
+  _In_ LCTYPE LCType,
+  _Out_writes_opt_(cchData) LPWSTR lpLCData,
+  _In_ int cchData)
+{
+    TRACE( "GetLocaleInfoEx not implemented (lcid=%s,lctype=0x%x,%s,%d)\n", debugstr_w(lpLocaleName), LCType, debugstr_w(lpLCData), cchData );
+    return 0;
+}
+
+BOOL 
+WINAPI
+IsValidLocaleName(
+  LPCWSTR lpLocaleName
+)
+{
+    TRACE( "IsValidLocaleName not implemented (lpLocaleName=%s)\n", debugstr_w(lpLocaleName));
+    return TRUE;
+}
+
+INT 
+WINAPI
+GetUserDefaultLocaleName(
+  LPWSTR lpLocaleName,
+  INT    cchLocaleName
+)
+{
+    TRACE( "GetUserDefaultLocaleName not implemented (lpLocaleName=%s, cchLocaleName=%d)\n", debugstr_w(lpLocaleName), cchLocaleName);
+    return 0;
+}
+#endif
 
 /******************************************************************************
  *             SetLocaleInfoA  [KERNEL32.@]
@@ -1284,6 +1607,56 @@ BOOL WINAPI EnumSystemLocalesW( LOCALE_ENUMPROCW lpfnLocaleEnum, DWORD dwFlags )
     return TRUE;
 }
 
+
+struct enum_locale_ex_data
+{
+    LOCALE_ENUMPROCEX proc;
+    DWORD             flags;
+    LPARAM            lparam;
+};
+
+static BOOL CALLBACK enum_locale_ex_proc( HMODULE module, LPCWSTR type,
+                                          LPCWSTR name, WORD lang, LONG_PTR lparam )
+{
+    struct enum_locale_ex_data *data = (struct enum_locale_ex_data *)lparam;
+    WCHAR buffer[256];
+    DWORD neutral;
+    unsigned int flags;
+
+    GetLocaleInfoW( MAKELCID( lang, SORT_DEFAULT ), LOCALE_SNAME | LOCALE_NOUSEROVERRIDE,
+                    buffer, ARRAY_SIZE( buffer ));
+    if (!GetLocaleInfoW( MAKELCID( lang, SORT_DEFAULT ),
+                         LOCALE_INEUTRAL | LOCALE_NOUSEROVERRIDE | LOCALE_RETURN_NUMBER,
+                         (LPWSTR)&neutral, sizeof(neutral) / sizeof(WCHAR) ))
+        neutral = 0;
+    flags = LOCALE_WINDOWS;
+    flags |= neutral ? LOCALE_NEUTRALDATA : LOCALE_SPECIFICDATA;
+    if (data->flags && !(data->flags & flags)) return TRUE;
+    return data->proc( buffer, flags, data->lparam );
+}
+
+/******************************************************************************
+ *           EnumSystemLocalesEx  (KERNEL32.@)
+ */
+BOOL WINAPI EnumSystemLocalesEx( LOCALE_ENUMPROCEX proc, DWORD flags, LPARAM lparam, LPVOID reserved )
+{
+    struct enum_locale_ex_data data;
+
+    if (reserved)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    data.proc   = proc;
+    data.flags  = flags;
+    data.lparam = lparam;
+    EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING,
+                            (LPCWSTR)MAKEINTRESOURCE((LOCALE_SNAME >> 4) + 1),
+                            enum_locale_ex_proc, (LONG_PTR)&data );
+    return TRUE;
+}
+
+
 /***********************************************************************
  *           VerLanguageNameA  (KERNEL32.@)
  *
index 7f57373..a4088cb 100644 (file)
@@ -124,7 +124,7 @@ static DWORD NLS_GetLocaleNumber(LCID lcid, DWORD dwFlags)
   DWORD dwVal = 0;
 
   szBuff[0] = '\0';
-  GetLocaleInfoW(lcid, dwFlags, szBuff, sizeof(szBuff) / sizeof(WCHAR));
+  GetLocaleInfoW(lcid, dwFlags, szBuff, ARRAY_SIZE(szBuff));
 
   if (szBuff[0] && szBuff[1] == ';' && szBuff[2] != '0')
     dwVal = (szBuff[0] - '0') * 10 + (szBuff[2] - '0');
@@ -149,7 +149,7 @@ static WCHAR* NLS_GetLocaleString(LCID lcid, DWORD dwFlags)
   DWORD dwLen;
 
   szBuff[0] = '\0';
-  GetLocaleInfoW(lcid, dwFlags, szBuff, sizeof(szBuff) / sizeof(WCHAR));
+  GetLocaleInfoW(lcid, dwFlags, szBuff, ARRAY_SIZE(szBuff));
   dwLen = strlenW(szBuff) + 1;
   str = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
   if (str)
@@ -278,7 +278,7 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
     GET_LOCALE_STRING(new_node->cyfmt.lpCurrencySymbol, LOCALE_SCURRENCY);
 
     /* Date/Time Format info, negative character, etc */
-    for (i = 0; i < sizeof(NLS_LocaleIndices)/sizeof(NLS_LocaleIndices[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(NLS_LocaleIndices); i++)
     {
       GET_LOCALE_STRING(new_node->lppszStrings[i], NLS_LocaleIndices[i]);
     }
@@ -322,7 +322,7 @@ static const NLS_FORMAT_NODE *NLS_GetFormats(LCID lcid, DWORD dwFlags)
       /* We raced and lost: The node was already added by another thread.
        * node points to the currently cached node, so free new_node.
        */
-      for (i = 0; i < sizeof(NLS_LocaleIndices)/sizeof(NLS_LocaleIndices[0]); i++)
+      for (i = 0; i < ARRAY_SIZE(NLS_LocaleIndices); i++)
         HeapFree(GetProcessHeap(), 0, new_node->lppszStrings[i]);
       HeapFree(GetProcessHeap(), 0, new_node->fmt.lpDecimalSep);
       HeapFree(GetProcessHeap(), 0, new_node->fmt.lpThousandSep);
@@ -697,7 +697,7 @@ static INT NLS_GetDateTimeFormatW(LCID lcid, DWORD dwFlags,
       {
         static const WCHAR fmtW[] = {'%','.','*','d',0};
         /* We have a numeric value to add */
-        snprintfW(buff, sizeof(buff)/sizeof(WCHAR), fmtW, count, dwVal);
+        snprintfW(buff, ARRAY_SIZE(buff), fmtW, count, dwVal);
       }
 
       dwLen = szAdd ? strlenW(szAdd) : 0;
@@ -793,10 +793,10 @@ static INT NLS_GetDateTimeFormatA(LCID lcid, DWORD dwFlags,
   }
 
   if (lpFormat)
-    MultiByteToWideChar(cp, 0, lpFormat, -1, szFormat, sizeof(szFormat)/sizeof(WCHAR));
+    MultiByteToWideChar(cp, 0, lpFormat, -1, szFormat, ARRAY_SIZE(szFormat));
 
-  if (cchOut > (int)(sizeof(szOut)/sizeof(WCHAR)))
-    cchOut = sizeof(szOut)/sizeof(WCHAR);
+  if (cchOut > (int) ARRAY_SIZE(szOut))
+    cchOut = ARRAY_SIZE(szOut);
 
   szOut[0] = '\0';
 
@@ -866,7 +866,7 @@ INT WINAPI GetDateFormatA( LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
                                 lpFormat, lpDateStr, cchOut);
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /******************************************************************************
  * GetDateFormatEx [KERNEL32.@]
  *
@@ -906,7 +906,7 @@ INT WINAPI GetDateFormatEx(LPCWSTR localename, DWORD flags,
                                 flags | DATE_DATEVARSONLY, date, format,
                                 outbuf, bufsize);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 /******************************************************************************
  * GetDateFormatW      [KERNEL32.@]
@@ -974,7 +974,7 @@ INT WINAPI GetTimeFormatA(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime,
                                 lpFormat, lpTimeStr, cchOut);
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /******************************************************************************
  * GetTimeFormatEx [KERNEL32.@]
  *
@@ -1006,7 +1006,7 @@ INT WINAPI GetTimeFormatEx(LPCWSTR localename, DWORD flags,
                                 flags | TIME_TIMEVARSONLY, time, format,
                                 outbuf, bufsize);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 /******************************************************************************
  *             GetTimeFormatW  [KERNEL32.@]
@@ -1087,21 +1087,21 @@ INT WINAPI GetNumberFormatA(LCID lcid, DWORD dwFlags,
     pfmt = &fmt;
     if (lpFormat->lpDecimalSep)
     {
-      MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, sizeof(szDec)/sizeof(WCHAR));
+      MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, ARRAY_SIZE(szDec));
       fmt.lpDecimalSep = szDec;
     }
     if (lpFormat->lpThousandSep)
     {
-      MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, sizeof(szGrp)/sizeof(WCHAR));
+      MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, ARRAY_SIZE(szGrp));
       fmt.lpThousandSep = szGrp;
     }
   }
 
   if (lpszValue)
-    MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, sizeof(szIn)/sizeof(WCHAR));
+    MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, ARRAY_SIZE(szIn));
 
-  if (cchOut > (int)(sizeof(szOut)/sizeof(WCHAR)))
-    cchOut = sizeof(szOut)/sizeof(WCHAR);
+  if (cchOut > (int) ARRAY_SIZE(szOut))
+    cchOut = ARRAY_SIZE(szOut);
 
   szOut[0] = '\0';
 
@@ -1136,7 +1136,7 @@ INT WINAPI GetNumberFormatW(LCID lcid, DWORD dwFlags,
                             LPCWSTR lpszValue,  const NUMBERFMTW *lpFormat,
                             LPWSTR lpNumberStr, int cchOut)
 {
-  WCHAR szBuff[128], *szOut = szBuff + sizeof(szBuff) / sizeof(WCHAR) - 1;
+  WCHAR szBuff[128], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
   WCHAR szNegBuff[8];
   const WCHAR *lpszNeg = NULL, *lpszNegStart, *szSrc;
   DWORD dwState = 0, dwDecimals = 0, dwGroupCount = 0, dwCurrentGroupCount = 0;
@@ -1164,7 +1164,7 @@ INT WINAPI GetNumberFormatW(LCID lcid, DWORD dwFlags,
   else
   {
     GetLocaleInfoW(lcid, LOCALE_SNEGATIVESIGN|(dwFlags & LOCALE_NOUSEROVERRIDE),
-                   szNegBuff, sizeof(szNegBuff)/sizeof(WCHAR));
+                   szNegBuff, ARRAY_SIZE(szNegBuff));
     lpszNegStart = lpszNeg = szNegBuff;
   }
   lpszNeg = lpszNeg + strlenW(lpszNeg) - 1;
@@ -1368,7 +1368,7 @@ error:
   return 0;
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /**************************************************************************
  *              GetNumberFormatEx      (KERNEL32.@)
  */
@@ -1387,7 +1387,7 @@ INT WINAPI GetNumberFormatEx(LPCWSTR name, DWORD flags,
 
   return GetNumberFormatW(lcid, flags, value, format, number, numout);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 /**************************************************************************
  *              GetCurrencyFormatA     (KERNEL32.@)
@@ -1453,26 +1453,26 @@ INT WINAPI GetCurrencyFormatA(LCID lcid, DWORD dwFlags,
     pfmt = &fmt;
     if (lpFormat->lpDecimalSep)
     {
-      MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, sizeof(szDec)/sizeof(WCHAR));
+      MultiByteToWideChar(cp, 0, lpFormat->lpDecimalSep, -1, szDec, ARRAY_SIZE(szDec));
       fmt.lpDecimalSep = szDec;
     }
     if (lpFormat->lpThousandSep)
     {
-      MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, sizeof(szGrp)/sizeof(WCHAR));
+      MultiByteToWideChar(cp, 0, lpFormat->lpThousandSep, -1, szGrp, ARRAY_SIZE(szGrp));
       fmt.lpThousandSep = szGrp;
     }
     if (lpFormat->lpCurrencySymbol)
     {
-      MultiByteToWideChar(cp, 0, lpFormat->lpCurrencySymbol, -1, szCy, sizeof(szCy)/sizeof(WCHAR));
+      MultiByteToWideChar(cp, 0, lpFormat->lpCurrencySymbol, -1, szCy, ARRAY_SIZE(szCy));
       fmt.lpCurrencySymbol = szCy;
     }
   }
 
   if (lpszValue)
-    MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, sizeof(szIn)/sizeof(WCHAR));
+    MultiByteToWideChar(cp, 0, lpszValue, -1, szIn, ARRAY_SIZE(szIn));
 
-  if (cchOut > (int)(sizeof(szOut)/sizeof(WCHAR)))
-    cchOut = sizeof(szOut)/sizeof(WCHAR);
+  if (cchOut > (int) ARRAY_SIZE(szOut))
+    cchOut = ARRAY_SIZE(szOut);
 
   szOut[0] = '\0';
 
@@ -1528,7 +1528,7 @@ INT WINAPI GetCurrencyFormatW(LCID lcid, DWORD dwFlags,
     CF_CY_LEFT|CF_CY_SPACE,  /* $ 1.1 */
     CF_CY_RIGHT|CF_CY_SPACE, /* 1.1 $ */
   };
-  WCHAR szBuff[128], *szOut = szBuff + sizeof(szBuff) / sizeof(WCHAR) - 1;
+  WCHAR szBuff[128], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
   WCHAR szNegBuff[8];
   const WCHAR *lpszNeg = NULL, *lpszNegStart, *szSrc, *lpszCy, *lpszCyStart;
   DWORD dwState = 0, dwDecimals = 0, dwGroupCount = 0, dwCurrentGroupCount = 0, dwFmt;
@@ -1559,7 +1559,7 @@ INT WINAPI GetCurrencyFormatW(LCID lcid, DWORD dwFlags,
   else
   {
     GetLocaleInfoW(lcid, LOCALE_SNEGATIVESIGN|(dwFlags & LOCALE_NOUSEROVERRIDE),
-                   szNegBuff, sizeof(szNegBuff)/sizeof(WCHAR));
+                   szNegBuff, ARRAY_SIZE(szNegBuff));
     lpszNegStart = lpszNeg = szNegBuff;
   }
   dwFlags &= (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP);
@@ -1782,6 +1782,21 @@ error:
   return 0;
 }
 
+#if _WIN32_WINNT >= 0x600
+/***********************************************************************
+ *            GetCurrencyFormatEx (KERNEL32.@)
+ */
+int WINAPI GetCurrencyFormatEx(LPCWSTR localename, DWORD flags, LPCWSTR value,
+                                const CURRENCYFMTW *format, LPWSTR str, int len)
+{
+    TRACE("(%s,0x%08x,%s,%p,%p,%d)\n", debugstr_w(localename), flags,
+            debugstr_w(value), format, str, len);
+
+    return GetCurrencyFormatW( LocaleNameToLCID(localename, 0), flags, value, format, str, len);
+}
+#endif
+
+
 /* FIXME: Everything below here needs to move somewhere else along with the
  *        other EnumXXX functions, when a method for storing resources for
  *        alternate calendars is determined.
@@ -1854,9 +1869,9 @@ static BOOL NLS_EnumDateFormats(const struct enumdateformats_context *ctxt)
 
     lctype |= ctxt->flags & LOCALE_USE_CP_ACP;
     if (ctxt->unicode)
-        ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, sizeof(bufW)/sizeof(bufW[0]));
+        ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, ARRAY_SIZE(bufW));
     else
-        ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, sizeof(bufA)/sizeof(bufA[0]));
+        ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, ARRAY_SIZE(bufA));
 
     if (ret)
     {
@@ -1949,7 +1964,7 @@ BOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW proc, LCID lcid, DWORD flags)
     return NLS_EnumDateFormats(&ctxt);
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /**************************************************************************
  *              EnumDateFormatsExEx    (KERNEL32.@)
  */
@@ -1966,7 +1981,7 @@ BOOL WINAPI EnumDateFormatsExEx(DATEFMT_ENUMPROCEXEX proc, const WCHAR *locale,
 
     return NLS_EnumDateFormats(&ctxt);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 struct enumtimeformats_context {
     enum enum_callback_type type;  /* callback kind */
@@ -2009,9 +2024,9 @@ static BOOL NLS_EnumTimeFormats(struct enumtimeformats_context *ctxt)
 
     lctype |= ctxt->flags & LOCALE_USE_CP_ACP;
     if (ctxt->unicode)
-        ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, sizeof(bufW)/sizeof(bufW[0]));
+        ret = GetLocaleInfoW(ctxt->lcid, lctype, bufW, ARRAY_SIZE(bufW));
     else
-        ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, sizeof(bufA)/sizeof(bufA[0]));
+        ret = GetLocaleInfoA(ctxt->lcid, lctype, bufA, ARRAY_SIZE(bufA));
 
     if (ret)
     {
@@ -2073,7 +2088,7 @@ BOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW proc, LCID lcid, DWORD flags)
     return NLS_EnumTimeFormats(&ctxt);
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /**************************************************************************
  *              EnumTimeFormatsEx      (KERNEL32.@)
  */
@@ -2090,7 +2105,7 @@ BOOL WINAPI EnumTimeFormatsEx(TIMEFMT_ENUMPROCEX proc, const WCHAR *locale, DWOR
 
     return NLS_EnumTimeFormats(&ctxt);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 struct enumcalendar_context {
     enum enum_callback_type type;  /* callback kind */
@@ -2321,7 +2336,7 @@ BOOL WINAPI EnumCalendarInfoExW( CALINFO_ENUMPROCEXW calinfoproc,LCID locale,
   return NLS_EnumCalendarInfo(&ctxt);
 }
 
-#ifndef __REACTOS__
+#if _WIN32_WINNT >= 0x600
 /******************************************************************************
  *             EnumCalendarInfoExEx    [KERNEL32.@]
  */
@@ -2341,7 +2356,7 @@ BOOL WINAPI EnumCalendarInfoExEx( CALINFO_ENUMPROCEXEX calinfoproc, LPCWSTR loca
   ctxt.unicode = TRUE;
   return NLS_EnumCalendarInfo(&ctxt);
 }
-#endif /* !__REACTOS__ */
+#endif /* _WIN32_WINNT >= 0x600 */
 
 /*********************************************************************
  *     GetCalendarInfoA                                (KERNEL32.@)
@@ -2567,6 +2582,23 @@ int WINAPI GetCalendarInfoW(LCID Locale, CALID Calendar, CALTYPE CalType,
     return 0;
 }
 
+#if _WIN32_WINNT >= 0x600
+/*********************************************************************
+ *     GetCalendarInfoEx                               (KERNEL32.@)
+ */
+int WINAPI GetCalendarInfoEx(LPCWSTR locale, CALID calendar, LPCWSTR lpReserved, CALTYPE caltype,
+    LPWSTR data, int len, DWORD *value)
+{
+    static int once;
+
+    LCID lcid = LocaleNameToLCID(locale, 0);
+    if (!once++)
+        FIXME("(%s, %d, %p, 0x%08x, %p, %d, %p): semi-stub\n", debugstr_w(locale), calendar, lpReserved, caltype,
+        data, len, value);
+    return GetCalendarInfoW(lcid, calendar, caltype, data, len, value);
+}
+#endif
+
 /*********************************************************************
  *     SetCalendarInfoA                                (KERNEL32.@)
  *
index 86449e8..391eca8 100644 (file)
@@ -2261,4 +2261,17 @@ GetNLSVersion(IN NLS_FUNCTION Function,
     return TRUE;
 }
 
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+GetNLSVersionEx(IN NLS_FUNCTION function,
+                IN LPCWSTR lpLocaleName,
+                IN OUT LPNLSVERSIONINFOEX lpVersionInformation)
+{
+    STUB;
+    return TRUE;
+}
+
 /* EOF */
index 9b59c15..4b31162 100644 (file)
@@ -283,7 +283,7 @@ kernel32 -
   reactos/dll/win32/kernel32/winnls/string/fold.c        # Synced to WineStaging-3.3
   reactos/dll/win32/kernel32/winnls/string/format_msg.c  # Synced to WineStaging-3.3
   reactos/dll/win32/kernel32/winnls/string/lang.c        # Synced in r52754
-  reactos/dll/win32/kernel32/winnls/string/lcformat.c    # Synced to WineStaging-3.3
+  reactos/dll/win32/kernel32/winnls/string/lcformat.c    # Synced to WineStaging-3.21
   reactos/dll/win32/kernel32/winnls/string/nls.c         # Synced in r52754
   reactos/dll/win32/kernel32/winnls/string/sortkey.c     # Synced to WineStaging-3.3
 
index eb9f948..61baa71 100644 (file)
@@ -198,6 +198,15 @@ extern "C" {
 #define LCID_INSTALLED 1
 #define LCID_SUPPORTED 2
 #define LCID_ALTERNATE_SORTS 4
+
+#define LOCALE_ALL                  0x00
+#define LOCALE_WINDOWS              0x01
+#define LOCALE_SUPPLEMENTAL         0x02
+#define LOCALE_ALTERNATE_SORTS      0x04
+#define LOCALE_REPLACEMENT          0x08
+#define LOCALE_NEUTRALDATA          0x10
+#define LOCALE_SPECIFICDATA         0x20
+
 #define MAP_FOLDCZONE 16
 #define MAP_FOLDDIGITS 128
 #define MAP_PRECOMPOSED 32
@@ -611,6 +620,13 @@ typedef struct nlsversioninfo {
        DWORD dwNLSVersion;
        DWORD dwDefinedVersion;
 } NLSVERSIONINFO,*LPNLSVERSIONINFO;
+typedef struct _nlsversioninfoex {
+    DWORD dwNLSVersionInfoSize;
+    DWORD dwNLSVersion;
+    DWORD dwDefinedVersion;
+    DWORD dwEffectiveId;
+    GUID  guidCustomVersion;
+} NLSVERSIONINFOEX, *LPNLSVERSIONINFOEX;
 typedef struct _numberfmtA {
        UINT NumDigits;
        UINT LeadingZero;
@@ -760,6 +776,7 @@ GetCurrencyFormatW(
 
 int WINAPI GetDateFormatA(LCID,DWORD,const SYSTEMTIME*,LPCSTR,LPSTR,int);
 int WINAPI GetDateFormatW(LCID,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int);
+int WINAPI GetDateFormatEx(LPCWSTR,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int,LPCWSTR);
 
 int
 WINAPI
@@ -797,6 +814,13 @@ GetLocaleInfoW(
 
 BOOL WINAPI GetNLSVersion(_In_ NLS_FUNCTION, _In_ LCID, _Inout_ LPNLSVERSIONINFO);
 
+BOOL
+WINAPI
+GetNLSVersionEx(
+  _In_ NLS_FUNCTION function,
+  _In_ LPCWSTR lpLocaleName,
+  _Inout_ LPNLSVERSIONINFOEX lpVersionInformation);
+
 int
 WINAPI
 GetNumberFormatA(
@@ -859,6 +883,7 @@ LCID WINAPI GetSystemDefaultLCID(void);
 LCID WINAPI GetThreadLocale(void);
 int WINAPI GetTimeFormatA(LCID,DWORD,const SYSTEMTIME*,LPCSTR,LPSTR,int);
 int WINAPI GetTimeFormatW(LCID,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int);
+int WINAPI GetTimeFormatEx(LPCWSTR,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int);
 LANGID WINAPI GetUserDefaultLangID(void);
 LCID WINAPI GetUserDefaultLCID(void);
 GEOID WINAPI GetUserGeoID(_In_ GEOCLASS);
@@ -978,6 +1003,8 @@ GetLocaleInfoEx(
   _Out_writes_opt_(cchData) LPWSTR lpLCData,
   _In_ int cchData);
 
+BOOL WINAPI IsValidLocaleName(_In_ LPCWSTR lpLocaleName);
+
 BOOL
 WINAPI
 GetProcessPreferredUILanguages(
@@ -1076,6 +1103,8 @@ GetStringScripts(
 BOOL WINAPI SetProcessPreferredUILanguages(_In_ DWORD, _In_opt_ PCZZWSTR, _Out_opt_ PULONG);
 BOOL WINAPI SetThreadPreferredUILanguages(_In_ DWORD, _In_opt_ PCZZWSTR, _Out_opt_ PULONG);
 BOOL WINAPI VerifyScripts(_In_ DWORD, _In_ LPCWSTR, _In_ int, _In_ LPCWSTR, _In_ int);
+INT  WINAPI LCMapStringEx(_In_ LPCWSTR, _In_ DWORD, _In_ LPCWSTR, _In_ INT, _Out_opt_ LPWSTR, _In_ INT, _In_ LPNLSVERSIONINFO, _In_ LPVOID, _In_ LPARAM);
+LCID WINAPI LocaleNameToLCID(_In_ LPCWSTR, _In_ DWORD);
 
 #endif /* (WINVER >= 0x0600) */