io-console 0.6.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.document +5 -0
- data/{LICENSE.txt → BSDL} +3 -3
- data/COPYING +56 -0
- data/ext/io/console/console.c +597 -349
- data/ext/io/console/extconf.rb +25 -2
- data/ext/io/console/win32_vk.inc +162 -163
- metadata +7 -7
data/ext/io/console/console.c
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
/*
|
3
3
|
* console IO module
|
4
4
|
*/
|
5
|
+
|
6
|
+
static const char *const
|
7
|
+
IO_CONSOLE_VERSION = "0.8.1";
|
8
|
+
|
5
9
|
#include "ruby.h"
|
6
10
|
#include "ruby/io.h"
|
7
11
|
#include "ruby/thread.h"
|
@@ -75,9 +79,14 @@ getattr(int fd, conmode *t)
|
|
75
79
|
#define SET_LAST_ERROR (0)
|
76
80
|
#endif
|
77
81
|
|
78
|
-
|
79
|
-
|
80
|
-
static ID
|
82
|
+
#define CSI "\x1b\x5b"
|
83
|
+
|
84
|
+
static ID id_getc, id_close;
|
85
|
+
static ID id_gets, id_flush, id_chomp_bang;
|
86
|
+
|
87
|
+
#ifndef HAVE_RB_INTERNED_STR_CSTR
|
88
|
+
# define rb_str_to_interned_str(str) rb_str_freeze(str)
|
89
|
+
# define rb_interned_str_cstr(str) rb_str_freeze(rb_usascii_str_new_cstr(str))
|
81
90
|
#endif
|
82
91
|
|
83
92
|
#if defined HAVE_RUBY_FIBER_SCHEDULER_H
|
@@ -87,7 +96,48 @@ extern VALUE rb_scheduler_timeout(struct timeval *timeout);
|
|
87
96
|
# define rb_fiber_scheduler_make_timeout rb_scheduler_timeout
|
88
97
|
#endif
|
89
98
|
|
90
|
-
#
|
99
|
+
#ifndef HAVE_RB_IO_DESCRIPTOR
|
100
|
+
static int
|
101
|
+
io_descriptor_fallback(VALUE io)
|
102
|
+
{
|
103
|
+
rb_io_t *fptr;
|
104
|
+
GetOpenFile(io, fptr);
|
105
|
+
return fptr->fd;
|
106
|
+
}
|
107
|
+
#define rb_io_descriptor io_descriptor_fallback
|
108
|
+
#endif
|
109
|
+
|
110
|
+
#ifndef HAVE_RB_IO_PATH
|
111
|
+
static VALUE
|
112
|
+
io_path_fallback(VALUE io)
|
113
|
+
{
|
114
|
+
rb_io_t *fptr;
|
115
|
+
GetOpenFile(io, fptr);
|
116
|
+
return fptr->pathv;
|
117
|
+
}
|
118
|
+
#define rb_io_path io_path_fallback
|
119
|
+
#endif
|
120
|
+
|
121
|
+
#ifndef HAVE_RB_IO_GET_WRITE_IO
|
122
|
+
static VALUE
|
123
|
+
io_get_write_io_fallback(VALUE io)
|
124
|
+
{
|
125
|
+
rb_io_t *fptr;
|
126
|
+
GetOpenFile(io, fptr);
|
127
|
+
VALUE wio = fptr->tied_io_for_writing;
|
128
|
+
return wio ? wio : io;
|
129
|
+
}
|
130
|
+
#define rb_io_get_write_io io_get_write_io_fallback
|
131
|
+
#endif
|
132
|
+
|
133
|
+
#ifndef DHAVE_RB_SYSERR_FAIL_STR
|
134
|
+
# define rb_syserr_fail_str(e, mesg) rb_exc_raise(rb_syserr_new_str(e, mesg))
|
135
|
+
#endif
|
136
|
+
|
137
|
+
#define sys_fail(io) do { \
|
138
|
+
int err = errno; \
|
139
|
+
rb_syserr_fail_str(err, rb_io_path(io)); \
|
140
|
+
} while (0)
|
91
141
|
|
92
142
|
#ifndef HAVE_RB_F_SEND
|
93
143
|
#ifndef RB_PASS_CALLED_KEYWORDS
|
@@ -293,33 +343,21 @@ set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg)
|
|
293
343
|
return setattr(fd, &r);
|
294
344
|
}
|
295
345
|
|
296
|
-
#define GetReadFD(
|
297
|
-
|
298
|
-
static inline int
|
299
|
-
get_write_fd(const rb_io_t *fptr)
|
300
|
-
{
|
301
|
-
VALUE wio = fptr->tied_io_for_writing;
|
302
|
-
rb_io_t *ofptr;
|
303
|
-
if (!wio) return fptr->fd;
|
304
|
-
GetOpenFile(wio, ofptr);
|
305
|
-
return ofptr->fd;
|
306
|
-
}
|
307
|
-
#define GetWriteFD(fptr) get_write_fd(fptr)
|
346
|
+
#define GetReadFD(io) rb_io_descriptor(io)
|
347
|
+
#define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io))
|
308
348
|
|
309
349
|
#define FD_PER_IO 2
|
310
350
|
|
311
351
|
static VALUE
|
312
352
|
ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
|
313
353
|
{
|
314
|
-
rb_io_t *fptr;
|
315
354
|
int status = -1;
|
316
355
|
int error = 0;
|
317
356
|
int fd[FD_PER_IO];
|
318
357
|
conmode t[FD_PER_IO];
|
319
358
|
VALUE result = Qnil;
|
320
359
|
|
321
|
-
|
322
|
-
fd[0] = GetReadFD(fptr);
|
360
|
+
fd[0] = GetReadFD(io);
|
323
361
|
if (fd[0] != -1) {
|
324
362
|
if (set_ttymode(fd[0], t+0, setter, arg)) {
|
325
363
|
status = 0;
|
@@ -329,7 +367,7 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
|
|
329
367
|
fd[0] = -1;
|
330
368
|
}
|
331
369
|
}
|
332
|
-
fd[1] = GetWriteFD(
|
370
|
+
fd[1] = GetWriteFD(io);
|
333
371
|
if (fd[1] != -1 && fd[1] != fd[0]) {
|
334
372
|
if (set_ttymode(fd[1], t+1, setter, arg)) {
|
335
373
|
status = 0;
|
@@ -342,14 +380,13 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
|
|
342
380
|
if (status == 0) {
|
343
381
|
result = rb_protect(func, farg, &status);
|
344
382
|
}
|
345
|
-
|
346
|
-
if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
|
383
|
+
if (fd[0] != -1 && fd[0] == GetReadFD(io)) {
|
347
384
|
if (!setattr(fd[0], t+0)) {
|
348
385
|
error = errno;
|
349
386
|
status = -1;
|
350
387
|
}
|
351
388
|
}
|
352
|
-
if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(
|
389
|
+
if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) {
|
353
390
|
if (!setattr(fd[1], t+1)) {
|
354
391
|
error = errno;
|
355
392
|
status = -1;
|
@@ -435,15 +472,11 @@ static VALUE
|
|
435
472
|
console_set_raw(int argc, VALUE *argv, VALUE io)
|
436
473
|
{
|
437
474
|
conmode t;
|
438
|
-
rb_io_t *fptr;
|
439
|
-
int fd;
|
440
475
|
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
441
|
-
|
442
|
-
|
443
|
-
fd = GetReadFD(fptr);
|
444
|
-
if (!getattr(fd, &t)) sys_fail_fptr(fptr);
|
476
|
+
int fd = GetReadFD(io);
|
477
|
+
if (!getattr(fd, &t)) sys_fail(io);
|
445
478
|
set_rawmode(&t, optp);
|
446
|
-
if (!setattr(fd, &t))
|
479
|
+
if (!setattr(fd, &t)) sys_fail(io);
|
447
480
|
return io;
|
448
481
|
}
|
449
482
|
|
@@ -479,14 +512,10 @@ static VALUE
|
|
479
512
|
console_set_cooked(VALUE io)
|
480
513
|
{
|
481
514
|
conmode t;
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
GetOpenFile(io, fptr);
|
486
|
-
fd = GetReadFD(fptr);
|
487
|
-
if (!getattr(fd, &t)) sys_fail_fptr(fptr);
|
515
|
+
int fd = GetReadFD(io);
|
516
|
+
if (!getattr(fd, &t)) sys_fail(io);
|
488
517
|
set_cookedmode(&t, NULL);
|
489
|
-
if (!setattr(fd, &t))
|
518
|
+
if (!setattr(fd, &t)) sys_fail(io);
|
490
519
|
return io;
|
491
520
|
}
|
492
521
|
|
@@ -638,17 +667,17 @@ static VALUE
|
|
638
667
|
console_set_echo(VALUE io, VALUE f)
|
639
668
|
{
|
640
669
|
conmode t;
|
641
|
-
|
642
|
-
|
670
|
+
int fd = GetReadFD(io);
|
671
|
+
|
672
|
+
if (!getattr(fd, &t)) sys_fail(io);
|
643
673
|
|
644
|
-
GetOpenFile(io, fptr);
|
645
|
-
fd = GetReadFD(fptr);
|
646
|
-
if (!getattr(fd, &t)) sys_fail_fptr(fptr);
|
647
674
|
if (RTEST(f))
|
648
|
-
|
675
|
+
set_echo(&t, NULL);
|
649
676
|
else
|
650
|
-
|
651
|
-
|
677
|
+
set_noecho(&t, NULL);
|
678
|
+
|
679
|
+
if (!setattr(fd, &t)) sys_fail(io);
|
680
|
+
|
652
681
|
return io;
|
653
682
|
}
|
654
683
|
|
@@ -664,12 +693,9 @@ static VALUE
|
|
664
693
|
console_echo_p(VALUE io)
|
665
694
|
{
|
666
695
|
conmode t;
|
667
|
-
|
668
|
-
int fd;
|
696
|
+
int fd = GetReadFD(io);
|
669
697
|
|
670
|
-
|
671
|
-
fd = GetReadFD(fptr);
|
672
|
-
if (!getattr(fd, &t)) sys_fail_fptr(fptr);
|
698
|
+
if (!getattr(fd, &t)) sys_fail(io);
|
673
699
|
return echo_p(&t) ? Qtrue : Qfalse;
|
674
700
|
}
|
675
701
|
|
@@ -748,12 +774,9 @@ static VALUE
|
|
748
774
|
console_conmode_get(VALUE io)
|
749
775
|
{
|
750
776
|
conmode t;
|
751
|
-
|
752
|
-
int fd;
|
777
|
+
int fd = GetReadFD(io);
|
753
778
|
|
754
|
-
|
755
|
-
fd = GetReadFD(fptr);
|
756
|
-
if (!getattr(fd, &t)) sys_fail_fptr(fptr);
|
779
|
+
if (!getattr(fd, &t)) sys_fail(io);
|
757
780
|
|
758
781
|
return conmode_new(cConmode, &t);
|
759
782
|
}
|
@@ -770,14 +793,12 @@ static VALUE
|
|
770
793
|
console_conmode_set(VALUE io, VALUE mode)
|
771
794
|
{
|
772
795
|
conmode *t, r;
|
773
|
-
|
774
|
-
int fd;
|
796
|
+
int fd = GetReadFD(io);
|
775
797
|
|
776
798
|
TypedData_Get_Struct(mode, conmode, &conmode_type, t);
|
777
799
|
r = *t;
|
778
|
-
|
779
|
-
fd
|
780
|
-
if (!setattr(fd, &r)) sys_fail_fptr(fptr);
|
800
|
+
|
801
|
+
if (!setattr(fd, &r)) sys_fail(io);
|
781
802
|
|
782
803
|
return mode;
|
783
804
|
}
|
@@ -813,13 +834,9 @@ typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
|
|
813
834
|
static VALUE
|
814
835
|
console_winsize(VALUE io)
|
815
836
|
{
|
816
|
-
rb_io_t *fptr;
|
817
|
-
int fd;
|
818
837
|
rb_console_size_t ws;
|
819
|
-
|
820
|
-
|
821
|
-
fd = GetWriteFD(fptr);
|
822
|
-
if (!getwinsize(fd, &ws)) sys_fail_fptr(fptr);
|
838
|
+
int fd = GetWriteFD(io);
|
839
|
+
if (!getwinsize(fd, &ws)) sys_fail(io);
|
823
840
|
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
|
824
841
|
}
|
825
842
|
|
@@ -835,7 +852,6 @@ console_winsize(VALUE io)
|
|
835
852
|
static VALUE
|
836
853
|
console_set_winsize(VALUE io, VALUE size)
|
837
854
|
{
|
838
|
-
rb_io_t *fptr;
|
839
855
|
rb_console_size_t ws;
|
840
856
|
#if defined _WIN32
|
841
857
|
HANDLE wh;
|
@@ -844,20 +860,17 @@ console_set_winsize(VALUE io, VALUE size)
|
|
844
860
|
#endif
|
845
861
|
VALUE row, col, xpixel, ypixel;
|
846
862
|
const VALUE *sz;
|
847
|
-
int fd;
|
848
863
|
long sizelen;
|
864
|
+
int fd;
|
849
865
|
|
850
|
-
GetOpenFile(io, fptr);
|
851
866
|
size = rb_Array(size);
|
852
867
|
if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
|
853
|
-
|
854
|
-
"wrong number of arguments (given %ld, expected 2 or 4)",
|
855
|
-
sizelen);
|
868
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %ld, expected 2 or 4)", sizelen);
|
856
869
|
}
|
857
870
|
sz = RARRAY_CONST_PTR(size);
|
858
871
|
row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
|
859
872
|
if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
|
860
|
-
fd = GetWriteFD(
|
873
|
+
fd = GetWriteFD(io);
|
861
874
|
#if defined TIOCSWINSZ
|
862
875
|
ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
|
863
876
|
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
|
@@ -866,7 +879,7 @@ console_set_winsize(VALUE io, VALUE size)
|
|
866
879
|
SET(xpixel);
|
867
880
|
SET(ypixel);
|
868
881
|
#undef SET
|
869
|
-
if (!setwinsize(fd, &ws))
|
882
|
+
if (!setwinsize(fd, &ws)) sys_fail(io);
|
870
883
|
#elif defined _WIN32
|
871
884
|
wh = (HANDLE)rb_w32_get_osfhandle(fd);
|
872
885
|
#define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
|
@@ -901,15 +914,23 @@ console_set_winsize(VALUE io, VALUE size)
|
|
901
914
|
#endif
|
902
915
|
|
903
916
|
#ifdef _WIN32
|
917
|
+
/*
|
918
|
+
* call-seq:
|
919
|
+
* io.check_winsize_changed { ... } -> io
|
920
|
+
*
|
921
|
+
* Yields while console input events are queued.
|
922
|
+
*
|
923
|
+
* This method is Windows only.
|
924
|
+
*
|
925
|
+
* You must require 'io/console' to use this method.
|
926
|
+
*/
|
904
927
|
static VALUE
|
905
928
|
console_check_winsize_changed(VALUE io)
|
906
929
|
{
|
907
|
-
rb_io_t *fptr;
|
908
930
|
HANDLE h;
|
909
931
|
DWORD num;
|
910
932
|
|
911
|
-
|
912
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
|
933
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
|
913
934
|
while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
|
914
935
|
INPUT_RECORD rec;
|
915
936
|
if (ReadConsoleInput(h, &rec, 1, &num)) {
|
@@ -935,15 +956,11 @@ console_check_winsize_changed(VALUE io)
|
|
935
956
|
static VALUE
|
936
957
|
console_iflush(VALUE io)
|
937
958
|
{
|
938
|
-
rb_io_t *fptr;
|
939
|
-
int fd;
|
940
|
-
|
941
|
-
GetOpenFile(io, fptr);
|
942
|
-
fd = GetReadFD(fptr);
|
943
959
|
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
944
|
-
|
960
|
+
int fd = GetReadFD(io);
|
961
|
+
if (tcflush(fd, TCIFLUSH)) sys_fail(io);
|
945
962
|
#endif
|
946
|
-
|
963
|
+
|
947
964
|
return io;
|
948
965
|
}
|
949
966
|
|
@@ -958,13 +975,9 @@ console_iflush(VALUE io)
|
|
958
975
|
static VALUE
|
959
976
|
console_oflush(VALUE io)
|
960
977
|
{
|
961
|
-
|
962
|
-
int fd;
|
963
|
-
|
964
|
-
GetOpenFile(io, fptr);
|
965
|
-
fd = GetWriteFD(fptr);
|
978
|
+
int fd = GetWriteFD(io);
|
966
979
|
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
967
|
-
if (tcflush(fd, TCOFLUSH))
|
980
|
+
if (tcflush(fd, TCOFLUSH)) sys_fail(io);
|
968
981
|
#endif
|
969
982
|
(void)fd;
|
970
983
|
return io;
|
@@ -981,40 +994,38 @@ console_oflush(VALUE io)
|
|
981
994
|
static VALUE
|
982
995
|
console_ioflush(VALUE io)
|
983
996
|
{
|
984
|
-
rb_io_t *fptr;
|
985
997
|
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
986
|
-
int fd1
|
987
|
-
|
998
|
+
int fd1 = GetReadFD(io);
|
999
|
+
int fd2 = GetWriteFD(io);
|
988
1000
|
|
989
|
-
GetOpenFile(io, fptr);
|
990
|
-
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
991
|
-
fd1 = GetReadFD(fptr);
|
992
|
-
fd2 = GetWriteFD(fptr);
|
993
1001
|
if (fd2 != -1 && fd1 != fd2) {
|
994
|
-
|
995
|
-
|
1002
|
+
if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
|
1003
|
+
if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
|
996
1004
|
}
|
997
1005
|
else {
|
998
|
-
|
1006
|
+
if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
|
999
1007
|
}
|
1000
1008
|
#endif
|
1009
|
+
|
1001
1010
|
return io;
|
1002
1011
|
}
|
1003
1012
|
|
1013
|
+
/*
|
1014
|
+
* call-seq:
|
1015
|
+
* io.beep
|
1016
|
+
*
|
1017
|
+
* Beeps on the output console.
|
1018
|
+
*
|
1019
|
+
* You must require 'io/console' to use this method.
|
1020
|
+
*/
|
1004
1021
|
static VALUE
|
1005
1022
|
console_beep(VALUE io)
|
1006
1023
|
{
|
1007
|
-
rb_io_t *fptr;
|
1008
|
-
int fd;
|
1009
|
-
|
1010
|
-
GetOpenFile(io, fptr);
|
1011
|
-
fd = GetWriteFD(fptr);
|
1012
1024
|
#ifdef _WIN32
|
1013
|
-
(void)fd;
|
1014
1025
|
MessageBeep(0);
|
1015
1026
|
#else
|
1016
|
-
|
1017
|
-
|
1027
|
+
int fd = GetWriteFD(io);
|
1028
|
+
if (write(fd, "\a", 1) < 0) sys_fail(io);
|
1018
1029
|
#endif
|
1019
1030
|
return io;
|
1020
1031
|
}
|
@@ -1035,79 +1046,6 @@ mode_in_range(VALUE val, int high, const char *modename)
|
|
1035
1046
|
}
|
1036
1047
|
|
1037
1048
|
#if defined _WIN32
|
1038
|
-
static VALUE
|
1039
|
-
console_goto(VALUE io, VALUE y, VALUE x)
|
1040
|
-
{
|
1041
|
-
rb_io_t *fptr;
|
1042
|
-
int fd;
|
1043
|
-
COORD pos;
|
1044
|
-
|
1045
|
-
GetOpenFile(io, fptr);
|
1046
|
-
fd = GetWriteFD(fptr);
|
1047
|
-
pos.X = NUM2UINT(x);
|
1048
|
-
pos.Y = NUM2UINT(y);
|
1049
|
-
if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
|
1050
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1051
|
-
}
|
1052
|
-
return io;
|
1053
|
-
}
|
1054
|
-
|
1055
|
-
static VALUE
|
1056
|
-
console_cursor_pos(VALUE io)
|
1057
|
-
{
|
1058
|
-
rb_io_t *fptr;
|
1059
|
-
int fd;
|
1060
|
-
rb_console_size_t ws;
|
1061
|
-
|
1062
|
-
GetOpenFile(io, fptr);
|
1063
|
-
fd = GetWriteFD(fptr);
|
1064
|
-
if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
|
1065
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1066
|
-
}
|
1067
|
-
return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
|
1068
|
-
}
|
1069
|
-
|
1070
|
-
static VALUE
|
1071
|
-
console_move(VALUE io, int y, int x)
|
1072
|
-
{
|
1073
|
-
rb_io_t *fptr;
|
1074
|
-
HANDLE h;
|
1075
|
-
rb_console_size_t ws;
|
1076
|
-
COORD *pos = &ws.dwCursorPosition;
|
1077
|
-
|
1078
|
-
GetOpenFile(io, fptr);
|
1079
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1080
|
-
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1081
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1082
|
-
}
|
1083
|
-
pos->X += x;
|
1084
|
-
pos->Y += y;
|
1085
|
-
if (!SetConsoleCursorPosition(h, *pos)) {
|
1086
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1087
|
-
}
|
1088
|
-
return io;
|
1089
|
-
}
|
1090
|
-
|
1091
|
-
static VALUE
|
1092
|
-
console_goto_column(VALUE io, VALUE val)
|
1093
|
-
{
|
1094
|
-
rb_io_t *fptr;
|
1095
|
-
HANDLE h;
|
1096
|
-
rb_console_size_t ws;
|
1097
|
-
COORD *pos = &ws.dwCursorPosition;
|
1098
|
-
|
1099
|
-
GetOpenFile(io, fptr);
|
1100
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1101
|
-
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1102
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1103
|
-
}
|
1104
|
-
pos->X = NUM2INT(val);
|
1105
|
-
if (!SetConsoleCursorPosition(h, *pos)) {
|
1106
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1107
|
-
}
|
1108
|
-
return io;
|
1109
|
-
}
|
1110
|
-
|
1111
1049
|
static void
|
1112
1050
|
constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
|
1113
1051
|
{
|
@@ -1117,87 +1055,13 @@ constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
|
|
1117
1055
|
FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
|
1118
1056
|
}
|
1119
1057
|
|
1120
|
-
static VALUE
|
1121
|
-
console_erase_line(VALUE io, VALUE val)
|
1122
|
-
{
|
1123
|
-
rb_io_t *fptr;
|
1124
|
-
HANDLE h;
|
1125
|
-
rb_console_size_t ws;
|
1126
|
-
COORD *pos = &ws.dwCursorPosition;
|
1127
|
-
DWORD w;
|
1128
|
-
int mode = mode_in_range(val, 2, "line erase");
|
1129
|
-
|
1130
|
-
GetOpenFile(io, fptr);
|
1131
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1132
|
-
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1133
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1134
|
-
}
|
1135
|
-
w = winsize_col(&ws);
|
1136
|
-
switch (mode) {
|
1137
|
-
case 0: /* after cursor */
|
1138
|
-
w -= pos->X;
|
1139
|
-
break;
|
1140
|
-
case 1: /* before *and* cursor */
|
1141
|
-
w = pos->X + 1;
|
1142
|
-
pos->X = 0;
|
1143
|
-
break;
|
1144
|
-
case 2: /* entire line */
|
1145
|
-
pos->X = 0;
|
1146
|
-
break;
|
1147
|
-
}
|
1148
|
-
constat_clear(h, ws.wAttributes, w, *pos);
|
1149
|
-
return io;
|
1150
|
-
}
|
1151
|
-
|
1152
|
-
static VALUE
|
1153
|
-
console_erase_screen(VALUE io, VALUE val)
|
1154
|
-
{
|
1155
|
-
rb_io_t *fptr;
|
1156
|
-
HANDLE h;
|
1157
|
-
rb_console_size_t ws;
|
1158
|
-
COORD *pos = &ws.dwCursorPosition;
|
1159
|
-
DWORD w;
|
1160
|
-
int mode = mode_in_range(val, 3, "screen erase");
|
1161
|
-
|
1162
|
-
GetOpenFile(io, fptr);
|
1163
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1164
|
-
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1165
|
-
rb_syserr_fail(LAST_ERROR, 0);
|
1166
|
-
}
|
1167
|
-
w = winsize_col(&ws);
|
1168
|
-
switch (mode) {
|
1169
|
-
case 0: /* erase after cursor */
|
1170
|
-
w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
|
1171
|
-
break;
|
1172
|
-
case 1: /* erase before *and* cursor */
|
1173
|
-
w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
|
1174
|
-
pos->X = 0;
|
1175
|
-
pos->Y = ws.srWindow.Top;
|
1176
|
-
break;
|
1177
|
-
case 2: /* erase entire screen */
|
1178
|
-
w = (w * winsize_row(&ws));
|
1179
|
-
pos->X = 0;
|
1180
|
-
pos->Y = ws.srWindow.Top;
|
1181
|
-
break;
|
1182
|
-
case 3: /* erase entire screen */
|
1183
|
-
w = (w * ws.dwSize.Y);
|
1184
|
-
pos->X = 0;
|
1185
|
-
pos->Y = 0;
|
1186
|
-
break;
|
1187
|
-
}
|
1188
|
-
constat_clear(h, ws.wAttributes, w, *pos);
|
1189
|
-
return io;
|
1190
|
-
}
|
1191
|
-
|
1192
1058
|
static VALUE
|
1193
1059
|
console_scroll(VALUE io, int line)
|
1194
1060
|
{
|
1195
|
-
rb_io_t *fptr;
|
1196
1061
|
HANDLE h;
|
1197
1062
|
rb_console_size_t ws;
|
1198
1063
|
|
1199
|
-
|
1200
|
-
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1064
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
|
1201
1065
|
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1202
1066
|
rb_syserr_fail(LAST_ERROR, 0);
|
1203
1067
|
}
|
@@ -1219,8 +1083,22 @@ console_scroll(VALUE io, int line)
|
|
1219
1083
|
return io;
|
1220
1084
|
}
|
1221
1085
|
|
1086
|
+
#define GPERF_DOWNCASE 1
|
1087
|
+
#define GPERF_CASE_STRCMP 1
|
1088
|
+
#define gperf_case_strcmp STRCASECMP
|
1222
1089
|
#include "win32_vk.inc"
|
1223
1090
|
|
1091
|
+
/*
|
1092
|
+
* call-seq:
|
1093
|
+
* io.pressed?(key) -> bool
|
1094
|
+
*
|
1095
|
+
* Returns +true+ if +key+ is pressed. +key+ may be a virtual key
|
1096
|
+
* code or its name (String or Symbol) with out "VK_" prefix.
|
1097
|
+
*
|
1098
|
+
* This method is Windows only.
|
1099
|
+
*
|
1100
|
+
* You must require 'io/console' to use this method.
|
1101
|
+
*/
|
1224
1102
|
static VALUE
|
1225
1103
|
console_key_pressed_p(VALUE io, VALUE k)
|
1226
1104
|
{
|
@@ -1256,23 +1134,11 @@ static int
|
|
1256
1134
|
direct_query(VALUE io, const struct query_args *query)
|
1257
1135
|
{
|
1258
1136
|
if (RB_TYPE_P(io, T_FILE)) {
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
VALUE s = rb_str_new_cstr(query->qstr);
|
1265
|
-
rb_io_write(wio, s);
|
1266
|
-
rb_io_flush(wio);
|
1267
|
-
return 1;
|
1268
|
-
}
|
1269
|
-
if (write(fptr->fd, query->qstr, strlen(query->qstr)) != -1) {
|
1270
|
-
return 1;
|
1271
|
-
}
|
1272
|
-
if (fptr->fd == 0 &&
|
1273
|
-
write(1, query->qstr, strlen(query->qstr)) != -1) {
|
1274
|
-
return 1;
|
1275
|
-
}
|
1137
|
+
VALUE wio = rb_io_get_write_io(io);
|
1138
|
+
VALUE s = rb_str_new_cstr(query->qstr);
|
1139
|
+
rb_io_write(wio, s);
|
1140
|
+
rb_io_flush(wio);
|
1141
|
+
return 1;
|
1276
1142
|
}
|
1277
1143
|
return 0;
|
1278
1144
|
}
|
@@ -1323,9 +1189,41 @@ console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qa
|
|
1323
1189
|
}
|
1324
1190
|
|
1325
1191
|
static VALUE
|
1326
|
-
|
1192
|
+
console_scroll(VALUE io, int line)
|
1327
1193
|
{
|
1328
|
-
|
1194
|
+
if (line) {
|
1195
|
+
VALUE s = rb_sprintf(CSI "%d%c", line < 0 ? -line : line,
|
1196
|
+
line < 0 ? 'T' : 'S');
|
1197
|
+
rb_io_write(io, s);
|
1198
|
+
}
|
1199
|
+
return io;
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
# define console_key_pressed_p rb_f_notimplement
|
1203
|
+
#endif
|
1204
|
+
|
1205
|
+
/*
|
1206
|
+
* call-seq:
|
1207
|
+
* io.cursor -> [row, column]
|
1208
|
+
*
|
1209
|
+
* Returns the current cursor position as a two-element array of integers (row, column)
|
1210
|
+
*
|
1211
|
+
* io.cursor # => [3, 5]
|
1212
|
+
*
|
1213
|
+
* You must require 'io/console' to use this method.
|
1214
|
+
*/
|
1215
|
+
static VALUE
|
1216
|
+
console_cursor_pos(VALUE io)
|
1217
|
+
{
|
1218
|
+
#ifdef _WIN32
|
1219
|
+
rb_console_size_t ws;
|
1220
|
+
int fd = GetWriteFD(io);
|
1221
|
+
if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
|
1222
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1223
|
+
}
|
1224
|
+
return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
|
1225
|
+
#else
|
1226
|
+
static const struct query_args query = {"\033[6n", 0};
|
1329
1227
|
VALUE resp = console_vt_response(0, 0, io, &query);
|
1330
1228
|
VALUE row, column, term;
|
1331
1229
|
unsigned int r, c;
|
@@ -1341,64 +1239,205 @@ console_cursor_pos(VALUE io)
|
|
1341
1239
|
RARRAY_ASET(resp, 0, INT2NUM(r));
|
1342
1240
|
RARRAY_ASET(resp, 1, INT2NUM(c));
|
1343
1241
|
return resp;
|
1242
|
+
#endif
|
1344
1243
|
}
|
1345
1244
|
|
1245
|
+
/*
|
1246
|
+
* call-seq:
|
1247
|
+
* io.goto(line, column) -> io
|
1248
|
+
*
|
1249
|
+
* Set the cursor position at +line+ and +column+.
|
1250
|
+
*
|
1251
|
+
* You must require 'io/console' to use this method.
|
1252
|
+
*/
|
1346
1253
|
static VALUE
|
1347
1254
|
console_goto(VALUE io, VALUE y, VALUE x)
|
1348
1255
|
{
|
1349
|
-
|
1256
|
+
#ifdef _WIN32
|
1257
|
+
COORD pos;
|
1258
|
+
int fd = GetWriteFD(io);
|
1259
|
+
pos.X = NUM2UINT(x);
|
1260
|
+
pos.Y = NUM2UINT(y);
|
1261
|
+
if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
|
1262
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1263
|
+
}
|
1264
|
+
#else
|
1265
|
+
rb_io_write(io, rb_sprintf(CSI "%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
|
1266
|
+
#endif
|
1350
1267
|
return io;
|
1351
1268
|
}
|
1352
1269
|
|
1353
1270
|
static VALUE
|
1354
1271
|
console_move(VALUE io, int y, int x)
|
1355
1272
|
{
|
1273
|
+
#ifdef _WIN32
|
1274
|
+
HANDLE h;
|
1275
|
+
rb_console_size_t ws;
|
1276
|
+
COORD *pos = &ws.dwCursorPosition;
|
1277
|
+
|
1278
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
|
1279
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1280
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1281
|
+
}
|
1282
|
+
pos->X += x;
|
1283
|
+
pos->Y += y;
|
1284
|
+
if (!SetConsoleCursorPosition(h, *pos)) {
|
1285
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1286
|
+
}
|
1287
|
+
#else
|
1356
1288
|
if (x || y) {
|
1357
1289
|
VALUE s = rb_str_new_cstr("");
|
1358
|
-
if (y) rb_str_catf(s, "
|
1359
|
-
if (x) rb_str_catf(s, "
|
1290
|
+
if (y) rb_str_catf(s, CSI "%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
|
1291
|
+
if (x) rb_str_catf(s, CSI "%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
|
1360
1292
|
rb_io_write(io, s);
|
1361
1293
|
rb_io_flush(io);
|
1362
1294
|
}
|
1295
|
+
#endif
|
1363
1296
|
return io;
|
1364
1297
|
}
|
1365
1298
|
|
1299
|
+
/*
|
1300
|
+
* call-seq:
|
1301
|
+
* io.goto_column(column) -> io
|
1302
|
+
*
|
1303
|
+
* Set the cursor position at +column+ in the same line of the current
|
1304
|
+
* position.
|
1305
|
+
*
|
1306
|
+
* You must require 'io/console' to use this method.
|
1307
|
+
*/
|
1366
1308
|
static VALUE
|
1367
1309
|
console_goto_column(VALUE io, VALUE val)
|
1368
1310
|
{
|
1369
|
-
|
1311
|
+
#ifdef _WIN32
|
1312
|
+
HANDLE h;
|
1313
|
+
rb_console_size_t ws;
|
1314
|
+
COORD *pos = &ws.dwCursorPosition;
|
1315
|
+
|
1316
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
|
1317
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1318
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1319
|
+
}
|
1320
|
+
pos->X = NUM2INT(val);
|
1321
|
+
if (!SetConsoleCursorPosition(h, *pos)) {
|
1322
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1323
|
+
}
|
1324
|
+
#else
|
1325
|
+
rb_io_write(io, rb_sprintf(CSI "%dG", NUM2UINT(val)+1));
|
1326
|
+
#endif
|
1370
1327
|
return io;
|
1371
1328
|
}
|
1372
1329
|
|
1330
|
+
/*
|
1331
|
+
* call-seq:
|
1332
|
+
* io.erase_line(mode) -> io
|
1333
|
+
*
|
1334
|
+
* Erases the line at the cursor corresponding to +mode+.
|
1335
|
+
* +mode+ may be either:
|
1336
|
+
* 0: after cursor
|
1337
|
+
* 1: before and cursor
|
1338
|
+
* 2: entire line
|
1339
|
+
*
|
1340
|
+
* You must require 'io/console' to use this method.
|
1341
|
+
*/
|
1373
1342
|
static VALUE
|
1374
1343
|
console_erase_line(VALUE io, VALUE val)
|
1375
1344
|
{
|
1376
1345
|
int mode = mode_in_range(val, 2, "line erase");
|
1377
|
-
|
1346
|
+
#ifdef _WIN32
|
1347
|
+
HANDLE h;
|
1348
|
+
rb_console_size_t ws;
|
1349
|
+
COORD *pos = &ws.dwCursorPosition;
|
1350
|
+
DWORD w;
|
1351
|
+
|
1352
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
|
1353
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1354
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1355
|
+
}
|
1356
|
+
w = winsize_col(&ws);
|
1357
|
+
switch (mode) {
|
1358
|
+
case 0: /* after cursor */
|
1359
|
+
w -= pos->X;
|
1360
|
+
break;
|
1361
|
+
case 1: /* before *and* cursor */
|
1362
|
+
w = pos->X + 1;
|
1363
|
+
pos->X = 0;
|
1364
|
+
break;
|
1365
|
+
case 2: /* entire line */
|
1366
|
+
pos->X = 0;
|
1367
|
+
break;
|
1368
|
+
}
|
1369
|
+
constat_clear(h, ws.wAttributes, w, *pos);
|
1370
|
+
return io;
|
1371
|
+
#else
|
1372
|
+
rb_io_write(io, rb_sprintf(CSI "%dK", mode));
|
1373
|
+
#endif
|
1378
1374
|
return io;
|
1379
1375
|
}
|
1380
1376
|
|
1377
|
+
/*
|
1378
|
+
* call-seq:
|
1379
|
+
* io.erase_screen(mode) -> io
|
1380
|
+
*
|
1381
|
+
* Erases the screen at the cursor corresponding to +mode+.
|
1382
|
+
* +mode+ may be either:
|
1383
|
+
* 0: after cursor
|
1384
|
+
* 1: before and cursor
|
1385
|
+
* 2: entire screen
|
1386
|
+
*
|
1387
|
+
* You must require 'io/console' to use this method.
|
1388
|
+
*/
|
1381
1389
|
static VALUE
|
1382
1390
|
console_erase_screen(VALUE io, VALUE val)
|
1383
1391
|
{
|
1384
1392
|
int mode = mode_in_range(val, 3, "screen erase");
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1393
|
+
#ifdef _WIN32
|
1394
|
+
HANDLE h;
|
1395
|
+
rb_console_size_t ws;
|
1396
|
+
COORD *pos = &ws.dwCursorPosition;
|
1397
|
+
DWORD w;
|
1388
1398
|
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1399
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
|
1400
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1401
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1402
|
+
}
|
1403
|
+
w = winsize_col(&ws);
|
1404
|
+
switch (mode) {
|
1405
|
+
case 0: /* erase after cursor */
|
1406
|
+
w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
|
1407
|
+
break;
|
1408
|
+
case 1: /* erase before *and* cursor */
|
1409
|
+
w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
|
1410
|
+
pos->X = 0;
|
1411
|
+
pos->Y = ws.srWindow.Top;
|
1412
|
+
break;
|
1413
|
+
case 2: /* erase entire screen */
|
1414
|
+
w = (w * winsize_row(&ws));
|
1415
|
+
pos->X = 0;
|
1416
|
+
pos->Y = ws.srWindow.Top;
|
1417
|
+
break;
|
1418
|
+
case 3: /* erase entire screen */
|
1419
|
+
w = (w * ws.dwSize.Y);
|
1420
|
+
pos->X = 0;
|
1421
|
+
pos->Y = 0;
|
1422
|
+
break;
|
1396
1423
|
}
|
1424
|
+
constat_clear(h, ws.wAttributes, w, *pos);
|
1425
|
+
#else
|
1426
|
+
rb_io_write(io, rb_sprintf(CSI "%dJ", mode));
|
1427
|
+
#endif
|
1397
1428
|
return io;
|
1398
1429
|
}
|
1399
|
-
# define console_key_pressed_p rb_f_notimplement
|
1400
|
-
#endif
|
1401
1430
|
|
1431
|
+
/*
|
1432
|
+
* call-seq:
|
1433
|
+
* io.cursor = [line, column] -> io
|
1434
|
+
*
|
1435
|
+
* Same as <tt>io.goto(line, column)</tt>
|
1436
|
+
*
|
1437
|
+
* See IO#goto.
|
1438
|
+
*
|
1439
|
+
* You must require 'io/console' to use this method.
|
1440
|
+
*/
|
1402
1441
|
static VALUE
|
1403
1442
|
console_cursor_set(VALUE io, VALUE cpos)
|
1404
1443
|
{
|
@@ -1407,42 +1446,98 @@ console_cursor_set(VALUE io, VALUE cpos)
|
|
1407
1446
|
return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
|
1408
1447
|
}
|
1409
1448
|
|
1449
|
+
/*
|
1450
|
+
* call-seq:
|
1451
|
+
* io.cursor_up(n) -> io
|
1452
|
+
*
|
1453
|
+
* Moves the cursor up +n+ lines.
|
1454
|
+
*
|
1455
|
+
* You must require 'io/console' to use this method.
|
1456
|
+
*/
|
1410
1457
|
static VALUE
|
1411
1458
|
console_cursor_up(VALUE io, VALUE val)
|
1412
1459
|
{
|
1413
1460
|
return console_move(io, -NUM2INT(val), 0);
|
1414
1461
|
}
|
1415
1462
|
|
1463
|
+
/*
|
1464
|
+
* call-seq:
|
1465
|
+
* io.cursor_down(n) -> io
|
1466
|
+
*
|
1467
|
+
* Moves the cursor down +n+ lines.
|
1468
|
+
*
|
1469
|
+
* You must require 'io/console' to use this method.
|
1470
|
+
*/
|
1416
1471
|
static VALUE
|
1417
1472
|
console_cursor_down(VALUE io, VALUE val)
|
1418
1473
|
{
|
1419
1474
|
return console_move(io, +NUM2INT(val), 0);
|
1420
1475
|
}
|
1421
1476
|
|
1477
|
+
/*
|
1478
|
+
* call-seq:
|
1479
|
+
* io.cursor_left(n) -> io
|
1480
|
+
*
|
1481
|
+
* Moves the cursor left +n+ columns.
|
1482
|
+
*
|
1483
|
+
* You must require 'io/console' to use this method.
|
1484
|
+
*/
|
1422
1485
|
static VALUE
|
1423
1486
|
console_cursor_left(VALUE io, VALUE val)
|
1424
1487
|
{
|
1425
1488
|
return console_move(io, 0, -NUM2INT(val));
|
1426
1489
|
}
|
1427
1490
|
|
1491
|
+
/*
|
1492
|
+
* call-seq:
|
1493
|
+
* io.cursor_right(n) -> io
|
1494
|
+
*
|
1495
|
+
* Moves the cursor right +n+ columns.
|
1496
|
+
*
|
1497
|
+
* You must require 'io/console' to use this method.
|
1498
|
+
*/
|
1428
1499
|
static VALUE
|
1429
1500
|
console_cursor_right(VALUE io, VALUE val)
|
1430
1501
|
{
|
1431
1502
|
return console_move(io, 0, +NUM2INT(val));
|
1432
1503
|
}
|
1433
1504
|
|
1505
|
+
/*
|
1506
|
+
* call-seq:
|
1507
|
+
* io.scroll_forward(n) -> io
|
1508
|
+
*
|
1509
|
+
* Scrolls the entire scrolls forward +n+ lines.
|
1510
|
+
*
|
1511
|
+
* You must require 'io/console' to use this method.
|
1512
|
+
*/
|
1434
1513
|
static VALUE
|
1435
1514
|
console_scroll_forward(VALUE io, VALUE val)
|
1436
1515
|
{
|
1437
1516
|
return console_scroll(io, +NUM2INT(val));
|
1438
1517
|
}
|
1439
1518
|
|
1519
|
+
/*
|
1520
|
+
* call-seq:
|
1521
|
+
* io.scroll_backward(n) -> io
|
1522
|
+
*
|
1523
|
+
* Scrolls the entire scrolls backward +n+ lines.
|
1524
|
+
*
|
1525
|
+
* You must require 'io/console' to use this method.
|
1526
|
+
*/
|
1440
1527
|
static VALUE
|
1441
1528
|
console_scroll_backward(VALUE io, VALUE val)
|
1442
1529
|
{
|
1443
1530
|
return console_scroll(io, -NUM2INT(val));
|
1444
1531
|
}
|
1445
1532
|
|
1533
|
+
/*
|
1534
|
+
* call-seq:
|
1535
|
+
* io.clear_screen -> io
|
1536
|
+
*
|
1537
|
+
* Clears the entire screen and moves the cursor top-left corner.
|
1538
|
+
*
|
1539
|
+
* You must require 'io/console' to use this method.
|
1540
|
+
*/
|
1446
1541
|
static VALUE
|
1447
1542
|
console_clear_screen(VALUE io)
|
1448
1543
|
{
|
@@ -1451,6 +1546,92 @@ console_clear_screen(VALUE io)
|
|
1451
1546
|
return io;
|
1452
1547
|
}
|
1453
1548
|
|
1549
|
+
#ifndef HAVE_RB_IO_OPEN_DESCRIPTOR
|
1550
|
+
static VALUE
|
1551
|
+
io_open_descriptor_fallback(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, void *encoding)
|
1552
|
+
{
|
1553
|
+
VALUE arguments[2] = {
|
1554
|
+
(rb_update_max_fd(descriptor), INT2NUM(descriptor)),
|
1555
|
+
INT2FIX(mode),
|
1556
|
+
};
|
1557
|
+
|
1558
|
+
VALUE self = rb_class_new_instance(2, arguments, klass);
|
1559
|
+
|
1560
|
+
rb_io_t *fptr;
|
1561
|
+
GetOpenFile(self, fptr);
|
1562
|
+
fptr->pathv = path;
|
1563
|
+
fptr->mode |= mode;
|
1564
|
+
|
1565
|
+
return self;
|
1566
|
+
}
|
1567
|
+
#define rb_io_open_descriptor io_open_descriptor_fallback
|
1568
|
+
#endif
|
1569
|
+
|
1570
|
+
#ifndef HAVE_RB_IO_CLOSED_P
|
1571
|
+
static VALUE
|
1572
|
+
rb_io_closed_p(VALUE io)
|
1573
|
+
{
|
1574
|
+
rb_io_t *fptr = RFILE(io)->fptr;
|
1575
|
+
return fptr->fd == -1 ? Qtrue : Qfalse;
|
1576
|
+
}
|
1577
|
+
#endif
|
1578
|
+
|
1579
|
+
#if defined(RB_EXT_RACTOR_SAFE) && defined(HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY)
|
1580
|
+
# define USE_RACTOR_STORAGE 1
|
1581
|
+
#else
|
1582
|
+
# define USE_RACTOR_STORAGE 0
|
1583
|
+
#endif
|
1584
|
+
|
1585
|
+
#if USE_RACTOR_STORAGE
|
1586
|
+
#include "ruby/ractor.h"
|
1587
|
+
static rb_ractor_local_key_t key_console_dev;
|
1588
|
+
|
1589
|
+
static bool
|
1590
|
+
console_dev_get(VALUE klass, VALUE *dev)
|
1591
|
+
{
|
1592
|
+
return rb_ractor_local_storage_value_lookup(key_console_dev, dev);
|
1593
|
+
}
|
1594
|
+
|
1595
|
+
static void
|
1596
|
+
console_dev_set(VALUE klass, VALUE value)
|
1597
|
+
{
|
1598
|
+
rb_ractor_local_storage_value_set(key_console_dev, value);
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
static void
|
1602
|
+
console_dev_remove(VALUE klass)
|
1603
|
+
{
|
1604
|
+
console_dev_set(klass, Qnil);
|
1605
|
+
}
|
1606
|
+
|
1607
|
+
#else
|
1608
|
+
|
1609
|
+
static ID id_console;
|
1610
|
+
|
1611
|
+
static int
|
1612
|
+
console_dev_get(VALUE klass, VALUE *dev)
|
1613
|
+
{
|
1614
|
+
if (rb_const_defined(klass, id_console)) {
|
1615
|
+
*dev = rb_const_get(klass, id_console);
|
1616
|
+
return 1;
|
1617
|
+
}
|
1618
|
+
return 0;
|
1619
|
+
}
|
1620
|
+
|
1621
|
+
static void
|
1622
|
+
console_dev_set(VALUE klass, VALUE value)
|
1623
|
+
{
|
1624
|
+
rb_const_set(klass, id_console, value);
|
1625
|
+
}
|
1626
|
+
|
1627
|
+
static void
|
1628
|
+
console_dev_remove(VALUE klass)
|
1629
|
+
{
|
1630
|
+
rb_const_remove(klass, id_console);
|
1631
|
+
}
|
1632
|
+
|
1633
|
+
#endif
|
1634
|
+
|
1454
1635
|
/*
|
1455
1636
|
* call-seq:
|
1456
1637
|
* IO.console -> #<File:/dev/tty>
|
@@ -1468,34 +1649,36 @@ static VALUE
|
|
1468
1649
|
console_dev(int argc, VALUE *argv, VALUE klass)
|
1469
1650
|
{
|
1470
1651
|
VALUE con = 0;
|
1471
|
-
rb_io_t *fptr;
|
1472
1652
|
VALUE sym = 0;
|
1473
1653
|
|
1474
1654
|
rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
|
1655
|
+
|
1475
1656
|
if (argc) {
|
1476
|
-
|
1657
|
+
Check_Type(sym = argv[0], T_SYMBOL);
|
1477
1658
|
}
|
1659
|
+
|
1660
|
+
// Force the class to be File.
|
1478
1661
|
if (klass == rb_cIO) klass = rb_cFile;
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
(
|
1483
|
-
|
1484
|
-
|
1485
|
-
}
|
1662
|
+
|
1663
|
+
if (console_dev_get(klass, &con)) {
|
1664
|
+
if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
|
1665
|
+
console_dev_remove(klass);
|
1666
|
+
con = 0;
|
1667
|
+
}
|
1486
1668
|
}
|
1669
|
+
|
1487
1670
|
if (sym) {
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1671
|
+
if (sym == ID2SYM(id_close) && argc == 1) {
|
1672
|
+
if (con) {
|
1673
|
+
rb_io_close(con);
|
1674
|
+
console_dev_remove(klass);
|
1675
|
+
con = 0;
|
1676
|
+
}
|
1677
|
+
return Qnil;
|
1678
|
+
}
|
1496
1679
|
}
|
1680
|
+
|
1497
1681
|
if (!con) {
|
1498
|
-
VALUE args[2];
|
1499
1682
|
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
|
1500
1683
|
# define CONSOLE_DEVICE "/dev/tty"
|
1501
1684
|
#elif defined _WIN32
|
@@ -1507,44 +1690,35 @@ console_dev(int argc, VALUE *argv, VALUE klass)
|
|
1507
1690
|
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
|
1508
1691
|
#endif
|
1509
1692
|
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
1510
|
-
|
1511
|
-
rb_io_t *ofptr;
|
1693
|
+
VALUE out;
|
1512
1694
|
#endif
|
1513
|
-
|
1695
|
+
int fd;
|
1696
|
+
VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
|
1514
1697
|
|
1515
1698
|
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
args[1] = INT2FIX(O_WRONLY);
|
1520
|
-
args[0] = INT2NUM(fd);
|
1521
|
-
out = rb_class_new_instance(2, args, klass);
|
1699
|
+
fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
|
1700
|
+
if (fd < 0) return Qnil;
|
1701
|
+
out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
|
1522
1702
|
#endif
|
1523
|
-
|
1524
|
-
|
1703
|
+
fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
|
1704
|
+
if (fd < 0) {
|
1525
1705
|
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
1526
|
-
|
1706
|
+
rb_io_close(out);
|
1527
1707
|
#endif
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
args[0] = INT2NUM(fd);
|
1533
|
-
con = rb_class_new_instance(2, args, klass);
|
1534
|
-
GetOpenFile(con, fptr);
|
1535
|
-
fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
|
1708
|
+
return Qnil;
|
1709
|
+
}
|
1710
|
+
|
1711
|
+
con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
|
1536
1712
|
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
1537
|
-
|
1538
|
-
ofptr->pathv = fptr->pathv;
|
1539
|
-
fptr->tied_io_for_writing = out;
|
1540
|
-
ofptr->mode |= FMODE_SYNC;
|
1713
|
+
rb_io_set_write_io(con, out);
|
1541
1714
|
#endif
|
1542
|
-
|
1543
|
-
rb_const_set(klass, id_console, con);
|
1715
|
+
console_dev_set(klass, con);
|
1544
1716
|
}
|
1717
|
+
|
1545
1718
|
if (sym) {
|
1546
|
-
|
1719
|
+
return rb_f_send(argc, argv, con);
|
1547
1720
|
}
|
1721
|
+
|
1548
1722
|
return con;
|
1549
1723
|
}
|
1550
1724
|
|
@@ -1560,13 +1734,18 @@ io_getch(int argc, VALUE *argv, VALUE io)
|
|
1560
1734
|
return rb_funcallv(io, id_getc, argc, argv);
|
1561
1735
|
}
|
1562
1736
|
|
1563
|
-
#if ENABLE_IO_GETPASS
|
1564
1737
|
static VALUE
|
1565
1738
|
puts_call(VALUE io)
|
1566
1739
|
{
|
1567
1740
|
return rb_io_write(io, rb_default_rs);
|
1568
1741
|
}
|
1569
1742
|
|
1743
|
+
static VALUE
|
1744
|
+
gets_call(VALUE io)
|
1745
|
+
{
|
1746
|
+
return rb_funcallv(io, id_gets, 0, 0);
|
1747
|
+
}
|
1748
|
+
|
1570
1749
|
static VALUE
|
1571
1750
|
getpass_call(VALUE io)
|
1572
1751
|
{
|
@@ -1587,7 +1766,8 @@ static VALUE
|
|
1587
1766
|
str_chomp(VALUE str)
|
1588
1767
|
{
|
1589
1768
|
if (!NIL_P(str)) {
|
1590
|
-
|
1769
|
+
const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */
|
1770
|
+
rb_funcallv(str, id_chomp_bang, 1, &rs);
|
1591
1771
|
}
|
1592
1772
|
return str;
|
1593
1773
|
}
|
@@ -1604,6 +1784,12 @@ str_chomp(VALUE str)
|
|
1604
1784
|
* see String#chomp!.
|
1605
1785
|
*
|
1606
1786
|
* You must require 'io/console' to use this method.
|
1787
|
+
*
|
1788
|
+
* require 'io/console'
|
1789
|
+
* IO::console.getpass("Enter password:")
|
1790
|
+
* Enter password:
|
1791
|
+
* # => "mypassword"
|
1792
|
+
*
|
1607
1793
|
*/
|
1608
1794
|
static VALUE
|
1609
1795
|
console_getpass(int argc, VALUE *argv, VALUE io)
|
@@ -1614,6 +1800,7 @@ console_getpass(int argc, VALUE *argv, VALUE io)
|
|
1614
1800
|
wio = rb_io_get_write_io(io);
|
1615
1801
|
if (wio == io && io == rb_stdin) wio = rb_stderr;
|
1616
1802
|
prompt(argc, argv, wio);
|
1803
|
+
rb_io_flush(wio);
|
1617
1804
|
str = rb_ensure(getpass_call, io, puts_call, wio);
|
1618
1805
|
return str_chomp(str);
|
1619
1806
|
}
|
@@ -1631,10 +1818,64 @@ io_getpass(int argc, VALUE *argv, VALUE io)
|
|
1631
1818
|
|
1632
1819
|
rb_check_arity(argc, 0, 1);
|
1633
1820
|
prompt(argc, argv, io);
|
1634
|
-
|
1635
|
-
|
1636
|
-
return str;
|
1821
|
+
rb_check_funcall(io, id_flush, 0, 0);
|
1822
|
+
str = rb_ensure(gets_call, io, puts_call, io);
|
1823
|
+
return str_chomp(str);
|
1824
|
+
}
|
1825
|
+
|
1826
|
+
#if defined(_WIN32) || defined(HAVE_TTYNAME_R) || defined(HAVE_TTYNAME)
|
1827
|
+
/*
|
1828
|
+
* call-seq:
|
1829
|
+
* io.ttyname -> string or nil
|
1830
|
+
*
|
1831
|
+
* Returns name of associated terminal (tty) if +io+ is not a tty.
|
1832
|
+
* Returns +nil+ otherwise.
|
1833
|
+
*/
|
1834
|
+
static VALUE
|
1835
|
+
console_ttyname(VALUE io)
|
1836
|
+
{
|
1837
|
+
int fd = rb_io_descriptor(io);
|
1838
|
+
if (!isatty(fd)) return Qnil;
|
1839
|
+
# if defined _WIN32
|
1840
|
+
return rb_usascii_str_new_lit("con");
|
1841
|
+
# elif defined HAVE_TTYNAME_R
|
1842
|
+
{
|
1843
|
+
char termname[1024], *tn = termname;
|
1844
|
+
size_t size = sizeof(termname);
|
1845
|
+
int e;
|
1846
|
+
if (ttyname_r(fd, tn, size) == 0)
|
1847
|
+
return rb_interned_str_cstr(tn);
|
1848
|
+
if ((e = errno) == ERANGE) {
|
1849
|
+
VALUE s = rb_str_new(0, size);
|
1850
|
+
while (1) {
|
1851
|
+
tn = RSTRING_PTR(s);
|
1852
|
+
size = rb_str_capacity(s);
|
1853
|
+
if (ttyname_r(fd, tn, size) == 0) {
|
1854
|
+
return rb_str_to_interned_str(rb_str_resize(s, strlen(tn)));
|
1855
|
+
}
|
1856
|
+
if ((e = errno) != ERANGE) break;
|
1857
|
+
if ((size *= 2) >= INT_MAX/2) break;
|
1858
|
+
rb_str_resize(s, size);
|
1859
|
+
}
|
1860
|
+
}
|
1861
|
+
rb_syserr_fail_str(e, rb_sprintf("ttyname_r(%d)", fd));
|
1862
|
+
UNREACHABLE_RETURN(Qnil);
|
1863
|
+
}
|
1864
|
+
# elif defined HAVE_TTYNAME
|
1865
|
+
{
|
1866
|
+
const char *tn = ttyname(fd);
|
1867
|
+
if (!tn) {
|
1868
|
+
int e = errno;
|
1869
|
+
rb_syserr_fail_str(e, rb_sprintf("ttyname(%d)", fd));
|
1870
|
+
}
|
1871
|
+
return rb_interned_str_cstr(tn);
|
1872
|
+
}
|
1873
|
+
# else
|
1874
|
+
# error No ttyname function
|
1875
|
+
# endif
|
1637
1876
|
}
|
1877
|
+
#else
|
1878
|
+
# define console_ttyname rb_f_notimplement
|
1638
1879
|
#endif
|
1639
1880
|
|
1640
1881
|
/*
|
@@ -1643,13 +1884,20 @@ io_getpass(int argc, VALUE *argv, VALUE io)
|
|
1643
1884
|
void
|
1644
1885
|
Init_console(void)
|
1645
1886
|
{
|
1887
|
+
#if USE_RACTOR_STORAGE
|
1888
|
+
RB_EXT_RACTOR_SAFE(true);
|
1889
|
+
#endif
|
1890
|
+
|
1646
1891
|
#undef rb_intern
|
1892
|
+
#if USE_RACTOR_STORAGE
|
1893
|
+
key_console_dev = rb_ractor_local_storage_value_newkey();
|
1894
|
+
#else
|
1895
|
+
id_console = rb_intern("console");
|
1896
|
+
#endif
|
1647
1897
|
id_getc = rb_intern("getc");
|
1648
|
-
#if ENABLE_IO_GETPASS
|
1649
1898
|
id_gets = rb_intern("gets");
|
1899
|
+
id_flush = rb_intern("flush");
|
1650
1900
|
id_chomp_bang = rb_intern("chomp!");
|
1651
|
-
#endif
|
1652
|
-
id_console = rb_intern("console");
|
1653
1901
|
id_close = rb_intern("close");
|
1654
1902
|
#define init_rawmode_opt_id(name) \
|
1655
1903
|
rawmode_opt_ids[kwd_##name] = rb_intern(#name)
|
@@ -1696,20 +1944,20 @@ InitVM_console(void)
|
|
1696
1944
|
rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
|
1697
1945
|
rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
|
1698
1946
|
rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
|
1699
|
-
#if ENABLE_IO_GETPASS
|
1700
1947
|
rb_define_method(rb_cIO, "getpass", console_getpass, -1);
|
1701
|
-
|
1948
|
+
rb_define_method(rb_cIO, "ttyname", console_ttyname, 0);
|
1702
1949
|
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
|
1703
1950
|
{
|
1951
|
+
/* :stopdoc: */
|
1704
1952
|
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
|
1953
|
+
/* :startdoc: */
|
1705
1954
|
rb_define_method(mReadable, "getch", io_getch, -1);
|
1706
|
-
#if ENABLE_IO_GETPASS
|
1707
1955
|
rb_define_method(mReadable, "getpass", io_getpass, -1);
|
1708
|
-
#endif
|
1709
1956
|
}
|
1710
1957
|
{
|
1711
1958
|
/* :stopdoc: */
|
1712
1959
|
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
|
1960
|
+
rb_define_const(cConmode, "VERSION", rb_obj_freeze(rb_str_new_cstr(IO_CONSOLE_VERSION)));
|
1713
1961
|
rb_define_alloc_func(cConmode, conmode_alloc);
|
1714
1962
|
rb_undef_method(cConmode, "initialize");
|
1715
1963
|
rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
|