tty: implement binary I/O terminal mode
Introduce a uv_tty_mode_t enum for uv_tty_set_mode(), with backward compatible values. Add a new mode UV_TTY_MODE_IO, which uses cfmakeraw() internally. PR-URL: https://github.com/libuv/libuv/pull/86 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
751ac48baa
commit
025602da13
@ -16,6 +16,22 @@ Data types
|
||||
|
||||
TTY handle type.
|
||||
|
||||
.. c:type:: uv_tty_mode_t
|
||||
|
||||
TTY mode type:
|
||||
|
||||
::
|
||||
|
||||
typedef enum {
|
||||
/* Initial/normal terminal mode */
|
||||
UV_TTY_MODE_NORMAL,
|
||||
/* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
|
||||
UV_TTY_MODE_RAW,
|
||||
/* Binary-safe I/O mode for IPC (Unix-only) */
|
||||
UV_TTY_MODE_IO
|
||||
} uv_tty_mode_t;
|
||||
|
||||
|
||||
|
||||
Public members
|
||||
^^^^^^^^^^^^^^
|
||||
@ -43,9 +59,9 @@ API
|
||||
.. note::
|
||||
TTY streams which are not readable have blocking writes.
|
||||
|
||||
.. c:function:: int uv_tty_set_mode(uv_tty_t*, int mode)
|
||||
.. c:function:: int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode)
|
||||
|
||||
Set the TTY mode. 0 for normal, 1 for raw.
|
||||
Set the TTY using the specified terminal mode.
|
||||
|
||||
.. c:function:: int uv_tty_reset_mode(void)
|
||||
|
||||
|
||||
21
include/uv.h
21
include/uv.h
@ -628,11 +628,30 @@ struct uv_tty_s {
|
||||
UV_TTY_PRIVATE_FIELDS
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
/* Initial/normal terminal mode */
|
||||
UV_TTY_MODE_NORMAL,
|
||||
/* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
|
||||
UV_TTY_MODE_RAW,
|
||||
/* Binary-safe I/O mode for IPC (Unix-only) */
|
||||
UV_TTY_MODE_IO
|
||||
} uv_tty_mode_t;
|
||||
|
||||
UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
|
||||
UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode);
|
||||
UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
|
||||
UV_EXTERN int uv_tty_reset_mode(void);
|
||||
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
|
||||
return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
|
||||
|
||||
/*
|
||||
|
||||
@ -98,19 +98,19 @@ skip:
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = 0;
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
||||
struct termios raw;
|
||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
struct termios tmp;
|
||||
int fd;
|
||||
|
||||
fd = uv__stream_fd(tty);
|
||||
|
||||
if (mode && tty->mode == 0) { /* on */
|
||||
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
|
||||
if (tcgetattr(fd, &tty->orig_termios))
|
||||
return -errno;
|
||||
|
||||
@ -121,27 +121,30 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
||||
orig_termios_fd = fd;
|
||||
}
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
|
||||
raw = tty->orig_termios;
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
raw.c_oflag |= (ONLCR);
|
||||
raw.c_cflag |= (CS8);
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
raw.c_cc[VMIN] = 1;
|
||||
raw.c_cc[VTIME] = 0;
|
||||
|
||||
/* Put terminal in raw mode after draining */
|
||||
if (tcsetattr(fd, TCSADRAIN, &raw))
|
||||
return -errno;
|
||||
|
||||
tty->mode = 1;
|
||||
} else if (mode == 0 && tty->mode) { /* off */
|
||||
/* Put terminal in original mode after flushing */
|
||||
if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios))
|
||||
return -errno;
|
||||
tty->mode = 0;
|
||||
}
|
||||
|
||||
tmp = tty->orig_termios;
|
||||
switch (mode) {
|
||||
case UV_TTY_MODE_NORMAL:
|
||||
break;
|
||||
case UV_TTY_MODE_RAW:
|
||||
tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
tmp.c_oflag |= (ONLCR);
|
||||
tmp.c_cflag |= (CS8);
|
||||
tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
tmp.c_cc[VMIN] = 1;
|
||||
tmp.c_cc[VTIME] = 0;
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
cfmakeraw(&tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Apply changes after draining */
|
||||
if (tcsetattr(fd, TCSADRAIN, &tmp))
|
||||
return -errno;
|
||||
|
||||
tty->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -170,7 +170,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
DWORD flags;
|
||||
unsigned char was_reading;
|
||||
uv_alloc_cb alloc_cb;
|
||||
@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
/* Raw input */
|
||||
flags = ENABLE_WINDOW_INPUT;
|
||||
} else {
|
||||
/* Line-buffered mode. */
|
||||
switch (mode) {
|
||||
case UV_TTY_MODE_NORMAL:
|
||||
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||||
break;
|
||||
case UV_TTY_MODE_RAW:
|
||||
flags = ENABLE_WINDOW_INPUT;
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
if (!SetConsoleMode(tty->handle, flags)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user