mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 13:38:34 +00:00
Merge #8276 'startup: Make -s - read from stdin'
This commit is contained in:
@@ -48,8 +48,14 @@
|
||||
#include "nvim/event/loop.h"
|
||||
#include "nvim/os/input.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/fileio.h"
|
||||
#include "nvim/api/private/handle.h"
|
||||
|
||||
|
||||
/// Index in scriptin
|
||||
static int curscript = 0;
|
||||
FileDescriptor *scriptin[NSCRIPT] = { NULL };
|
||||
|
||||
/*
|
||||
* These buffers are used for storing:
|
||||
* - stuffed characters: A command that is translated into another command.
|
||||
@@ -1243,10 +1249,13 @@ openscript (
|
||||
++curscript;
|
||||
/* use NameBuff for expanded name */
|
||||
expand_env(name, NameBuff, MAXPATHL);
|
||||
if ((scriptin[curscript] = mch_fopen((char *)NameBuff, READBIN)) == NULL) {
|
||||
EMSG2(_(e_notopen), name);
|
||||
if (curscript)
|
||||
--curscript;
|
||||
int error;
|
||||
if ((scriptin[curscript] = file_open_new(&error, (char *)NameBuff,
|
||||
kFileReadOnly, 0)) == NULL) {
|
||||
emsgf(_(e_notopen_2), name, os_strerror(error));
|
||||
if (curscript) {
|
||||
curscript--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
save_typebuf();
|
||||
@@ -1296,7 +1305,7 @@ static void closescript(void)
|
||||
free_typebuf();
|
||||
typebuf = saved_typebuf[curscript];
|
||||
|
||||
fclose(scriptin[curscript]);
|
||||
file_free(scriptin[curscript], false);
|
||||
scriptin[curscript] = NULL;
|
||||
if (curscript > 0)
|
||||
--curscript;
|
||||
@@ -2336,9 +2345,8 @@ inchar (
|
||||
int tb_change_cnt
|
||||
)
|
||||
{
|
||||
int len = 0; /* init for GCC */
|
||||
int retesc = FALSE; /* return ESC with gotint */
|
||||
int script_char;
|
||||
int len = 0; // Init for GCC.
|
||||
int retesc = false; // Return ESC with gotint.
|
||||
|
||||
if (wait_time == -1L || wait_time > 100L) {
|
||||
// flush output before waiting
|
||||
@@ -2356,45 +2364,38 @@ inchar (
|
||||
}
|
||||
undo_off = FALSE; /* restart undo now */
|
||||
|
||||
/*
|
||||
* Get a character from a script file if there is one.
|
||||
* If interrupted: Stop reading script files, close them all.
|
||||
*/
|
||||
script_char = -1;
|
||||
while (scriptin[curscript] != NULL && script_char < 0
|
||||
&& !ignore_script
|
||||
) {
|
||||
|
||||
|
||||
if (got_int || (script_char = getc(scriptin[curscript])) < 0) {
|
||||
/* Reached EOF.
|
||||
* Careful: closescript() frees typebuf.tb_buf[] and buf[] may
|
||||
* point inside typebuf.tb_buf[]. Don't use buf[] after this! */
|
||||
// Get a character from a script file if there is one.
|
||||
// If interrupted: Stop reading script files, close them all.
|
||||
ptrdiff_t read_size = -1;
|
||||
while (scriptin[curscript] != NULL && read_size <= 0 && !ignore_script) {
|
||||
char script_char;
|
||||
if (got_int
|
||||
|| (read_size = file_read(scriptin[curscript], &script_char, 1)) != 1) {
|
||||
// Reached EOF or some error occurred.
|
||||
// Careful: closescript() frees typebuf.tb_buf[] and buf[] may
|
||||
// point inside typebuf.tb_buf[]. Don't use buf[] after this!
|
||||
closescript();
|
||||
/*
|
||||
* When reading script file is interrupted, return an ESC to get
|
||||
* back to normal mode.
|
||||
* Otherwise return -1, because typebuf.tb_buf[] has changed.
|
||||
*/
|
||||
if (got_int)
|
||||
retesc = TRUE;
|
||||
else
|
||||
// When reading script file is interrupted, return an ESC to get
|
||||
// back to normal mode.
|
||||
// Otherwise return -1, because typebuf.tb_buf[] has changed.
|
||||
if (got_int) {
|
||||
retesc = true;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
buf[0] = (char_u)script_char;
|
||||
len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (script_char < 0) { /* did not get a character from script */
|
||||
/*
|
||||
* If we got an interrupt, skip all previously typed characters and
|
||||
* return TRUE if quit reading script file.
|
||||
* Stop reading typeahead when a single CTRL-C was read,
|
||||
* fill_input_buf() returns this when not able to read from stdin.
|
||||
* Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
|
||||
* and buf may be pointing inside typebuf.tb_buf[].
|
||||
*/
|
||||
if (read_size <= 0) { // Did not get a character from script.
|
||||
// If we got an interrupt, skip all previously typed characters and
|
||||
// return TRUE if quit reading script file.
|
||||
// Stop reading typeahead when a single CTRL-C was read,
|
||||
// fill_input_buf() returns this when not able to read from stdin.
|
||||
// Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
|
||||
// and buf may be pointing inside typebuf.tb_buf[].
|
||||
if (got_int) {
|
||||
#define DUM_LEN MAXMAPLEN * 3 + 3
|
||||
char_u dum[DUM_LEN + 1];
|
||||
@@ -2407,21 +2408,18 @@ inchar (
|
||||
return retesc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always flush the output characters when getting input characters
|
||||
* from the user.
|
||||
*/
|
||||
// Always flush the output characters when getting input characters
|
||||
// from the user.
|
||||
ui_flush();
|
||||
|
||||
/*
|
||||
* Fill up to a third of the buffer, because each character may be
|
||||
* tripled below.
|
||||
*/
|
||||
// Fill up to a third of the buffer, because each character may be
|
||||
// tripled below.
|
||||
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);
|
||||
}
|
||||
|
||||
if (typebuf_changed(tb_change_cnt))
|
||||
if (typebuf_changed(tb_change_cnt)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fix_input_buffer(buf, len);
|
||||
}
|
||||
|
@@ -1,24 +1,30 @@
|
||||
#ifndef NVIM_GETCHAR_H
|
||||
#define NVIM_GETCHAR_H
|
||||
|
||||
#include "nvim/os/fileio.h"
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
|
||||
/// Values for "noremap" argument of ins_typebuf(). Also used for
|
||||
/// map->m_noremap and menu->noremap[].
|
||||
/// @addtogroup REMAP_VALUES
|
||||
/// @{
|
||||
#define REMAP_YES 0 ///< allow remapping
|
||||
#define REMAP_NONE -1 ///< no remapping
|
||||
#define REMAP_SCRIPT -2 ///< remap script-local mappings only
|
||||
#define REMAP_SKIP -3 ///< no remapping for first char
|
||||
/// @}
|
||||
/// Values for "noremap" argument of ins_typebuf()
|
||||
///
|
||||
/// Also used for map->m_noremap and menu->noremap[].
|
||||
enum {
|
||||
REMAP_YES = 0, ///< Allow remapping.
|
||||
REMAP_NONE = -1, ///< No remapping.
|
||||
REMAP_SCRIPT = -2, ///< Remap script-local mappings only.
|
||||
REMAP_SKIP = -3, ///< No remapping for first char.
|
||||
} RemapValues;
|
||||
|
||||
#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
|
||||
#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */
|
||||
#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
|
||||
|
||||
/// Maximum number of streams to read script from
|
||||
enum { NSCRIPT = 15 };
|
||||
|
||||
/// Streams to read script from
|
||||
extern FileDescriptor *scriptin[NSCRIPT];
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "getchar.h.generated.h"
|
||||
|
@@ -834,10 +834,7 @@ EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
|
||||
EXTERN int need_highlight_changed INIT(= true);
|
||||
EXTERN char *used_shada_file INIT(= NULL); // name of the ShaDa file to use
|
||||
|
||||
#define NSCRIPT 15
|
||||
EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
|
||||
EXTERN int curscript INIT(= 0); /* index in scriptin[] */
|
||||
EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
|
||||
EXTERN FILE *scriptout INIT(= NULL); ///< Stream to write script to.
|
||||
|
||||
// volatile because it is used in a signal handler.
|
||||
EXTERN volatile int got_int INIT(= false); // set to true when interrupt
|
||||
@@ -1085,6 +1082,7 @@ EXTERN char_u e_norange[] INIT(= N_("E481: No range allowed"));
|
||||
EXTERN char_u e_noroom[] INIT(= N_("E36: Not enough room"));
|
||||
EXTERN char_u e_notmp[] INIT(= N_("E483: Can't get temp file name"));
|
||||
EXTERN char_u e_notopen[] INIT(= N_("E484: Can't open file %s"));
|
||||
EXTERN char_u e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
|
||||
EXTERN char_u e_notread[] INIT(= N_("E485: Can't read file %s"));
|
||||
EXTERN char_u e_nowrtmsg[] INIT(= N_(
|
||||
"E37: No write since last change (add ! to override)"));
|
||||
|
@@ -787,7 +787,8 @@ static void command_line_scan(mparm_T *parmp)
|
||||
mch_exit(0);
|
||||
} else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
|
||||
FileDescriptor fp;
|
||||
const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, true);
|
||||
const int fof_ret = file_open_fd(&fp, STDOUT_FILENO,
|
||||
kFileWriteOnly);
|
||||
msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
|
||||
|
||||
if (fof_ret != 0) {
|
||||
@@ -1085,17 +1086,36 @@ static void command_line_scan(mparm_T *parmp)
|
||||
case 's': /* "-s {scriptin}" read from script file */
|
||||
if (scriptin[0] != NULL) {
|
||||
scripterror:
|
||||
mch_errmsg(_("Attempt to open script file again: \""));
|
||||
mch_errmsg(argv[-1]);
|
||||
mch_errmsg(" ");
|
||||
mch_errmsg(argv[0]);
|
||||
mch_errmsg("\"\n");
|
||||
vim_snprintf((char *)IObuff, IOSIZE,
|
||||
_("Attempt to open script file again: \"%s %s\"\n"),
|
||||
argv[-1], argv[0]);
|
||||
mch_errmsg((const char *)IObuff);
|
||||
mch_exit(2);
|
||||
}
|
||||
if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL) {
|
||||
mch_errmsg(_("Cannot open for reading: \""));
|
||||
mch_errmsg(argv[0]);
|
||||
mch_errmsg("\"\n");
|
||||
int error;
|
||||
if (STRCMP(argv[0], "-") == 0) {
|
||||
const int stdin_dup_fd = os_dup(STDIN_FILENO);
|
||||
#ifdef WIN32
|
||||
// On Windows, replace the original stdin with the
|
||||
// console input handle.
|
||||
close(STDIN_FILENO);
|
||||
const HANDLE conin_handle =
|
||||
CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
|
||||
OPEN_EXISTING, 0, (HANDLE)NULL);
|
||||
const int conin_fd = _open_osfhandle(conin_handle, _O_RDONLY);
|
||||
assert(conin_fd == STDIN_FILENO);
|
||||
#endif
|
||||
FileDescriptor *const stdin_dup = file_open_fd_new(
|
||||
&error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
|
||||
assert(stdin_dup != NULL);
|
||||
scriptin[0] = stdin_dup;
|
||||
} else if ((scriptin[0] = file_open_new(
|
||||
&error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) {
|
||||
vim_snprintf((char *)IObuff, IOSIZE,
|
||||
_("Cannot open for reading: \"%s\": %s\n"),
|
||||
argv[0], os_strerror(error));
|
||||
mch_errmsg((const char *)IObuff);
|
||||
mch_exit(2);
|
||||
}
|
||||
save_typebuf();
|
||||
|
@@ -2351,10 +2351,9 @@ static int do_more_prompt(int typed_char)
|
||||
* yet. When stderr can't be used, collect error messages until the GUI has
|
||||
* started and they can be displayed in a message box.
|
||||
*/
|
||||
void mch_errmsg(char *str)
|
||||
void mch_errmsg(const char *const str)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
int len;
|
||||
|
||||
#ifdef UNIX
|
||||
/* On Unix use stderr if it's a tty.
|
||||
* When not going to start the GUI also use stderr.
|
||||
@@ -2368,14 +2367,13 @@ void mch_errmsg(char *str)
|
||||
/* avoid a delay for a message that isn't there */
|
||||
emsg_on_display = FALSE;
|
||||
|
||||
len = (int)STRLEN(str) + 1;
|
||||
const size_t len = strlen(str) + 1;
|
||||
if (error_ga.ga_data == NULL) {
|
||||
ga_set_growsize(&error_ga, 80);
|
||||
error_ga.ga_itemsize = 1;
|
||||
}
|
||||
ga_grow(&error_ga, len);
|
||||
memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
|
||||
(char_u *)str, len);
|
||||
memmove(error_ga.ga_data + error_ga.ga_len, str, len);
|
||||
#ifdef UNIX
|
||||
/* remove CR characters, they are displayed */
|
||||
{
|
||||
|
@@ -83,7 +83,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
return file_open_fd(ret_fp, fd, (wr == kTrue));
|
||||
return file_open_fd(ret_fp, fd, flags);
|
||||
}
|
||||
|
||||
/// Wrap file descriptor with FileDescriptor structure
|
||||
@@ -94,14 +94,23 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
|
||||
/// @param[out] ret_fp Address where information needed for reading from or
|
||||
/// writing to a file is saved
|
||||
/// @param[in] fd File descriptor to wrap.
|
||||
/// @param[in] wr True if fd is opened for writing only, false if it is read
|
||||
/// only.
|
||||
/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and
|
||||
/// writing to the file at once is not supported, so either
|
||||
/// FILE_WRITE_ONLY or FILE_READ_ONLY is required.
|
||||
///
|
||||
/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
|
||||
int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
|
||||
int file_open_fd(FileDescriptor *const ret_fp, const int fd,
|
||||
const int flags)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
ret_fp->wr = wr;
|
||||
ret_fp->wr = !!(flags & (kFileCreate
|
||||
|kFileCreateOnly
|
||||
|kFileTruncate
|
||||
|kFileAppend
|
||||
|kFileWriteOnly));
|
||||
ret_fp->non_blocking = !!(flags & kFileNonBlocking);
|
||||
// Non-blocking writes not supported currently.
|
||||
assert(!ret_fp->wr || !ret_fp->non_blocking);
|
||||
ret_fp->fd = fd;
|
||||
ret_fp->eof = false;
|
||||
ret_fp->rv = rbuffer_new(kRWBufferSize);
|
||||
@@ -138,15 +147,17 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
|
||||
///
|
||||
/// @param[out] error Error code, or 0 on success. @see os_strerror()
|
||||
/// @param[in] fd File descriptor to wrap.
|
||||
/// @param[in] wr True if fd is opened for writing only, false if it is read
|
||||
/// only.
|
||||
/// @param[in] flags Flags, @see FileOpenFlags.
|
||||
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
||||
/// does not have FILE_CREATE\*).
|
||||
///
|
||||
/// @return [allocated] Opened file or NULL in case of error.
|
||||
FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr)
|
||||
FileDescriptor *file_open_fd_new(int *const error, const int fd,
|
||||
const int flags)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
FileDescriptor *const fp = xmalloc(sizeof(*fp));
|
||||
if ((*error = file_open_fd(fp, fd, wr)) != 0) {
|
||||
if ((*error = file_open_fd(fp, fd, flags)) != 0) {
|
||||
xfree(fp);
|
||||
return NULL;
|
||||
}
|
||||
@@ -244,7 +255,8 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)
|
||||
return;
|
||||
}
|
||||
const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
|
||||
const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes);
|
||||
const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes,
|
||||
fp->non_blocking);
|
||||
if (wres != (ptrdiff_t)read_bytes) {
|
||||
if (wres >= 0) {
|
||||
fp->_error = UV_EIO;
|
||||
@@ -270,6 +282,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
char *buf = ret_buf;
|
||||
size_t read_remaining = size;
|
||||
RBuffer *const rv = fp->rv;
|
||||
bool called_read = false;
|
||||
while (read_remaining) {
|
||||
const size_t rv_size = rbuffer_size(rv);
|
||||
if (rv_size > 0) {
|
||||
@@ -277,7 +290,9 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
buf += rsize;
|
||||
read_remaining -= rsize;
|
||||
}
|
||||
if (fp->eof) {
|
||||
if (fp->eof
|
||||
// Allow only at most one os_read[v] call.
|
||||
|| (called_read && fp->non_blocking)) {
|
||||
break;
|
||||
}
|
||||
if (read_remaining) {
|
||||
@@ -294,7 +309,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
};
|
||||
assert(write_count == kRWBufferSize);
|
||||
const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
|
||||
ARRAY_SIZE(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));
|
||||
@@ -310,7 +325,8 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
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);
|
||||
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);
|
||||
@@ -321,7 +337,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
size_t write_count;
|
||||
const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
|
||||
rbuffer_write_ptr(rv, &write_count),
|
||||
kRWBufferSize);
|
||||
kRWBufferSize, fp->non_blocking);
|
||||
assert(write_count == kRWBufferSize);
|
||||
if (r_ret > 0) {
|
||||
rbuffer_produced(rv, (size_t)r_ret);
|
||||
@@ -330,6 +346,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
called_read = true;
|
||||
}
|
||||
}
|
||||
return (ptrdiff_t)(size - read_remaining);
|
||||
|
@@ -14,6 +14,7 @@ typedef struct {
|
||||
RBuffer *rv; ///< Read or write 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.
|
||||
} FileDescriptor;
|
||||
|
||||
/// file_open() flags
|
||||
@@ -32,6 +33,8 @@ typedef enum {
|
||||
///< kFileCreateOnly.
|
||||
kFileAppend = 64, ///< Append to the file. Implies kFileWriteOnly. Cannot
|
||||
///< be used with kFileCreateOnly.
|
||||
kFileNonBlocking = 128, ///< Do not restart read() or write() syscall if
|
||||
///< EAGAIN was encountered.
|
||||
} FileOpenFlags;
|
||||
|
||||
static inline bool file_eof(const FileDescriptor *const fp)
|
||||
|
@@ -436,6 +436,29 @@ int os_close(const int fd)
|
||||
return r;
|
||||
}
|
||||
|
||||
/// Duplicate file descriptor
|
||||
///
|
||||
/// @param[in] fd File descriptor to duplicate.
|
||||
///
|
||||
/// @return New file descriptor or libuv error code (< 0).
|
||||
int os_dup(const int fd)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
int ret;
|
||||
os_dup_dup:
|
||||
ret = dup(fd);
|
||||
if (ret < 0) {
|
||||
const int error = os_translate_sys_error(errno);
|
||||
errno = 0;
|
||||
if (error == UV_EINTR) {
|
||||
goto os_dup_dup;
|
||||
} else {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Read from a file
|
||||
///
|
||||
/// Handles EINTR and ENOMEM, but not other errors.
|
||||
@@ -445,10 +468,11 @@ int os_close(const int fd)
|
||||
/// to false. Initial value is ignored.
|
||||
/// @param[out] ret_buf Buffer to write to. May be NULL if size is zero.
|
||||
/// @param[in] size Amount of bytes to read.
|
||||
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
|
||||
///
|
||||
/// @return Number of bytes read or libuv error code (< 0).
|
||||
ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
|
||||
const size_t size)
|
||||
ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf,
|
||||
const size_t size, const bool non_blocking)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
*ret_eof = false;
|
||||
@@ -468,7 +492,9 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
|
||||
if (cur_read_bytes < 0) {
|
||||
const int error = os_translate_sys_error(errno);
|
||||
errno = 0;
|
||||
if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
if (non_blocking && error == UV_EAGAIN) {
|
||||
break;
|
||||
} else if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
continue;
|
||||
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
||||
try_to_free_memory();
|
||||
@@ -498,7 +524,11 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
|
||||
/// may change, it is incorrect to use data it points to after
|
||||
/// os_readv().
|
||||
/// @param[in] iov_size Number of buffers in iov.
|
||||
ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
|
||||
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
|
||||
///
|
||||
/// @return Number of bytes read or libuv error code (< 0).
|
||||
ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov,
|
||||
size_t iov_size, const bool non_blocking)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
*ret_eof = false;
|
||||
@@ -531,7 +561,9 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
|
||||
} else if (cur_read_bytes < 0) {
|
||||
const int error = os_translate_sys_error(errno);
|
||||
errno = 0;
|
||||
if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
if (non_blocking && error == UV_EAGAIN) {
|
||||
break;
|
||||
} else if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
continue;
|
||||
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
||||
try_to_free_memory();
|
||||
@@ -551,9 +583,11 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
|
||||
/// @param[in] fd File descriptor to write to.
|
||||
/// @param[in] buf Data to write. May be NULL if size is zero.
|
||||
/// @param[in] size Amount of bytes to write.
|
||||
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
|
||||
///
|
||||
/// @return Number of bytes written or libuv error code (< 0).
|
||||
ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)
|
||||
ptrdiff_t os_write(const int fd, const char *const buf, const size_t size,
|
||||
const bool non_blocking)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (buf == NULL) {
|
||||
@@ -571,7 +605,9 @@ ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)
|
||||
if (cur_written_bytes < 0) {
|
||||
const int error = os_translate_sys_error(errno);
|
||||
errno = 0;
|
||||
if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
if (non_blocking && error == UV_EAGAIN) {
|
||||
break;
|
||||
} else if (error == UV_EINTR || error == UV_EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
return error;
|
||||
|
Reference in New Issue
Block a user