diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 0ee21480cb..915c0a1f9f 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -304,6 +304,30 @@ void init_homedir(void) if (var == NULL) { var = os_getenv("USERPROFILE"); } + + // Weird but true: $HOME may contain an indirect reference to another + // variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set + // when $HOME is being set. + if (var != NULL && *var == '%') { + const char *p = strchr(var + 1, '%'); + if (p != NULL) { + vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1); + const char *exp = os_getenv(os_buf); + if (exp != NULL && *exp != NUL + && STRLEN(exp) + STRLEN(p) < MAXPATHL) { + vim_snprintf(os_buf, MAXPATHL, "%s%s", exp, p + 1); + var = os_buf; + } + } + } + + // Default home dir is C:/ + // Best assumption we can make in such a situation. + if (var == NULL + // Empty means "undefined" + || *var == NUL) { + var = "C:/"; + } #endif if (var != NULL) { @@ -705,17 +729,17 @@ char *vim_getenv(const char *name) // init_path() should have been called before now. assert(get_vim_var_str(VV_PROGPATH)[0] != NUL); - const char *kos_env_path = os_getenv(name); - if (kos_env_path != NULL) { - return xstrdup(kos_env_path); - } - #ifdef WIN32 if (strcmp(name, "HOME") == 0) { return xstrdup(homedir); } #endif + const char *kos_env_path = os_getenv(name); + if (kos_env_path != NULL) { + return xstrdup(kos_env_path); + } + bool vimruntime = (strcmp(name, "VIMRUNTIME") == 0); if (!vimruntime && strcmp(name, "VIM") != 0) { return NULL; diff --git a/src/nvim/testdir/test_windows_home.vim b/src/nvim/testdir/test_windows_home.vim index bbcbf96050..2e311b9aa5 100644 --- a/src/nvim/testdir/test_windows_home.vim +++ b/src/nvim/testdir/test_windows_home.vim @@ -86,7 +86,7 @@ func Test_WindowsHome() let $HOME = '%USERPROFILE%\bar' let $HOMEDRIVE = 'unused' let $HOMEPATH = 'unused' - " call CheckHome('C:\foo\bar', '%USERPROFILE%\bar') + call CheckHome('C:\foo\bar', '%USERPROFILE%\bar') " Invalid $HOME is kept let $USERPROFILE = 'C:\foo'