mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
Reimplement input functions on top of libuv
The functions `mch_inchar`, `mch_breakcheck`, `mch_char_avail` were reimplemented on top of libuv. Here's how it works: - When Neovim needs to wait for characters, it will transfer control to libuv event loop. - When the libuv event loop gets user input, it will transfer control back to Neovim - Neovim uses the `input_read` function to get the actual data read by libuv. With this scheme its possible to keep Neovim single-threaded while enjoying the benefits provided by libuv. This commit leaves SIGWINCH broken for now
This commit is contained in:
parent
f8432ef127
commit
452804638d
74
src/os/event.c
Normal file
74
src/os/event.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include "os/event.h"
|
||||
#include "os/input.h"
|
||||
|
||||
static uv_timer_t timer_req;
|
||||
static void timer_cb(uv_timer_t *handle, int);
|
||||
|
||||
void event_init()
|
||||
{
|
||||
/* Initialize input events */
|
||||
input_init();
|
||||
/* Timer to wake the event loop if a timeout argument is passed to
|
||||
* `event_poll` */
|
||||
uv_timer_init(uv_default_loop(), &timer_req);
|
||||
}
|
||||
|
||||
/* Wait for some event */
|
||||
EventType event_poll(int32_t ms)
|
||||
{
|
||||
bool timed_out;
|
||||
EventType event;
|
||||
uv_run_mode run_mode = UV_RUN_ONCE;
|
||||
|
||||
if ((event = input_check()) != kEventNone) {
|
||||
/* If there's a pending input event to be consumed, do it now */
|
||||
return event;
|
||||
}
|
||||
|
||||
input_start();
|
||||
timed_out = false;
|
||||
|
||||
if (ms > 0) {
|
||||
/* Timeout passed as argument, start the libuv timer to wake us up and
|
||||
* set our local flag */
|
||||
timer_req.data = &timed_out;
|
||||
uv_timer_start(&timer_req, timer_cb, ms, 0);
|
||||
} 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 {
|
||||
/* Wait for some event */
|
||||
uv_run(uv_default_loop(), run_mode);
|
||||
} while (
|
||||
/* Continue running if ... */
|
||||
(event = input_check()) == kEventNone && /* ... we have no input */
|
||||
run_mode != UV_RUN_NOWAIT && /* ... ms != 0 */
|
||||
!timed_out /* ... we didn't get a timeout */
|
||||
);
|
||||
|
||||
input_stop();
|
||||
|
||||
if (!timed_out && ms > 0) {
|
||||
/* Timer event did not trigger, stop the watcher since we no longer
|
||||
* care about it */
|
||||
uv_timer_stop(&timer_req);
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/* Set a flag in the `event_poll` loop for signaling of a timeout */
|
||||
static void timer_cb(uv_timer_t *handle, int status)
|
||||
{
|
||||
*((bool *)handle->data) = true;
|
||||
}
|
16
src/os/event.h
Normal file
16
src/os/event.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef NEOVIM_OS_EVENT_H
|
||||
#define NEOVIM_OS_EVENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
kEventNone,
|
||||
kEventInput,
|
||||
kEventEof
|
||||
} EventType;
|
||||
|
||||
void event_init(void);
|
||||
EventType event_poll(int32_t ms);
|
||||
|
||||
#endif
|
||||
|
272
src/os/input.c
Normal file
272
src/os/input.c
Normal file
@ -0,0 +1,272 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include "os/input.h"
|
||||
#include "os/event.h"
|
||||
#include "vim.h"
|
||||
#include "globals.h"
|
||||
#include "ui.h"
|
||||
#include "types.h"
|
||||
#include "fileio.h"
|
||||
#include "getchar.h"
|
||||
#include "term.h"
|
||||
#include "misc2.h"
|
||||
|
||||
#define READ_BUFFER_LENGTH 4096
|
||||
|
||||
typedef struct {
|
||||
uv_buf_t uvbuf;
|
||||
uint32_t rpos, wpos, fpos;
|
||||
char_u data[READ_BUFFER_LENGTH];
|
||||
bool reading;
|
||||
} ReadBuffer;
|
||||
|
||||
static ReadBuffer rbuffer;
|
||||
static uv_pipe_t read_stream;
|
||||
/* Use an idle handle to make reading from the fs look like a normal libuv
|
||||
* event */
|
||||
static uv_idle_t fread_idle;
|
||||
static uv_handle_type read_channel_type;
|
||||
static bool eof = false;
|
||||
|
||||
static EventType inbuf_poll(int32_t ms);
|
||||
static void stderr_switch(void);
|
||||
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 *, int);
|
||||
|
||||
void input_init()
|
||||
{
|
||||
rbuffer.wpos = rbuffer.rpos = rbuffer.fpos = 0;
|
||||
#ifdef DEBUG
|
||||
memset(&rbuffer.data, 0, READ_BUFFER_LENGTH);
|
||||
#endif
|
||||
|
||||
if ((read_channel_type = uv_guess_handle(read_cmd_fd)) == UV_FILE) {
|
||||
uv_idle_init(uv_default_loop(), &fread_idle);
|
||||
} else {
|
||||
uv_pipe_init(uv_default_loop(), &read_stream, 0);
|
||||
uv_pipe_open(&read_stream, read_cmd_fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there's a pending input event */
|
||||
EventType input_check()
|
||||
{
|
||||
if (rbuffer.rpos < rbuffer.wpos) {
|
||||
return kEventInput;
|
||||
}
|
||||
|
||||
if (eof) {
|
||||
return kEventEof;
|
||||
}
|
||||
|
||||
return kEventNone;
|
||||
}
|
||||
|
||||
/* Listen for input */
|
||||
void input_start()
|
||||
{
|
||||
/* Pin the buffer used by libuv */
|
||||
rbuffer.uvbuf.len = READ_BUFFER_LENGTH - rbuffer.wpos;
|
||||
rbuffer.uvbuf.base = (char *)(rbuffer.data + rbuffer.wpos);
|
||||
|
||||
if (read_channel_type == UV_FILE) {
|
||||
/* Just invoke the `fread_idle_cb` as soon as there are no pending events */
|
||||
uv_idle_start(&fread_idle, fread_idle_cb);
|
||||
} else {
|
||||
/* Start reading */
|
||||
rbuffer.reading = false;
|
||||
uv_read_start((uv_stream_t *)&read_stream, alloc_cb, read_cb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop listening for input */
|
||||
void input_stop()
|
||||
{
|
||||
if (read_channel_type == UV_FILE) {
|
||||
uv_idle_stop(&fread_idle);
|
||||
} else {
|
||||
uv_read_stop((uv_stream_t *)&read_stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copies (at most `count`) of was read from `read_cmd_fd` into `buf` */
|
||||
uint32_t input_read(char *buf, uint32_t count)
|
||||
{
|
||||
uint32_t read_count = rbuffer.wpos - rbuffer.rpos;
|
||||
|
||||
if (count < read_count) {
|
||||
read_count = count;
|
||||
}
|
||||
|
||||
if (read_count > 0) {
|
||||
memcpy(buf, rbuffer.data + rbuffer.rpos, read_count);
|
||||
rbuffer.rpos += read_count;
|
||||
}
|
||||
|
||||
if (rbuffer.wpos == READ_BUFFER_LENGTH) {
|
||||
/* `wpos` is at the end of the buffer, so free some space by moving unread
|
||||
* data... */
|
||||
memmove(
|
||||
rbuffer.data,/* ...To the beginning of the buffer(rpos 0) */
|
||||
rbuffer.data + rbuffer.rpos,/* ...From the first unread position */
|
||||
rbuffer.wpos - rbuffer.rpos/* ...By the number of unread bytes */
|
||||
);
|
||||
rbuffer.wpos -= rbuffer.rpos;
|
||||
rbuffer.rpos = 0;
|
||||
}
|
||||
|
||||
return read_count;
|
||||
}
|
||||
|
||||
|
||||
/* Low level input function. */
|
||||
int mch_inchar(char_u *buf, int maxlen, long ms, int tb_change_cnt)
|
||||
{
|
||||
EventType result;
|
||||
|
||||
if (ms >= 0) {
|
||||
if ((result = inbuf_poll(ms)) != kEventInput) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if ((result = inbuf_poll(p_ut)) != kEventInput) {
|
||||
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 input was put directly in typeahead buffer bail out here. */
|
||||
if (typebuf_changed(tb_change_cnt))
|
||||
return 0;
|
||||
|
||||
if (result == kEventEof) {
|
||||
read_error_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return read_from_input_buf(buf, (long)maxlen);
|
||||
}
|
||||
|
||||
/* Check if a character is available for reading */
|
||||
bool mch_char_avail()
|
||||
{
|
||||
return inbuf_poll(0) == kEventInput;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for CTRL-C typed by reading all available characters.
|
||||
* In cooked mode we should get SIGINT, no need to check.
|
||||
*/
|
||||
void mch_breakcheck()
|
||||
{
|
||||
if (curr_tmode == TMODE_RAW && event_poll(0) == kEventInput)
|
||||
fill_input_buf(FALSE);
|
||||
}
|
||||
|
||||
/* This is a replacement for the old `WaitForChar` function in os_unix.c */
|
||||
static EventType inbuf_poll(int32_t ms)
|
||||
{
|
||||
if (input_available())
|
||||
return kEventInput;
|
||||
|
||||
return event_poll(ms);
|
||||
}
|
||||
|
||||
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 */
|
||||
uv_idle_stop(&fread_idle);
|
||||
/* Use stderr for stdin, also works for shell commands. */
|
||||
read_cmd_fd = 2;
|
||||
/* Initialize and start the input stream */
|
||||
uv_pipe_init(uv_default_loop(), &read_stream, 0);
|
||||
uv_pipe_open(&read_stream, read_cmd_fd);
|
||||
uv_read_start((uv_stream_t *)&read_stream, alloc_cb, read_cb);
|
||||
rbuffer.reading = false;
|
||||
/* Set the mode back to what it was */
|
||||
settmode(mode);
|
||||
}
|
||||
|
||||
/* Called by libuv to allocate memory for reading. */
|
||||
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
|
||||
{
|
||||
if (rbuffer.reading) {
|
||||
buf->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
buf->base = rbuffer.uvbuf.base;
|
||||
buf->len = rbuffer.uvbuf.len;
|
||||
/* Avoid `alloc_cb`, `alloc_cb` sequences on windows */
|
||||
rbuffer.reading = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback invoked by libuv after it copies the data into the buffer provided
|
||||
* by `alloc_cb`. This is also called on EOF or when `alloc_cb` returns a
|
||||
* 0-length buffer.
|
||||
*/
|
||||
static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
|
||||
{
|
||||
if (cnt <= 0) {
|
||||
if (cnt != UV_ENOBUFS) {
|
||||
/* Read error or EOF, either way vim must exit */
|
||||
eof = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Data was already written, so all we need is to update 'wpos' to reflect
|
||||
* the space actually used in the buffer. */
|
||||
rbuffer.wpos += cnt;
|
||||
}
|
||||
|
||||
/* Called by the by the 'idle' handle to emulate a reading event */
|
||||
static void fread_idle_cb(uv_idle_t *handle, int status)
|
||||
{
|
||||
uv_fs_t req;
|
||||
|
||||
/* Synchronous read */
|
||||
uv_fs_read(
|
||||
uv_default_loop(),
|
||||
&req,
|
||||
read_cmd_fd,
|
||||
&rbuffer.uvbuf,
|
||||
1,
|
||||
rbuffer.fpos,
|
||||
NULL
|
||||
);
|
||||
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
if (req.result <= 0) {
|
||||
if (rbuffer.fpos == 0 && uv_guess_handle(2) == UV_TTY) {
|
||||
/* 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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rbuffer.wpos += req.result;
|
||||
rbuffer.fpos += req.result;
|
||||
}
|
20
src/os/input.h
Normal file
20
src/os/input.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef NEOVIM_OS_INPUT_H
|
||||
#define NEOVIM_OS_INPUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "os/event.h"
|
||||
#include "types.h"
|
||||
|
||||
void input_init(void);
|
||||
EventType input_check(void);
|
||||
void input_start(void);
|
||||
void input_stop(void);
|
||||
uint32_t input_read(char *buf, uint32_t count);
|
||||
int mch_inchar(char_u *, int, long, int);
|
||||
bool mch_char_avail(void);
|
||||
void mch_breakcheck(void);
|
||||
|
||||
#endif
|
||||
|
129
src/os_unix.c
129
src/os_unix.c
@ -31,7 +31,6 @@
|
||||
|
||||
#include "vim.h"
|
||||
#include "os_unix.h"
|
||||
#include "os/time.h"
|
||||
#include "buffer.h"
|
||||
#include "charset.h"
|
||||
#include "eval.h"
|
||||
@ -51,6 +50,8 @@
|
||||
#include "ui.h"
|
||||
#include "os/os.h"
|
||||
#include "os/time.h"
|
||||
#include "os/event.h"
|
||||
#include "os/input.h"
|
||||
|
||||
#include "os_unixx.h" /* unix includes for os_unix.c only */
|
||||
|
||||
@ -108,7 +109,6 @@ typedef int waitstatus;
|
||||
#endif
|
||||
static pid_t wait4pid(pid_t, waitstatus *);
|
||||
|
||||
static int WaitForChar(long);
|
||||
static int RealWaitForChar(int, long, int *);
|
||||
|
||||
|
||||
@ -248,98 +248,12 @@ void mch_write(char_u *s, int len)
|
||||
RealWaitForChar(read_cmd_fd, p_wd, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* mch_inchar(): low level input function.
|
||||
* Get a characters from the keyboard.
|
||||
* Return the number of characters that are available.
|
||||
* If wtime == 0 do not wait for characters.
|
||||
* If wtime == n wait a short time for characters.
|
||||
* If wtime == -1 wait forever for characters.
|
||||
*/
|
||||
int mch_inchar(
|
||||
char_u *buf,
|
||||
int maxlen,
|
||||
long wtime, /* don't use "time", MIPS cannot handle it */
|
||||
int tb_change_cnt
|
||||
)
|
||||
{
|
||||
int len;
|
||||
|
||||
|
||||
/* Check if window changed size while we were busy, perhaps the ":set
|
||||
* columns=99" command was used. */
|
||||
while (do_resize)
|
||||
handle_resize();
|
||||
|
||||
if (wtime >= 0) {
|
||||
while (WaitForChar(wtime) == 0) { /* no character available */
|
||||
if (!do_resize) /* return if not interrupted by resize */
|
||||
return 0;
|
||||
handle_resize();
|
||||
}
|
||||
} else { /* wtime == -1 */
|
||||
/*
|
||||
* If there is no character available within 'updatetime' seconds
|
||||
* flush all the swap files to disk.
|
||||
* Also done when interrupted by SIGWINCH.
|
||||
*/
|
||||
if (WaitForChar(p_ut) == 0) {
|
||||
if (trigger_cursorhold() && maxlen >= 3
|
||||
&& !typebuf_changed(tb_change_cnt)) {
|
||||
buf[0] = K_SPECIAL;
|
||||
buf[1] = KS_EXTRA;
|
||||
buf[2] = (int)KE_CURSORHOLD;
|
||||
return 3;
|
||||
}
|
||||
before_blocking();
|
||||
}
|
||||
}
|
||||
|
||||
for (;; ) { /* repeat until we got a character */
|
||||
while (do_resize) /* window changed size */
|
||||
handle_resize();
|
||||
|
||||
/*
|
||||
* We want to be interrupted by the winch signal
|
||||
* or by an event on the monitored file descriptors.
|
||||
*/
|
||||
if (WaitForChar(-1L) == 0) {
|
||||
if (do_resize) /* interrupted by SIGWINCH signal */
|
||||
handle_resize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If input was put directly in typeahead buffer bail out here. */
|
||||
if (typebuf_changed(tb_change_cnt))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For some terminals we only get one character at a time.
|
||||
* We want the get all available characters, so we could keep on
|
||||
* trying until none is available
|
||||
* For some other terminals this is quite slow, that's why we don't do
|
||||
* it.
|
||||
*/
|
||||
len = read_from_input_buf(buf, (long)maxlen);
|
||||
if (len > 0) {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_resize()
|
||||
{
|
||||
do_resize = FALSE;
|
||||
shell_resized();
|
||||
}
|
||||
|
||||
/*
|
||||
* return non-zero if a character is available
|
||||
*/
|
||||
int mch_char_avail()
|
||||
{
|
||||
return WaitForChar(0L);
|
||||
}
|
||||
|
||||
#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
|
||||
/*
|
||||
@ -682,6 +596,8 @@ void mch_init()
|
||||
#ifdef MACOS_CONVERT
|
||||
mac_conv_init();
|
||||
#endif
|
||||
|
||||
event_init();
|
||||
}
|
||||
|
||||
static void set_signals()
|
||||
@ -2460,43 +2376,6 @@ error:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for CTRL-C typed by reading all available characters.
|
||||
* In cooked mode we should get SIGINT, no need to check.
|
||||
*/
|
||||
void mch_breakcheck()
|
||||
{
|
||||
if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
|
||||
fill_input_buf(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait "msec" msec until a character is available from the keyboard or from
|
||||
* inbuf[]. msec == -1 will block forever.
|
||||
* When a GUI is being used, this will never get called -- webb
|
||||
*/
|
||||
static int WaitForChar(msec)
|
||||
long msec;
|
||||
{
|
||||
int avail;
|
||||
|
||||
if (input_available()) /* something in inbuf[] */
|
||||
return 1;
|
||||
|
||||
/* May need to query the mouse position. */
|
||||
if (WantQueryMouse) {
|
||||
WantQueryMouse = FALSE;
|
||||
mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
|
||||
}
|
||||
|
||||
/*
|
||||
* For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
|
||||
* events. This is a bit complicated, because they might both be defined.
|
||||
*/
|
||||
avail = RealWaitForChar(read_cmd_fd, msec, NULL);
|
||||
return avail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait "msec" msec until a character is available from file descriptor "fd".
|
||||
* "msec" == 0 will check for characters once.
|
||||
|
@ -2,8 +2,6 @@
|
||||
#define NEOVIM_OS_UNIX_H
|
||||
/* os_unix.c */
|
||||
void mch_write(char_u *s, int len);
|
||||
int mch_inchar(char_u *buf, int maxlen, long wtime, int tb_change_cnt);
|
||||
int mch_char_avail(void);
|
||||
void mch_startjmp(void);
|
||||
void mch_endjmp(void);
|
||||
void mch_didjmp(void);
|
||||
@ -45,7 +43,6 @@ int mch_get_shellsize(void);
|
||||
void mch_set_shellsize(void);
|
||||
void mch_new_shellsize(void);
|
||||
int mch_call_shell(char_u *cmd, int options);
|
||||
void mch_breakcheck(void);
|
||||
int mch_expandpath(garray_T *gap, char_u *path, int flags);
|
||||
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
|
||||
char_u ***file,
|
||||
|
32
src/ui.c
32
src/ui.c
@ -33,6 +33,7 @@
|
||||
#include "option.h"
|
||||
#include "os_unix.h"
|
||||
#include "os/time.h"
|
||||
#include "os/input.h"
|
||||
#include "screen.h"
|
||||
#include "term.h"
|
||||
#include "window.h"
|
||||
@ -475,7 +476,6 @@ void fill_input_buf(int exit_on_error)
|
||||
#if defined(UNIX) || defined(OS2) || defined(VMS) || defined(MACOS_X_UNIX)
|
||||
int len;
|
||||
int try;
|
||||
static int did_read_something = FALSE;
|
||||
static char_u *rest = NULL; /* unconverted rest of previous read */
|
||||
static int restlen = 0;
|
||||
int unconverted;
|
||||
@ -513,40 +513,20 @@ void fill_input_buf(int exit_on_error)
|
||||
|
||||
len = 0; /* to avoid gcc warning */
|
||||
for (try = 0; try < 100; ++try) {
|
||||
len = read(read_cmd_fd,
|
||||
(char *)inbuf + inbufcount, (size_t)((INBUFLEN - inbufcount)
|
||||
/ input_conv.vc_factor
|
||||
));
|
||||
len = input_read(
|
||||
(char *)inbuf + inbufcount,
|
||||
(size_t)((INBUFLEN - inbufcount) / input_conv.vc_factor));
|
||||
|
||||
if (len > 0 || got_int)
|
||||
break;
|
||||
/*
|
||||
* If reading stdin results in an error, continue reading stderr.
|
||||
* This helps when using "foo | xargs vim".
|
||||
*/
|
||||
if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0) {
|
||||
int m = cur_tmode;
|
||||
|
||||
/* We probably set the wrong file descriptor to raw mode. Switch
|
||||
* back to cooked mode, use another descriptor and set the mode to
|
||||
* what it was. */
|
||||
settmode(TMODE_COOK);
|
||||
#ifdef HAVE_DUP
|
||||
/* Use stderr for stdin, also works for shell commands. */
|
||||
close(0);
|
||||
ignored = dup(2);
|
||||
#else
|
||||
read_cmd_fd = 2; /* read from stderr instead of stdin */
|
||||
#endif
|
||||
settmode(m);
|
||||
}
|
||||
if (!exit_on_error)
|
||||
return;
|
||||
}
|
||||
|
||||
if (len <= 0 && !got_int)
|
||||
read_error_exit();
|
||||
if (len > 0)
|
||||
did_read_something = TRUE;
|
||||
|
||||
if (got_int) {
|
||||
/* Interrupted, pretend a CTRL-C was typed. */
|
||||
inbuf[0] = 3;
|
||||
|
Loading…
Reference in New Issue
Block a user