src/locale/windows/SDL_syslocale.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 04 May 2020 02:27:29 -0400
changeset 13797 55ec5ae4aa0b
child 13843 cbd001bb0b89
permissions -rw-r--r--
locale: Implemented SDL_GetPreferredLocales().

This was something I proposed a long time ago, Sylvain Becker did
additional work on it, then back to me.

Fixes Bugzilla #2131.
icculus@13797
     1
/*
icculus@13797
     2
  Simple DirectMedia Layer
icculus@13797
     3
  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
icculus@13797
     4
icculus@13797
     5
  This software is provided 'as-is', without any express or implied
icculus@13797
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@13797
     7
  arising from the use of this software.
icculus@13797
     8
icculus@13797
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@13797
    10
  including commercial applications, and to alter it and redistribute it
icculus@13797
    11
  freely, subject to the following restrictions:
icculus@13797
    12
icculus@13797
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@13797
    14
     claim that you wrote the original software. If you use this software
icculus@13797
    15
     in a product, an acknowledgment in the product documentation would be
icculus@13797
    16
     appreciated but is not required.
icculus@13797
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@13797
    18
     misrepresented as being the original software.
icculus@13797
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@13797
    20
*/
icculus@13797
    21
icculus@13797
    22
#include "../../SDL_internal.h"
icculus@13797
    23
#include "../../core/windows/SDL_windows.h"
icculus@13797
    24
#include "../SDL_syslocale.h"
icculus@13797
    25
#include "SDL_assert.h"
icculus@13797
    26
icculus@13797
    27
typedef BOOL (WINAPI *pfnGetUserPreferredUILanguages)(DWORD,PULONG,PZZWSTR,PULONG);
icculus@13797
    28
#ifndef MUI_LANGUAGE_NAME
icculus@13797
    29
#define MUI_LANGUAGE_NAME 0x8 
icculus@13797
    30
#endif
icculus@13797
    31
icculus@13797
    32
static pfnGetUserPreferredUILanguages pGetUserPreferredUILanguages = NULL;
icculus@13797
    33
static HMODULE kernel32 = 0;
icculus@13797
    34
icculus@13797
    35
icculus@13797
    36
/* this is the fallback for WinXP...one language, not a list. */
icculus@13797
    37
static void
icculus@13797
    38
SDL_SYS_GetPreferredLocales_winxp(char *buf, size_t buflen)
icculus@13797
    39
{
icculus@13797
    40
    const char **retval = NULL;
icculus@13797
    41
    char lang[16];
icculus@13797
    42
    char country[16];
icculus@13797
    43
icculus@13797
    44
	const int langrc = GetLocaleInfoA(LOCALE_USER_DEFAULT,
icculus@13797
    45
                                      LOCALE_SISO639LANGNAME,
icculus@13797
    46
                                      lang, sizeof (lang));
icculus@13797
    47
icculus@13797
    48
	const int ctryrc =  GetLocaleInfoA(LOCALE_USER_DEFAULT,
icculus@13797
    49
                                       LOCALE_SISO3166CTRYNAME,
icculus@13797
    50
                                       country, sizeof (country));
icculus@13797
    51
icculus@13797
    52
    /* Win95 systems will fail, because they don't have LOCALE_SISO*NAME ... */
icculus@13797
    53
    if (langrc == 0) {
icculus@13797
    54
        SDL_SetError("Couldn't obtain language info");
icculus@13797
    55
    } else {
icculus@13797
    56
        SDL_snprintf(buf, buflen, "%s%s%s", lang, ctryrc ? "_" : "", ctryrc ? country : "");
icculus@13797
    57
    }
icculus@13797
    58
}
icculus@13797
    59
icculus@13797
    60
/* this works on Windows Vista and later. */
icculus@13797
    61
static void
icculus@13797
    62
SDL_SYS_GetPreferredLocales_vista(char *buf, size_t buflen)
icculus@13797
    63
{
icculus@13797
    64
    ULONG numlangs = 0;
icculus@13797
    65
    WCHAR *wbuf = NULL;
icculus@13797
    66
    ULONG wbuflen = 0;
icculus@13797
    67
    SDL_bool isstack;
icculus@13797
    68
icculus@13797
    69
    SDL_assert(pGetUserPreferredUILanguages != NULL);
icculus@13797
    70
    pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numlangs, NULL, &wbuflen);
icculus@13797
    71
icculus@13797
    72
    wbuf = SDL_small_alloc(WCHAR, wbuflen, &isstack);
icculus@13797
    73
    if (!wbuf) {
icculus@13797
    74
        SDL_OutOfMemory();
icculus@13797
    75
        return;
icculus@13797
    76
    }
icculus@13797
    77
icculus@13797
    78
    if (!pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numlangs, wbuf, &wbuflen)) {
icculus@13797
    79
        SDL_SYS_GetPreferredLocales_winxp(buf, buflen);  /* oh well, try the fallback. */
icculus@13797
    80
    } else {
icculus@13797
    81
        const ULONG endidx = SDL_min(buflen, wbuflen - 1);
icculus@13797
    82
        ULONG str_start = 0;
icculus@13797
    83
        ULONG i;
icculus@13797
    84
        for (i = 0; i < endidx; i++) {
icculus@13797
    85
            const char ch = (char) wbuf[i];  /* these should all be low-ASCII, safe to cast */
icculus@13797
    86
            if (ch == '\0') {
icculus@13797
    87
                buf[i] = ',';  /* change null separators to commas */
icculus@13797
    88
                str_start = i;
icculus@13797
    89
            } else if (ch == '-') {
icculus@13797
    90
                buf[i] = '_';  /* change '-' to '_' */
icculus@13797
    91
            } else {
icculus@13797
    92
                buf[i] = ch;   /* copy through as-is. */
icculus@13797
    93
            }
icculus@13797
    94
        }
icculus@13797
    95
        buf[str_start] = '\0';  /* terminate string, chop off final ',' */
icculus@13797
    96
    }
icculus@13797
    97
icculus@13797
    98
    SDL_small_free(wbuf, isstack);
icculus@13797
    99
}
icculus@13797
   100
icculus@13797
   101
void
icculus@13797
   102
SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
icculus@13797
   103
{
icculus@13797
   104
    if (!kernel32) {
icculus@13797
   105
        kernel32 = LoadLibraryW(L"kernel32.dll");
icculus@13797
   106
        if (kernel32) {
icculus@13797
   107
            pGetUserPreferredUILanguages = (pfnGetUserPreferredUILanguages) GetProcAddress(kernel32, "GetUserPreferredUILanguages");
icculus@13797
   108
        }
icculus@13797
   109
    }
icculus@13797
   110
icculus@13797
   111
    if (pGetUserPreferredUILanguages == NULL) {
icculus@13797
   112
        SDL_SYS_GetPreferredLocales_winxp(buf, buflen);  /* this is always available */
icculus@13797
   113
    } else {
icculus@13797
   114
        SDL_SYS_GetPreferredLocales_vista(buf, buflen);  /* available on Vista and later. */
icculus@13797
   115
    }
icculus@13797
   116
}
icculus@13797
   117
icculus@13797
   118
/* vi: set ts=4 sw=4 expandtab: */
icculus@13797
   119