From da51dc9cf202772f60bd2da975dbef257bd9237c Mon Sep 17 00:00:00 2001 From: Eliseo Martínez Date: Mon, 12 May 2014 02:25:17 +0200 Subject: Introduce nvim namespace: Move files. Move files from src/ to src/nvim/. - src/nvim/ becomes the new root dir for nvim executable sources. - src/libnvim/ is planned to become root dir of the neovim library. --- src/os/channel.c | 175 ------------------- src/os/channel.h | 29 ---- src/os/channel_defs.h | 8 - src/os/env.c | 80 --------- src/os/event.c | 148 ---------------- src/os/event.h | 18 -- src/os/event_defs.h | 25 --- src/os/fs.c | 277 ------------------------------ src/os/input.c | 195 --------------------- src/os/input.h | 23 --- src/os/job.c | 370 --------------------------------------- src/os/job.h | 78 --------- src/os/job_defs.h | 15 -- src/os/mem.c | 10 -- src/os/msgpack_rpc.c | 408 ------------------------------------------- src/os/msgpack_rpc.h | 107 ------------ src/os/os.h | 146 ---------------- src/os/rstream.c | 297 -------------------------------- src/os/rstream.h | 82 --------- src/os/rstream_defs.h | 16 -- src/os/server.c | 243 -------------------------- src/os/server.h | 30 ---- src/os/server_defs.h | 7 - src/os/shell.c | 465 -------------------------------------------------- src/os/shell.h | 45 ----- src/os/signal.c | 163 ------------------ src/os/signal.h | 13 -- src/os/time.c | 86 ---------- src/os/time.h | 35 ---- src/os/users.c | 87 ---------- src/os/uv_helpers.c | 70 -------- src/os/uv_helpers.h | 47 ----- src/os/wstream.c | 117 ------------- src/os/wstream.h | 40 ----- src/os/wstream_defs.h | 7 - 35 files changed, 3962 deletions(-) delete mode 100644 src/os/channel.c delete mode 100644 src/os/channel.h delete mode 100644 src/os/channel_defs.h delete mode 100644 src/os/env.c delete mode 100644 src/os/event.c delete mode 100644 src/os/event.h delete mode 100644 src/os/event_defs.h delete mode 100644 src/os/fs.c delete mode 100644 src/os/input.c delete mode 100644 src/os/input.h delete mode 100644 src/os/job.c delete mode 100644 src/os/job.h delete mode 100644 src/os/job_defs.h delete mode 100644 src/os/mem.c delete mode 100644 src/os/msgpack_rpc.c delete mode 100644 src/os/msgpack_rpc.h delete mode 100644 src/os/os.h delete mode 100644 src/os/rstream.c delete mode 100644 src/os/rstream.h delete mode 100644 src/os/rstream_defs.h delete mode 100644 src/os/server.c delete mode 100644 src/os/server.h delete mode 100644 src/os/server_defs.h delete mode 100644 src/os/shell.c delete mode 100644 src/os/shell.h delete mode 100644 src/os/signal.c delete mode 100644 src/os/signal.h delete mode 100644 src/os/time.c delete mode 100644 src/os/time.h delete mode 100644 src/os/users.c delete mode 100644 src/os/uv_helpers.c delete mode 100644 src/os/uv_helpers.h delete mode 100644 src/os/wstream.c delete mode 100644 src/os/wstream.h delete mode 100644 src/os/wstream_defs.h (limited to 'src/os') diff --git a/src/os/channel.c b/src/os/channel.c deleted file mode 100644 index 2427db2a14..0000000000 --- a/src/os/channel.c +++ /dev/null @@ -1,175 +0,0 @@ -#include - -#include -#include - -#include "lib/klist.h" -#include "os/channel.h" -#include "os/channel_defs.h" -#include "os/rstream.h" -#include "os/rstream_defs.h" -#include "os/wstream.h" -#include "os/wstream_defs.h" -#include "os/job.h" -#include "os/job_defs.h" -#include "os/msgpack_rpc.h" -#include "vim.h" -#include "memory.h" - -typedef struct { - ChannelProtocol protocol; - bool is_job; - union { - struct { - msgpack_unpacker *unpacker; - msgpack_sbuffer *sbuffer; - } msgpack; - } proto; - union { - int job_id; - struct { - RStream *read; - WStream *write; - } streams; - } data; -} Channel; - -#define _destroy_channel(x) - -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); - -void channel_init() -{ - channels = kl_init(Channel); -} - -void channel_teardown() -{ - if (!channels) { - return; - } - - 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); - } - } -} - -void channel_from_job(char **argv, ChannelProtocol prot) -{ - Channel *channel = xmalloc(sizeof(Channel)); - rstream_cb rcb = NULL; - - switch (prot) { - case kChannelProtocolMsgpack: - rcb = on_job_stdout; - channel->proto.msgpack.unpacker = - msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); - channel->proto.msgpack.sbuffer = msgpack_sbuffer_new(); - break; - default: - abort(); - } - - 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; -} - -void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot) -{ - Channel *channel = xmalloc(sizeof(Channel)); - rstream_cb rcb = NULL; - - switch (prot) { - case kChannelProtocolMsgpack: - rcb = parse_msgpack; - channel->proto.msgpack.unpacker = - msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); - channel->proto.msgpack.sbuffer = msgpack_sbuffer_new(); - break; - default: - abort(); - } - - stream->data = NULL; - channel->protocol = prot; - channel->is_job = false; - // read stream - channel->data.streams.read = rstream_new(rcb, 1024, channel, true); - rstream_set_stream(channel->data.streams.read, stream); - rstream_start(channel->data.streams.read); - // 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; -} - -static void on_job_stdout(RStream *rstream, void *data, bool eof) -{ - Job *job = data; - parse_msgpack(rstream, job_data(job), eof); -} - -static void on_job_stderr(RStream *rstream, void *data, bool eof) -{ - // TODO(tarruda): plugin error messages should be sent to the error buffer -} - -static void parse_msgpack(RStream *rstream, void *data, bool eof) -{ - msgpack_unpacked unpacked; - Channel *channel = data; - uint32_t count = rstream_available(rstream); - - // Feed the unpacker with data - msgpack_unpacker_reserve_buffer(channel->proto.msgpack.unpacker, count); - rstream_read(rstream, - msgpack_unpacker_buffer(channel->proto.msgpack.unpacker), - count); - msgpack_unpacker_buffer_consumed(channel->proto.msgpack.unpacker, count); - - msgpack_unpacked_init(&unpacked); - - // 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 - msgpack_packer response; - msgpack_packer_init(&response, - channel->proto.msgpack.sbuffer, - msgpack_sbuffer_write); - // Perform the call - msgpack_rpc_call(&unpacked.data, &response); - wstream_write(channel->data.streams.write, - xmemdup(channel->proto.msgpack.sbuffer->data, - channel->proto.msgpack.sbuffer->size), - channel->proto.msgpack.sbuffer->size, - true); - - // Clear the buffer for future calls - msgpack_sbuffer_clear(channel->proto.msgpack.sbuffer); - } -} diff --git a/src/os/channel.h b/src/os/channel.h deleted file mode 100644 index c58e91a0e5..0000000000 --- a/src/os/channel.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef NEOVIM_OS_CHANNEL_H -#define NEOVIM_OS_CHANNEL_H - -#include - -#include "os/channel_defs.h" - -/// Initializes the module -void channel_init(void); - -/// Teardown the module -void channel_teardown(void); - -/// Creates an API channel from a libuv stream representing a tcp or -/// pipe/socket client connection -/// -/// @param stream The established connection -/// @param prot The rpc protocol used -void channel_from_stream(uv_stream_t *stream, ChannelProtocol prot); - -/// Creates an API channel by starting a job and connecting to its -/// stdin/stdout. stderr is forwarded to the editor error stream. -/// -/// @param argv The argument vector for the process -/// @param prot The rpc protocol used -void channel_from_job(char **argv, ChannelProtocol prot); - -#endif // NEOVIM_OS_CHANNEL_H - diff --git a/src/os/channel_defs.h b/src/os/channel_defs.h deleted file mode 100644 index 27ba103fbe..0000000000 --- a/src/os/channel_defs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NEOVIM_OS_CHANNEL_DEFS_H -#define NEOVIM_OS_CHANNEL_DEFS_H - -typedef enum { - kChannelProtocolMsgpack -} ChannelProtocol; - -#endif // NEOVIM_OS_CHANNEL_DEFS_H diff --git a/src/os/env.c b/src/os/env.c deleted file mode 100644 index e6cdb92ea8..0000000000 --- a/src/os/env.c +++ /dev/null @@ -1,80 +0,0 @@ -// env.c -- environment variable access - -#include - -#include "os/os.h" -#include "misc2.h" - -#ifdef HAVE__NSGETENVIRON -#include -#endif - -#ifdef HAVE_SYS_UTSNAME_H -#include -#endif - -const char *os_getenv(const char *name) -{ - return getenv(name); -} - -int os_setenv(const char *name, const char *value, int overwrite) -{ - return setenv(name, value, overwrite); -} - -char *os_getenvname_at_index(size_t index) -{ -# if defined(HAVE__NSGETENVIRON) - char **environ = *_NSGetEnviron(); -# elif !defined(__WIN32__) - // Borland C++ 5.2 has this in a header file. - extern char **environ; -# endif - // check if index is inside the environ array - for (size_t i = 0; i < index; i++) { - if (environ[i] == NULL) { - return NULL; - } - } - char *str = environ[index]; - if (str == NULL) { - return NULL; - } - int namesize = 0; - while (str[namesize] != '=' && str[namesize] != NUL) { - namesize++; - } - char *name = (char *)vim_strnsave((char_u *)str, namesize); - return name; -} - - -int64_t os_get_pid() -{ -#ifdef _WIN32 - return (int64_t)GetCurrentProcessId(); -#else - return (int64_t)getpid(); -#endif -} - -void os_get_hostname(char *hostname, size_t len) -{ -#ifdef HAVE_SYS_UTSNAME_H - struct utsname vutsname; - - if (uname(&vutsname) < 0) { - *hostname = '\0'; - } else { - strncpy(hostname, vutsname.nodename, len - 1); - hostname[len - 1] = '\0'; - } -#else - // TODO(unknown): Implement this for windows. - // See the implementation used in vim: - // https://code.google.com/p/vim/source/browse/src/os_win32.c?r=6b69d8dde19e32909f4ee3a6337e6a2ecfbb6f72#2899 - *hostname = '\0'; -#endif -} - diff --git a/src/os/event.c b/src/os/event.c deleted file mode 100644 index 2c25852778..0000000000 --- a/src/os/event.c +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include - -#include - -#include "lib/klist.h" -#include "os/event.h" -#include "os/input.h" -#include "os/channel.h" -#include "os/server.h" -#include "os/signal.h" -#include "os/rstream.h" -#include "os/job.h" -#include "vim.h" -#include "memory.h" -#include "misc2.h" - -// event will be cleaned up after it gets processed -#define _destroy_event(x) // do nothing -KLIST_INIT(Event, Event, _destroy_event) - -static klist_t(Event) *event_queue; -static uv_timer_t timer; -static uv_prepare_t timer_prepare; -static void timer_cb(uv_timer_t *handle); -static void timer_prepare_cb(uv_prepare_t *); - -void event_init() -{ - // Initialize the event queue - event_queue = kl_init(Event); - // Initialize input events - input_init(); - // Timer to wake the event loop if a timeout argument is passed to - // `event_poll` - // Signals - signal_init(); - // Jobs - job_init(); - // Channels - channel_init(); - // Servers - server_init(); - uv_timer_init(uv_default_loop(), &timer); - // This prepare handle that actually starts the timer - uv_prepare_init(uv_default_loop(), &timer_prepare); -} - -void event_teardown() -{ - channel_teardown(); - job_teardown(); - server_teardown(); -} - -// Wait for some event -bool event_poll(int32_t ms) -{ - bool timed_out; - uv_run_mode run_mode = UV_RUN_ONCE; - - if (input_ready()) { - // If there's a pending input event to be consumed, do it now - return true; - } - - input_start(); - timed_out = false; - - if (ms > 0) { - // Timeout passed as argument to the timer - timer.data = &timed_out; - // We only start the timer after the loop is running, for that we - // use an prepare handle(pass the interval as data to it) - timer_prepare.data = &ms; - uv_prepare_start(&timer_prepare, timer_prepare_cb); - } else if (ms == 0) { - // For ms == 0, we need to do a non-blocking event poll by - // setting the run mode to UV_RUN_NOWAIT. - run_mode = UV_RUN_NOWAIT; - } - - do { - // Run one event loop iteration, blocking for events if run_mode is - // UV_RUN_ONCE - uv_run(uv_default_loop(), run_mode); - } while ( - // Continue running if ... - !input_ready() && // we have no input - kl_empty(event_queue) && // no events are waiting to be processed - run_mode != UV_RUN_NOWAIT && // ms != 0 - !timed_out); // we didn't get a timeout - - input_stop(); - - if (ms > 0) { - // Stop the timer - uv_timer_stop(&timer); - } - - return input_ready() || event_is_pending(); -} - -bool event_is_pending() -{ - return !kl_empty(event_queue); -} - -// Push an event to the queue -void event_push(Event event) -{ - *kl_pushp(Event, event_queue) = event; -} - -// Runs the appropriate action for each queued event -void event_process() -{ - Event event; - - while (kl_shift(Event, event_queue, &event) == 0) { - switch (event.type) { - case kEventSignal: - signal_handle(event); - break; - case kEventRStreamData: - rstream_read_event(event); - break; - case kEventJobExit: - job_exit_event(event); - break; - default: - abort(); - } - } -} - -// Set a flag in the `event_poll` loop for signaling of a timeout -static void timer_cb(uv_timer_t *handle) -{ - *((bool *)handle->data) = true; -} - -static void timer_prepare_cb(uv_prepare_t *handle) -{ - uv_timer_start(&timer, timer_cb, *(uint32_t *)timer_prepare.data, 0); - uv_prepare_stop(&timer_prepare); -} diff --git a/src/os/event.h b/src/os/event.h deleted file mode 100644 index 5ddca46875..0000000000 --- a/src/os/event.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef NEOVIM_OS_EVENT_H -#define NEOVIM_OS_EVENT_H - -#include -#include - -#include "os/event_defs.h" -#include "os/job_defs.h" - -void event_init(void); -void event_teardown(void); -bool event_poll(int32_t ms); -bool event_is_pending(void); -void event_push(Event event); -void event_process(void); - -#endif // NEOVIM_OS_EVENT_H - diff --git a/src/os/event_defs.h b/src/os/event_defs.h deleted file mode 100644 index 428ae50f3e..0000000000 --- a/src/os/event_defs.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef NEOVIM_OS_EVENT_DEFS_H -#define NEOVIM_OS_EVENT_DEFS_H - -#include "os/job_defs.h" -#include "os/rstream_defs.h" - -typedef enum { - kEventSignal, - kEventRStreamData, - kEventJobExit -} EventType; - -typedef struct { - EventType type; - union { - int signum; - struct { - RStream *ptr; - bool eof; - } rstream; - Job *job; - } data; -} Event; - -#endif // NEOVIM_OS_EVENT_DEFS_H diff --git a/src/os/fs.c b/src/os/fs.c deleted file mode 100644 index 89eb4c8691..0000000000 --- a/src/os/fs.c +++ /dev/null @@ -1,277 +0,0 @@ -// fs.c -- filesystem access - -#include "os/os.h" -#include "memory.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "path.h" - -static bool is_executable(const char_u *name); -static bool is_executable_in_path(const char_u *name); - -// Many fs functions from libuv return that value on success. -static const int kLibuvSuccess = 0; - -int os_chdir(const char *path) { - if (p_verbose >= 5) { - verbose_enter(); - smsg((char_u *)"chdir(%s)", path); - verbose_leave(); - } - return uv_chdir(path); -} - -int os_dirname(char_u *buf, size_t len) -{ - assert(buf && len); - - int errno; - if ((errno = uv_cwd((char *)buf, &len)) != kLibuvSuccess) { - vim_strncpy(buf, (char_u *)uv_strerror(errno), len - 1); - return FAIL; - } - return OK; -} - -bool os_isdir(const char_u *name) -{ - int32_t mode = os_getperm(name); - if (mode < 0) { - return false; - } - - if (!S_ISDIR(mode)) { - return false; - } - - return true; -} - -bool os_can_exe(const char_u *name) -{ - // If it's an absolute or relative path don't need to use $PATH. - if (path_is_absolute_path(name) || - (name[0] == '.' && (name[1] == '/' || - (name[1] == '.' && name[2] == '/')))) { - return is_executable(name); - } - - return is_executable_in_path(name); -} - -// Return true if "name" is an executable file, false if not or it doesn't -// exist. -static bool is_executable(const char_u *name) -{ - int32_t mode = os_getperm(name); - - if (mode < 0) { - return false; - } - - if (S_ISREG(mode) && (S_IEXEC & mode)) { - return true; - } - - return false; -} - -/// Check if a file is inside the $PATH and is executable. -/// -/// @return `true` if `name` is an executable inside $PATH. -static bool is_executable_in_path(const char_u *name) -{ - const char *path = getenv("PATH"); - // PATH environment variable does not exist or is empty. - if (path == NULL || *path == NUL) { - return false; - } - - int buf_len = STRLEN(name) + STRLEN(path) + 2; - char_u *buf = alloc((unsigned)(buf_len)); - - // Walk through all entries in $PATH to check if "name" exists there and - // is an executable file. - for (;; ) { - const char *e = strchr(path, ':'); - if (e == NULL) { - e = path + STRLEN(path); - } - - // Glue together the given directory from $PATH with name and save into - // buf. - vim_strncpy(buf, (char_u *) path, e - path); - append_path((char *) buf, (const char *) name, buf_len); - - if (is_executable(buf)) { - // Found our executable. Free buf and return. - free(buf); - return true; - } - - if (*e != ':') { - // End of $PATH without finding any executable called name. - free(buf); - return false; - } - - path = e + 1; - } - - // We should never get to this point. - assert(false); - return false; -} - -int os_stat(const char_u *name, uv_stat_t *statbuf) -{ - uv_fs_t request; - int result = uv_fs_stat(uv_default_loop(), &request, - (const char *)name, NULL); - *statbuf = request.statbuf; - uv_fs_req_cleanup(&request); - - if (result == kLibuvSuccess) { - return OK; - } - - return FAIL; -} - -int32_t os_getperm(const char_u *name) -{ - uv_stat_t statbuf; - if (os_stat(name, &statbuf) == FAIL) { - return -1; - } else { - return (int32_t)statbuf.st_mode; - } -} - -int os_setperm(const char_u *name, int perm) -{ - uv_fs_t request; - int result = uv_fs_chmod(uv_default_loop(), &request, - (const char*)name, perm, NULL); - uv_fs_req_cleanup(&request); - - if (result == kLibuvSuccess) { - return OK; - } - - return FAIL; -} - -bool os_file_exists(const char_u *name) -{ - uv_stat_t statbuf; - if (os_stat(name, &statbuf) == OK) { - return true; - } - - return false; -} - -bool os_file_is_readonly(const char *name) -{ - return access(name, W_OK) != 0; -} - -int os_file_is_writable(const char *name) -{ - if (access(name, W_OK) == 0) { - if (os_isdir((char_u *)name)) { - return 2; - } - return 1; - } - return 0; -} - -bool os_get_file_size(const char *name, off_t *size) -{ - uv_stat_t statbuf; - if (os_stat((char_u *)name, &statbuf) == OK) { - *size = statbuf.st_size; - return true; - } - return false; -} - -int os_rename(const char_u *path, const char_u *new_path) -{ - uv_fs_t request; - int result = uv_fs_rename(uv_default_loop(), &request, - (const char *)path, (const char *)new_path, NULL); - uv_fs_req_cleanup(&request); - - if (result == kLibuvSuccess) { - return OK; - } - - return FAIL; -} - -int os_mkdir(const char *path, int32_t mode) -{ - uv_fs_t request; - int result = uv_fs_mkdir(uv_default_loop(), &request, path, mode, NULL); - uv_fs_req_cleanup(&request); - return result; -} - -int os_rmdir(const char *path) -{ - uv_fs_t request; - int result = uv_fs_rmdir(uv_default_loop(), &request, path, NULL); - uv_fs_req_cleanup(&request); - return result; -} - -int os_remove(const char *path) -{ - uv_fs_t request; - int result = uv_fs_unlink(uv_default_loop(), &request, path, NULL); - uv_fs_req_cleanup(&request); - return result; -} - -bool os_get_file_info(const char *path, FileInfo *file_info) -{ - if (os_stat((char_u *)path, &(file_info->stat)) == OK) { - return true; - } - return false; -} - -bool os_get_file_info_link(const char *path, FileInfo *file_info) -{ - uv_fs_t request; - int result = uv_fs_lstat(uv_default_loop(), &request, path, NULL); - file_info->stat = request.statbuf; - uv_fs_req_cleanup(&request); - if (result == kLibuvSuccess) { - return true; - } - return false; -} - -bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info) -{ - uv_fs_t request; - int result = uv_fs_fstat(uv_default_loop(), &request, file_descriptor, NULL); - file_info->stat = request.statbuf; - uv_fs_req_cleanup(&request); - if (result == kLibuvSuccess) { - return true; - } - return false; -} - -bool os_file_info_id_equal(FileInfo *file_info_1, FileInfo *file_info_2) -{ - return file_info_1->stat.st_ino == file_info_2->stat.st_ino - && file_info_1->stat.st_dev == file_info_2->stat.st_dev; -} - diff --git a/src/os/input.c b/src/os/input.c deleted file mode 100644 index 4310edd514..0000000000 --- a/src/os/input.c +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include -#include - -#include - -#include "os/input.h" -#include "os/event.h" -#include "os/rstream_defs.h" -#include "os/rstream.h" -#include "vim.h" -#include "ui.h" -#include "fileio.h" -#include "getchar.h" -#include "term.h" - -#define READ_BUFFER_SIZE 256 - -typedef enum { - kInputNone, - kInputAvail, - kInputEof -} InbufPollResult; - -static RStream *read_stream; -static bool eof = false, started_reading = false; - -static InbufPollResult inbuf_poll(int32_t ms); -static void stderr_switch(void); -static void read_cb(RStream *rstream, void *data, bool eof); -// Helper function used to push bytes from the 'event' key sequence partially -// between calls to os_inchar when maxlen < 3 -static int push_event_key(uint8_t *buf, int maxlen); - -void input_init() -{ - read_stream = rstream_new(read_cb, READ_BUFFER_SIZE, NULL, false); - rstream_set_file(read_stream, read_cmd_fd); -} - -// Check if there's pending input -bool input_ready() -{ - return rstream_available(read_stream) > 0 || eof; -} - -// Listen for input -void input_start() -{ - rstream_start(read_stream); -} - -// Stop listening for input -void input_stop() -{ - rstream_stop(read_stream); -} - -// Copies (at most `count`) of was read from `read_cmd_fd` into `buf` -uint32_t input_read(char *buf, uint32_t count) -{ - return rstream_read(read_stream, buf, count); -} - - -// Low level input function. -int os_inchar(uint8_t *buf, int maxlen, int32_t ms, int tb_change_cnt) -{ - InbufPollResult result; - - if (event_is_pending()) { - // Return pending event bytes - return push_event_key(buf, maxlen); - } - - if (ms >= 0) { - if ((result = inbuf_poll(ms)) == kInputNone) { - return 0; - } - } else { - if ((result = inbuf_poll(p_ut)) == kInputNone) { - if (trigger_cursorhold() && maxlen >= 3 - && !typebuf_changed(tb_change_cnt)) { - buf[0] = K_SPECIAL; - buf[1] = KS_EXTRA; - buf[2] = KE_CURSORHOLD; - return 3; - } - - before_blocking(); - result = inbuf_poll(-1); - } - } - - // If there are pending events, return the keys directly - if (event_is_pending()) { - return push_event_key(buf, maxlen); - } - - // If input was put directly in typeahead buffer bail out here. - if (typebuf_changed(tb_change_cnt)) { - return 0; - } - - if (result == kInputEof) { - read_error_exit(); - return 0; - } - - return read_from_input_buf(buf, (int64_t)maxlen); -} - -// Check if a character is available for reading -bool os_char_avail() -{ - return inbuf_poll(0) == kInputAvail; -} - -// Check for CTRL-C typed by reading all available characters. -// In cooked mode we should get SIGINT, no need to check. -void os_breakcheck() -{ - if (curr_tmode == TMODE_RAW && event_poll(0)) - fill_input_buf(false); -} - -bool os_isatty(int fd) -{ - return uv_guess_handle(fd) == UV_TTY; -} - -// This is a replacement for the old `WaitForChar` function in os_unix.c -static InbufPollResult inbuf_poll(int32_t ms) -{ - if (input_available()) { - return kInputAvail; - } - - if (event_poll(ms)) { - return eof && rstream_available(read_stream) == 0 ? - kInputEof : - kInputAvail; - } - - return kInputNone; -} - -static void stderr_switch() -{ - int mode = cur_tmode; - // We probably set the wrong file descriptor to raw mode. Switch back to - // cooked mode - settmode(TMODE_COOK); - // Stop the idle handle - rstream_stop(read_stream); - // Use stderr for stdin, also works for shell commands. - read_cmd_fd = 2; - // Initialize and start the input stream - rstream_set_file(read_stream, read_cmd_fd); - rstream_start(read_stream); - // Set the mode back to what it was - settmode(mode); -} - -static void read_cb(RStream *rstream, void *data, bool at_eof) -{ - if (at_eof) { - if (!started_reading - && rstream_is_regular_file(rstream) - && os_isatty(STDERR_FILENO)) { - // Read error. Since stderr is a tty we switch to reading from it. This - // is for handling for cases like "foo | xargs vim" because xargs - // redirects stdin from /dev/null. Previously, this was done in ui.c - stderr_switch(); - } else { - eof = true; - } - } - - started_reading = true; -} - -static int push_event_key(uint8_t *buf, int maxlen) -{ - static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT }; - static int key_idx = 0; - int buf_idx = 0; - - do { - buf[buf_idx++] = key[key_idx++]; - key_idx %= 3; - } while (key_idx > 0 && buf_idx < maxlen); - - return buf_idx; -} diff --git a/src/os/input.h b/src/os/input.h deleted file mode 100644 index 9ffd50fd3f..0000000000 --- a/src/os/input.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef NEOVIM_OS_INPUT_H -#define NEOVIM_OS_INPUT_H - -#include -#include - -void input_init(void); -bool input_ready(void); -void input_start(void); -void input_stop(void); -uint32_t input_read(char *buf, uint32_t count); -int os_inchar(uint8_t *, int, int32_t, int); -bool os_char_avail(void); -void os_breakcheck(void); - -/// Test whether a file descriptor refers to a terminal. -/// -/// @param fd File descriptor. -/// @return `true` if file descriptor refers to a terminal. -bool os_isatty(int fd); - -#endif // NEOVIM_OS_INPUT_H - diff --git a/src/os/job.c b/src/os/job.c deleted file mode 100644 index 7940338b70..0000000000 --- a/src/os/job.c +++ /dev/null @@ -1,370 +0,0 @@ -#include -#include - -#include - -#include "os/uv_helpers.h" -#include "os/job.h" -#include "os/job_defs.h" -#include "os/rstream.h" -#include "os/rstream_defs.h" -#include "os/wstream.h" -#include "os/wstream_defs.h" -#include "os/event.h" -#include "os/event_defs.h" -#include "os/time.h" -#include "os/shell.h" -#include "vim.h" -#include "memory.h" -#include "term.h" - -#define EXIT_TIMEOUT 25 -#define MAX_RUNNING_JOBS 100 -#define JOB_BUFFER_SIZE 1024 -#define JOB_WRITE_MAXMEM 1024 * 1024 - -struct job { - // Job id the index in the job table plus one. - int id; - // Number of polls after a SIGTERM that will trigger a SIGKILL - int exit_timeout; - // exit_cb may be called while there's still pending data from stdout/stderr. - // We use this reference count to ensure the JobExit event is only emitted - // when stdout/stderr are drained - int pending_refs; - // Same as above, but for freeing the job memory which contains - // libuv handles. Only after all are closed the job can be safely freed. - int pending_closes; - // If the job was already stopped - bool stopped; - // Data associated with the job - void *data; - // Callbacks - job_exit_cb exit_cb; - rstream_cb stdout_cb, stderr_cb; - // Readable streams(std{out,err}) - RStream *out, *err; - // Writable stream(stdin) - WStream *in; - // Structures for process spawning/management used by libuv - uv_process_t proc; - uv_process_options_t proc_opts; - uv_stdio_container_t stdio[3]; - uv_pipe_t proc_stdin, proc_stdout, proc_stderr; -}; - -static Job *table[MAX_RUNNING_JOBS] = {NULL}; -static uint32_t job_count = 0; -static uv_prepare_t job_prepare; - -// Some helpers shared in this module -static bool is_alive(Job *job); -static Job * find_job(int id); -static void free_job(Job *job); - -// Callbacks for libuv -static void job_prepare_cb(uv_prepare_t *handle); -static void read_cb(RStream *rstream, void *data, bool eof); -static void exit_cb(uv_process_t *proc, int64_t status, int term_signal); -static void close_cb(uv_handle_t *handle); -static void emit_exit_event(Job *job); - -void job_init() -{ - uv_disable_stdio_inheritance(); - uv_prepare_init(uv_default_loop(), &job_prepare); -} - -void job_teardown() -{ - // 20 tries will give processes about 1 sec to exit cleanly - uint32_t remaining_tries = 20; - bool all_dead = true; - int i; - Job *job; - - // Politely ask each job to terminate - for (i = 0; i < MAX_RUNNING_JOBS; i++) { - if ((job = table[i]) != NULL) { - all_dead = false; - uv_process_kill(&job->proc, SIGTERM); - } - } - - if (all_dead) { - return; - } - - os_delay(10, 0); - // Right now any exited process are zombies waiting for us to acknowledge - // their status with `wait` or handling SIGCHLD. libuv does that - // automatically (and then calls `exit_cb`) but we have to give it a chance - // by running the loop one more time - uv_run(uv_default_loop(), UV_RUN_NOWAIT); - - // Prepare to start shooting - for (i = 0; i < MAX_RUNNING_JOBS; i++) { - if ((job = table[i]) == NULL) { - continue; - } - - // Still alive - while (is_alive(job) && remaining_tries--) { - os_delay(50, 0); - // Acknowledge child exits - uv_run(uv_default_loop(), UV_RUN_NOWAIT); - } - - if (is_alive(job)) { - uv_process_kill(&job->proc, SIGKILL); - } - } -} - -int job_start(char **argv, - void *data, - rstream_cb stdout_cb, - rstream_cb stderr_cb, - job_exit_cb job_exit_cb) -{ - int i; - Job *job; - - // Search for a free slot in the table - for (i = 0; i < MAX_RUNNING_JOBS; i++) { - if (table[i] == NULL) { - break; - } - } - - if (i == MAX_RUNNING_JOBS) { - // No free slots - return 0; - } - - job = xmalloc(sizeof(Job)); - // Initialize - job->id = i + 1; - job->pending_refs = 3; - job->pending_closes = 4; - job->data = data; - job->stdout_cb = stdout_cb; - job->stderr_cb = stderr_cb; - job->exit_cb = job_exit_cb; - job->stopped = false; - job->exit_timeout = EXIT_TIMEOUT; - job->proc_opts.file = argv[0]; - job->proc_opts.args = argv; - job->proc_opts.stdio = job->stdio; - job->proc_opts.stdio_count = 3; - job->proc_opts.flags = UV_PROCESS_WINDOWS_HIDE; - job->proc_opts.exit_cb = exit_cb; - job->proc_opts.cwd = NULL; - job->proc_opts.env = NULL; - job->proc.data = NULL; - job->proc_stdin.data = NULL; - job->proc_stdout.data = NULL; - job->proc_stderr.data = NULL; - - // Initialize the job std{in,out,err} - uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0); - job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin; - - uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0); - job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout; - - uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0); - job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr; - - // Spawn the job - if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) { - free_job(job); - return -1; - } - - // Give all handles a reference to the job - handle_set_job((uv_handle_t *)&job->proc, job); - handle_set_job((uv_handle_t *)&job->proc_stdin, job); - handle_set_job((uv_handle_t *)&job->proc_stdout, job); - handle_set_job((uv_handle_t *)&job->proc_stderr, job); - - job->in = wstream_new(JOB_WRITE_MAXMEM); - wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin); - // Start the readable streams - job->out = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true); - job->err = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true); - rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout); - rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr); - rstream_start(job->out); - rstream_start(job->err); - // Save the job to the table - table[i] = job; - - // Start polling job status if this is the first - if (job_count == 0) { - uv_prepare_start(&job_prepare, job_prepare_cb); - } - job_count++; - - return job->id; -} - -bool job_stop(int id) -{ - Job *job = find_job(id); - - if (job == NULL || job->stopped) { - return false; - } - - job->stopped = true; - - return true; -} - -bool job_write(int id, char *data, uint32_t len) -{ - Job *job = find_job(id); - - if (job == NULL || job->stopped) { - free(data); - return false; - } - - if (!wstream_write(job->in, data, len, true)) { - job_stop(job->id); - return false; - } - - return true; -} - -void job_exit_event(Event event) -{ - Job *job = event.data.job; - - // Free the slot now, 'exit_cb' may want to start another job to replace - // this one - table[job->id - 1] = NULL; - - if (job->exit_cb) { - // Invoke the exit callback - job->exit_cb(job, job->data); - } - - // Free the job resources - free_job(job); - - // Stop polling job status if this was the last - job_count--; - if (job_count == 0) { - uv_prepare_stop(&job_prepare); - } -} - -int job_id(Job *job) -{ - return job->id; -} - -void *job_data(Job *job) -{ - return job->data; -} - -static bool is_alive(Job *job) -{ - return uv_process_kill(&job->proc, 0) == 0; -} - -static Job * find_job(int id) -{ - if (id <= 0 || id > MAX_RUNNING_JOBS) { - return NULL; - } - - return table[id - 1]; -} - -static void free_job(Job *job) -{ - uv_close((uv_handle_t *)&job->proc_stdout, close_cb); - uv_close((uv_handle_t *)&job->proc_stdin, close_cb); - uv_close((uv_handle_t *)&job->proc_stderr, close_cb); - uv_close((uv_handle_t *)&job->proc, close_cb); -} - -/// Iterates the table, sending SIGTERM to stopped jobs and SIGKILL to those -/// that didn't die from SIGTERM after a while(exit_timeout is 0). -static void job_prepare_cb(uv_prepare_t *handle) -{ - Job *job; - int i; - - for (i = 0; i < MAX_RUNNING_JOBS; i++) { - if ((job = table[i]) == NULL || !job->stopped) { - continue; - } - - if ((job->exit_timeout--) == EXIT_TIMEOUT) { - // Job was just stopped, close all stdio handles and send SIGTERM - uv_process_kill(&job->proc, SIGTERM); - } else if (job->exit_timeout == 0) { - // We've waited long enough, send SIGKILL - uv_process_kill(&job->proc, SIGKILL); - } - } -} - -// Wraps the call to std{out,err}_cb and emits a JobExit event if necessary. -static void read_cb(RStream *rstream, void *data, bool eof) -{ - Job *job = data; - - if (rstream == job->out) { - job->stdout_cb(rstream, data, eof); - } else { - job->stderr_cb(rstream, data, eof); - } - - if (eof && --job->pending_refs == 0) { - emit_exit_event(job); - } -} - -// Emits a JobExit event if both rstreams are closed -static void exit_cb(uv_process_t *proc, int64_t status, int term_signal) -{ - Job *job = handle_get_job((uv_handle_t *)proc); - - if (--job->pending_refs == 0) { - emit_exit_event(job); - } -} - -static void emit_exit_event(Job *job) -{ - Event event; - event.type = kEventJobExit; - event.data.job = job; - event_push(event); -} - -static void close_cb(uv_handle_t *handle) -{ - Job *job = handle_get_job(handle); - - if (--job->pending_closes == 0) { - // Only free the job memory after all the associated handles are properly - // closed by libuv - rstream_free(job->out); - rstream_free(job->err); - wstream_free(job->in); - shell_free_argv(job->proc_opts.args); - free(job->data); - free(job); - } -} diff --git a/src/os/job.h b/src/os/job.h deleted file mode 100644 index db147f2c24..0000000000 --- a/src/os/job.h +++ /dev/null @@ -1,78 +0,0 @@ -// Job is a short name we use to refer to child processes that run in parallel -// with the editor, probably executing long-running tasks and sending updates -// asynchronously. Communication happens through anonymous pipes connected to -// the job's std{in,out,err}. They are more like bash/zsh co-processes than the -// usual shell background job. The name 'Job' was chosen because it applies to -// the concept while being significantly shorter. -#ifndef NEOVIM_OS_JOB_H -#define NEOVIM_OS_JOB_H - -#include -#include - -#include "os/event_defs.h" -#include "os/rstream_defs.h" - -/// Initializes job control resources -void job_init(void); - -/// Releases job control resources and terminates running jobs -void job_teardown(void); - -/// Tries to start a new job. -/// -/// @param argv Argument vector for the process. The first item is the -/// executable to run. -/// @param data Caller data that will be associated with the job -/// @param stdout_cb Callback that will be invoked when data is available -/// on stdout -/// @param stderr_cb Callback that will be invoked when data is available -/// on stderr -/// @param exit_cb Callback that will be invoked when the job exits. This is -/// optional. -/// @return The job id if the job started successfully. If the the first item / -/// of `argv`(the program) could not be executed, -1 will be returned. -// 0 will be returned if the job table is full. -int job_start(char **argv, - void *data, - rstream_cb stdout_cb, - rstream_cb stderr_cb, - job_exit_cb exit_cb); - -/// Terminates a job. This is a non-blocking operation, but if the job exists -/// it's guaranteed to succeed(SIGKILL will eventually be sent) -/// -/// @param id The job id -/// @return true if the stop request was successfully sent, false if the job -/// id is invalid(probably because it has already stopped) -bool job_stop(int id); - -/// Writes data to the job's stdin. This is a non-blocking operation, it -/// returns when the write request was sent. -/// -/// @param id The job id -/// @param data Buffer containing the data to be written -/// @param len Size of the data -/// @return true if the write request was successfully sent, false if the job -/// id is invalid(probably because it has already stopped) -bool job_write(int id, char *data, uint32_t len); - -/// Runs the read callback associated with the job exit event -/// -/// @param event Object containing data necessary to invoke the callback -void job_exit_event(Event event); - -/// Get the job id -/// -/// @param job A pointer to the job -/// @return The job id -int job_id(Job *job); - -/// Get data associated with a job -/// -/// @param job A pointer to the job -/// @return The job data -void *job_data(Job *job); - -#endif // NEOVIM_OS_JOB_H - diff --git a/src/os/job_defs.h b/src/os/job_defs.h deleted file mode 100644 index e98b639154..0000000000 --- a/src/os/job_defs.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef NEOVIM_OS_JOB_DEFS_H -#define NEOVIM_OS_JOB_DEFS_H - -#include "os/rstream_defs.h" - -typedef struct job Job; - -/// Function called when the job reads data -/// -/// @param id The job id -/// @param data Some data associated with the job by the caller -typedef void (*job_exit_cb)(Job *job, void *data); - -#endif // NEOVIM_OS_JOB_DEFS_H - diff --git a/src/os/mem.c b/src/os/mem.c deleted file mode 100644 index e5549340ff..0000000000 --- a/src/os/mem.c +++ /dev/null @@ -1,10 +0,0 @@ -/// Functions for accessing system memory information. - -#include - -#include "os/os.h" - -uint64_t os_get_total_mem_kib(void) { - // Convert bytes to KiB. - return uv_get_total_memory() >> 10; -} diff --git a/src/os/msgpack_rpc.c b/src/os/msgpack_rpc.c deleted file mode 100644 index e429bf0519..0000000000 --- a/src/os/msgpack_rpc.c +++ /dev/null @@ -1,408 +0,0 @@ -#include - -#include "msgpack_rpc.h" -#include "vim.h" -#include "memory.h" - -static bool msgpack_rpc_to_uint16_t(msgpack_object *obj, uint16_t *arg); - -void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) -{ - // The initial response structure is the same no matter what happens, - // we set it up here - // Array of size 4 - msgpack_pack_array(res, 4); - // Response type is 1 - msgpack_pack_int(res, 1); - - // Validate the basic structure of the msgpack-rpc payload - if (req->type != MSGPACK_OBJECT_ARRAY) { - msgpack_pack_int(res, 0); // no message id yet - msgpack_rpc_error("Request is not an array", res); - return; - } - - if (req->via.array.size != 4) { - msgpack_pack_int(res, 0); // no message id yet - char error_msg[256]; - snprintf(error_msg, - sizeof(error_msg), - "Request array size is %u, it should be 4", - req->via.array.size); - msgpack_rpc_error(error_msg, res); - } - - if (req->via.array.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - msgpack_pack_int(res, 0); // no message id yet - msgpack_rpc_error("Id must be a positive integer", res); - } - - // Set the response id, which is the same as the request - msgpack_pack_int(res, req->via.array.ptr[1].via.u64); - - if (req->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - msgpack_rpc_error("Message type must be an integer", res); - return; - } - - if (req->via.array.ptr[0].via.u64 != 0) { - msgpack_rpc_error("Message type must be 0", res); - return; - } - - if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - msgpack_rpc_error("Method id must be a positive integer", res); - return; - } - - if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) { - msgpack_rpc_error("Paremeters must be an array", res); - return; - } - - // dispatch the message - msgpack_rpc_dispatch(req, res); -} - -void msgpack_rpc_error(char *msg, msgpack_packer *res) -{ - size_t len = strlen(msg); - - // error message - msgpack_pack_raw(res, len); - msgpack_pack_raw_body(res, msg, len); - // Nil result - msgpack_pack_nil(res); -} - -bool msgpack_rpc_to_bool(msgpack_object *obj, bool *arg) -{ - *arg = obj->via.boolean; - return obj->type == MSGPACK_OBJECT_BOOLEAN; -} - -bool msgpack_rpc_to_int64_t(msgpack_object *obj, int64_t *arg) -{ - *arg = obj->via.i64; - return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER - || obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER; -} - -bool msgpack_rpc_to_double(msgpack_object *obj, double *arg) -{ - *arg = obj->via.dec; - return obj->type == MSGPACK_OBJECT_DOUBLE; -} - -bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) -{ - arg->data = (char *)obj->via.raw.ptr; - arg->size = obj->via.raw.size; - return obj->type == MSGPACK_OBJECT_RAW; -} - -bool msgpack_rpc_to_buffer(msgpack_object *obj, Buffer *arg) -{ - return msgpack_rpc_to_uint16_t(obj, arg); -} - -bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg) -{ - return msgpack_rpc_to_uint16_t(obj, arg); -} - -bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg) -{ - return msgpack_rpc_to_uint16_t(obj, arg); -} - -bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) -{ - switch (obj->type) { - case MSGPACK_OBJECT_NIL: - arg->type = kObjectTypeNil; - return true; - - case MSGPACK_OBJECT_BOOLEAN: - arg->type = kObjectTypeBool; - return msgpack_rpc_to_bool(obj, &arg->data.boolean); - - case MSGPACK_OBJECT_POSITIVE_INTEGER: - case MSGPACK_OBJECT_NEGATIVE_INTEGER: - arg->type = kObjectTypeInt; - return msgpack_rpc_to_int64_t(obj, &arg->data.integer); - - case MSGPACK_OBJECT_DOUBLE: - arg->type = kObjectTypeFloat; - return msgpack_rpc_to_double(obj, &arg->data.floating_point); - - case MSGPACK_OBJECT_RAW: - arg->type = kObjectTypeString; - return msgpack_rpc_to_string(obj, &arg->data.string); - - case MSGPACK_OBJECT_ARRAY: - arg->type = kObjectTypeArray; - return msgpack_rpc_to_array(obj, &arg->data.array); - - case MSGPACK_OBJECT_MAP: - arg->type = kObjectTypeDictionary; - return msgpack_rpc_to_dictionary(obj, &arg->data.dictionary); - - default: - return false; - } -} - -bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg) -{ - if (obj->type != MSGPACK_OBJECT_ARRAY) { - return false; - } - - arg->size = obj->via.array.size; - arg->items = xcalloc(obj->via.array.size, sizeof(String)); - - for (uint32_t i = 0; i < obj->via.array.size; i++) { - if (!msgpack_rpc_to_string(obj->via.array.ptr + i, &arg->items[i])) { - return false; - } - } - - return true; -} - -bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg) -{ - // positions are represented by integer arrays of size 2 - if (obj->type != MSGPACK_OBJECT_ARRAY - || obj->via.array.size != 2 - || obj->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER - || obj->via.array.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { - return false; - } - - arg->row = obj->via.array.ptr[0].via.u64; - arg->col = obj->via.array.ptr[1].via.u64; - - return true; -} - - -bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg) -{ - if (obj->type != MSGPACK_OBJECT_ARRAY) { - return false; - } - - arg->size = obj->via.array.size; - arg->items = xcalloc(obj->via.array.size, sizeof(Object)); - - for (uint32_t i = 0; i < obj->via.array.size; i++) { - if (!msgpack_rpc_to_object(obj->via.array.ptr + i, &arg->items[i])) { - return false; - } - } - - return true; -} - -bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg) -{ - if (obj->type != MSGPACK_OBJECT_MAP) { - return false; - } - - arg->size = obj->via.array.size; - arg->items = xcalloc(obj->via.map.size, sizeof(KeyValuePair)); - - - for (uint32_t i = 0; i < obj->via.map.size; i++) { - if (!msgpack_rpc_to_string(&obj->via.map.ptr[i].key, - &arg->items[i].key)) { - return false; - } - - if (!msgpack_rpc_to_object(&obj->via.map.ptr[i].val, - &arg->items[i].value)) { - return false; - } - } - - return true; -} - -void msgpack_rpc_from_bool(bool result, msgpack_packer *res) -{ - if (result) { - msgpack_pack_true(res); - } else { - msgpack_pack_false(res); - } -} - -void msgpack_rpc_from_int64_t(int64_t result, msgpack_packer *res) -{ - msgpack_pack_int64(res, result); -} - -void msgpack_rpc_from_uint64_t(uint64_t result, msgpack_packer *res) -{ - msgpack_pack_uint64(res, result); -} - -void msgpack_rpc_from_double(double result, msgpack_packer *res) -{ - msgpack_pack_double(res, result); -} - -void msgpack_rpc_from_string(String result, msgpack_packer *res) -{ - msgpack_pack_raw(res, result.size); - msgpack_pack_raw_body(res, result.data, result.size); -} - -void msgpack_rpc_from_buffer(Buffer result, msgpack_packer *res) -{ - msgpack_rpc_from_uint64_t(result, res); -} - -void msgpack_rpc_from_window(Window result, msgpack_packer *res) -{ - msgpack_rpc_from_uint64_t(result, res); -} - -void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res) -{ - msgpack_rpc_from_uint64_t(result, res); -} - -void msgpack_rpc_from_object(Object result, msgpack_packer *res) -{ - switch (result.type) { - case kObjectTypeNil: - msgpack_pack_nil(res); - break; - - case kObjectTypeBool: - msgpack_rpc_from_bool(result.data.boolean, res); - break; - - case kObjectTypeInt: - msgpack_rpc_from_int64_t(result.data.integer, res); - break; - - case kObjectTypeFloat: - msgpack_rpc_from_double(result.data.floating_point, res); - break; - - case kObjectTypeString: - msgpack_rpc_from_string(result.data.string, res); - break; - - case kObjectTypeArray: - msgpack_rpc_from_array(result.data.array, res); - break; - - case kObjectTypeDictionary: - msgpack_rpc_from_dictionary(result.data.dictionary, res); - break; - - default: - abort(); - } -} - -void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res) -{ - msgpack_pack_array(res, result.size); - - for (size_t i = 0; i < result.size; i++) { - msgpack_rpc_from_string(result.items[i], res); - } -} - -void msgpack_rpc_from_position(Position result, msgpack_packer *res) -{ - msgpack_pack_array(res, 2);; - msgpack_pack_uint16(res, result.row); - msgpack_pack_uint16(res, result.col); -} - -void msgpack_rpc_from_array(Array result, msgpack_packer *res) -{ - msgpack_pack_array(res, result.size); - - for (size_t i = 0; i < result.size; i++) { - msgpack_rpc_from_object(result.items[i], res); - } -} - -void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res) -{ - msgpack_pack_map(res, result.size); - - for (size_t i = 0; i < result.size; i++) { - msgpack_rpc_from_string(result.items[i].key, res); - msgpack_rpc_from_object(result.items[i].value, res); - } -} - -void msgpack_rpc_free_object(Object value) -{ - switch (value.type) { - case kObjectTypeNil: - case kObjectTypeBool: - case kObjectTypeInt: - case kObjectTypeFloat: - break; - - case kObjectTypeString: - msgpack_rpc_free_string(value.data.string); - break; - - case kObjectTypeArray: - msgpack_rpc_free_array(value.data.array); - break; - - case kObjectTypeDictionary: - msgpack_rpc_free_dictionary(value.data.dictionary); - break; - - default: - abort(); - } -} - -void msgpack_rpc_free_stringarray(StringArray value) { - for (uint32_t i = 0; i < value.size; i++) { - msgpack_rpc_free_string(value.items[i]); - } - - free(value.items); -} - -void msgpack_rpc_free_array(Array value) -{ - for (uint32_t i = 0; i < value.size; i++) { - msgpack_rpc_free_object(value.items[i]); - } - - free(value.items); -} - -void msgpack_rpc_free_dictionary(Dictionary value) -{ - for (uint32_t i = 0; i < value.size; i++) { - msgpack_rpc_free_string(value.items[i].key); - msgpack_rpc_free_object(value.items[i].value); - } - - free(value.items); -} - -static bool msgpack_rpc_to_uint16_t(msgpack_object *obj, uint16_t *arg) -{ - *arg = obj->via.u64; - return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER; -} - diff --git a/src/os/msgpack_rpc.h b/src/os/msgpack_rpc.h deleted file mode 100644 index 7f754bfca1..0000000000 --- a/src/os/msgpack_rpc.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef NEOVIM_OS_MSGPACK_RPC_H -#define NEOVIM_OS_MSGPACK_RPC_H - -#include -#include - -#include - -#include "api/defs.h" - -/// Validates the basic structure of the msgpack-rpc call and fills `res` -/// with the basic response structure. -/// -/// @param req The parsed request object -/// @param res A packer that contains the response -void msgpack_rpc_call(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 -/// to C types, and converting the return value back to msgpack types. -/// The implementation is generated at compile time with metadata extracted -/// from the api/*.h headers, -/// -/// @param req The parsed request object -/// @param res A packer that contains the response -void msgpack_rpc_dispatch(msgpack_object *req, msgpack_packer *res); - -/// 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); - -/// Functions for validating and converting from msgpack types to C types. -/// These are used by `msgpack_rpc_dispatch` to validate and convert each -/// argument. -/// -/// @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_bool(msgpack_object *obj, bool *arg); -bool msgpack_rpc_to_int64_t(msgpack_object *obj, int64_t *arg); -bool msgpack_rpc_to_double(msgpack_object *obj, double *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_array(msgpack_object *obj, Array *arg); -bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg); - -/// Functions for converting from C types to msgpack types. -/// These are used by `msgpack_rpc_dispatch` to convert return values -/// from the API -/// -/// @param result A pointer to the result -/// @param res A packer that contains the response -void msgpack_rpc_from_bool(bool result, msgpack_packer *res); -void msgpack_rpc_from_int64_t(int64_t result, msgpack_packer *res); -void msgpack_rpc_from_double(double 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_array(Array result, msgpack_packer *res); -void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); - -/// Helpers for initializing types that may be freed later -#define msgpack_rpc_init_bool -#define msgpack_rpc_init_int64_t -#define msgpack_rpc_init_double -#define msgpack_rpc_init_position -#define msgpack_rpc_init_string -#define msgpack_rpc_init_buffer -#define msgpack_rpc_init_window -#define msgpack_rpc_init_tabpage -#define msgpack_rpc_init_object = {.type = kObjectTypeNil} -#define msgpack_rpc_init_stringarray = {.items = NULL, .size = 0} -#define msgpack_rpc_init_array = {.items = NULL, .size = 0} -#define msgpack_rpc_init_dictionary = {.items = NULL, .size = 0} - -/// Helpers for freeing arguments/return value -/// -/// @param value The value to be freed -#define msgpack_rpc_free_bool(value) -#define msgpack_rpc_free_int64_t(value) -#define msgpack_rpc_free_double(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) -#define msgpack_rpc_free_buffer(value) -#define msgpack_rpc_free_window(value) -#define msgpack_rpc_free_tabpage(value) -void msgpack_rpc_free_object(Object value); -void msgpack_rpc_free_stringarray(StringArray value); -void msgpack_rpc_free_array(Array value); -void msgpack_rpc_free_dictionary(Dictionary value); - - -#endif // NEOVIM_OS_MSGPACK_RPC_H - diff --git a/src/os/os.h b/src/os/os.h deleted file mode 100644 index b30872f06d..0000000000 --- a/src/os/os.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef NEOVIM_OS_OS_H -#define NEOVIM_OS_OS_H -#include - -#include "vim.h" - -/// Change to the given directory. -/// -/// @return `0` on success, a libuv error code on failure. -int os_chdir(const char *path); - -/// Get the name of current directory. -/// -/// @param buf Buffer to store the directory name. -/// @param len Length of `buf`. -/// @return `OK` for success, `FAIL` for failure. -int os_dirname(char_u *buf, size_t len); - -/// Check if the given path is a directory or not. -/// -/// @return `true` if `fname` is a directory. -bool os_isdir(const char_u *name); - -/// Check if the given path represents an executable file. -/// -/// @return `true` if `name` is executable and -/// - can be found in $PATH, -/// - is relative to current dir or -/// - is absolute. -/// -/// @return `false` otherwise. -bool os_can_exe(const char_u *name); - -/// Get the file permissions for a given file. -/// -/// @return `-1` when `name` doesn't exist. -int32_t os_getperm(const char_u *name); - -/// Set the permission of a file. -/// -/// @return `OK` for success, `FAIL` for failure. -int os_setperm(const char_u *name, int perm); - -/// Check if a file exists. -/// -/// @return `true` if `name` exists. -bool os_file_exists(const char_u *name); - -/// Check if a file is readonly. -/// -/// @return `true` if `name` is readonly. -bool os_file_is_readonly(const char *name); - -/// Check if a file is writable. -/// -/// @return `0` if `name` is not writable, -/// @return `1` if `name` is writable, -/// @return `2` for a directory which we have rights to write into. -int os_file_is_writable(const char *name); - -/// Get the size of a file in bytes. -/// -/// @param[out] size pointer to an off_t to put the size into. -/// @return `true` for success, `false` for failure. -bool os_get_file_size(const char *name, off_t *size); - -/// Rename a file or directory. -/// -/// @return `OK` for success, `FAIL` for failure. -int os_rename(const char_u *path, const char_u *new_path); - -/// Make a directory. -/// -/// @return `0` for success, non-zero for failure. -int os_mkdir(const char *path, int32_t mode); - -/// Remove a directory. -/// -/// @return `0` for success, non-zero for failure. -int os_rmdir(const char *path); - -/// Remove a file. -/// -/// @return `0` for success, non-zero for failure. -int os_remove(const char *path); - -/// Get the total system physical memory in KiB. -uint64_t os_get_total_mem_kib(void); -const char *os_getenv(const char *name); -int os_setenv(const char *name, const char *value, int overwrite); -char *os_getenvname_at_index(size_t index); - -/// Get the process ID of the Neovim process. -/// -/// @return the process ID. -int64_t os_get_pid(void); - -/// Get the hostname of the machine runing Neovim. -/// -/// @param hostname Buffer to store the hostname. -/// @param len Length of `hostname`. -void os_get_hostname(char *hostname, size_t len); - -int os_get_usernames(garray_T *usernames); -int os_get_user_name(char *s, size_t len); -int os_get_uname(uid_t uid, char *s, size_t len); -char *os_get_user_directory(const char *name); - -/// Get stat information for a file. -/// -/// @return OK on success, FAIL if an failure occured. -int os_stat(const char_u *name, uv_stat_t *statbuf); - -/// Struct which encapsulates stat information. -typedef struct { - // TODO(stefan991): make stat private - uv_stat_t stat; -} FileInfo; - -/// Get the file information for a given path -/// -/// @param file_descriptor File descriptor of the file. -/// @param[out] file_info Pointer to a FileInfo to put the information in. -/// @return `true` on sucess, `false` for failure. -bool os_get_file_info(const char *path, FileInfo *file_info); - -/// Get the file information for a given path without following links -/// -/// @param path Path to the file. -/// @param[out] file_info Pointer to a FileInfo to put the information in. -/// @return `true` on sucess, `false` for failure. -bool os_get_file_info_link(const char *path, FileInfo *file_info); - -/// Get the file information for a given file descriptor -/// -/// @param file_descriptor File descriptor of the file. -/// @param[out] file_info Pointer to a FileInfo to put the information in. -/// @return `true` on sucess, `false` for failure. -bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info); - -/// Compare the inodes of two FileInfos -/// -/// @return `true` if the two FileInfos represent the same file. -bool os_file_info_id_equal(FileInfo *file_info_1, FileInfo *file_info_2); - -#endif // NEOVIM_OS_OS_H diff --git a/src/os/rstream.c b/src/os/rstream.c deleted file mode 100644 index e14075c8db..0000000000 --- a/src/os/rstream.c +++ /dev/null @@ -1,297 +0,0 @@ -#include -#include -#include - -#include - -#include "os/uv_helpers.h" -#include "os/rstream_defs.h" -#include "os/rstream.h" -#include "os/event_defs.h" -#include "os/event.h" -#include "vim.h" -#include "memory.h" - -struct rstream { - uv_buf_t uvbuf; - void *data; - char *buffer; - uv_stream_t *stream; - uv_idle_t *fread_idle; - uv_handle_type file_type; - uv_file fd; - rstream_cb cb; - size_t buffer_size, rpos, wpos, fpos; - bool reading, free_handle, async; -}; - -// Callbacks used by libuv -static void alloc_cb(uv_handle_t *, size_t, uv_buf_t *); -static void read_cb(uv_stream_t *, ssize_t, const uv_buf_t *); -static void fread_idle_cb(uv_idle_t *); -static void close_cb(uv_handle_t *handle); -static void emit_read_event(RStream *rstream, bool eof); - -RStream * rstream_new(rstream_cb cb, - uint32_t buffer_size, - void *data, - bool async) -{ - RStream *rv = xmalloc(sizeof(RStream)); - rv->buffer = xmalloc(buffer_size); - rv->buffer_size = buffer_size; - rv->data = data; - rv->async = async; - rv->cb = cb; - rv->rpos = rv->wpos = rv->fpos = 0; - rv->stream = NULL; - rv->fread_idle = NULL; - rv->free_handle = false; - rv->file_type = UV_UNKNOWN_HANDLE; - - return rv; -} - -void rstream_free(RStream *rstream) -{ - if (rstream->free_handle) { - if (rstream->fread_idle != NULL) { - uv_close((uv_handle_t *)rstream->fread_idle, close_cb); - } else { - uv_close((uv_handle_t *)rstream->stream, close_cb); - } - } - - free(rstream->buffer); - free(rstream); -} - -void rstream_set_stream(RStream *rstream, uv_stream_t *stream) -{ - handle_set_rstream((uv_handle_t *)stream, rstream); - rstream->stream = stream; -} - -void rstream_set_file(RStream *rstream, uv_file file) -{ - rstream->file_type = uv_guess_handle(file); - - if (rstream->free_handle) { - // If this is the second time we're calling this function, free the - // previously allocated memory - if (rstream->fread_idle != NULL) { - uv_close((uv_handle_t *)rstream->fread_idle, close_cb); - } else { - uv_close((uv_handle_t *)rstream->stream, close_cb); - } - } - - if (rstream->file_type == UV_FILE) { - // Non-blocking file reads are simulated with a idle handle that reads - // in chunks of rstream->buffer_size, giving time for other events to - // be processed between reads. - rstream->fread_idle = xmalloc(sizeof(uv_idle_t)); - uv_idle_init(uv_default_loop(), rstream->fread_idle); - rstream->fread_idle->data = NULL; - handle_set_rstream((uv_handle_t *)rstream->fread_idle, rstream); - } else { - // Only pipes are supported for now - assert(rstream->file_type == UV_NAMED_PIPE - || rstream->file_type == UV_TTY); - rstream->stream = xmalloc(sizeof(uv_pipe_t)); - uv_pipe_init(uv_default_loop(), (uv_pipe_t *)rstream->stream, 0); - uv_pipe_open((uv_pipe_t *)rstream->stream, file); - rstream->stream->data = NULL; - handle_set_rstream((uv_handle_t *)rstream->stream, rstream); - } - - rstream->fd = file; - rstream->free_handle = true; -} - -bool rstream_is_regular_file(RStream *rstream) -{ - return rstream->file_type == UV_FILE; -} - -void rstream_start(RStream *rstream) -{ - if (rstream->file_type == UV_FILE) { - uv_idle_start(rstream->fread_id