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__;
114 #ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
123 if (!vopts) vopts =
Qnil;
166 set_rawmode(conmode *t,
void *
arg)
168 #ifdef HAVE_CFMAKERAW
170 t->c_lflag &= ~(ECHOE|ECHOK);
171 #elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
172 t->c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL);
173 t->c_oflag &= ~OPOST;
174 t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|XCASE);
175 t->c_cflag &= ~(CSIZE|PARENB);
179 #elif defined HAVE_SGTTY_H
180 t->sg_flags &= ~ECHO;
188 if (r->
vmin >= 0) t->c_cc[VMIN] = r->
vmin;
195 t->c_iflag |= BRKINT;
205 set_cookedmode(conmode *t,
void *
arg)
207 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
208 t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
210 t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN);
211 #elif defined HAVE_SGTTY_H
215 *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT;
220 set_noecho(conmode *t,
void *
arg)
222 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
223 t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
224 #elif defined HAVE_SGTTY_H
225 t->sg_flags &= ~ECHO;
227 *t &= ~ENABLE_ECHO_INPUT;
232 set_echo(conmode *t,
void *
arg)
234 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
235 t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
236 #elif defined HAVE_SGTTY_H
239 *t |= ENABLE_ECHO_INPUT;
246 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
247 return (t->c_lflag & (ECHO | ECHONL)) != 0;
248 #elif defined HAVE_SGTTY_H
249 return (t->sg_flags & ECHO) != 0;
251 return (*t & ENABLE_ECHO_INPUT) != 0;
256 set_ttymode(
int fd, conmode *t,
void (*setter)(conmode *,
void *),
void *
arg)
259 if (!getattr(fd, t))
return 0;
262 return setattr(fd, &r);
265 #define GetReadFD(fptr) ((fptr)->fd)
268 get_write_fd(
const rb_io_t *fptr)
272 if (!wio)
return fptr->
fd;
276 #define GetWriteFD(fptr) get_write_fd(fptr)
293 if (set_ttymode(fd[0], t+0, setter,
arg)) {
302 if (fd[1] != -1 && fd[1] != fd[0]) {
303 if (set_ttymode(fd[1], t+1, setter,
arg)) {
315 if (fd[0] != -1 && fd[0] ==
GetReadFD(fptr)) {
316 if (!setattr(fd[0], t+0)) {
321 if (fd[1] != -1 && fd[1] != fd[0] && fd[1] ==
GetWriteFD(fptr)) {
322 if (!setattr(fd[1], t+1)) {
344 ttymode_callback(
VALUE args)
357 return ttymode(
io, ttymode_callback, (
VALUE)&cargs, setter,
arg);
414 set_rawmode(&t, optp);
457 set_cookedmode(&t,
NULL);
506 return ttymode(
io, getc_call,
io, set_rawmode, optp);
521 tv.tv_usec = (optp->
vtime % 10) * 100000;
523 if (optp->
vmin != 1) {
532 rb_warning(
"vtime option ignored if intr flag is unset");
569 console_noecho(
VALUE io)
597 set_noecho(&t,
NULL);
611 console_echo_p(
VALUE io)
629 static VALUE cConmode;
671 set_rawmode(t, optp);
682 set_rawmode(&t, optp);
695 console_conmode_get(
VALUE io)
705 return conmode_new(cConmode, &t);
732 #if defined TIOCGWINSZ
733 typedef struct winsize rb_console_size_t;
734 #define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0)
735 #define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0)
736 #define winsize_row(buf) (buf)->ws_row
737 #define winsize_col(buf) (buf)->ws_col
739 typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
740 #define getwinsize(fd, buf) ( \
741 GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \
743 #define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1)
744 #define winsize_col(buf) (buf)->dwSize.X
747 #if defined TIOCGWINSZ || defined _WIN32
748 #define USE_CONSOLE_GETSIZE 1
751 #ifdef USE_CONSOLE_GETSIZE
761 console_winsize(
VALUE io)
765 rb_console_size_t ws;
786 rb_console_size_t ws;
792 VALUE row, col, xpixel, ypixel;
801 "wrong number of arguments (given %ld, expected 2 or 4)",
805 row = sz[0], col = sz[1], xpixel = ypixel =
Qnil;
806 if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
808 #if defined TIOCSWINSZ
809 ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
810 #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
819 #define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
825 if (!GetConsoleScreenBufferInfo(wh, &ws)) {
828 ws.dwSize.X = newcol;
829 ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
830 ws.srWindow.Left = 0;
832 ws.srWindow.Right = newcol-1;
833 ws.srWindow.Bottom = newrow-1;
834 if (!SetConsoleWindowInfo(wh,
TRUE, &ws.srWindow)) {
838 if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
842 if (!SetConsoleWindowInfo(wh,
TRUE, &ws.srWindow)) {
860 while (GetNumberOfConsoleInputEvents(
h, &num) && num > 0) {
862 if (ReadConsoleInput(
h, &rec, 1, &num)) {
863 if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
871 #define console_check_winsize_changed rb_f_notimplement
883 console_iflush(
VALUE io)
890 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
906 console_oflush(
VALUE io)
913 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
929 console_ioflush(
VALUE io)
932 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
937 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
940 if (fd2 != -1 && fd1 != fd2) {
952 console_beep(
VALUE io)
963 if (
write(fd,
"\a", 1) < 0)
970 mode_in_range(
VALUE val,
int high,
const char *modename)
973 if (
NIL_P(val))
return 0;
978 if ((mode =
NUM2INT(val)) < 0 || mode > high) {
1003 console_cursor_pos(
VALUE io)
1007 rb_console_size_t ws;
1018 console_move(
VALUE io,
int y,
int x)
1022 rb_console_size_t ws;
1023 COORD *pos = &ws.dwCursorPosition;
1027 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1032 if (!SetConsoleCursorPosition(
h, *pos)) {
1043 rb_console_size_t ws;
1044 COORD *pos = &ws.dwCursorPosition;
1048 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1052 if (!SetConsoleCursorPosition(
h, *pos)) {
1059 constat_clear(HANDLE handle, WORD attr,
DWORD len, COORD pos)
1063 FillConsoleOutputAttribute(handle, attr,
len, pos, &written);
1064 FillConsoleOutputCharacterW(handle,
L' ',
len, pos, &written);
1072 rb_console_size_t ws;
1073 COORD *pos = &ws.dwCursorPosition;
1075 int mode = mode_in_range(val, 2,
"line erase");
1079 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1082 w = winsize_col(&ws);
1095 constat_clear(
h, ws.wAttributes, w, *pos);
1104 rb_console_size_t ws;
1105 COORD *pos = &ws.dwCursorPosition;
1107 int mode = mode_in_range(val, 3,
"screen erase");
1111 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1114 w = winsize_col(&ws);
1117 w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
1120 w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
1122 pos->Y = ws.srWindow.Top;
1125 w = (w * winsize_row(&ws));
1127 pos->Y = ws.srWindow.Top;
1130 w = (w * ws.dwSize.Y);
1135 constat_clear(
h, ws.wAttributes, w, *pos);
1140 console_scroll(
VALUE io,
int line)
1144 rb_console_size_t ws;
1148 if (!GetConsoleScreenBufferInfo(
h, &ws)) {
1156 scroll.Top = line > 0 ? line : 0;
1157 scroll.Right = winsize_col(&ws) - 1;
1158 scroll.Bottom = winsize_row(&ws) - 1 + (line < 0 ? line : 0);
1160 destination.Y = line < 0 ? -line : 0;
1161 fill.Char.UnicodeChar =
L' ';
1162 fill.Attributes = ws.wAttributes;
1164 ScrollConsoleScreenBuffer(
h, &scroll,
NULL, destination, &fill);
1169 #include "win32_vk.inc"
1180 const struct vktable *t;
1190 if (!t || (vk = (
short)t->vk) == -1) {
1219 if (fptr->
fd == 0 &&
1236 if (!direct_query(io, qargs))
return Qnil;
1248 num = num * 10 + c -
'0';
1250 else if (
opt && c ==
opt) {
1268 VALUE ret = ttymode_with_io(io, read_vt_response, query, set_rawmode, optp);
1273 console_cursor_pos(
VALUE io)
1275 static const struct query_args query = {
"\033[6n", 0};
1276 VALUE resp = console_vt_response(0, 0, io, &query);
1301 console_move(
VALUE io,
int y,
int x)
1305 if (y)
rb_str_catf(s,
"\x1b[%d%c", y < 0 ? -y : y, y < 0 ?
'A' :
'B');
1306 if (x)
rb_str_catf(s,
"\x1b[%d%c", x < 0 ? -x : x, x < 0 ?
'D' :
'C');
1323 int mode = mode_in_range(val, 2,
"line erase");
1331 int mode = mode_in_range(val, 3,
"screen erase");
1337 console_scroll(
VALUE io,
int line)
1341 line < 0 ?
'T' :
'S');
1346 # define console_key_pressed_p rb_f_notimplement
1360 return console_move(io, -
NUM2INT(val), 0);
1366 return console_move(io, +
NUM2INT(val), 0);
1372 return console_move(io, 0, -
NUM2INT(val));
1378 return console_move(io, 0, +
NUM2INT(val));
1384 return console_scroll(io, +
NUM2INT(val));
1390 return console_scroll(io, -
NUM2INT(val));
1394 console_clear_screen(
VALUE io)
1396 console_erase_screen(io,
INT2FIX(2));
1446 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
1447 # define CONSOLE_DEVICE "/dev/tty"
1448 #elif defined _WIN32
1449 # define CONSOLE_DEVICE "con$"
1450 # define CONSOLE_DEVICE_FOR_READING "conin$"
1451 # define CONSOLE_DEVICE_FOR_WRITING "conout$"
1453 #ifndef CONSOLE_DEVICE_FOR_READING
1454 # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
1456 #ifdef CONSOLE_DEVICE_FOR_WRITING
1462 #ifdef CONSOLE_DEVICE_FOR_WRITING
1464 if (fd < 0)
return Qnil;
1472 #ifdef CONSOLE_DEVICE_FOR_WRITING
1483 #ifdef CONSOLE_DEVICE_FOR_WRITING
1510 #if ENABLE_IO_GETPASS
1518 getpass_call(
VALUE io)
1561 return str_chomp(
str);
1591 #if ENABLE_IO_GETPASS
1599 #ifndef HAVE_RB_F_SEND
1639 #if ENABLE_IO_GETPASS
1646 #if ENABLE_IO_GETPASS