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:
Yuri D'Elia 2014-12-27 13:19:27 +01:00 committed by Ben Noordhuis
parent 751ac48baa
commit 025602da13
4 changed files with 74 additions and 33 deletions

View File

@ -16,6 +16,22 @@ Data types
TTY handle type. 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 Public members
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
@ -43,9 +59,9 @@ API
.. note:: .. note::
TTY streams which are not readable have blocking writes. 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) .. c:function:: int uv_tty_reset_mode(void)

View File

@ -628,11 +628,30 @@ struct uv_tty_s {
UV_TTY_PRIVATE_FIELDS 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_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_reset_mode(void);
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); 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); UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
/* /*

View File

@ -98,19 +98,19 @@ skip:
uv__nonblock(fd, 1); uv__nonblock(fd, 1);
uv__stream_open((uv_stream_t*) tty, fd, flags); uv__stream_open((uv_stream_t*) tty, fd, flags);
tty->mode = 0; tty->mode = UV_TTY_MODE_NORMAL;
return 0; return 0;
} }
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) {
struct termios raw; struct termios tmp;
int fd; int fd;
fd = uv__stream_fd(tty); 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)) if (tcgetattr(fd, &tty->orig_termios))
return -errno; return -errno;
@ -121,27 +121,30 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
orig_termios_fd = fd; orig_termios_fd = fd;
} }
uv_spinlock_unlock(&termios_spinlock); 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; return 0;
} }

View File

@ -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; DWORD flags;
unsigned char was_reading; unsigned char was_reading;
uv_alloc_cb alloc_cb; uv_alloc_cb alloc_cb;
@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
return 0; return 0;
} }
if (mode) { switch (mode) {
/* Raw input */ case UV_TTY_MODE_NORMAL:
flags = ENABLE_WINDOW_INPUT; flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
} else { break;
/* Line-buffered mode. */ case UV_TTY_MODE_RAW:
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; flags = ENABLE_WINDOW_INPUT;
break;
case UV_TTY_MODE_IO:
return UV_ENOTSUP;
} }
if (!SetConsoleMode(tty->handle, flags)) { if (!SetConsoleMode(tty->handle, flags)) {