From 339d106f7c1e756782980e884304b44e5faebddd Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:03 -0300 Subject: Dead code: Remove unused vimscript functions(from FEAT_CLIENTSERVER) --- src/nvim/eval.c | 68 --------------------------------------------------------- 1 file changed, 68 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4ddf037f64..d09a83abcd 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -680,11 +680,6 @@ static void f_range(typval_T *argvars, typval_T *rettv); static void f_readfile(typval_T *argvars, typval_T *rettv); static void f_reltime(typval_T *argvars, typval_T *rettv); static void f_reltimestr(typval_T *argvars, typval_T *rettv); -static void f_remote_expr(typval_T *argvars, typval_T *rettv); -static void f_remote_foreground(typval_T *argvars, typval_T *rettv); -static void f_remote_peek(typval_T *argvars, typval_T *rettv); -static void f_remote_read(typval_T *argvars, typval_T *rettv); -static void f_remote_send(typval_T *argvars, typval_T *rettv); static void f_remove(typval_T *argvars, typval_T *rettv); static void f_rename(typval_T *argvars, typval_T *rettv); static void f_repeat(typval_T *argvars, typval_T *rettv); @@ -700,8 +695,6 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv); static void f_searchpair(typval_T *argvars, typval_T *rettv); static void f_searchpairpos(typval_T *argvars, typval_T *rettv); static void f_searchpos(typval_T *argvars, typval_T *rettv); -static void f_server2client(typval_T *argvars, typval_T *rettv); -static void f_serverlist(typval_T *argvars, typval_T *rettv); static void f_setbufvar(typval_T *argvars, typval_T *rettv); static void f_setcmdpos(typval_T *argvars, typval_T *rettv); static void f_setline(typval_T *argvars, typval_T *rettv); @@ -6936,11 +6929,6 @@ static struct fst { {"readfile", 1, 3, f_readfile}, {"reltime", 0, 2, f_reltime}, {"reltimestr", 1, 1, f_reltimestr}, - {"remote_expr", 2, 3, f_remote_expr}, - {"remote_foreground", 1, 1, f_remote_foreground}, - {"remote_peek", 1, 2, f_remote_peek}, - {"remote_read", 1, 1, f_remote_read}, - {"remote_send", 2, 3, f_remote_send}, {"remove", 2, 3, f_remove}, {"rename", 2, 2, f_rename}, {"repeat", 2, 2, f_repeat}, @@ -6956,8 +6944,6 @@ static struct fst { {"searchpair", 3, 7, f_searchpair}, {"searchpairpos", 3, 7, f_searchpairpos}, {"searchpos", 1, 4, f_searchpos}, - {"server2client", 2, 2, f_server2client}, - {"serverlist", 0, 0, f_serverlist}, {"setbufvar", 3, 3, f_setbufvar}, {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, @@ -12226,46 +12212,6 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); } - - -/* - * "remote_expr()" function - */ -static void f_remote_expr(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -} - -/* - * "remote_foreground()" function - */ -static void f_remote_foreground(typval_T *argvars, typval_T *rettv) -{ -} - -static void f_remote_peek(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = -1; -} - -static void f_remote_read(typval_T *argvars, typval_T *rettv) -{ - char_u *r = NULL; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = r; -} - -/* - * "remote_send()" function - */ -static void f_remote_send(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -} - /* * "remove()" function */ @@ -13136,20 +13082,6 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv) list_append_number(rettv->vval.v_list, (varnumber_T)n); } - -static void f_server2client(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = -1; -} - -static void f_serverlist(typval_T *argvars, typval_T *rettv) -{ - char_u *r = NULL; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = r; -} - /* * "setbufvar()" function */ -- cgit From 4bac5e9ce19afd4647ee4d313c9485229d05a334 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:05 -0300 Subject: API: Refactor: Duplicate/free string arguments coming from msgpack When receiving strings *from* msgpack, we don't need to duplicate/free since the data only lives in the msgpack parse buffer until the end of the call. But in order to reuse `msgpack_rpc_free_object` when sending event data(which is sent *to* msgpack), Strings must be freed, which means they must also be allocated separately. --- src/nvim/api/buffer.c | 2 +- src/nvim/api/private/defs.h | 1 + src/nvim/api/private/helpers.c | 2 +- src/nvim/os/msgpack_rpc.c | 17 +++++++++++++++-- src/nvim/os/msgpack_rpc.h | 6 ++---- 5 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index bf30ccf856..ef2f9e9d0e 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -307,7 +307,7 @@ Integer buffer_get_number(Buffer buffer, Error *err) String buffer_get_name(Buffer buffer, Error *err) { - String rv = {.size = 0, .data = ""}; + String rv = STRING_INIT; buf_T *buf = find_buffer(buffer, err); if (!buf || buf->b_ffname == NULL) { diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index a91907f4f8..4d9f5fb708 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -6,6 +6,7 @@ #include #define ARRAY_DICT_INIT {.size = 0, .items = NULL} +#define STRING_INIT {.data = NULL, .size = 0} #define REMOTE_TYPE(type) typedef uint64_t type #define TYPED_ARRAY_OF(type) \ diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a43e7a8d2a..206129dd78 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -319,7 +319,7 @@ tabpage_T * find_tab(Tabpage tabpage, Error *err) String cstr_to_string(const char *str) { if (str == NULL) { - return (String) { .data = NULL, .size = 0 }; + return (String) STRING_INIT; } size_t len = strlen(str); diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index d7ffa6f559..8ca1e0a8c0 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -147,9 +147,13 @@ bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg) bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) { - arg->data = (char *)obj->via.raw.ptr; + if (obj->type != MSGPACK_OBJECT_RAW) { + return false; + } + + arg->data = xmemdup(obj->via.raw.ptr, obj->via.raw.size); arg->size = obj->via.raw.size; - return obj->type == MSGPACK_OBJECT_RAW; + return true; } bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) @@ -328,6 +332,15 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res) } } +void msgpack_rpc_free_string(String value) +{ + if (!value.data) { + return; + } + + free(value.data); +} + void msgpack_rpc_free_object(Object value) { switch (value.type) { diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index a6a909ac1f..aab284f2c8 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -81,7 +81,7 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); #define msgpack_rpc_init_integer #define msgpack_rpc_init_float #define msgpack_rpc_init_position -#define msgpack_rpc_init_string +#define msgpack_rpc_init_string = STRING_INIT #define msgpack_rpc_init_buffer #define msgpack_rpc_init_window #define msgpack_rpc_init_tabpage @@ -100,9 +100,7 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); #define msgpack_rpc_free_integer(value) #define msgpack_rpc_free_float(value) #define msgpack_rpc_free_position(value) -// Strings are not copied from msgpack and so don't need to be freed(they -// probably "live" in the msgpack streaming buffer) -#define msgpack_rpc_free_string(value) +void msgpack_rpc_free_string(String value); #define msgpack_rpc_free_buffer(value) #define msgpack_rpc_free_window(value) #define msgpack_rpc_free_tabpage(value) -- cgit From 7a00caf7c40e8526db2c75cd4c1445b624023728 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:06 -0300 Subject: API: Refactor: Close/free channels when their streams reach EOF --- src/nvim/os/channel.c | 82 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index 10766ca76e..8184003593 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -3,7 +3,6 @@ #include #include -#include "nvim/lib/klist.h" #include "nvim/os/channel.h" #include "nvim/os/channel_defs.h" #include "nvim/os/rstream.h" @@ -15,8 +14,10 @@ #include "nvim/os/msgpack_rpc.h" #include "nvim/vim.h" #include "nvim/memory.h" +#include "nvim/map.h" typedef struct { + uint64_t id; ChannelProtocol protocol; bool is_job; union { @@ -30,22 +31,23 @@ typedef struct { struct { RStream *read; WStream *write; + uv_stream_t *uv; } streams; } data; } Channel; -#define _destroy_channel(x) +static uint64_t next_id = 1; +static Map(uint64_t) *channels = NULL; -KLIST_INIT(Channel, Channel *, _destroy_channel) - -static klist_t(Channel) *channels = NULL; static void on_job_stdout(RStream *rstream, void *data, bool eof); static void on_job_stderr(RStream *rstream, void *data, bool eof); static void parse_msgpack(RStream *rstream, void *data, bool eof); +static void close_channel(Channel *channel); +static void close_cb(uv_handle_t *handle); void channel_init() { - channels = kl_init(Channel); + channels = map_new(uint64_t)(); } void channel_teardown() @@ -56,24 +58,9 @@ void channel_teardown() Channel *channel; - while (kl_shift(Channel, channels, &channel) == 0) { - - switch (channel->protocol) { - case kChannelProtocolMsgpack: - msgpack_sbuffer_free(channel->proto.msgpack.sbuffer); - msgpack_unpacker_free(channel->proto.msgpack.unpacker); - break; - default: - abort(); - } - - if (channel->is_job) { - job_stop(channel->data.job_id); - } else { - rstream_free(channel->data.streams.read); - wstream_free(channel->data.streams.write); - } - } + map_foreach_value(channels, channel, { + close_channel(channel); + }); } void channel_from_job(char **argv, ChannelProtocol prot) @@ -92,10 +79,11 @@ void channel_from_job(char **argv, ChannelProtocol prot) abort(); } + channel->id = next_id++; channel->protocol = prot; channel->is_job = true; channel->data.job_id = job_start(argv, channel, rcb, on_job_stderr, NULL); - *kl_pushp(Channel, channels) = channel; + map_put(uint64_t)(channels, channel->id, channel); } void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot) @@ -115,6 +103,7 @@ void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot) } stream->data = NULL; + channel->id = next_id++; channel->protocol = prot; channel->is_job = false; // read stream @@ -124,8 +113,8 @@ void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot) // write stream channel->data.streams.write = wstream_new(1024 * 1024); wstream_set_stream(channel->data.streams.write, stream); - // push to channel list - *kl_pushp(Channel, channels) = channel; + channel->data.streams.uv = stream; + map_put(uint64_t)(channels, channel->id, channel); } static void on_job_stdout(RStream *rstream, void *data, bool eof) @@ -141,8 +130,13 @@ static void on_job_stderr(RStream *rstream, void *data, bool eof) static void parse_msgpack(RStream *rstream, void *data, bool eof) { - msgpack_unpacked unpacked; Channel *channel = data; + + if (eof) { + close_channel(channel); + return; + } + uint32_t count = rstream_available(rstream); // Feed the unpacker with data @@ -152,6 +146,7 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) count); msgpack_unpacker_buffer_consumed(channel->proto.msgpack.unpacker, count); + msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); // Deserialize everything we can. @@ -173,3 +168,34 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) msgpack_sbuffer_clear(channel->proto.msgpack.sbuffer); } } + +static void close_channel(Channel *channel) +{ + map_del(uint64_t)(channels, channel->id); + + switch (channel->protocol) { + case kChannelProtocolMsgpack: + msgpack_sbuffer_free(channel->proto.msgpack.sbuffer); + msgpack_unpacker_free(channel->proto.msgpack.unpacker); + break; + default: + abort(); + } + + if (channel->is_job) { + job_stop(channel->data.job_id); + } else { + rstream_free(channel->data.streams.read); + wstream_free(channel->data.streams.write); + uv_close((uv_handle_t *)channel->data.streams.uv, close_cb); + } + + free(channel); +} + +static void close_cb(uv_handle_t *handle) +{ + free(handle->data); + free(handle); +} + -- cgit From 139c7ffdc785b19297e8c3b2d2586dfa284f97a5 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:08 -0300 Subject: API: Events: Return channel id from the API discover request This refactors msgapck_rpc_{dipatch,call} to receive the channel id as argument. Now the discovery request returns the [id, metadata] array. --- src/nvim/os/channel.c | 2 +- src/nvim/os/msgpack_rpc.c | 7 +++++-- src/nvim/os/msgpack_rpc.h | 8 ++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index 8184003593..c103a71f46 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -157,7 +157,7 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) channel->proto.msgpack.sbuffer, msgpack_sbuffer_write); // Perform the call - msgpack_rpc_call(&unpacked.data, &response); + msgpack_rpc_call(channel->id, &unpacked.data, &response); wstream_write(channel->data.streams.write, xmemdup(channel->proto.msgpack.sbuffer->data, channel->proto.msgpack.sbuffer->size), diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index 8ca1e0a8c0..62d68ebdec 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -1,3 +1,6 @@ +#include +#include + #include #include "nvim/os/msgpack_rpc.h" @@ -52,7 +55,7 @@ free(value.items); \ } -void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) +void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res) { // The initial response structure is the same no matter what happens, // we set it up here @@ -107,7 +110,7 @@ void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) } // dispatch the message - msgpack_rpc_dispatch(req, res); + msgpack_rpc_dispatch(id, req, res); } void msgpack_rpc_error(char *msg, msgpack_packer *res) diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index aab284f2c8..bc216c0856 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -11,9 +11,10 @@ /// Validates the basic structure of the msgpack-rpc call and fills `res` /// with the basic response structure. /// +/// @param id The channel id /// @param req The parsed request object /// @param res A packer that contains the response -void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res); +void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res); /// Dispatches to the actual API function after basic payload validation by /// `msgpack_rpc_call`. It is responsible for validating/converting arguments @@ -21,9 +22,12 @@ void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res); /// The implementation is generated at compile time with metadata extracted /// from the api/*.h headers, /// +/// @param id The channel id /// @param req The parsed request object /// @param res A packer that contains the response -void msgpack_rpc_dispatch(msgpack_object *req, msgpack_packer *res); +void msgpack_rpc_dispatch(uint64_t id, + msgpack_object *req, + msgpack_packer *res); /// Finishes the msgpack-rpc call with an error message. /// -- cgit From f3dc04bf7f658f7d5d15047494fd15e286b4c7b6 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:10 -0300 Subject: API: Events: Implement channel_send_event and vimscript wrapper This function can be used to send arbitrary objects via the API channel back to connected clients, identified by channel id. --- src/nvim/eval.c | 34 +++++++++++++++++++++++++++++++++- src/nvim/os/channel.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/nvim/os/channel.h | 9 +++++++++ src/nvim/os/msgpack_rpc.c | 9 +++++++++ src/nvim/os/msgpack_rpc.h | 7 +++++++ 5 files changed, 101 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d09a83abcd..87054aa9df 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -12,7 +12,6 @@ #include #include - #include "nvim/vim.h" #include "nvim/eval.h" #include "nvim/buffer.h" @@ -67,6 +66,7 @@ #include "nvim/os/rstream.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/time.h" +#include "nvim/os/channel.h" #if defined(FEAT_FLOAT) # include @@ -695,6 +695,7 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv); static void f_searchpair(typval_T *argvars, typval_T *rettv); static void f_searchpairpos(typval_T *argvars, typval_T *rettv); static void f_searchpos(typval_T *argvars, typval_T *rettv); +static void f_send_event(typval_T *argvars, typval_T *rettv); static void f_setbufvar(typval_T *argvars, typval_T *rettv); static void f_setcmdpos(typval_T *argvars, typval_T *rettv); static void f_setline(typval_T *argvars, typval_T *rettv); @@ -6944,6 +6945,7 @@ static struct fst { {"searchpair", 3, 7, f_searchpair}, {"searchpairpos", 3, 7, f_searchpairpos}, {"searchpos", 1, 4, f_searchpos}, + {"send_event", 3, 3, f_send_event}, {"setbufvar", 3, 3, f_setbufvar}, {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, @@ -13057,6 +13059,36 @@ do_searchpair ( return retval; } +// "send_event()" function +static void f_send_event(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = 0; + + if (check_restricted() || check_secure()) { + return; + } + + if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number <= 0) { + EMSG2(_(e_invarg2), "Channel id must be a positive integer"); + return; + } + + if (argvars[1].v_type != VAR_STRING) { + EMSG2(_(e_invarg2), "Event type must be a string"); + return; + } + + if (!channel_send_event((uint64_t)argvars[0].vval.v_number, + (char *)argvars[1].vval.v_string, + &argvars[2])) { + EMSG2(_(e_invarg2), "Channel doesn't exist"); + return; + } + + rettv->vval.v_number = 1; +} + /* * "searchpos()" function */ diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index c103a71f46..4981a268b2 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -3,6 +3,7 @@ #include #include +#include "nvim/api/private/helpers.h" #include "nvim/os/channel.h" #include "nvim/os/channel_defs.h" #include "nvim/os/rstream.h" @@ -38,16 +39,19 @@ typedef struct { static uint64_t next_id = 1; static Map(uint64_t) *channels = NULL; +static msgpack_sbuffer msgpack_event_buffer; static void on_job_stdout(RStream *rstream, void *data, bool eof); static void on_job_stderr(RStream *rstream, void *data, bool eof); static void parse_msgpack(RStream *rstream, void *data, bool eof); +static void send_msgpack(Channel *channel, String type, Object data); static void close_channel(Channel *channel); static void close_cb(uv_handle_t *handle); void channel_init() { channels = map_new(uint64_t)(); + msgpack_sbuffer_init(&msgpack_event_buffer); } void channel_teardown() @@ -117,6 +121,30 @@ void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot) map_put(uint64_t)(channels, channel->id, channel); } +bool channel_send_event(uint64_t id, char *type, typval_T *data) +{ + Channel *channel = map_get(uint64_t)(channels, id); + + if (!channel) { + return false; + } + + String event_type = {.size = strnlen(type, 1024), .data = type}; + Object event_data = vim_to_object(data); + + switch (channel->protocol) { + case kChannelProtocolMsgpack: + send_msgpack(channel, event_type, event_data); + break; + default: + abort(); + } + + msgpack_rpc_free_object(event_data); + + return true; +} + static void on_job_stdout(RStream *rstream, void *data, bool eof) { Job *job = data; @@ -169,6 +197,21 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) } } +static void send_msgpack(Channel *channel, String type, Object data) +{ + msgpack_packer packer; + msgpack_packer_init(&packer, &msgpack_event_buffer, msgpack_sbuffer_write); + msgpack_rpc_notification(type, data, &packer); + char *bytes = xmemdup(msgpack_event_buffer.data, msgpack_event_buffer.size); + + wstream_write(channel->data.streams.write, + bytes, + msgpack_event_buffer.size, + true); + + msgpack_sbuffer_clear(&msgpack_event_buffer); +} + static void close_channel(Channel *channel) { map_del(uint64_t)(channels, channel->id); diff --git a/src/nvim/os/channel.h b/src/nvim/os/channel.h index 4a3962575d..543b91dd89 100644 --- a/src/nvim/os/channel.h +++ b/src/nvim/os/channel.h @@ -3,6 +3,7 @@ #include +#include "nvim/vim.h" #include "nvim/os/channel_defs.h" /// Initializes the module @@ -25,5 +26,13 @@ void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot); /// @param prot The rpc protocol used void channel_from_job(char **argv, ChannelProtocol prot); +/// Sends event/data to channel +/// +/// @param id The channel id +/// @param type The event type, an arbitrary string +/// @param obj The event data +/// @return True if the data was sent successfully, false otherwise. +bool channel_send_event(uint64_t id, char *type, typval_T *data); + #endif // NVIM_OS_CHANNEL_H diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index 62d68ebdec..423c5d584d 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -113,6 +113,15 @@ void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res) msgpack_rpc_dispatch(id, req, res); } +void msgpack_rpc_notification(String type, Object data, msgpack_packer *pac) +{ + msgpack_pack_array(pac, 3); + msgpack_pack_int(pac, 2); + msgpack_pack_raw(pac, type.size); + msgpack_pack_raw_body(pac, type.data, type.size); + msgpack_rpc_from_object(data, pac); +} + void msgpack_rpc_error(char *msg, msgpack_packer *res) { size_t len = strlen(msg); diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index bc216c0856..319a069df7 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -16,6 +16,13 @@ /// @param res A packer that contains the response void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res); +/// Packs a notification message +/// +/// @param type The message type, an arbitrary string +/// @param data The notification data +/// @param packer Where the notification will be packed to +void msgpack_rpc_notification(String type, Object data, msgpack_packer *pac); + /// Dispatches to the actual API function after basic payload validation by /// `msgpack_rpc_call`. It is responsible for validating/converting arguments /// to C types, and converting the return value back to msgpack types. -- cgit From e994b6f1b1082d5808f27addd7638e86f02aeaf1 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:12 -0300 Subject: Build: Add 'nonnull' attributes to msgpack_rpc functions --- src/nvim/os/msgpack_rpc.h | 103 +++++++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 319a069df7..4d8d51699b 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -6,6 +6,7 @@ #include +#include "nvim/func_attr.h" #include "nvim/api/private/defs.h" /// Validates the basic structure of the msgpack-rpc call and fills `res` @@ -14,14 +15,16 @@ /// @param id The channel id /// @param req The parsed request object /// @param res A packer that contains the response -void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res); +void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3); /// Packs a notification message /// /// @param type The message type, an arbitrary string /// @param data The notification data /// @param packer Where the notification will be packed to -void msgpack_rpc_notification(String type, Object data, msgpack_packer *pac); +void msgpack_rpc_notification(String type, Object data, msgpack_packer *pac) + FUNC_ATTR_NONNULL_ARG(3); /// Dispatches to the actual API function after basic payload validation by /// `msgpack_rpc_call`. It is responsible for validating/converting arguments @@ -34,13 +37,15 @@ void msgpack_rpc_notification(String type, Object data, msgpack_packer *pac); /// @param res A packer that contains the response void msgpack_rpc_dispatch(uint64_t id, msgpack_object *req, - msgpack_packer *res); + msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3); /// Finishes the msgpack-rpc call with an error message. /// /// @param msg The error message /// @param res A packer that contains the response -void msgpack_rpc_error(char *msg, msgpack_packer *res); +void msgpack_rpc_error(char *msg, msgpack_packer *res) + FUNC_ATTR_NONNULL_ALL; /// Functions for validating and converting from msgpack types to C types. /// These are used by `msgpack_rpc_dispatch` to validate and convert each @@ -49,21 +54,36 @@ void msgpack_rpc_error(char *msg, msgpack_packer *res); /// @param obj The object to convert /// @param[out] arg A pointer to the avalue /// @return true if the convertion succeeded, false otherwise -bool msgpack_rpc_to_boolean(msgpack_object *obj, Boolean *arg); -bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg); -bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg); -bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg); -bool msgpack_rpc_to_string(msgpack_object *obj, String *arg); -bool msgpack_rpc_to_buffer(msgpack_object *obj, Buffer *arg); -bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg); -bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg); -bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg); -bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg); -bool msgpack_rpc_to_bufferarray(msgpack_object *obj, BufferArray *arg); -bool msgpack_rpc_to_windowarray(msgpack_object *obj, WindowArray *arg); -bool msgpack_rpc_to_tabpagearray(msgpack_object *obj, TabpageArray *arg); -bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg); -bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg); +bool msgpack_rpc_to_boolean(msgpack_object *obj, Boolean *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_buffer(msgpack_object *obj, Buffer *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_bufferarray(msgpack_object *obj, BufferArray *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_windowarray(msgpack_object *obj, WindowArray *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_tabpagearray(msgpack_object *obj, TabpageArray *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg) + FUNC_ATTR_NONNULL_ALL; +bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg) + FUNC_ATTR_NONNULL_ALL; /// Functions for converting from C types to msgpack types. /// These are used by `msgpack_rpc_dispatch` to convert return values @@ -71,21 +91,36 @@ bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg); /// /// @param result A pointer to the result /// @param res A packer that contains the response -void msgpack_rpc_from_boolean(Boolean result, msgpack_packer *res); -void msgpack_rpc_from_integer(Integer result, msgpack_packer *res); -void msgpack_rpc_from_float(Float result, msgpack_packer *res); -void msgpack_rpc_from_position(Position result, msgpack_packer *res); -void msgpack_rpc_from_string(String result, msgpack_packer *res); -void msgpack_rpc_from_buffer(Buffer result, msgpack_packer *res); -void msgpack_rpc_from_window(Window result, msgpack_packer *res); -void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res); -void msgpack_rpc_from_object(Object result, msgpack_packer *res); -void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res); -void msgpack_rpc_from_bufferarray(BufferArray result, msgpack_packer *res); -void msgpack_rpc_from_windowarray(WindowArray result, msgpack_packer *res); -void msgpack_rpc_from_tabpagearray(TabpageArray result, msgpack_packer *res); -void msgpack_rpc_from_array(Array result, msgpack_packer *res); -void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); +void msgpack_rpc_from_boolean(Boolean result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_integer(Integer result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_float(Float result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_position(Position result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_string(String result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_buffer(Buffer result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_window(Window result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_object(Object result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_bufferarray(BufferArray result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_windowarray(WindowArray result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_tabpagearray(TabpageArray result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_array(Array result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); +void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res) + FUNC_ATTR_NONNULL_ARG(2); /// Helpers for initializing types that may be freed later #define msgpack_rpc_init_boolean -- cgit From 3f990f1afb75ff6b15e6a5b729f71779d71fba37 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:14 -0300 Subject: Build: Add api/{helpers,handle}.c to CONV_SRCS --- src/nvim/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index eb270eecb5..bdb262731d 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -50,7 +50,8 @@ set(CONV_SRCS os/wstream.c os/msgpack_rpc.c api/buffer.c - api/helpers.c + api/private/helpers.c + api/private/handle.c api/tabpage.c api/window.c api/vim.h -- cgit From d6291894d48c2ae558a603a2207c52833ce10f01 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:16 -0300 Subject: Build: Add more files to clint-files.txt and fix errors --- src/nvim/api/private/defs.h | 6 +++--- src/nvim/api/private/handle.h | 6 +++--- src/nvim/api/private/helpers.h | 6 +++--- src/nvim/os/channel.c | 4 ++-- src/nvim/os/server.c | 4 ++-- src/nvim/os/server.h | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 4d9f5fb708..fbf9018043 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -1,5 +1,5 @@ -#ifndef NVIM_API_DEFS_H -#define NVIM_API_DEFS_H +#ifndef NVIM_API_PRIVATE_DEFS_H +#define NVIM_API_PRIVATE_DEFS_H #include #include @@ -85,5 +85,5 @@ struct key_value_pair { }; -#endif // NVIM_API_DEFS_H +#endif // NVIM_API_PRIVATE_DEFS_H diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h index 27df453233..1a196f6797 100644 --- a/src/nvim/api/private/handle.h +++ b/src/nvim/api/private/handle.h @@ -1,5 +1,5 @@ -#ifndef NVIM_API_HANDLE_H -#define NVIM_API_HANDLE_H +#ifndef NVIM_API_PRIVATE_HANDLE_H +#define NVIM_API_PRIVATE_HANDLE_H #include "nvim/vim.h" #include "nvim/buffer_defs.h" @@ -16,5 +16,5 @@ HANDLE_DECLS(tabpage_T, tabpage) void handle_init(void); -#endif // NVIM_API_HANDLE_H +#endif // NVIM_API_PRIVATE_HANDLE_H diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 2d917c2b5e..04b128d3f1 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -1,5 +1,5 @@ -#ifndef NVIM_API_HELPERS_H -#define NVIM_API_HELPERS_H +#ifndef NVIM_API_PRIVATE_HELPERS_H +#define NVIM_API_PRIVATE_HELPERS_H #include @@ -94,5 +94,5 @@ tabpage_T * find_tab(Tabpage tabpage, Error *err); /// empty String is returned String cstr_to_string(const char *str); -#endif // NVIM_API_HELPERS_H +#endif // NVIM_API_PRIVATE_HELPERS_H diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index 4981a268b2..f275c70805 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -177,9 +177,9 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); - // Deserialize everything we can. + // Deserialize everything we can. while (msgpack_unpacker_next(channel->proto.msgpack.unpacker, &unpacked)) { - // Each object is a new msgpack-rpc request and requires an empty response + // Each object is a new msgpack-rpc request and requires an empty response msgpack_packer response; msgpack_packer_init(&response, channel->proto.msgpack.sbuffer, diff --git a/src/nvim/os/server.c b/src/nvim/os/server.c index b2faa49a86..7b2326556c 100644 --- a/src/nvim/os/server.c +++ b/src/nvim/os/server.c @@ -123,8 +123,8 @@ void server_start(char *endpoint, ChannelProtocol prot) char *port_end; // Extract the port port = strtol(ip_end + 1, &port_end, 10); - errno = 0; + if (errno != 0 || port == 0 || port > 0xffff) { // Invalid port, treat as named pipe or unix socket server_type = kServerTypePipe; @@ -156,7 +156,7 @@ void server_start(char *endpoint, ChannelProtocol prot) } } else { // Listen on named pipe or unix socket - strcpy(server->socket.pipe.addr, addr); + xstrlcpy(server->socket.pipe.addr, addr, sizeof(server->socket.pipe.addr)); uv_pipe_init(uv_default_loop(), &server->socket.pipe.handle, 0); server->socket.pipe.handle.data = server; uv_pipe_bind(&server->socket.pipe.handle, server->socket.pipe.addr); diff --git a/src/nvim/os/server.h b/src/nvim/os/server.h index 541746eb5f..73c6bd1fea 100644 --- a/src/nvim/os/server.h +++ b/src/nvim/os/server.h @@ -10,7 +10,7 @@ void server_init(); void server_teardown(); /// Starts listening on arbitrary tcp/unix addresses specified by -/// `endpoint` for API calls. The type of socket used(tcp or unix/pipe) will +/// `endpoint` for API calls. The type of socket used(tcp or unix/pipe) will /// be determined by parsing `endpoint`: If it's a valid tcp address in the /// 'ip:port' format, then it will be tcp socket, else it will be a unix /// socket or named pipe. -- cgit From 0cc6050300b0e6b53b750e3bd017c1eca9a072dc Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:19 -0300 Subject: API: Bugfix: Remove memory leak from set_option_to --- src/nvim/api/private/helpers.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 206129dd78..861ac8cc1b 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -267,6 +267,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) char *val = xstrndup(value.data.string.data, value.data.string.size); set_option_value_for(key, 0, val, opt_flags, type, to, err); + free(val); } cleanup: -- cgit From 807f940aa499fb1a33a4b1d066204ff58f25e075 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:21 -0300 Subject: API: Bugfix: Remove memory leak from buffer_set_slice --- src/nvim/api/buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index ef2f9e9d0e..c8a8240fee 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -217,7 +217,8 @@ void buffer_set_slice(Buffer buffer, goto end; } - // Same as with replacing + // Same as with replacing, but we also need to free lines + free(lines[i]); lines[i] = NULL; extra++; } -- cgit From 327347e3b47704f25e9a8d7d617d4f91fb128d43 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:23 -0300 Subject: API: Bugfix: Remove memory leak from buffer_set_name --- src/nvim/api/buffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index c8a8240fee..33ddacce69 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -334,6 +334,7 @@ void buffer_set_name(Buffer buffer, String name, Error *err) // Using aucmd_*: autocommands will be executed by rename_buffer aucmd_prepbuf(&aco, buf); ren_ret = rename_buffer((char_u *)val); + free(val); aucmd_restbuf(&aco); if (try_end(err)) { -- cgit From cbf9564ee01535e3a2168219ef8f84f857519da3 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 26 May 2014 13:39:25 -0300 Subject: API: Bugfix: Remove memory leak from buffer_get_line --- src/nvim/api/buffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 33ddacce69..4721045048 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -60,6 +60,8 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) rv = slice.items[0]; } + free(slice.items); + return rv; } -- cgit