15 #ifdef HAVE_SYS_IOCTL_H
16 #include <sys/ioctl.h>
19 #if defined HAVE_TERMIOS_H
21 typedef struct termios conmode;
24 setattr(
int fd, conmode *t)
26 while (tcsetattr(fd, TCSANOW, t)) {
31 # define getattr(fd, t) (tcgetattr(fd, t) == 0)
32 #elif defined HAVE_TERMIO_H
34 typedef struct termio conmode;
35 # define setattr(fd, t) (ioctl(fd, TCSETAF, t) == 0)
36 # define getattr(fd, t) (ioctl(fd, TCGETA, t) == 0)
37 #elif defined HAVE_SGTTY_H
39 typedef struct sgttyb conmode;
41 # define setattr(fd, t) (stty(fd, t) == 0)
43 # define setattr(fd, t) (ioctl((fd), TIOCSETP, (t)) == 0)
46 # define getattr(fd, t) (gtty(fd, t) == 0)
48 # define getattr(fd, t) (ioctl((fd), TIOCGETP, (t)) == 0)
53 typedef DWORD conmode;
55 #define LAST_ERROR rb_w32_map_errno(GetLastError())
56 #define SET_LAST_ERROR (errno = LAST_ERROR, 0)
59 setattr(
int fd, conmode *t)
62 if (!x)
errno = LAST_ERROR;
67 getattr(
int fd, conmode *t)
70 if (!x)
errno = LAST_ERROR;
74 #ifndef SET_LAST_ERROR
75 #define SET_LAST_ERROR (0)
78 static ID id_getc, id_console, id_close, id_min, id_time, id_intr;
83 #ifndef HAVE_RB_F_SEND
84 static ID id___send__;
120 if (!vopts) vopts =
Qnil;
162 set_rawmode(conmode *t,
void *
arg)
164 #ifdef HAVE_CFMAKERAW
166 t->c_lflag &= ~(ECHOE|ECHOK);
167 #elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
168 t->c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL);
169 t->c_oflag &= ~OPOST;
170 t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|XCASE);
171 t->c_cflag &= ~(CSIZE|PARENB);
175 #elif defined HAVE_SGTTY_H
176 t->sg_flags &= ~ECHO;
184 if (r->
vmin >= 0) t->c_cc[VMIN] = r->
vmin;
191 t->c_iflag |= BRKINT|IXON;
200 set_cookedmode(conmode *t,
void *
arg)
202 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
203 t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
205 t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN);
206 #elif defined HAVE_SGTTY_H
210 *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT;
215 set_noecho(conmode *t,
void *
arg)
217 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
218 t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
219 #elif defined HAVE_SGTTY_H
220 t->sg_flags &= ~ECHO;
222 *t &= ~ENABLE_ECHO_INPUT;
227 set_echo(conmode *t,
void *
arg)
229 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
230 t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
231 #elif defined HAVE_SGTTY_H
234 *t |= ENABLE_ECHO_INPUT;
241 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
242 return (t->c_lflag & (ECHO | ECHONL)) != 0;
243 #elif defined HAVE_SGTTY_H
244 return (t->sg_flags & ECHO) != 0;
246 return (*t & ENABLE_ECHO_INPUT) != 0;
251 set_ttymode(
int fd, conmode *t,
void (*setter)(conmode *,
void *),
void *
arg)
254 if (!getattr(fd, t))
return 0;
257 return setattr(fd, &r);
260 #define GetReadFD(fptr) ((fptr)->fd)
263 get_write_fd(
const rb_io_t *fptr)
267 if (!wio)
return fptr->
fd;
271 #define GetWriteFD(fptr) get_write_fd(fptr)
288 if (set_ttymode(fd[0], t+0, setter,
arg)) {
297 if (fd[1] != -1 && fd[1] != fd[0]) {
298 if (set_ttymode(fd[1], t+1, setter,
arg)) {
310 if (fd[0] != -1 && fd[0] ==
GetReadFD(fptr)) {
311 if (!setattr(fd[0], t+0)) {
316 if (fd[1] != -1 && fd[1] != fd[0] && fd[1] ==
GetWriteFD(fptr)) {
317 if (!setattr(fd[1], t+1)) {
339 ttymode_callback(
VALUE args)
352 return ttymode(
io, ttymode_callback, (
VALUE)&cargs, setter,
arg);
406 set_rawmode(&t, optp);
449 set_cookedmode(&t,
NULL);
498 return ttymode(
io, getc_call,
io, set_rawmode, optp);
513 tv.tv_usec = (optp->
vtime % 10) * 100000;
515 if (optp->
vmin != 1) {
524 rb_warning(
"vtime option ignored if intr flag is unset");
561 console_noecho(
VALUE io)
589 set_noecho(&t,
NULL);
603 console_echo_p(
VALUE io)
621 static VALUE cConmode;
663 set_rawmode(t, optp);
674 set_rawmode(&t, optp);
687 console_conmode_get(
VALUE io)
697 return conmode_new(cConmode, &t);
724 #if defined TIOCGWINSZ
725 typedef struct winsize rb_console_size_t;
726 #define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0)
727 #define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0)
728 #define winsize_row(buf) (buf)->ws_row
729 #define winsize_col(buf) (buf)->ws_col
731 typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
732 #define getwinsize(fd, buf) ( \
733 GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \
735 #define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1)
736 #define winsize_col(buf) (buf)->dwSize.X
739 #if defined TIOCGWINSZ || defined _WIN32
740 #define USE_CONSOLE_GETSIZE 1
743 #ifdef USE_CONSOLE_GETSIZE
753 console_winsize(
VALUE io)
757 rb_console_size_t ws;
778 rb_console_size_t ws;
784 VALUE row, col, xpixel, ypixel;
793 "wrong number of arguments (given %ld, expected 2 or 4)",
797 row = sz[0], col = sz[1], xpixel = ypixel =
Qnil;
798 if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
800 #if defined TIOCSWINSZ
801 ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
802 #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
811 #define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
817 if (!GetConsoleScreenBufferInfo(wh, &ws)) {
820 ws.dwSize.X = newcol;
821 ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
822 ws.srWindow.Left = 0;
824 ws.srWindow.Right = newcol-1;
825 ws.srWindow.Bottom = newrow-1;
826 if (!SetConsoleWindowInfo(wh,
TRUE, &ws.srWindow)) {
830 if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
834 if (!SetConsoleWindowInfo(wh,
TRUE, &ws.srWindow)) {
852 while (GetNumberOfConsoleInputEvents(
h, &num) && num > 0) {
854 if (ReadConsoleInput(
h, &rec, 1, &num)) {
855 if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
863 #define console_check_winsize_changed rb_f_notimplement
875 console_iflush(
VALUE io)
882 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
898 console_oflush(
VALUE io)
905 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
921 console_ioflush(
VALUE io)
924 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
929 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
932 if (fd2 != -1 && fd1 != fd2) {
944 console_beep(
VALUE io)
955 if (
write(fd,
"\a", 1) < 0)
962 mode_in_range(
VALUE val,
int high,
const char *modename)
965 if (
NIL_P(val))
return 0;
970 if ((mode =
NUM2INT(val)) < 0 || mode > high) {
995 console_cursor_pos(
VALUE io)
999 rb_console_size_t ws;
1010 console_move(
VALUE io,
int y,
int x)
1014 rb_console_size_t ws;
1015 COORD *pos = &ws.dwCursorPosition;
1019 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1024 if (!SetConsoleCursorPosition(
h, *pos)) {
1035 rb_console_size_t ws;
1036 COORD *pos = &ws.dwCursorPosition;
1040 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1044 if (!SetConsoleCursorPosition(
h, *pos)) {
1051 constat_clear(HANDLE handle, WORD attr,
DWORD len, COORD pos)
1055 FillConsoleOutputAttribute(handle, attr,
len, pos, &written);
1056 FillConsoleOutputCharacterW(handle,
L' ',
len, pos, &written);
1064 rb_console_size_t ws;
1065 COORD *pos = &ws.dwCursorPosition;
1067 int mode = mode_in_range(val, 2,
"line erase");
1071 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1074 w = winsize_col(&ws);
1087 constat_clear(
h, ws.wAttributes, w, *pos);
1096 rb_console_size_t ws;
1097 COORD *pos = &ws.dwCursorPosition;
1099 int mode = mode_in_range(val, 3,
"screen erase");
1103 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1106 w = winsize_col(&ws);
1109 w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
1112 w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
1114 pos->Y = ws.srWindow.Top;
1117 w = (w * winsize_row(&ws));
1119 pos->Y = ws.srWindow.Top;
1122 w = (w * ws.dwSize.Y);
1127 constat_clear(
h, ws.wAttributes, w, *pos);
1132 console_scroll(
VALUE io,
int line)
1136 rb_console_size_t ws;
1140 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1148 scroll.Top = line > 0 ? line : 0;
1149 scroll.Right = winsize_col(&ws) - 1;
1150 scroll.Bottom = winsize_row(&ws) - 1 + (line < 0 ? line : 0);
1152 destination.Y = line < 0 ? -line : 0;
1153 fill.Char.UnicodeChar =
L' ';
1154 fill.Attributes = ws.wAttributes;
1156 ScrollConsoleScreenBuffer(
h, &scroll,
NULL, destination, &fill);
1161 #include "win32_vk.inc"
1172 const struct vktable *t;
1182 if (!t || (vk = (
short)t->vk) == -1) {
1211 if (fptr->
fd == 0 &&
1228 if (!direct_query(io, qargs))
return Qnil;
1240 num = num * 10 + c -
'0';
1242 else if (
opt && c ==
opt) {
1260 VALUE ret = ttymode_with_io(io, read_vt_response, query, set_rawmode, optp);
1265 console_cursor_pos(
VALUE io)
1267 static const struct query_args query = {
"\033[6n", 0};
1268 VALUE resp = console_vt_response(0, 0, io, &query);
1293 console_move(
VALUE io,
int y,
int x)
1297 if (y)
rb_str_catf(s,
"\x1b[%d%c", y < 0 ? -y : y, y < 0 ?
'A' :
'B');
1298 if (x)
rb_str_catf(s,
"\x1b[%d%c", x < 0 ? -x : x, x < 0 ?
'D' :
'C');
1315 int mode = mode_in_range(val, 2,
"line erase");
1323 int mode = mode_in_range(val, 3,
"screen erase");
1329 console_scroll(
VALUE io,
int line)
1333 line < 0 ?
'T' :
'S');
1338 # define console_key_pressed_p rb_f_notimplement
1352 return console_move(io, -
NUM2INT(val), 0);
1358 return console_move(io, +
NUM2INT(val), 0);
1364 return console_move(io, 0, -
NUM2INT(val));
1370 return console_move(io, 0, +
NUM2INT(val));
1376 return console_scroll(io, +
NUM2INT(val));
1382 return console_scroll(io, -
NUM2INT(val));
1386 console_clear_screen(
VALUE io)
1388 console_erase_screen(io,
INT2FIX(2));
1438 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
1439 # define CONSOLE_DEVICE "/dev/tty"
1440 #elif defined _WIN32
1441 # define CONSOLE_DEVICE "con$"
1442 # define CONSOLE_DEVICE_FOR_READING "conin$"
1443 # define CONSOLE_DEVICE_FOR_WRITING "conout$"
1445 #ifndef CONSOLE_DEVICE_FOR_READING
1446 # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
1448 #ifdef CONSOLE_DEVICE_FOR_WRITING
1454 #ifdef CONSOLE_DEVICE_FOR_WRITING
1456 if (fd < 0)
return Qnil;
1464 #ifdef CONSOLE_DEVICE_FOR_WRITING
1475 #ifdef CONSOLE_DEVICE_FOR_WRITING
1502 #if ENABLE_IO_GETPASS
1510 getpass_call(
VALUE io)
1553 return str_chomp(
str);
1583 #if ENABLE_IO_GETPASS
1591 #ifndef HAVE_RB_F_SEND
1631 #if ENABLE_IO_GETPASS
1638 #if ENABLE_IO_GETPASS