aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
commit9be89f131f87608f224f0ee06d199fcd09d32176 (patch)
tree11022dcfa9e08cb4ac5581b16734196128688d48 /src/nvim/os
parentff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff)
parent88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff)
downloadrneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'src/nvim/os')
-rw-r--r--src/nvim/os/env.c59
-rw-r--r--src/nvim/os/fileio.c314
-rw-r--r--src/nvim/os/fileio.h6
-rw-r--r--src/nvim/os/fileio_defs.h24
-rw-r--r--src/nvim/os/fs.c21
-rw-r--r--src/nvim/os/input.c215
-rw-r--r--src/nvim/os/proc.c (renamed from src/nvim/os/process.c)16
-rw-r--r--src/nvim/os/proc.h (renamed from src/nvim/os/process.h)2
-rw-r--r--src/nvim/os/pty_conpty_win.c4
-rw-r--r--src/nvim/os/pty_proc.h7
-rw-r--r--src/nvim/os/pty_proc_unix.c (renamed from src/nvim/os/pty_process_unix.c)49
-rw-r--r--src/nvim/os/pty_proc_unix.h (renamed from src/nvim/os/pty_process_unix.h)8
-rw-r--r--src/nvim/os/pty_proc_win.c (renamed from src/nvim/os/pty_process_win.c)96
-rw-r--r--src/nvim/os/pty_proc_win.h (renamed from src/nvim/os/pty_process_win.h)12
-rw-r--r--src/nvim/os/pty_process.h7
-rw-r--r--src/nvim/os/shell.c163
-rw-r--r--src/nvim/os/stdpaths.c20
17 files changed, 530 insertions, 493 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 5a79004c41..ccf6c9554a 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -63,13 +63,13 @@ const char *os_getenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
char *e = NULL;
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return NULL;
}
int r = 0;
if (map_has(cstr_t, &envmap, name)
&& !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) {
- if (e[0] != '\0') {
+ if (e[0] != NUL) {
// Found non-empty cached env var.
// NOTE: This risks incoherence if an in-process library changes the
// environment without going through our os_setenv() wrapper. If
@@ -85,11 +85,11 @@ const char *os_getenv(const char *name)
if (r == UV_ENOBUFS) {
e = xmalloc(size);
r = uv_os_getenv(name, e, &size);
- if (r != 0 || size == 0 || e[0] == '\0') {
+ if (r != 0 || size == 0 || e[0] == NUL) {
XFREE_CLEAR(e);
goto end;
}
- } else if (r != 0 || size == 0 || buf[0] == '\0') {
+ } else if (r != 0 || size == 0 || buf[0] == NUL) {
e = NULL;
goto end;
} else {
@@ -110,7 +110,7 @@ end:
bool os_env_exists(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return false;
}
// Use a tiny buffer because we don't care about the value: if uv_os_getenv()
@@ -134,14 +134,14 @@ bool os_env_exists(const char *name)
int os_setenv(const char *name, const char *value, int overwrite)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
#ifdef MSWIN
if (!overwrite && os_getenv(name) != NULL) {
return 0;
}
- if (value[0] == '\0') {
+ if (value[0] == NUL) {
// Windows (Vim-compat): Empty string undefines the env var.
return os_unsetenv(name);
}
@@ -174,7 +174,7 @@ int os_setenv(const char *name, const char *value, int overwrite)
int os_unsetenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
pmap_del2(&envmap, name);
@@ -344,7 +344,7 @@ char *os_getenvname_at_index(size_t index)
#endif
}
-/// Get the process ID of the Neovim process.
+/// Get the process ID of the Nvim process.
///
/// @return the process ID.
int64_t os_get_pid(void)
@@ -366,7 +366,7 @@ void os_get_hostname(char *hostname, size_t size)
struct utsname vutsname;
if (uname(&vutsname) < 0) {
- *hostname = '\0';
+ *hostname = NUL;
} else {
xstrlcpy(hostname, vutsname.nodename, size);
}
@@ -374,12 +374,12 @@ void os_get_hostname(char *hostname, size_t size)
wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1];
DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]);
if (GetComputerNameW(host_utf16, &host_wsize) == 0) {
- *hostname = '\0';
+ *hostname = NUL;
DWORD err = GetLastError();
semsg("GetComputerNameW failed: %d", err);
return;
}
- host_utf16[host_wsize] = '\0';
+ host_utf16[host_wsize] = NUL;
char *host_utf8;
int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8);
@@ -391,27 +391,38 @@ void os_get_hostname(char *hostname, size_t size)
xfree(host_utf8);
#else
emsg("os_get_hostname failed: missing uname()");
- *hostname = '\0';
+ *hostname = NUL;
#endif
}
-/// To get the "real" home directory:
+/// The "real" home directory as determined by `init_homedir`.
+static char *homedir = NULL;
+static char *os_uv_homedir(void);
+
+/// Gets the "real", resolved user home directory as determined by `init_homedir`.
+const char *os_homedir(void)
+{
+ if (!homedir) {
+ emsg("os_homedir failed: homedir not initialized");
+ return NULL;
+ }
+ return homedir;
+}
+
+/// Sets `homedir` to the "real", resolved user home directory, as follows:
/// 1. get value of $HOME
/// 2. if $HOME is not set, try the following
/// For Windows:
/// 1. assemble homedir using HOMEDRIVE and HOMEPATH
-/// 2. try os_homedir()
+/// 2. try os_uv_homedir()
/// 3. resolve a direct reference to another system variable
/// 4. guess C drive
/// For Unix:
-/// 1. try os_homedir()
+/// 1. try os_uv_homedir()
/// 2. go to that directory
/// This also works with mounts and links.
/// Don't do this for Windows, it will change the "current dir" for a drive.
/// 3. fall back to current working directory as a last resort
-static char *homedir = NULL;
-static char *os_homedir(void);
-
void init_homedir(void)
{
// In case we are called a second time.
@@ -440,7 +451,7 @@ void init_homedir(void)
}
}
if (var == NULL) {
- var = os_homedir();
+ var = os_uv_homedir();
}
// Weird but true: $HOME may contain an indirect reference to another
@@ -471,7 +482,7 @@ void init_homedir(void)
#ifdef UNIX
if (var == NULL) {
- var = os_homedir();
+ var = os_uv_homedir();
}
// Get the actual path. This resolves links.
@@ -492,7 +503,7 @@ void init_homedir(void)
static char homedir_buf[MAXPATHL];
-static char *os_homedir(void)
+static char *os_uv_homedir(void)
{
homedir_buf[0] = NUL;
size_t homedir_size = MAXPATHL;
@@ -885,9 +896,9 @@ void vim_get_prefix_from_exepath(char *exe_name)
// but c_grammar.lua does not recognize it (yet).
xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name));
char *path_end = path_tail_with_sep(exe_name);
- *path_end = '\0'; // remove the trailing "nvim.exe"
+ *path_end = NUL; // remove the trailing "nvim.exe"
path_end = path_tail(exe_name);
- *path_end = '\0'; // remove the trailing "bin/"
+ *path_end = NUL; // remove the trailing "bin/"
}
/// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME,
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index da6fb13768..1981d0dfd4 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -21,8 +21,6 @@
#include "nvim/os/fileio.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#ifdef HAVE_SYS_UIO_H
@@ -120,12 +118,10 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags)
assert(!ret_fp->wr || !ret_fp->non_blocking);
ret_fp->fd = fd;
ret_fp->eof = false;
- ret_fp->rv = rbuffer_new(kRWBufferSize);
- ret_fp->_error = 0;
- if (ret_fp->wr) {
- ret_fp->rv->data = ret_fp;
- ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
- }
+ ret_fp->buffer = alloc_block();
+ ret_fp->read_pos = ret_fp->buffer;
+ ret_fp->write_pos = ret_fp->buffer;
+ ret_fp->bytes_read = 0;
return 0;
}
@@ -140,6 +136,19 @@ int file_open_stdin(FileDescriptor *fp)
return error;
}
+/// opens buffer for reading
+void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len)
+{
+ ret_fp->wr = false;
+ ret_fp->non_blocking = false;
+ ret_fp->fd = -1;
+ ret_fp->eof = true;
+ ret_fp->buffer = NULL; // we don't take ownership
+ ret_fp->read_pos = data;
+ ret_fp->write_pos = data + len;
+ ret_fp->bytes_read = 0;
+}
+
/// Close file and free its buffer
///
/// @param[in,out] fp File to close.
@@ -149,32 +158,19 @@ int file_open_stdin(FileDescriptor *fp)
int file_close(FileDescriptor *const fp, const bool do_fsync)
FUNC_ATTR_NONNULL_ALL
{
+ if (fp->fd < 0) {
+ return 0;
+ }
+
const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
const int close_error = os_close(fp->fd);
- rbuffer_free(fp->rv);
+ free_block(fp->buffer);
if (close_error != 0) {
return close_error;
}
return flush_error;
}
-/// Flush file modifications to disk
-///
-/// @param[in,out] fp File to work with.
-///
-/// @return 0 or error code.
-int file_flush(FileDescriptor *const fp)
- FUNC_ATTR_NONNULL_ALL
-{
- if (!fp->wr) {
- return 0;
- }
- file_rb_write_full_cb(fp->rv, fp);
- const int error = fp->_error;
- fp->_error = 0;
- return error;
-}
-
/// Flush file modifications to disk and run fsync()
///
/// @param[in,out] fp File to work with.
@@ -200,36 +196,29 @@ int file_fsync(FileDescriptor *const fp)
return 0;
}
-/// Buffer used for writing
-///
-/// Like IObuff, but allows file_\* callers not to care about spoiling it.
-static char writebuf[kRWBufferSize];
-
-/// Function run when RBuffer is full when writing to a file
-///
-/// Actually does writing to the file, may also be invoked directly.
+/// Flush file modifications to disk
///
-/// @param[in,out] rv RBuffer instance used.
/// @param[in,out] fp File to work with.
-static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in)
+///
+/// @return 0 or error code.
+int file_flush(FileDescriptor *fp)
FUNC_ATTR_NONNULL_ALL
{
- FileDescriptor *const fp = fp_in;
- assert(fp->wr);
- assert(rv->data == (void *)fp);
- if (rbuffer_size(rv) == 0) {
- return;
+ if (!fp->wr) {
+ return 0;
}
- const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
- const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes,
+
+ ptrdiff_t to_write = fp->write_pos - fp->read_pos;
+ if (to_write == 0) {
+ return 0;
+ }
+ const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write,
fp->non_blocking);
- if (wres != (ptrdiff_t)read_bytes) {
- if (wres >= 0) {
- fp->_error = UV_EIO;
- } else {
- fp->_error = (int)wres;
- }
+ fp->read_pos = fp->write_pos = fp->buffer;
+ if (wres != to_write) {
+ return (wres >= 0) ? UV_EIO : (int)wres;
}
+ return 0;
}
/// Read from file
@@ -244,79 +233,98 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(!fp->wr);
- char *buf = ret_buf;
- size_t read_remaining = size;
- RBuffer *const rv = fp->rv;
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ memcpy(ret_buf, fp->read_pos, from_buffer);
+
+ char *buf = ret_buf + from_buffer;
+ size_t read_remaining = size - from_buffer;
+ if (!read_remaining) {
+ fp->bytes_read += from_buffer;
+ fp->read_pos += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ // at this point, we have consumed all of an existing buffer. restart from the beginning
+ fp->read_pos = fp->write_pos = fp->buffer;
+
+#ifdef HAVE_READV
bool called_read = false;
while (read_remaining) {
- const size_t rv_size = rbuffer_size(rv);
- if (rv_size > 0) {
- const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining));
- buf += rsize;
- read_remaining -= rsize;
- }
- if (fp->eof
- // Allow only at most one os_read[v] call.
- || (called_read && fp->non_blocking)) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- if (read_remaining) {
- assert(rbuffer_size(rv) == 0);
- rbuffer_reset(rv);
-#ifdef HAVE_READV
- // If there is readv() syscall, then take an opportunity to populate
- // both target buffer and RBuffer at once, …
- size_t write_count;
- struct iovec iov[] = {
- { .iov_base = buf, .iov_len = read_remaining },
- { .iov_base = rbuffer_write_ptr(rv, &write_count),
- .iov_len = kRWBufferSize },
- };
- assert(write_count == kRWBufferSize);
- const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
- ARRAY_SIZE(iov), fp->non_blocking);
- if (r_ret > 0) {
- if (r_ret > (ptrdiff_t)read_remaining) {
- rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining));
- read_remaining = 0;
- } else {
- buf += (size_t)r_ret;
- read_remaining -= (size_t)r_ret;
- }
- } else if (r_ret < 0) {
- return r_ret;
- }
-#else
- if (read_remaining >= kRWBufferSize) {
- // …otherwise leave RBuffer empty and populate only target buffer,
- // because filtering information through rbuffer will be more syscalls.
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
- fp->non_blocking);
- if (r_ret >= 0) {
- read_remaining -= (size_t)r_ret;
- return (ptrdiff_t)(size - read_remaining);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ // If there is readv() syscall, then take an opportunity to populate
+ // both target buffer and RBuffer at once, …
+ struct iovec iov[] = {
+ { .iov_base = buf, .iov_len = read_remaining },
+ { .iov_base = fp->write_pos,
+ .iov_len = ARENA_BLOCK_SIZE },
+ };
+ const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
+ ARRAY_SIZE(iov), fp->non_blocking);
+ if (r_ret > 0) {
+ if (r_ret > (ptrdiff_t)read_remaining) {
+ fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining);
+ read_remaining = 0;
} else {
- size_t write_count;
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
- rbuffer_write_ptr(rv, &write_count),
- kRWBufferSize, fp->non_blocking);
- assert(write_count == kRWBufferSize);
- if (r_ret > 0) {
- rbuffer_produced(rv, (size_t)r_ret);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ buf += r_ret;
+ read_remaining -= (size_t)r_ret;
}
-#endif
- called_read = true;
+ } else if (r_ret < 0) {
+ return r_ret;
}
+ called_read = true;
}
+#else
+ if (fp->eof) {
+ // already eof, cannot read more
+ } else if (read_remaining >= ARENA_BLOCK_SIZE) {
+ // …otherwise leave fp->buffer empty and populate only target buffer,
+ // because filtering information through rbuffer will be more syscalls.
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
+ fp->non_blocking);
+ if (r_ret >= 0) {
+ read_remaining -= (size_t)r_ret;
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ } else {
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
+ fp->write_pos,
+ ARENA_BLOCK_SIZE, fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else {
+ fp->write_pos += r_ret;
+ size_t to_copy = MIN((size_t)r_ret, read_remaining);
+ memcpy(buf, fp->read_pos, to_copy);
+ fp->read_pos += to_copy;
+ read_remaining -= to_copy;
+ }
+ }
+#endif
+
+ fp->bytes_read += (size - read_remaining);
return (ptrdiff_t)(size - read_remaining);
}
+/// try to read already buffered data in place
+///
+/// @return NULL if enough data is not available
+/// valid pointer to chunk of "size". pointer becomes invalid in the next "file_read" call!
+char *file_try_read_buffered(FileDescriptor *const fp, const size_t size)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if ((size_t)(fp->write_pos - fp->read_pos) >= size) {
+ char *ret = fp->read_pos;
+ fp->read_pos += size;
+ fp->bytes_read += size;
+ return ret;
+ }
+ return NULL;
+}
+
/// Write to a file
///
/// @param[in] fd File descriptor to write to.
@@ -328,51 +336,67 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
assert(fp->wr);
- const size_t written = rbuffer_write(fp->rv, buf, size);
- if (fp->_error != 0) {
- const int error = fp->_error;
- fp->_error = 0;
- return error;
- } else if (written != size) {
- return UV_EIO;
+ // includes the trivial case of size==0
+ if (size < file_space(fp)) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
}
- return (ptrdiff_t)written;
-}
-/// Buffer used for skipping. Its contents is undefined and should never be
-/// used.
-static char skipbuf[kRWBufferSize];
+ // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf
+ int status = file_flush(fp);
+ if (status < 0) {
+ return status;
+ }
+
+ if (size < ARENA_BLOCK_SIZE) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
+ }
+
+ const ptrdiff_t wres = os_write(fp->fd, buf, size,
+ fp->non_blocking);
+ return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres;
+}
/// Skip some bytes
///
/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply
-/// reads to a buffer and discards the result.
+/// reads to the buffer and discards the result.
ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
FUNC_ATTR_NONNULL_ALL
{
assert(!fp->wr);
- size_t read_bytes = 0;
- do {
- const ptrdiff_t new_read_bytes =
- file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
- if (new_read_bytes < 0) {
- return new_read_bytes;
- } else if (new_read_bytes == 0) {
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ size_t skip_remaining = size - from_buffer;
+ if (skip_remaining == 0) {
+ fp->read_pos += from_buffer;
+ fp->bytes_read += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ fp->read_pos = fp->write_pos = fp->buffer;
+ bool called_read = false;
+ while (skip_remaining > 0) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- read_bytes += (size_t)new_read_bytes;
- } while (read_bytes < size && !file_eof(fp));
-
- return (ptrdiff_t)read_bytes;
-}
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE,
+ fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else if ((size_t)r_ret > skip_remaining) {
+ fp->read_pos = fp->buffer + skip_remaining;
+ fp->write_pos = fp->buffer + r_ret;
+ fp->bytes_read += size;
+ return (ptrdiff_t)size;
+ }
+ skip_remaining -= (size_t)r_ret;
+ called_read = true;
+ }
-/// Print error which occurs when failing to write msgpack data
-///
-/// @param[in] error Error code of the error to print.
-///
-/// @return -1 (error return for msgpack_packer callbacks).
-int msgpack_file_write_error(const int error)
-{
- semsg(_("E5420: Failed to write to file: %s"), os_strerror(error));
- return -1;
+ fp->bytes_read += size - skip_remaining;
+ return (ptrdiff_t)(size - skip_remaining);
}
diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h
index e8fd2209db..523f9657a4 100644
--- a/src/nvim/os/fileio.h
+++ b/src/nvim/os/fileio.h
@@ -2,6 +2,7 @@
#include <stddef.h> // IWYU pragma: keep
+#include "nvim/memory_defs.h"
#include "nvim/os/fileio_defs.h" // IWYU pragma: keep
/// file_open() flags
@@ -32,6 +33,11 @@ enum {
kRWBufferSize = 1024,
};
+static inline size_t file_space(FileDescriptor *fp)
+{
+ return (size_t)((fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos);
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fileio.h.generated.h"
#endif
diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h
index 3dc8c7b22a..47f0629ccf 100644
--- a/src/nvim/os/fileio_defs.h
+++ b/src/nvim/os/fileio_defs.h
@@ -1,22 +1,23 @@
#pragma once
#include <stdbool.h>
-
-#include "nvim/func_attr.h"
-#include "nvim/rbuffer_defs.h"
+#include <stdint.h>
/// Structure used to read from/write to file
typedef struct {
- int fd; ///< File descriptor.
- int _error; ///< Error code for use with RBuffer callbacks or zero.
- RBuffer *rv; ///< Read or write buffer.
+ int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer)
+ char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated
+ char *read_pos; ///< read position in buffer
+ char *write_pos; ///< write position in buffer
bool wr; ///< True if file is in write mode.
bool eof; ///< True if end of file was encountered.
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
+ uint64_t bytes_read; ///< total bytes read so far
} FileDescriptor;
-static inline bool file_eof(const FileDescriptor *fp)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fileio_defs.h.inline.generated.h"
+#endif
/// Check whether end of file was encountered
///
@@ -25,19 +26,18 @@ static inline bool file_eof(const FileDescriptor *fp)
/// @return true if it was, false if it was not or read operation was never
/// performed.
static inline bool file_eof(const FileDescriptor *const fp)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return fp->eof && rbuffer_size(fp->rv) == 0;
+ return fp->eof && fp->read_pos == fp->write_pos;
}
-static inline int file_fd(const FileDescriptor *fp)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
-
/// Return the file descriptor associated with the FileDescriptor structure
///
/// @param[in] fp File to check.
///
/// @return File descriptor.
static inline int file_fd(const FileDescriptor *const fp)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
return fp->fd;
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 19bdf30311..d0da37b8e7 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -35,6 +35,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
+#include "nvim/errors.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/log.h"
@@ -301,7 +302,7 @@ static bool is_executable_ext(const char *name, char **abspath)
char *nameext = strrchr(name, '.');
size_t nameext_len = nameext ? strlen(nameext) : 0;
xstrlcpy(os_buf, name, sizeof(os_buf));
- char *buf_end = xstrchrnul(os_buf, '\0');
+ char *buf_end = xstrchrnul(os_buf, NUL);
const char *pathext = os_getenv("PATHEXT");
if (!pathext) {
pathext = ".com;.exe;.bat;.cmd";
@@ -309,7 +310,7 @@ static bool is_executable_ext(const char *name, char **abspath)
const char *ext = pathext;
while (*ext) {
// If $PATHEXT itself contains dot:
- if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) {
+ if (ext[0] == '.' && (ext[1] == NUL || ext[1] == ENV_SEPCHAR)) {
if (is_executable(name, abspath)) {
return true;
}
@@ -355,10 +356,16 @@ static bool is_executable_in_path(const char *name, char **abspath)
}
#ifdef MSWIN
- // Prepend ".;" to $PATH.
- size_t pathlen = strlen(path_env);
- char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2);
- memcpy(path + 2, path_env, pathlen);
+ char *path = NULL;
+ if (!os_env_exists("NoDefaultCurrentDirectoryInExePath")) {
+ // Prepend ".;" to $PATH.
+ size_t pathlen = strlen(path_env);
+ path = xmallocz(pathlen + 2);
+ memcpy(path, "." ENV_SEPSTR, 2);
+ memcpy(path + 2, path_env, pathlen);
+ } else {
+ path = xstrdup(path_env);
+ }
#else
char *path = xstrdup(path_env);
#endif
@@ -435,7 +442,7 @@ FILE *os_fopen(const char *path, const char *flags)
assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2);
int iflags = 0;
// Per table in fopen(3) manpage.
- if (flags[1] == '\0' || flags[1] == 'b') {
+ if (flags[1] == NUL || flags[1] == 'b') {
switch (flags[0]) {
case 'r':
iflags = O_RDONLY;
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 60b5b48745..7c5293a8b8 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -27,22 +27,17 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/time.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state.h"
#include "nvim/state_defs.h"
#define READ_BUFFER_SIZE 0xfff
-#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
+#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
-typedef enum {
- kInputNone,
- kInputAvail,
- kInputEof,
-} InbufPollResult;
+static RStream read_stream = { .s.closed = true }; // Input before UI starts.
+static char input_buffer[INPUT_BUFFER_SIZE];
+static char *input_read_pos = input_buffer;
+static char *input_write_pos = input_buffer;
-static Stream read_stream = { .closed = true }; // Input before UI starts.
-static RBuffer *input_buffer = NULL;
static bool input_eof = false;
static bool blocking = false;
static int cursorhold_time = 0; ///< time waiting for CursorHold event
@@ -52,39 +47,27 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte
# include "os/input.c.generated.h"
#endif
-void input_init(void)
-{
- input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
-}
-
void input_start(void)
{
- if (!read_stream.closed) {
+ if (!read_stream.s.closed) {
return;
}
used_stdin = true;
- rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE);
+ rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO);
rstream_start(&read_stream, input_read_cb, NULL);
}
void input_stop(void)
{
- if (read_stream.closed) {
+ if (read_stream.s.closed) {
return;
}
rstream_stop(&read_stream);
- stream_close(&read_stream, NULL, NULL);
+ rstream_may_close(&read_stream);
}
-#ifdef EXITFREE
-void input_free_all_mem(void)
-{
- rbuffer_free(input_buffer);
-}
-#endif
-
static void cursorhold_event(void **argv)
{
event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
@@ -95,54 +78,76 @@ static void cursorhold_event(void **argv)
static void create_cursorhold_event(bool events_enabled)
{
// If events are enabled and the queue has any items, this function should not
- // have been called (inbuf_poll would return kInputAvail).
+ // have been called (`inbuf_poll` would return `kTrue`).
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
// `state_check` callback for the states where it can be triggered.
assert(!events_enabled || multiqueue_empty(main_loop.events));
multiqueue_put(main_loop.events, cursorhold_event, NULL);
}
-static void restart_cursorhold_wait(int tb_change_cnt)
+static void reset_cursorhold_wait(int tb_change_cnt)
{
cursorhold_time = 0;
cursorhold_tb_change_cnt = tb_change_cnt;
}
-/// Low level input function
+/// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`).
///
-/// Wait until either the input buffer is non-empty or, if `events` is not NULL
-/// until `events` is non-empty.
-int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
+/// - Consumes available input received from the OS.
+/// - Consumes pending events.
+/// - Manages CursorHold events.
+/// - Handles EOF conditions.
+///
+/// Originally based on the Vim `mch_inchar` function.
+///
+/// @param buf Buffer to store consumed input.
+/// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading.
+/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
+/// @param tb_change_cnt Used to detect when typeahead changes.
+/// @param events (optional) Events to process.
+/// @return Bytes read into buf, or 0 if no input was read
+int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
{
// This check is needed so that feeding typeahead from RPC can prevent CursorHold.
if (tb_change_cnt != cursorhold_tb_change_cnt) {
- restart_cursorhold_wait(tb_change_cnt);
+ reset_cursorhold_wait(tb_change_cnt);
}
- if (maxlen && rbuffer_size(input_buffer)) {
- restart_cursorhold_wait(tb_change_cnt);
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
- }
+#define TRY_READ() \
+ do { \
+ if (maxlen && input_available()) { \
+ reset_cursorhold_wait(tb_change_cnt); \
+ assert(maxlen >= 0); \
+ size_t to_read = MIN((size_t)maxlen, input_available()); \
+ memcpy(buf, input_read_pos, to_read); \
+ input_read_pos += to_read; \
+ /* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \
+ assert(to_read <= INT_MAX); \
+ return (int)to_read; \
+ } \
+ } while (0)
+
+ TRY_READ();
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) {
ctrl_c_interrupts = false;
}
- InbufPollResult result;
+ TriState result; ///< inbuf_poll result.
if (ms >= 0) {
- if ((result = inbuf_poll(ms, events)) == kInputNone) {
+ if ((result = inbuf_poll(ms, events)) == kFalse) {
return 0;
}
} else {
uint64_t wait_start = os_hrtime();
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
- if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
- if (read_stream.closed && silent_mode) {
+ if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) {
+ if (read_stream.s.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
- restart_cursorhold_wait(tb_change_cnt);
+ reset_cursorhold_wait(tb_change_cnt);
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
create_cursorhold_event(events == main_loop.events);
} else {
@@ -161,29 +166,26 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return 0;
}
- if (maxlen && rbuffer_size(input_buffer)) {
- restart_cursorhold_wait(tb_change_cnt);
- // Safe to convert rbuffer_read to int, it will never overflow since we use
- // relatively small buffers.
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
- }
+ TRY_READ();
// If there are events, return the keys directly
if (maxlen && pending_events(events)) {
return push_event_key(buf, maxlen);
}
- if (result == kInputEof) {
+ if (result == kNone) {
read_error_exit();
}
return 0;
+
+#undef TRY_READ
}
// Check if a character is available for reading
bool os_char_avail(void)
{
- return inbuf_poll(0, NULL) == kInputAvail;
+ return inbuf_poll(0, NULL) == kTrue;
}
/// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed.
@@ -247,11 +249,28 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY;
}
-void input_enqueue_raw(String keys)
+size_t input_available(void)
{
- if (keys.size > 0) {
- rbuffer_write(input_buffer, keys.data, keys.size);
+ return (size_t)(input_write_pos - input_read_pos);
+}
+
+static size_t input_space(void)
+{
+ return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos);
+}
+
+void input_enqueue_raw(const char *data, size_t size)
+{
+ if (input_read_pos > input_buffer) {
+ size_t available = input_available();
+ memmove(input_buffer, input_read_pos, available);
+ input_read_pos = input_buffer;
+ input_write_pos = input_buffer + available;
}
+
+ size_t to_write = MIN(size, input_space());
+ memcpy(input_write_pos, data, to_write);
+ input_write_pos += to_write;
}
size_t input_enqueue(String keys)
@@ -259,7 +278,7 @@ size_t input_enqueue(String keys)
const char *ptr = keys.data;
const char *end = ptr + keys.size;
- while (rbuffer_space(input_buffer) >= 19 && ptr < end) {
+ while (input_space() >= 19 && ptr < end) {
// A "<x>" form occupies at least 1 characters, and produces up
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
// In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed,
@@ -272,7 +291,7 @@ size_t input_enqueue(String keys)
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
- rbuffer_write(input_buffer, (char *)buf, new_size);
+ input_enqueue_raw((char *)buf, new_size);
continue;
}
@@ -293,11 +312,11 @@ size_t input_enqueue(String keys)
// copy the character, escaping K_SPECIAL
if ((uint8_t)(*ptr) == K_SPECIAL) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1);
} else {
- rbuffer_write(input_buffer, ptr, 1);
+ input_enqueue_raw(ptr, 1);
}
ptr++;
}
@@ -422,7 +441,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
return bufsize;
}
-size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
+void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
{
modifier |= check_multiclick(code, grid, row, col);
uint8_t buf[7];
@@ -442,8 +461,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co
mouse_col = col;
size_t written = 3 + (size_t)(p - buf);
- rbuffer_write(input_buffer, (char *)buf, written);
- return written;
+ input_enqueue_raw((char *)buf, written);
}
/// @return true if the main loop is blocked and waiting for input.
@@ -452,15 +470,22 @@ bool input_blocking(void)
return blocking;
}
-// This is a replacement for the old `WaitForChar` function in os_unix.c
-static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
+/// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting.
+///
+/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait.
+/// @param events (optional) Queue to check for pending events.
+/// @return TriState:
+/// - kTrue: Input/events available
+/// - kFalse: No input/events
+/// - kNone: EOF reached on the input stream
+static TriState inbuf_poll(int ms, MultiQueue *events)
{
if (os_input_ready(events)) {
- return kInputAvail;
+ return kTrue;
}
if (do_profiling == PROF_YES && ms) {
- prof_inchar_enter();
+ prof_input_start();
}
if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) {
@@ -468,38 +493,29 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
blocking = true;
multiqueue_process_events(ch_before_blocking_events);
}
- DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
- events && !multiqueue_empty(events));
- LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
- os_input_ready(events) || input_eof);
+ DLOG("blocking... events=%s", !!events ? "true" : "false");
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof);
blocking = false;
if (do_profiling == PROF_YES && ms) {
- prof_inchar_exit();
+ prof_input_end();
}
if (os_input_ready(events)) {
- return kInputAvail;
+ return kTrue;
}
- return input_eof ? kInputEof : kInputNone;
-}
-
-bool input_available(void)
-{
- return rbuffer_size(input_buffer) != 0;
+ return input_eof ? kNone : kFalse;
}
-static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
+static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
{
if (at_eof) {
input_eof = true;
}
- assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
- RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
- (void)rbuffer_write(input_buffer, ptr, len);
- rbuffer_consumed(buf, len);
- }
+ assert(input_space() >= c);
+ input_enqueue_raw(buf, c);
+ return c;
}
static void process_ctrl_c(void)
@@ -508,28 +524,29 @@ static void process_ctrl_c(void)
return;
}
- size_t consume_count = 0;
- RBUFFER_EACH_REVERSE(input_buffer, c, i) {
- if ((uint8_t)c == Ctrl_C
- || ((uint8_t)c == 'C' && i >= 3
- && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
- && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
- && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
- *rbuffer_get(input_buffer, i) = Ctrl_C;
+ size_t available = input_available();
+ ssize_t i;
+ for (i = (ssize_t)available - 1; i >= 0; i--) { // Reverse-search input for Ctrl_C.
+ uint8_t c = (uint8_t)input_read_pos[i];
+ if (c == Ctrl_C
+ || (c == 'C' && i >= 3
+ && (uint8_t)input_read_pos[i - 3] == K_SPECIAL
+ && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER
+ && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) {
+ input_read_pos[i] = Ctrl_C;
got_int = true;
- consume_count = i;
break;
}
}
- if (got_int && consume_count) {
+ if (got_int && i > 0) {
// Remove all unprocessed input (typeahead) before the CTRL-C.
- rbuffer_consumed(input_buffer, consume_count);
+ input_read_pos += i;
}
}
-// Helper function used to push bytes from the 'event' key sequence partially
-// between calls to os_inchar when maxlen < 3
+/// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when
+/// `maxlen < 3`.
static int push_event_key(uint8_t *buf, int maxlen)
{
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
@@ -548,7 +565,7 @@ static int push_event_key(uint8_t *buf, int maxlen)
bool os_input_ready(MultiQueue *events)
{
return (typebuf_was_filled // API call filled typeahead
- || rbuffer_size(input_buffer) // Input buffer filled
+ || input_available() // Input buffer filled
|| pending_events(events)); // Events must be processed
}
@@ -559,7 +576,7 @@ static void read_error_exit(void)
if (silent_mode) { // Normal way to exit for "nvim -es".
getout(0);
}
- preserve_exit(_("Vim: Error reading input, exiting...\n"));
+ preserve_exit(_("Nvim: Error reading input, exiting...\n"));
}
static bool pending_events(MultiQueue *events)
diff --git a/src/nvim/os/process.c b/src/nvim/os/proc.c
index e8d38d5b8a..053f5f3ba0 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/proc.c
@@ -37,24 +37,24 @@
#include "nvim/log.h"
#include "nvim/memory.h"
-#include "nvim/os/process.h"
+#include "nvim/os/proc.h"
#ifdef MSWIN
# include "nvim/api/private/helpers.h"
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/process.c.generated.h"
+# include "os/proc.c.generated.h"
#endif
#ifdef MSWIN
-static bool os_proc_tree_kill_rec(HANDLE process, int sig)
+static bool os_proc_tree_kill_rec(HANDLE proc, int sig)
{
- if (process == NULL) {
+ if (proc == NULL) {
return false;
}
PROCESSENTRY32 pe;
- DWORD pid = GetProcessId(process);
+ DWORD pid = GetProcessId(proc);
if (pid != 0) {
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -77,7 +77,7 @@ static bool os_proc_tree_kill_rec(HANDLE process, int sig)
}
theend:
- return (bool)TerminateProcess(process, (unsigned)sig);
+ return (bool)TerminateProcess(proc, (unsigned)sig);
}
/// Kills process `pid` and its descendants recursively.
bool os_proc_tree_kill(int pid, int sig)
@@ -230,9 +230,9 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count)
///
/// @param pid Process to inspect.
/// @return Map of process properties, empty on error.
-Dictionary os_proc_info(int pid, Arena *arena)
+Dict os_proc_info(int pid, Arena *arena)
{
- Dictionary pinfo = ARRAY_DICT_INIT;
+ Dict pinfo = ARRAY_DICT_INIT;
PROCESSENTRY32 pe;
// Snapshot of all processes. This is used instead of:
diff --git a/src/nvim/os/process.h b/src/nvim/os/proc.h
index 3b116b4bad..1831f21cc3 100644
--- a/src/nvim/os/process.h
+++ b/src/nvim/os/proc.h
@@ -7,5 +7,5 @@
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/process.h.generated.h"
+# include "os/proc.h.generated.h"
#endif
diff --git a/src/nvim/os/pty_conpty_win.c b/src/nvim/os/pty_conpty_win.c
index e7697880af..6402330a52 100644
--- a/src/nvim/os/pty_conpty_win.c
+++ b/src/nvim/os/pty_conpty_win.c
@@ -143,7 +143,7 @@ finished:
return conpty_object;
}
-bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *name,
+bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *proc_handle, wchar_t *name,
wchar_t *cmd_line, wchar_t *cwd, wchar_t *env)
{
PROCESS_INFORMATION pi = { 0 };
@@ -159,7 +159,7 @@ bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *n
&pi)) {
return false;
}
- *process_handle = pi.hProcess;
+ *proc_handle = pi.hProcess;
return true;
}
diff --git a/src/nvim/os/pty_proc.h b/src/nvim/os/pty_proc.h
new file mode 100644
index 0000000000..d815aae69c
--- /dev/null
+++ b/src/nvim/os/pty_proc.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#ifdef MSWIN
+# include "nvim/os/pty_proc_win.h"
+#else
+# include "nvim/os/pty_proc_unix.h"
+#endif
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_proc_unix.c
index 4d34e8fac4..3bca065d2d 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_proc_unix.c
@@ -30,20 +30,19 @@
#endif
#include "auto/config.h"
-#include "klib/klist.h"
#include "nvim/eval/typval.h"
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
-#include "nvim/event/process.h"
+#include "nvim/event/proc.h"
#include "nvim/log.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
-#include "nvim/os/pty_process.h"
-#include "nvim/os/pty_process_unix.h"
+#include "nvim/os/pty_proc.h"
+#include "nvim/os/pty_proc_unix.h"
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process_unix.c.generated.h"
+# include "os/pty_proc_unix.c.generated.h"
#endif
#if defined(__sun) && !defined(HAVE_FORKPTY)
@@ -158,7 +157,7 @@ static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct win
#endif
/// @returns zero on success, or negative error code
-int pty_process_spawn(PtyProcess *ptyproc)
+int pty_proc_spawn(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
// termios initialized at first use
@@ -168,8 +167,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
int status = 0; // zero or negative error code (libuv convention)
- Process *proc = (Process *)ptyproc;
- assert(proc->err.closed);
+ Proc *proc = (Proc *)ptyproc;
+ assert(proc->err.s.closed);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
uv_disable_stdio_inheritance();
@@ -208,8 +207,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
&& (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) {
goto error;
}
- if (!proc->out.closed
- && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) {
+ if (!proc->out.s.closed
+ && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) {
goto error;
}
@@ -224,29 +223,29 @@ error:
return status;
}
-const char *pty_process_tty_name(PtyProcess *ptyproc)
+const char *pty_proc_tty_name(PtyProc *ptyproc)
{
return ptsname(ptyproc->tty_fd);
}
-void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
+void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
ptyproc->winsize = (struct winsize){ height, width, 0, 0 };
ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
}
-void pty_process_close(PtyProcess *ptyproc)
+void pty_proc_close(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
- pty_process_close_master(ptyproc);
- Process *proc = (Process *)ptyproc;
+ pty_proc_close_master(ptyproc);
+ Proc *proc = (Proc *)ptyproc;
if (proc->internal_close_cb) {
proc->internal_close_cb(proc);
}
}
-void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
+void pty_proc_close_master(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL
{
if (ptyproc->tty_fd >= 0) {
close(ptyproc->tty_fd);
@@ -254,12 +253,12 @@ void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
}
}
-void pty_process_teardown(Loop *loop)
+void pty_proc_teardown(Loop *loop)
{
uv_signal_stop(&loop->children_watcher);
}
-static void init_child(PtyProcess *ptyproc)
+static void init_child(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
#if defined(HAVE__NSGETENVIRON)
@@ -277,13 +276,13 @@ static void init_child(PtyProcess *ptyproc)
signal(SIGTERM, SIG_DFL);
signal(SIGALRM, SIG_DFL);
- Process *proc = (Process *)ptyproc;
+ Proc *proc = (Proc *)ptyproc;
if (proc->cwd && os_chdir(proc->cwd) != 0) {
ELOG("chdir(%s) failed: %s", proc->cwd, strerror(errno));
return;
}
- const char *prog = process_get_exepath(proc);
+ const char *prog = proc_get_exepath(proc);
assert(proc->env);
environ = tv_dict_to_env(proc->env);
@@ -387,8 +386,8 @@ static void chld_handler(uv_signal_t *handle, int signum)
Loop *loop = handle->loop->data;
- kl_iter(WatcherPtr, loop->children, current) {
- Process *proc = (*current)->data;
+ for (size_t i = 0; i < kv_size(loop->children); i++) {
+ Proc *proc = kv_A(loop->children, i);
do {
pid = waitpid(proc->pid, &stat, WNOHANG);
} while (pid < 0 && errno == EINTR);
@@ -406,10 +405,10 @@ static void chld_handler(uv_signal_t *handle, int signum)
}
}
-PtyProcess pty_process_init(Loop *loop, void *data)
+PtyProc pty_proc_init(Loop *loop, void *data)
{
- PtyProcess rv;
- rv.process = process_init(loop, kProcessTypePty, data);
+ PtyProc rv = { 0 };
+ rv.proc = proc_init(loop, kProcTypePty, data);
rv.width = 80;
rv.height = 24;
rv.tty_fd = -1;
diff --git a/src/nvim/os/pty_process_unix.h b/src/nvim/os/pty_proc_unix.h
index 1a77ae5fd5..47f9af088e 100644
--- a/src/nvim/os/pty_process_unix.h
+++ b/src/nvim/os/pty_proc_unix.h
@@ -1,5 +1,5 @@
#pragma once
-// IWYU pragma: private, include "nvim/os/pty_process.h"
+// IWYU pragma: private, include "nvim/os/pty_proc.h"
#include <stdint.h>
#include <sys/ioctl.h>
@@ -7,12 +7,12 @@
#include "nvim/event/defs.h"
typedef struct {
- Process process;
+ Proc proc;
uint16_t width, height;
struct winsize winsize;
int tty_fd;
-} PtyProcess;
+} PtyProc;
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process_unix.h.generated.h"
+# include "os/pty_proc_unix.h.generated.h"
#endif
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_proc_win.c
index 12831ff05f..5bd6eead51 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_proc_win.c
@@ -10,20 +10,20 @@
#include "nvim/memory.h"
#include "nvim/os/os.h"
#include "nvim/os/pty_conpty_win.h"
-#include "nvim/os/pty_process_win.h"
+#include "nvim/os/pty_proc_win.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process_win.c.generated.h"
+# include "os/pty_proc_win.c.generated.h"
#endif
-static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
+static void CALLBACK pty_proc_finish1(void *context, BOOLEAN unused)
FUNC_ATTR_NONNULL_ALL
{
- PtyProcess *ptyproc = (PtyProcess *)context;
- Process *proc = (Process *)ptyproc;
+ PtyProc *ptyproc = (PtyProc *)context;
+ Proc *proc = (Proc *)ptyproc;
os_conpty_free(ptyproc->conpty);
- // NB: pty_process_finish1() is called on a separate thread,
+ // NB: pty_proc_finish1() is called on a separate thread,
// but the timer only works properly if it's started by the main thread.
loop_schedule_fast(proc->loop, event_create(start_wait_eof_timer, ptyproc));
}
@@ -31,7 +31,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
static void start_wait_eof_timer(void **argv)
FUNC_ATTR_NONNULL_ALL
{
- PtyProcess *ptyproc = (PtyProcess *)argv[0];
+ PtyProc *ptyproc = (PtyProc *)argv[0];
if (ptyproc->finish_wait != NULL) {
uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200);
@@ -39,15 +39,15 @@ static void start_wait_eof_timer(void **argv)
}
/// @returns zero on success, or negative error code.
-int pty_process_spawn(PtyProcess *ptyproc)
+int pty_proc_spawn(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
- Process *proc = (Process *)ptyproc;
+ Proc *proc = (Proc *)ptyproc;
int status = 0;
conpty_t *conpty_object = NULL;
char *in_name = NULL;
char *out_name = NULL;
- HANDLE process_handle = NULL;
+ HANDLE proc_handle = NULL;
uv_connect_t *in_req = NULL;
uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL;
@@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
wchar_t *env = NULL;
const char *emsg = NULL;
- assert(proc->err.closed);
+ assert(proc->err.s.closed);
if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name,
&out_name, ptyproc->width,
@@ -69,15 +69,15 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_pipe_connect(in_req,
&proc->in.uv.pipe,
in_name,
- pty_process_connect_cb);
+ pty_proc_connect_cb);
}
- if (!proc->out.closed) {
+ if (!proc->out.s.closed) {
out_req = xmalloc(sizeof(uv_connect_t));
uv_pipe_connect(out_req,
- &proc->out.uv.pipe,
+ &proc->out.s.uv.pipe,
out_name,
- pty_process_connect_cb);
+ pty_proc_connect_cb);
}
if (proc->cwd != NULL) {
@@ -105,7 +105,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
if (!os_conpty_spawn(conpty_object,
- &process_handle,
+ &proc_handle,
NULL,
cmd_line,
cwd,
@@ -114,42 +114,42 @@ int pty_process_spawn(PtyProcess *ptyproc)
status = (int)GetLastError();
goto cleanup;
}
- proc->pid = (int)GetProcessId(process_handle);
+ proc->pid = (int)GetProcessId(proc_handle);
uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
ptyproc->wait_eof_timer.data = (void *)ptyproc;
if (!RegisterWaitForSingleObject(&ptyproc->finish_wait,
- process_handle,
- pty_process_finish1,
+ proc_handle,
+ pty_proc_finish1,
ptyproc,
INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
abort();
}
- // Wait until pty_process_connect_cb is called.
+ // Wait until pty_proc_connect_cb is called.
while ((in_req != NULL && in_req->handle != NULL)
|| (out_req != NULL && out_req->handle != NULL)) {
uv_run(&proc->loop->uv, UV_RUN_ONCE);
}
ptyproc->conpty = conpty_object;
- ptyproc->process_handle = process_handle;
+ ptyproc->proc_handle = proc_handle;
conpty_object = NULL;
- process_handle = NULL;
+ proc_handle = NULL;
cleanup:
if (status) {
// In the case of an error of MultiByteToWideChar or CreateProcessW.
- ELOG("pty_process_spawn(%s): %s: error code: %d",
+ ELOG("pty_proc_spawn(%s): %s: error code: %d",
proc->argv[0], emsg, status);
status = os_translate_sys_error(status);
}
os_conpty_free(conpty_object);
xfree(in_name);
xfree(out_name);
- if (process_handle != NULL) {
- CloseHandle(process_handle);
+ if (proc_handle != NULL) {
+ CloseHandle(proc_handle);
}
xfree(in_req);
xfree(out_req);
@@ -159,32 +159,32 @@ cleanup:
return status;
}
-const char *pty_process_tty_name(PtyProcess *ptyproc)
+const char *pty_proc_tty_name(PtyProc *ptyproc)
{
return "?";
}
-void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
+void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
os_conpty_set_size(ptyproc->conpty, width, height);
}
-void pty_process_close(PtyProcess *ptyproc)
+void pty_proc_close(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
- Process *proc = (Process *)ptyproc;
+ Proc *proc = (Proc *)ptyproc;
- pty_process_close_master(ptyproc);
+ pty_proc_close_master(ptyproc);
if (ptyproc->finish_wait != NULL) {
UnregisterWaitEx(ptyproc->finish_wait, NULL);
ptyproc->finish_wait = NULL;
uv_close((uv_handle_t *)&ptyproc->wait_eof_timer, NULL);
}
- if (ptyproc->process_handle != NULL) {
- CloseHandle(ptyproc->process_handle);
- ptyproc->process_handle = NULL;
+ if (ptyproc->proc_handle != NULL) {
+ CloseHandle(ptyproc->proc_handle);
+ ptyproc->proc_handle = NULL;
}
if (proc->internal_close_cb) {
@@ -192,17 +192,17 @@ void pty_process_close(PtyProcess *ptyproc)
}
}
-void pty_process_close_master(PtyProcess *ptyproc)
+void pty_proc_close_master(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
}
-void pty_process_teardown(Loop *loop)
+void pty_proc_teardown(Loop *loop)
FUNC_ATTR_NONNULL_ALL
{
}
-static void pty_process_connect_cb(uv_connect_t *req, int status)
+static void pty_proc_connect_cb(uv_connect_t *req, int status)
FUNC_ATTR_NONNULL_ALL
{
assert(status == 0);
@@ -212,23 +212,23 @@ static void pty_process_connect_cb(uv_connect_t *req, int status)
static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
FUNC_ATTR_NONNULL_ALL
{
- PtyProcess *ptyproc = wait_eof_timer->data;
- Process *proc = (Process *)ptyproc;
+ PtyProc *ptyproc = wait_eof_timer->data;
+ Proc *proc = (Proc *)ptyproc;
assert(ptyproc->finish_wait != NULL);
- if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) {
+ if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer);
- pty_process_finish2(ptyproc);
+ pty_proc_finish2(ptyproc);
}
}
-static void pty_process_finish2(PtyProcess *ptyproc)
+static void pty_proc_finish2(PtyProc *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
- Process *proc = (Process *)ptyproc;
+ Proc *proc = (Proc *)ptyproc;
DWORD exit_code = 0;
- GetExitCodeProcess(ptyproc->process_handle, &exit_code);
+ GetExitCodeProcess(ptyproc->proc_handle, &exit_code);
proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code;
proc->internal_exit_cb(proc);
@@ -399,7 +399,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block)
QUEUE_INSERT_TAIL(&env_q, &env_node->node);
}
- // Additional '\0' after the final entry
+ // Additional NUL after the final entry
env_block_len++;
*env_block = xmalloc(sizeof(**env_block) * env_block_len);
@@ -427,14 +427,14 @@ cleanup:
return rc;
}
-PtyProcess pty_process_init(Loop *loop, void *data)
+PtyProc pty_proc_init(Loop *loop, void *data)
{
- PtyProcess rv;
- rv.process = process_init(loop, kProcessTypePty, data);
+ PtyProc rv;
+ rv.proc = proc_init(loop, kProcTypePty, data);
rv.width = 80;
rv.height = 24;
rv.conpty = NULL;
rv.finish_wait = NULL;
- rv.process_handle = NULL;
+ rv.proc_handle = NULL;
return rv;
}
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_proc_win.h
index 3528f6bfe5..c2fdea506e 100644
--- a/src/nvim/os/pty_process_win.h
+++ b/src/nvim/os/pty_proc_win.h
@@ -1,20 +1,20 @@
#pragma once
-// IWYU pragma: private, include "nvim/os/pty_process.h"
+// IWYU pragma: private, include "nvim/os/pty_proc.h"
#include <uv.h>
-#include "nvim/event/process.h"
+#include "nvim/event/proc.h"
#include "nvim/lib/queue_defs.h"
#include "nvim/os/pty_conpty_win.h"
typedef struct pty_process {
- Process process;
+ Proc proc;
uint16_t width, height;
conpty_t *conpty;
HANDLE finish_wait;
- HANDLE process_handle;
+ HANDLE proc_handle;
uv_timer_t wait_eof_timer;
-} PtyProcess;
+} PtyProc;
// Structure used by build_cmd_line()
typedef struct arg_node {
@@ -23,5 +23,5 @@ typedef struct arg_node {
} ArgNode;
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process_win.h.generated.h"
+# include "os/pty_proc_win.h.generated.h"
#endif
diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h
deleted file mode 100644
index 2c7a5f66bd..0000000000
--- a/src/nvim/os/pty_process.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-#ifdef MSWIN
-# include "nvim/os/pty_process_win.h"
-#else
-# include "nvim/os/pty_process_unix.h"
-#endif
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 2a10510b0f..efcdee9c8b 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -10,13 +10,14 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
-#include "nvim/event/libuv_process.h"
+#include "nvim/event/libuv_proc.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
-#include "nvim/event/process.h"
+#include "nvim/event/proc.h"
#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
#include "nvim/event/wstream.h"
@@ -39,8 +40,6 @@
#include "nvim/path.h"
#include "nvim/pos_defs.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
@@ -48,17 +47,11 @@
#include "nvim/ui.h"
#include "nvim/vim_defs.h"
-#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 }
#define NS_1_SECOND 1000000000U // 1 second, in nanoseconds
#define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data.
#define SHELL_SPECIAL "\t \"&'$;<>()\\|"
-typedef struct {
- char *data;
- size_t cap, len;
-} DynamicBuffer;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/shell.c.generated.h"
#endif
@@ -122,7 +115,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
size_t len;
char *p;
char *extra_shell_arg = NULL;
- ShellOpts shellopts = kShellOptExpand | kShellOptSilent;
+ int shellopts = kShellOptExpand | kShellOptSilent;
int j;
char *tempname;
#define STYLE_ECHO 0 // use "echo", the default
@@ -255,11 +248,11 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
} else {
STRCPY(command, "(");
}
- STRCAT(command, pat[0] + 1); // exclude first backtick
+ strcat(command, pat[0] + 1); // exclude first backtick
p = command + strlen(command) - 1;
if (is_fish_shell) {
*p-- = ';';
- STRCAT(command, " end");
+ strcat(command, " end");
} else {
*p-- = ')'; // remove last backtick
}
@@ -270,7 +263,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
ampersand = true;
*p = ' ';
}
- STRCAT(command, ">");
+ strcat(command, ">");
} else {
STRCPY(command, "");
if (shell_style == STYLE_GLOB) {
@@ -278,26 +271,26 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
// otherwise, this may set the positional parameters for the shell,
// e.g. "$*".
if (flags & EW_NOTFOUND) {
- STRCAT(command, "set nonomatch; ");
+ strcat(command, "set nonomatch; ");
} else {
- STRCAT(command, "unset nonomatch; ");
+ strcat(command, "unset nonomatch; ");
}
}
if (shell_style == STYLE_GLOB) {
- STRCAT(command, "glob >");
+ strcat(command, "glob >");
} else if (shell_style == STYLE_PRINT) {
- STRCAT(command, "print -N >");
+ strcat(command, "print -N >");
} else if (shell_style == STYLE_VIMGLOB) {
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_vimglob_func);
} else if (shell_style == STYLE_GLOBSTAR) {
- STRCAT(command, sh_globstar_opt);
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_globstar_opt);
+ strcat(command, sh_vimglob_func);
} else {
- STRCAT(command, "echo >");
+ strcat(command, "echo >");
}
}
- STRCAT(command, tempname);
+ strcat(command, tempname);
if (shell_style != STYLE_BT) {
for (i = 0; i < num_pat; i++) {
@@ -341,7 +334,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
}
if (ampersand) {
- STRCAT(command, "&"); // put the '&' after the redirection
+ strcat(command, "&"); // put the '&' after the redirection
}
// Using zsh -G: If a pattern has no matches, it is just deleted from
@@ -647,13 +640,13 @@ char *shell_argv_to_str(char **const argv)
p++;
}
if (n < maxsize) {
- rv[n - 1] = '\0';
+ rv[n - 1] = NUL;
} else {
// Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..."
rv[maxsize - 4] = '.';
rv[maxsize - 3] = '.';
rv[maxsize - 2] = '.';
- rv[maxsize - 1] = '\0';
+ rv[maxsize - 1] = NUL;
}
return rv;
}
@@ -666,9 +659,9 @@ char *shell_argv_to_str(char **const argv)
/// @param extra_args Extra arguments to the shell, or NULL.
///
/// @return shell command exit code
-int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
+int os_call_shell(char *cmd, int opts, char *extra_args)
{
- DynamicBuffer input = DYNAMIC_BUFFER_INIT;
+ StringBuilder input = KV_INITIAL_VALUE;
char *output = NULL;
char **output_ptr = NULL;
int current_state = State;
@@ -697,9 +690,9 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
size_t nread;
int exitcode = do_os_system(shell_build_argv(cmd, extra_args),
- input.data, input.len, output_ptr, &nread,
+ input.items, input.size, output_ptr, &nread,
emsg_silent, forward_output);
- xfree(input.data);
+ kv_destroy(input);
if (output) {
write_output(output, nread, true);
@@ -721,8 +714,10 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
/// Invalidates cached tags.
///
+/// @param opts a combination of ShellOpts flags
+///
/// @return shell command exit code
-int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg)
+int call_shell(char *cmd, int opts, char *extra_shell_arg)
{
int retval;
proftime_T wait_time;
@@ -766,7 +761,7 @@ int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg)
/// @param ret_len length of the stdout
///
/// @return an allocated string, or NULL for error.
-char *get_cmd_output(char *cmd, char *infile, ShellOpts flags, size_t *ret_len)
+char *get_cmd_output(char *cmd, char *infile, int flags, size_t *ret_len)
{
char *buffer = NULL;
@@ -860,10 +855,10 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
{
out_data_decide_throttle(0); // Initialize throttle decider.
out_data_ring(NULL, 0); // Initialize output ring-buffer.
- bool has_input = (input != NULL && input[0] != '\0');
+ bool has_input = (input != NULL && input[0] != NUL);
// the output buffer
- DynamicBuffer buf = DYNAMIC_BUFFER_INIT;
+ StringBuilder buf = KV_INITIAL_VALUE;
stream_read_cb data_cb = system_data_cb;
if (nread) {
*nread = 0;
@@ -879,12 +874,12 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
char prog[MAXPATHL];
xstrlcpy(prog, argv[0], MAXPATHL);
- LibuvProcess uvproc = libuv_process_init(&main_loop, &buf);
- Process *proc = &uvproc.process;
+ LibuvProc uvproc = libuv_proc_init(&main_loop, &buf);
+ Proc *proc = &uvproc.proc;
MultiQueue *events = multiqueue_new_child(main_loop.events);
proc->events = events;
proc->argv = argv;
- int status = process_spawn(proc, has_input, true, true);
+ int status = proc_spawn(proc, has_input, true, true);
if (status) {
loop_poll_events(&main_loop, 0);
// Failed, probably 'shell' is not executable.
@@ -906,9 +901,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
if (has_input) {
wstream_init(&proc->in, 0);
}
- rstream_init(&proc->out, 0);
+ rstream_init(&proc->out);
rstream_start(&proc->out, data_cb, &buf);
- rstream_init(&proc->err, 0);
+ rstream_init(&proc->err);
rstream_start(&proc->err, data_cb, &buf);
// write the input, if any
@@ -917,7 +912,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
if (!wstream_write(&proc->in, input_buffer)) {
// couldn't write, stop the process and tell the user about it
- process_stop(proc);
+ proc_stop(proc);
return -1;
}
// close the input stream after everything is written
@@ -934,7 +929,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
msg_no_more = true;
lines_left = -1;
}
- int exitcode = process_wait(proc, -1, NULL);
+ int exitcode = proc_wait(proc, -1, NULL);
if (!got_int && out_data_decide_throttle(0)) {
// Last chunk of output was skipped; display it now.
out_data_ring(NULL, SIZE_MAX);
@@ -951,18 +946,17 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
// prepare the out parameters if requested
if (output) {
- if (buf.len == 0) {
+ assert(nread);
+ if (buf.size == 0) {
// no data received from the process, return NULL
*output = NULL;
- xfree(buf.data);
+ *nread = 0;
+ kv_destroy(buf);
} else {
+ *nread = buf.size;
// NUL-terminate to make the output directly usable as a C string
- buf.data[buf.len] = NUL;
- *output = buf.data;
- }
-
- if (nread) {
- *nread = buf.len;
+ kv_push(buf, NUL);
+ *output = buf.items;
}
}
@@ -972,29 +966,11 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
return exitcode;
}
-/// - ensures at least `desired` bytes in buffer
-///
-/// TODO(aktau): fold with kvec/garray
-static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
+static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
- if (buf->cap >= desired) {
- assert(buf->data);
- return;
- }
-
- buf->cap = desired;
- kv_roundup32(buf->cap);
- buf->data = xrealloc(buf->data, buf->cap);
-}
-
-static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
-{
- DynamicBuffer *dbuf = data;
-
- size_t nread = buf->size;
- dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
- rbuffer_read(buf, dbuf->data + dbuf->len, nread);
- dbuf->len += nread;
+ StringBuilder *dbuf = data;
+ kv_concat_len(*dbuf, buf, count);
+ return count;
}
/// Tracks output received for the current executing shell command, and displays
@@ -1023,7 +999,7 @@ static bool out_data_decide_throttle(size_t size)
static uint64_t started = 0; // Start time of the current throttle.
static size_t received = 0; // Bytes observed since last throttle.
static size_t visit = 0; // "Pulse" count of the current throttle.
- static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
+ static char pulse_msg[] = { ' ', ' ', ' ', NUL };
if (!size) {
bool previous_decision = (visit > 0);
@@ -1077,7 +1053,7 @@ static bool out_data_decide_throttle(size_t size)
///
/// @param output Data to save, or NULL to invoke a special mode.
/// @param size Length of `output`.
-static void out_data_ring(char *output, size_t size)
+static void out_data_ring(const char *output, size_t size)
{
#define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
@@ -1119,11 +1095,11 @@ static void out_data_ring(char *output, size_t size)
/// @param output Data to append to screen lines.
/// @param count Size of data.
/// @param eof If true, there will be no more data output.
-static void out_data_append_to_screen(char *output, size_t *count, bool eof)
+static void out_data_append_to_screen(const char *output, size_t *count, bool eof)
FUNC_ATTR_NONNULL_ALL
{
- char *p = output;
- char *end = output + *count;
+ const char *p = output;
+ const char *end = output + *count;
while (p < end) {
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
msg_putchar_attr((uint8_t)(*p), 0);
@@ -1151,25 +1127,16 @@ end:
ui_flush();
}
-static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof)
{
- size_t cnt;
- char *ptr = rbuffer_read_ptr(buf, &cnt);
-
- if (ptr != NULL && cnt > 0
- && out_data_decide_throttle(cnt)) { // Skip output above a threshold.
+ if (count > 0 && out_data_decide_throttle(count)) { // Skip output above a threshold.
// Save the skipped output. If it is the final chunk, we display it later.
- out_data_ring(ptr, cnt);
- } else if (ptr != NULL) {
- out_data_append_to_screen(ptr, &cnt, eof);
- }
-
- if (cnt) {
- rbuffer_consumed(buf, cnt);
+ out_data_ring(ptr, count);
+ } else if (count > 0) {
+ out_data_append_to_screen(ptr, &count, eof);
}
- // Move remaining data to start of buffer, so the buffer can never wrap around.
- rbuffer_reset(buf);
+ return count;
}
/// Parses a command string into a sequence of words, taking quotes into
@@ -1233,7 +1200,7 @@ static size_t word_length(const char *str)
/// event loop starts. If we don't (by writing in chunks returned by `ml_get`)
/// the buffer being modified might get modified by reading from the process
/// before we finish writing.
-static void read_input(DynamicBuffer *buf)
+static void read_input(StringBuilder *buf)
{
size_t written = 0;
size_t len = 0;
@@ -1247,14 +1214,11 @@ static void read_input(DynamicBuffer *buf)
} else if (lp[written] == NL) {
// NL -> NUL translation
len = 1;
- dynamic_buffer_ensure(buf, buf->len + len);
- buf->data[buf->len++] = NUL;
+ kv_push(*buf, NUL);
} else {
char *s = vim_strchr(lp + written, NL);
len = s == NULL ? l : (size_t)(s - (lp + written));
- dynamic_buffer_ensure(buf, buf->len + len);
- memcpy(buf->data + buf->len, lp + written, len);
- buf->len += len;
+ kv_concat_len(*buf, lp + written, len);
}
if (len == l) {
@@ -1263,8 +1227,7 @@ static void read_input(DynamicBuffer *buf)
|| (!curbuf->b_p_bin && curbuf->b_p_fixeol)
|| (lnum != curbuf->b_no_eol_lnum
&& (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {
- dynamic_buffer_ensure(buf, buf->len + 1);
- buf->data[buf->len++] = NL;
+ kv_push(*buf, NL);
}
lnum++;
if (lnum > curbuf->b_op_end.lnum) {
@@ -1331,7 +1294,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
uv_err_name(status));
}
- stream_close(stream, NULL, NULL);
+ stream_may_close(stream, false);
}
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index e5bdd56fe6..e9a74d197f 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -63,22 +63,32 @@ static const char *const xdg_defaults[] = {
#endif
};
-/// Get the value of $NVIM_APPNAME or "nvim" if not set.
+/// Gets the value of $NVIM_APPNAME, or "nvim" if not set.
+///
+/// @param namelike Write "name-like" value (no path separators) in `NameBuff`.
///
/// @return $NVIM_APPNAME value
-const char *get_appname(void)
+const char *get_appname(bool namelike)
{
const char *env_val = os_getenv("NVIM_APPNAME");
- if (env_val == NULL || *env_val == '\0') {
+ if (env_val == NULL || *env_val == NUL) {
env_val = "nvim";
}
+
+ if (namelike) {
+ // Appname may be a relative path, replace slashes to make it name-like.
+ xstrlcpy(NameBuff, env_val, sizeof(NameBuff));
+ memchrsub(NameBuff, '/', '-', sizeof(NameBuff));
+ memchrsub(NameBuff, '\\', '-', sizeof(NameBuff));
+ }
+
return env_val;
}
/// Ensure that APPNAME is valid. Must be a name or relative path.
bool appname_is_valid(void)
{
- const char *appname = get_appname();
+ const char *appname = get_appname(false);
if (path_is_absolute(appname)
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|| strequal(appname, "/")
@@ -193,7 +203,7 @@ char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
- const char *appname = get_appname();
+ const char *appname = get_appname(false);
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));