GnuCash fec5643+
Loading...
Searching...
No Matches
gnucash-locale-windows.c
1/*
2 * gnucash-locale-windows.c -- Windows specific locale handling
3 *
4 * Copyright (C) 2020 John Ralls <jralls@ceridwen.us>
5 * Copyright (C) 2021 Geert Janssens <geert@kobaltwit.be>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, contact:
19 *
20 * Free Software Foundation Voice: +1-617-542-5942
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22 * Boston, MA 02110-1301, USA gnu@gnu.org
23 */
24
25#include <Windows.h>
26#include <fcntl.h>
27#include <locale.h>
28#include <glib/gi18n.h>
29#include "gnucash-locale-platform.h"
30
31static void
32rectify_utf(const char* envvar, const char* locale,
33 const char* dot, const char* rest)
34{
35 char *new_locale;
36 if (rest && *rest)
37 new_locale = g_strdup_printf ("%s.UTF-%s@%s",
38 locale, dot + 3, rest);
39 else
40 new_locale = g_strdup_printf ("%s.UTF-%s", locale, dot + 3);
41
42 _putenv_s (envvar, new_locale);
43 g_free(new_locale);
44}
45
46static void
47rectify_iso(const char* envvar, const char* locale,
48 const char* dot, const char* rest)
49{
50
51 char *eefn = strstr (dot, "8859");
52
53 if (!(eefn && *eefn))
54 return;
55
56 char* isonum = (*(eefn + 4) == '-') ? eefn + 5 : eefn + 4;
57
58 if (*isonum == '\0')
59 return;
60
61 char *new_locale;
62 if (rest && *rest)
63 new_locale = g_strdup_printf ("%s.ISO-8859-%s@%s", locale, isonum, rest);
64 else
65 new_locale = g_strdup_printf ("%s.ISO-8859-%s", locale, isonum);
66
67 _putenv_s (envvar, new_locale);
68 g_free (new_locale);
69}
70
71static void
72rectify_environment_charset(const char* envvar)
73{
74 if (!(envvar && *envvar))
75 return;
76 if (strcmp (envvar, "LANG") && strncmp (envvar, "LC_", 3))
77 return;
78 char* saveptr;
79 char* varval = getenv (envvar);
80 char* locale = strtok_r (varval, ".", &saveptr);
81 char* dot = strtok_r (NULL, "@", &saveptr);
82
83 if (!dot) //strsep didn't find a .
84 return;
85
86 char* rest = strtok_r (NULL, "@", &saveptr);
87
88 if ((strncasecmp (dot, "utf", 3) == 0 || strncasecmp (dot, "ucs", 3) == 0) &&
89 dot[3] != '-')
90 return rectify_utf (envvar, locale, dot, rest);
91
92 if (strncasecmp (dot, "iso", 3) == 0 && strlen (dot) >= 8 &&
93 dot[3] != '-' && dot[8] != '-')
94 return rectify_iso (envvar, locale, dot, rest);
95
96 //Otherwise do nothing
97}
98
99/* If one of the Unix locale variables LC_ALL, LC_MESSAGES, or LANG is
100 * set in the environment check to see if it's a valid locale and if
101 * it is set both the Windows and POSIX locales to that. If not
102 * retrieve the Windows locale and set POSIX to match.
103 */
104char *
105set_platform_locale(void)
106{
107 WCHAR lpLocaleName[LOCALE_NAME_MAX_LENGTH];
108 char *locale = NULL;
109 /* Prevent Bug 799320 by ensuring that the localization
110 environment variables of interest have well-formed UTF or
111 ISO-8859 specifiers for GnuLib's interpretation of well-formed,
112 which means having minuses in the right places. This only
113 protects agains missing hyphens, it won't help if you specify
114 utf42 as a charset when you meant utf32.
115 */
116 rectify_environment_charset ("LANG");
117 rectify_environment_charset ("LC_ALL");
118 rectify_environment_charset ("LC_MESSAGES");
119 rectify_environment_charset ("LC_CTYPE");
120
121 if (((locale = getenv ("LC_ALL")) != NULL && locale[0] != '\0') ||
122 ((locale = getenv ("LC_MESSAGES")) != NULL && locale[0] != '\0') ||
123 ((locale = getenv ("LANG")) != NULL && locale[0] != '\0'))
124 {
125 gunichar2* wlocale = NULL;
126 int len = 0;
127 len = strchr(locale, '.') - locale;
128 locale[2] = '-';
129 wlocale = g_utf8_to_utf16 (locale, len, NULL, NULL, NULL);
130 if (IsValidLocaleName(wlocale))
131 {
132 LCID lcid = LocaleNameToLCID(wlocale, LOCALE_ALLOW_NEUTRAL_NAMES);
133 SetThreadLocale(lcid);
134 locale[2] = '_';
135 setlocale (LC_ALL, locale);
136 g_free(wlocale);
137 return g_strdup (locale);
138 }
139 g_free(locale);
140 g_free(wlocale);
141 }
142 if (GetUserDefaultLocaleName(lpLocaleName, LOCALE_NAME_MAX_LENGTH))
143 {
144 locale = g_utf16_to_utf8((gunichar2*)lpLocaleName,
145 LOCALE_NAME_MAX_LENGTH,
146 NULL, NULL, NULL);
147 (locale)[2] = '_';
148 setlocale (LC_ALL, locale);
149 return locale;
150 }
151 return g_strdup("C");
152}
153
154void
155set_platform_ctype_to_acp (void)
156{
157 // The C locale is always aligned with ACP. Use _wsetlocale because
158 // libintl's setlocale replacement refuses "C" when the ACP is UTF-8.
159 _wsetlocale (LC_CTYPE, L"C");
160}