Skip to content

Commit 7c23d1d

Browse files
committed
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)
1 parent 168dd00 commit 7c23d1d

File tree

6 files changed

+63
-5
lines changed

6 files changed

+63
-5
lines changed

src/misc1.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4453,9 +4453,6 @@ vim_setenv(char_u *name, char_u *val)
44534453
{
44544454
sprintf((char *)envbuf, "%s=%s", name, val);
44554455
putenv((char *)envbuf);
4456-
# ifdef libintl_putenv
4457-
libintl_putenv((char *)envbuf);
4458-
# endif
44594456
}
44604457
#endif
44614458
#ifdef FEAT_GETTEXT

src/os_win32.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ static char *null_libintl_textdomain(const char *);
515515
static char *null_libintl_bindtextdomain(const char *, const char *);
516516
static char *null_libintl_bind_textdomain_codeset(const char *, const char *);
517517
static int null_libintl_putenv(const char *);
518+
static int null_libintl_wputenv(const wchar_t *);
518519

519520
static HINSTANCE hLibintlDLL = NULL;
520521
char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext;
@@ -526,6 +527,7 @@ char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
526527
char *(*dyn_libintl_bind_textdomain_codeset)(const char *, const char *)
527528
= null_libintl_bind_textdomain_codeset;
528529
int (*dyn_libintl_putenv)(const char *) = null_libintl_putenv;
530+
int (*dyn_libintl_wputenv)(const wchar_t *) = null_libintl_wputenv;
529531

530532
int
531533
dyn_libintl_init(void)
@@ -591,9 +593,14 @@ dyn_libintl_init(void)
591593
/* _putenv() function for the libintl.dll is optional. */
592594
hmsvcrt = find_imported_module_by_funcname(hLibintlDLL, "getenv");
593595
if (hmsvcrt != NULL)
596+
{
594597
dyn_libintl_putenv = (void *)GetProcAddress(hmsvcrt, "_putenv");
595-
if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == putenv)
598+
dyn_libintl_wputenv = (void *)GetProcAddress(hmsvcrt, "_wputenv");
599+
}
600+
if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == _putenv)
596601
dyn_libintl_putenv = null_libintl_putenv;
602+
if (dyn_libintl_wputenv == NULL || dyn_libintl_wputenv == _wputenv)
603+
dyn_libintl_wputenv = null_libintl_wputenv;
597604

598605
return 1;
599606
}
@@ -610,6 +617,7 @@ dyn_libintl_end(void)
610617
dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
611618
dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset;
612619
dyn_libintl_putenv = null_libintl_putenv;
620+
dyn_libintl_wputenv = null_libintl_wputenv;
613621
}
614622

615623
/*ARGSUSED*/
@@ -658,6 +666,13 @@ null_libintl_putenv(const char *envstring)
658666
return 0;
659667
}
660668

669+
/*ARGSUSED*/
670+
int
671+
null_libintl_wputenv(const wchar_t *envstring)
672+
{
673+
return 0;
674+
}
675+
661676
#endif /* DYNAMIC_GETTEXT */
662677

663678
/* This symbol is not defined in older versions of the SDK or Visual C++ */
@@ -6985,3 +7000,43 @@ fix_arg_enc(void)
69857000
set_alist_count();
69867001
}
69877002
#endif
7003+
7004+
int
7005+
mch_setenv(char *var, char *value, int x)
7006+
{
7007+
char_u *envbuf;
7008+
7009+
envbuf = alloc((unsigned)(STRLEN(var) + STRLEN(value) + 2));
7010+
if (envbuf == NULL)
7011+
return -1;
7012+
7013+
sprintf((char *)envbuf, "%s=%s", var, value);
7014+
7015+
#ifdef FEAT_MBYTE
7016+
if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
7017+
{
7018+
WCHAR *p = enc_to_utf16(envbuf, NULL);
7019+
7020+
vim_free(envbuf);
7021+
if (p == NULL)
7022+
return -1;
7023+
_wputenv(p);
7024+
# ifdef libintl_wputenv
7025+
libintl_wputenv(p);
7026+
# endif
7027+
/* Unlike Un*x systems, we can free the string for _wputenv(). */
7028+
vim_free(p);
7029+
}
7030+
else
7031+
#endif
7032+
{
7033+
_putenv((char *)envbuf);
7034+
# ifdef libintl_putenv
7035+
libintl_putenv((char *)envbuf);
7036+
# endif
7037+
/* Unlike Un*x systems, we can free the string for _putenv(). */
7038+
vim_free(envbuf);
7039+
}
7040+
7041+
return 0;
7042+
}

src/os_win32.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,9 @@ Trace(char *pszFormat, ...);
202202
#define ASSERT_NULL_OR_POINTER(p, type) \
203203
ASSERT(((p) == NULL) || IsValidAddress((p), sizeof(type), FALSE))
204204

205-
#define mch_setenv(name, val, x) setenv(name, val, x)
205+
#ifndef HAVE_SETENV
206+
# define HAVE_SETENV
207+
#endif
206208
#define mch_getenv(x) (char_u *)getenv((char *)(x))
207209
#ifdef __BORLANDC__
208210
# define vim_mkdir(x, y) mkdir(x)

src/proto/os_win32.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,5 @@ void free_cmd_argsW(void);
6565
void used_file_arg(char *name, int literal, int full_path, int diff_mode);
6666
void set_alist_count(void);
6767
void fix_arg_enc(void);
68+
int mch_setenv(char *var, char *value, int x);
6869
/* vim: set ft=c : */

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,8 @@ static char *(features[]) =
764764

765765
static int included_patches[] =
766766
{ /* Add new patch number below this line */
767+
/**/
768+
280,
767769
/**/
768770
279,
769771
/**/

src/vim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ extern int (*dyn_libintl_putenv)(const char *envstring);
594594
# endif
595595
# define textdomain(domain) (*dyn_libintl_textdomain)(domain)
596596
# define libintl_putenv(envstring) (*dyn_libintl_putenv)(envstring)
597+
# define libintl_wputenv(envstring) (*dyn_libintl_wputenv)(envstring)
597598
# else
598599
# include <libintl.h>
599600
# define _(x) gettext((char *)(x))

0 commit comments

Comments
 (0)