aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os')
-rw-r--r--src/nvim/os/env.c53
-rw-r--r--src/nvim/os/pty_process_unix.c37
-rw-r--r--src/nvim/os/pty_process_win.c78
-rw-r--r--src/nvim/os/stdpaths.c11
-rw-r--r--src/nvim/os/time.c2
5 files changed, 150 insertions, 31 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 879266e3d4..008f5ef63b 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -394,13 +394,21 @@ void os_get_hostname(char *hostname, size_t size)
}
/// To get the "real" home directory:
-/// - get value of $HOME
+/// 1. get value of $HOME
+/// 2. if $HOME is not set, try the following
+/// For Windows:
+/// 1. assemble homedir using HOMEDRIVE and HOMEPATH
+/// 2. try os_homedir()
+/// 3. resolve a direct reference to another system variable
+/// 4. guess C drive
/// For Unix:
-/// - go to that directory
-/// - do os_dirname() to get the real name of that directory.
-/// This also works with mounts and links.
-/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 1. try os_homedir()
+/// 2. go to that directory
+/// This also works with mounts and links.
+/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 3. fall back to current working directory as a last resort
static char *homedir = NULL;
+static char *os_homedir(void);
void init_homedir(void)
{
@@ -430,7 +438,7 @@ void init_homedir(void)
}
}
if (var == NULL) {
- var = os_getenv("USERPROFILE");
+ var = os_homedir();
}
// Weird but true: $HOME may contain an indirect reference to another
@@ -440,6 +448,7 @@ void init_homedir(void)
const char *p = strchr(var + 1, '%');
if (p != NULL) {
vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1);
+ var = NULL;
const char *exp = os_getenv(os_buf);
if (exp != NULL && *exp != NUL
&& STRLEN(exp) + STRLEN(p) < MAXPATHL) {
@@ -458,8 +467,12 @@ void init_homedir(void)
}
#endif
- if (var != NULL) {
#ifdef UNIX
+ if (var == NULL) {
+ var = os_homedir();
+ }
+
+ if (var != NULL) {
// Change to the directory and get the actual path. This resolves
// links. Don't do it when we can't return.
if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) {
@@ -470,11 +483,37 @@ void init_homedir(void)
EMSG(_(e_prev_dir));
}
}
+ }
+
+ // Fall back to current working directory if home is not found
+ if ((var == NULL || *var == NUL)
+ && os_dirname((char_u *)os_buf, sizeof(os_buf)) == OK) {
+ var = os_buf;
+ }
#endif
+ if (var != NULL) {
homedir = xstrdup(var);
}
}
+static char homedir_buf[MAXPATHL];
+
+static char *os_homedir(void)
+{
+ homedir_buf[0] = NUL;
+ size_t homedir_size = MAXPATHL;
+ uv_mutex_lock(&mutex);
+ // http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir
+ int ret_value = uv_os_homedir(homedir_buf, &homedir_size);
+ uv_mutex_unlock(&mutex);
+ if (ret_value == 0 && homedir_size < MAXPATHL) {
+ return homedir_buf;
+ }
+ ELOG("uv_os_homedir() failed %d: %s", ret_value, os_strerror(ret_value));
+ homedir_buf[0] = NUL;
+ return NULL;
+}
+
#if defined(EXITFREE)
void free_homedir(void)
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 4d7d9a45df..348a139e79 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -20,6 +20,10 @@
# include <pty.h>
#endif
+#ifdef __APPLE__
+# include <crt_externs.h>
+#endif
+
#include <uv.h>
#include "nvim/lib/klist.h"
@@ -154,28 +158,14 @@ void pty_process_teardown(Loop *loop)
static void init_child(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
+#if defined(HAVE__NSGETENVIRON)
+#define environ (*_NSGetEnviron())
+#else
+ extern char **environ;
+#endif
// New session/process-group. #6530
setsid();
- os_unsetenv("COLUMNS");
- os_unsetenv("LINES");
- os_unsetenv("TERMCAP");
- os_unsetenv("COLORFGBG");
- // setting COLORTERM to "truecolor" if termguicolors is set and 256
- // otherwise, but only if it was set in the parent terminal at all
- if (os_env_exists("COLORTERM")) {
- const char *colorterm = os_getenv("COLORTERM");
- if (colorterm != NULL) {
- if (p_tgc) {
- os_setenv("COLORTERM", "truecolor", 1);
- } else {
- os_setenv("COLORTERM", "256", 1);
- }
- } else {
- os_unsetenv("COLORTERM");
- }
- }
-
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
@@ -190,9 +180,14 @@ static void init_child(PtyProcess *ptyproc)
}
char *prog = ptyproc->process.argv[0];
- os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
- execvp(prog, ptyproc->process.argv);
+
+ assert(proc->env);
+ tv_dict_add_str(proc->env, S_LEN("TERM"),
+ ptyproc->term_name ? ptyproc->term_name : "ansi");
+ environ = tv_dict_to_env(proc->env);
+ execvp(prog, proc->argv);
ELOG("execvp failed: %s: %s", strerror(errno), prog);
+
_exit(122); // 122 is EXEC_FAILED in the Vim source.
}
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 6f7100e846..52d2f84ace 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -52,6 +52,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL;
wchar_t *cwd = NULL;
+ wchar_t *env = NULL;
const char *emsg = NULL;
assert(proc->err.closed);
@@ -124,13 +125,22 @@ int pty_process_spawn(PtyProcess *ptyproc)
goto cleanup;
}
+ if (proc->env != NULL) {
+ status = build_env_block(proc->env, &env);
+ }
+
+ if (status != 0) {
+ emsg = "build_env_block failed";
+ goto cleanup;
+ }
+
if (ptyproc->type == kConpty) {
if (!os_conpty_spawn(conpty_object,
&process_handle,
NULL,
cmd_line,
cwd,
- NULL)) {
+ env)) {
emsg = "os_conpty_spawn failed";
status = (int)GetLastError();
goto cleanup;
@@ -141,7 +151,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
NULL, // Optional application name
cmd_line,
cwd,
- NULL, // Optional environment variables
+ env,
&err);
if (spawncfg == NULL) {
emsg = "winpty_spawn_config_new failed";
@@ -213,6 +223,7 @@ cleanup:
xfree(in_req);
xfree(out_req);
xfree(cmd_line);
+ xfree(env);
xfree(cwd);
return status;
}
@@ -454,3 +465,66 @@ int translate_winpty_error(int winpty_errno)
default: return UV_UNKNOWN;
}
}
+
+typedef struct EnvNode {
+ wchar_t *str;
+ size_t len;
+ QUEUE node;
+} EnvNode;
+
+/// Build the environment block to pass to CreateProcessW.
+///
+/// @param[in] denv Dict of environment name/value pairs
+/// @param[out] env Allocated environment block
+///
+/// @returns zero on success or error code of MultiByteToWideChar function.
+static int build_env_block(dict_T *denv, wchar_t **env_block)
+{
+ const size_t denv_size = (size_t)tv_dict_len(denv);
+ size_t env_block_len = 0;
+ int rc;
+ char **env = tv_dict_to_env(denv);
+
+ QUEUE *q;
+ QUEUE env_q;
+ QUEUE_INIT(&env_q);
+ // Convert env vars to wchar_t and calculate how big the final env block
+ // needs to be
+ for (size_t i = 0; i < denv_size; i++) {
+ EnvNode *env_node = xmalloc(sizeof(*env_node));
+ rc = utf8_to_utf16(env[i], -1, &env_node->str);
+ if (rc != 0) {
+ goto cleanup;
+ }
+ env_node->len = wcslen(env_node->str) + 1;
+ env_block_len += env_node->len;
+ QUEUE_INSERT_TAIL(&env_q, &env_node->node);
+ }
+
+ // Additional '\0' after the final entry
+ env_block_len++;
+
+ *env_block = xmalloc(sizeof(**env_block) * env_block_len);
+ wchar_t *pos = *env_block;
+
+ QUEUE_FOREACH(q, &env_q) {
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ memcpy(pos, env_node->str, env_node->len * sizeof(*pos));
+ pos += env_node->len;
+ }
+
+ *pos = L'\0';
+
+cleanup:
+ q = QUEUE_HEAD(&env_q);
+ while (q != &env_q) {
+ QUEUE *next = q->next;
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ XFREE_CLEAR(env_node->str);
+ QUEUE_REMOVE(q);
+ xfree(env_node);
+ q = next;
+ }
+
+ return rc;
+}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 66bc990402..93b8d5ca12 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -108,6 +108,17 @@ char *get_xdg_home(const XDGVarType idx)
return dir;
}
+/// Return subpath of $XDG_CACHE_HOME
+///
+/// @param[in] fname New component of the path.
+///
+/// @return [allocated] `$XDG_CACHE_HOME/nvim/{fname}`
+char *stdpaths_user_cache_subpath(const char *fname)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
+{
+ return concat_fnames_realloc(get_xdg_home(kXDGCacheHome), fname, true);
+}
+
/// Return subpath of $XDG_CONFIG_HOME
///
/// @param[in] fname New component of the path.
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 4b6533cd0c..5cf628935f 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -97,7 +97,7 @@ void os_microdelay(uint64_t us, bool ignoreinput)
const int rv = uv_cond_timedwait(&delay_cond, &delay_mutex, ns_delta);
if (0 != rv && UV_ETIMEDOUT != rv) {
- assert(false);
+ abort();
break;
} // Else: Timeout proceeded normally.