aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/channel.c')
-rw-r--r--src/nvim/channel.c110
1 files changed, 58 insertions, 52 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 65bb87bc2c..e8fe80a3b6 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -1,13 +1,11 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
#include <assert.h>
#include <inttypes.h>
+#include <lauxlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
-#include "lauxlib.h"
+#include "klib/kvec.h"
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
@@ -17,10 +15,10 @@
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
-#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/event/socket.h"
#include "nvim/event/wstream.h"
+#include "nvim/garray.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/log.h"
@@ -32,12 +30,14 @@
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
+#include "nvim/path.h"
#include "nvim/rbuffer.h"
+
#ifdef MSWIN
+# include "nvim/os/fs.h"
# include "nvim/os/os_win_console.h"
# include "nvim/os/pty_conpty_win.h"
#endif
-#include "nvim/path.h"
static bool did_stdio = false;
@@ -79,7 +79,7 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
// allow double close, even though we can't say what parts was valid.
return true;
}
- *error = (const char *)e_invchan;
+ *error = e_invchan;
return false;
}
@@ -89,19 +89,19 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
if (chan->is_rpc) {
rpc_close(chan);
} else if (part == kChannelPartRpc) {
- *error = (const char *)e_invstream;
+ *error = e_invstream;
return false;
}
} else if ((part == kChannelPartStdin || part == kChannelPartStdout)
&& chan->is_rpc) {
- *error = (const char *)e_invstreamrpc;
+ *error = e_invstreamrpc;
return false;
}
switch (chan->streamtype) {
case kChannelStreamSocket:
if (!close_main) {
- *error = (const char *)e_invstream;
+ *error = e_invstream;
return false;
}
stream_may_close(&chan->stream.socket);
@@ -132,14 +132,14 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
stream_may_close(&chan->stream.stdio.out);
}
if (part == kChannelPartStderr) {
- *error = (const char *)e_invstream;
+ *error = e_invstream;
return false;
}
break;
case kChannelStreamStderr:
if (part != kChannelPartAll && part != kChannelPartStderr) {
- *error = (const char *)e_invstream;
+ *error = e_invstream;
return false;
}
if (!chan->stream.err.closed) {
@@ -154,7 +154,7 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
case kChannelStreamInternal:
if (!close_main) {
- *error = (const char *)e_invstream;
+ *error = e_invstream;
return false;
}
if (chan->term) {
@@ -166,9 +166,6 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
channel_decref(chan);
}
break;
-
- default:
- abort();
}
return true;
@@ -207,7 +204,7 @@ Channel *channel_alloc(ChannelStreamType type)
void channel_create_event(Channel *chan, const char *ext_source)
{
-#if MIN_LOG_LEVEL <= LOGLVL_INF
+#ifdef NVIM_LOG_DEBUG
const char *source;
if (ext_source) {
@@ -216,7 +213,7 @@ void channel_create_event(Channel *chan, const char *ext_source)
source = ext_source;
} else {
eval_fmt_source_name_line(IObuff, sizeof(IObuff));
- source = (const char *)IObuff;
+ source = IObuff;
}
assert(chan->id <= VARNUMBER_MAX);
@@ -225,6 +222,7 @@ void channel_create_event(Channel *chan, const char *ext_source)
// TODO(bfredl): do the conversion in one step. Also would be nice
// to pretty print top level dict in defined order
(void)object_to_vim(DICTIONARY_OBJ(info), &tv, NULL);
+ assert(tv.v_type == VAR_DICT);
char *str = encode_tv2json(&tv, NULL);
ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str);
xfree(str);
@@ -277,7 +275,7 @@ static void free_channel_event(void **argv)
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
- pmap_del(uint64_t)(&channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
multiqueue_free(chan->events);
xfree(chan);
}
@@ -287,7 +285,7 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
- pmap_del(uint64_t)(&channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
chan->id = 0;
if ((--chan->refcount != 0)) {
@@ -307,6 +305,7 @@ static void close_cb(Stream *stream, void *data)
///
/// @param[in] argv Arguments vector specifying the command to run,
/// NULL-terminated
+/// @param[in] exepath The path to the executable. If NULL, use `argv[0]`.
/// @param[in] on_stdout Callback to read the job's stdout
/// @param[in] on_stderr Callback to read the job's stderr
/// @param[in] on_exit Callback to receive the job's exit status
@@ -328,10 +327,11 @@ static void close_cb(Stream *stream, void *data)
/// < 0 if the job can't start
///
/// @returns [allocated] channel
-Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader on_stderr,
- Callback on_exit, bool pty, bool rpc, bool overlapped, bool detach,
- ChannelStdinMode stdin_mode, const char *cwd, uint16_t pty_width,
- uint16_t pty_height, dict_T *env, varnumber_T *status_out)
+Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_stdout,
+ CallbackReader on_stderr, Callback on_exit, bool pty, bool rpc,
+ bool overlapped, bool detach, ChannelStdinMode stdin_mode,
+ const char *cwd, uint16_t pty_width, uint16_t pty_height, dict_T *env,
+ varnumber_T *status_out)
{
Channel *chan = channel_alloc(kChannelStreamProc);
chan->on_data = on_stdout;
@@ -362,6 +362,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader
Process *proc = &chan->stream.proc;
proc->argv = argv;
+ proc->exepath = exepath;
proc->cb = channel_process_exit_cb;
proc->events = chan->events;
proc->detach = detach;
@@ -369,8 +370,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader
proc->env = env;
proc->overlapped = overlapped;
- char *cmd = xstrdup(proc->argv[0]);
- bool has_in, has_out, has_err;
+ char *cmd = xstrdup(process_get_exepath(proc));
+ bool has_out, has_err;
if (proc->type == kProcessTypePty) {
has_out = true;
has_err = false;
@@ -380,14 +381,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader
proc->fwd_err = chan->on_stderr.fwd_err;
}
- switch (stdin_mode) {
- case kChannelStdinPipe:
- has_in = true;
- break;
- case kChannelStdinNull:
- has_in = false;
- break;
- }
+ bool has_in = stdin_mode == kChannelStdinPipe;
int status = process_spawn(proc, has_in, has_out, has_err);
if (status) {
@@ -790,10 +784,9 @@ void channel_terminal_open(buf_T *buf, Channel *chan)
topts.write_cb = term_write;
topts.resize_cb = term_resize;
topts.close_cb = term_close;
- buf->b_p_channel = (long)chan->id; // 'channel' option
- Terminal *term = terminal_open(buf, topts);
- chan->term = term;
+ buf->b_p_channel = (OptInt)chan->id; // 'channel' option
channel_incref(chan);
+ terminal_open(&chan->term, buf, topts);
}
static void term_write(char *buf, size_t size, void *data)
@@ -836,13 +829,12 @@ static void term_close(void *data)
multiqueue_put(chan->events, term_delayed_free, 1, data);
}
-void channel_info_changed(Channel *chan, bool new)
+void channel_info_changed(Channel *chan, bool new_chan)
{
- event_T event = new ? EVENT_CHANOPEN : EVENT_CHANINFO;
+ event_T event = new_chan ? EVENT_CHANOPEN : EVENT_CHANINFO;
if (has_event(event)) {
channel_incref(chan);
- multiqueue_put(main_loop.events, set_info_event,
- 2, chan, event);
+ multiqueue_put(main_loop.events, set_info_event, 2, chan, event);
}
}
@@ -856,6 +848,7 @@ static void set_info_event(void **argv)
Dictionary info = channel_info(chan->id);
typval_T retval;
(void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
+ assert(retval.v_type == VAR_DICT);
tv_dict_add_dict(dict, S_LEN("info"), retval.vval.v_dict);
tv_dict_set_keys_readonly(dict);
@@ -890,14 +883,14 @@ Dictionary channel_info(uint64_t id)
stream_desc = "job";
if (chan->stream.proc.type == kProcessTypePty) {
const char *name = pty_process_tty_name(&chan->stream.pty);
- PUT(info, "pty", STRING_OBJ(cstr_to_string(name)));
+ PUT(info, "pty", CSTR_TO_OBJ(name));
}
char **p = chan->stream.proc.argv;
Array argv = ARRAY_DICT_INIT;
if (p != NULL) {
while (*p != NULL) {
- ADD(argv, STRING_OBJ(cstr_to_string(*p)));
+ ADD(argv, CSTR_TO_OBJ(*p));
p++;
}
}
@@ -920,11 +913,8 @@ Dictionary channel_info(uint64_t id)
case kChannelStreamSocket:
stream_desc = "socket";
break;
-
- default:
- abort();
}
- PUT(info, "stream", STRING_OBJ(cstr_to_string(stream_desc)));
+ PUT(info, "stream", CSTR_TO_OBJ(stream_desc));
if (chan->is_rpc) {
mode_desc = "rpc";
@@ -935,17 +925,33 @@ Dictionary channel_info(uint64_t id)
} else {
mode_desc = "bytes";
}
- PUT(info, "mode", STRING_OBJ(cstr_to_string(mode_desc)));
+ PUT(info, "mode", CSTR_TO_OBJ(mode_desc));
return info;
}
+/// Simple int64_t comparison function for use with qsort()
+static int int64_t_cmp(const void *a, const void *b)
+{
+ int64_t diff = *(int64_t *)a - *(int64_t *)b;
+ return (diff < 0) ? -1 : (diff > 0);
+}
+
Array channel_all_info(void)
{
- Channel *channel;
- Array ret = ARRAY_DICT_INIT;
- map_foreach_value(&channels, channel, {
- ADD(ret, DICTIONARY_OBJ(channel_info(channel->id)));
+ // order the items in the array by channel number, for Determinismâ„¢
+ kvec_t(int64_t) ids = KV_INITIAL_VALUE;
+ kv_resize(ids, map_size(&channels));
+ uint64_t id;
+ map_foreach_key(&channels, id, {
+ kv_push(ids, (int64_t)id);
});
+ qsort(ids.items, ids.size, sizeof ids.items[0], int64_t_cmp);
+
+ Array ret = ARRAY_DICT_INIT;
+ for (size_t i = 0; i < ids.size; i++) {
+ ADD(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i])));
+ }
+ kv_destroy(ids);
return ret;
}