From 7c23d1d9d9cc1d3d19fe35708da7c5d5b3556e05 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 1 Feb 2017 13:14:16 +0100 Subject: patch 8.0.0280: problem setting multi-byte environment var on MS-Windows Problem: On MS-Windows setting an environment variable with multi-byte strings does not work well. Solution: Use wputenv when possible. (Taro Muraoka, Ken Takata) --- src/misc1.c | 3 --- src/os_win32.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- src/os_win32.h | 4 +++- src/proto/os_win32.pro | 1 + src/version.c | 2 ++ src/vim.h | 1 + 6 files changed, 63 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/misc1.c b/src/misc1.c index cc5d5e60f..f95c3fe47 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -4453,9 +4453,6 @@ vim_setenv(char_u *name, char_u *val) { sprintf((char *)envbuf, "%s=%s", name, val); putenv((char *)envbuf); -# ifdef libintl_putenv - libintl_putenv((char *)envbuf); -# endif } #endif #ifdef FEAT_GETTEXT diff --git a/src/os_win32.c b/src/os_win32.c index 9b86478d3..030b4b0da 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -515,6 +515,7 @@ static char *null_libintl_textdomain(const char *); static char *null_libintl_bindtextdomain(const char *, const char *); static char *null_libintl_bind_textdomain_codeset(const char *, const char *); static int null_libintl_putenv(const char *); +static int null_libintl_wputenv(const wchar_t *); static HINSTANCE hLibintlDLL = NULL; char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext; @@ -526,6 +527,7 @@ char *(*dyn_libintl_bindtextdomain)(const char *, const char *) char *(*dyn_libintl_bind_textdomain_codeset)(const char *, const char *) = null_libintl_bind_textdomain_codeset; int (*dyn_libintl_putenv)(const char *) = null_libintl_putenv; +int (*dyn_libintl_wputenv)(const wchar_t *) = null_libintl_wputenv; int dyn_libintl_init(void) @@ -591,9 +593,14 @@ dyn_libintl_init(void) /* _putenv() function for the libintl.dll is optional. */ hmsvcrt = find_imported_module_by_funcname(hLibintlDLL, "getenv"); if (hmsvcrt != NULL) + { dyn_libintl_putenv = (void *)GetProcAddress(hmsvcrt, "_putenv"); - if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == putenv) + dyn_libintl_wputenv = (void *)GetProcAddress(hmsvcrt, "_wputenv"); + } + if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == _putenv) dyn_libintl_putenv = null_libintl_putenv; + if (dyn_libintl_wputenv == NULL || dyn_libintl_wputenv == _wputenv) + dyn_libintl_wputenv = null_libintl_wputenv; return 1; } @@ -610,6 +617,7 @@ dyn_libintl_end(void) dyn_libintl_bindtextdomain = null_libintl_bindtextdomain; dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset; dyn_libintl_putenv = null_libintl_putenv; + dyn_libintl_wputenv = null_libintl_wputenv; } /*ARGSUSED*/ @@ -658,6 +666,13 @@ null_libintl_putenv(const char *envstring) return 0; } +/*ARGSUSED*/ + int +null_libintl_wputenv(const wchar_t *envstring) +{ + return 0; +} + #endif /* DYNAMIC_GETTEXT */ /* This symbol is not defined in older versions of the SDK or Visual C++ */ @@ -6985,3 +7000,43 @@ fix_arg_enc(void) set_alist_count(); } #endif + + int +mch_setenv(char *var, char *value, int x) +{ + char_u *envbuf; + + envbuf = alloc((unsigned)(STRLEN(var) + STRLEN(value) + 2)); + if (envbuf == NULL) + return -1; + + sprintf((char *)envbuf, "%s=%s", var, value); + +#ifdef FEAT_MBYTE + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + { + WCHAR *p = enc_to_utf16(envbuf, NULL); + + vim_free(envbuf); + if (p == NULL) + return -1; + _wputenv(p); +# ifdef libintl_wputenv + libintl_wputenv(p); +# endif + /* Unlike Un*x systems, we can free the string for _wputenv(). */ + vim_free(p); + } + else +#endif + { + _putenv((char *)envbuf); +# ifdef libintl_putenv + libintl_putenv((char *)envbuf); +# endif + /* Unlike Un*x systems, we can free the string for _putenv(). */ + vim_free(envbuf); + } + + return 0; +} diff --git a/src/os_win32.h b/src/os_win32.h index f620d742e..5017f532e 100644 --- a/src/os_win32.h +++ b/src/os_win32.h @@ -202,7 +202,9 @@ Trace(char *pszFormat, ...); #define ASSERT_NULL_OR_POINTER(p, type) \ ASSERT(((p) == NULL) || IsValidAddress((p), sizeof(type), FALSE)) -#define mch_setenv(name, val, x) setenv(name, val, x) +#ifndef HAVE_SETENV +# define HAVE_SETENV +#endif #define mch_getenv(x) (char_u *)getenv((char *)(x)) #ifdef __BORLANDC__ # define vim_mkdir(x, y) mkdir(x) diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro index a64c863bb..ca671464b 100644 --- a/src/proto/os_win32.pro +++ b/src/proto/os_win32.pro @@ -65,4 +65,5 @@ void free_cmd_argsW(void); void used_file_arg(char *name, int literal, int full_path, int diff_mode); void set_alist_count(void); void fix_arg_enc(void); +int mch_setenv(char *var, char *value, int x); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 82ee6d4e6..08e32cf90 100644 --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 280, /**/ 279, /**/ diff --git a/src/vim.h b/src/vim.h index abee386cb..f3e87fef5 100644 --- a/src/vim.h +++ b/src/vim.h @@ -594,6 +594,7 @@ extern int (*dyn_libintl_putenv)(const char *envstring); # endif # define textdomain(domain) (*dyn_libintl_textdomain)(domain) # define libintl_putenv(envstring) (*dyn_libintl_putenv)(envstring) +# define libintl_wputenv(envstring) (*dyn_libintl_wputenv)(envstring) # else # include # define _(x) gettext((char *)(x)) -- cgit v1.2.1