io-console 0.5.11 → 0.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a402e8ba6c8522b3b423e828a4575da34a084c97a5e6d27cbed65e35695a9c9e
4
- data.tar.gz: 50fa0e88472bcdd8f3242c3957c8ed7c39d5f6c6f41f3d7db48a0eaf73cc64f2
3
+ metadata.gz: ea376ca7a23381cc7ad476248aa32fc95ff2fe19be07170f6eb4031b42e897ab
4
+ data.tar.gz: 321d946b43b46f279bb28d08c173c48b05e9c9a087d51cbcf1715153c772cda1
5
5
  SHA512:
6
- metadata.gz: 6b190b4fb0d1dedaccc0613754d8c656f65dfa3766ac04624d0a0fd1943339a61aee118beed8be1274de764bfc8404697a303da30300377381d521fbc2d77acf
7
- data.tar.gz: 70a62bd336c53ccd8ae25bacc7bb5a8d7a26d0d5eabcd26ee9541137f8d86345159f134d5f04bde13be0486d057ab7bdbbf2a3667d88b92b6350b6543de12c11
6
+ metadata.gz: 88f4b33458250ec0e9039c9187d144fb9c851753c39b7e5191db26e2b8a898ce5ac6d6897330c93ae8eab1c6a4cd800a7af9f36ce83fd20b6caedfc52a12ed50
7
+ data.tar.gz: 4235ecf65e5e0b81c196d62a0a95649f708a29e2c300d645e99301dd3b6a470dc30b3cad6e2151b8ebf69c15c797962f62f55d6cdb935179f0656d2e450939af
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ LICENSE.txt
2
+ README.md
3
+ docs/
4
+ ext/
5
+ lib/io/console/size.rb
@@ -2,6 +2,10 @@
2
2
  /*
3
3
  * console IO module
4
4
  */
5
+
6
+ static const char *const
7
+ IO_CONSOLE_VERSION = "0.7.2";
8
+
5
9
  #include "ruby.h"
6
10
  #include "ruby/io.h"
7
11
  #include "ruby/thread.h"
@@ -75,10 +79,10 @@ getattr(int fd, conmode *t)
75
79
  #define SET_LAST_ERROR (0)
76
80
  #endif
77
81
 
78
- static ID id_getc, id_console, id_close, id_min, id_time, id_intr;
79
- #if ENABLE_IO_GETPASS
80
- static ID id_gets, id_chomp_bang;
81
- #endif
82
+ #define CSI "\x1b\x5b"
83
+
84
+ static ID id_getc, id_console, id_close;
85
+ static ID id_gets, id_flush, id_chomp_bang;
82
86
 
83
87
  #if defined HAVE_RUBY_FIBER_SCHEDULER_H
84
88
  # include "ruby/fiber/scheduler.h"
@@ -87,7 +91,41 @@ extern VALUE rb_scheduler_timeout(struct timeval *timeout);
87
91
  # define rb_fiber_scheduler_make_timeout rb_scheduler_timeout
88
92
  #endif
89
93
 
90
- #define sys_fail_fptr(fptr) rb_sys_fail_str((fptr)->pathv)
94
+ #ifndef HAVE_RB_IO_DESCRIPTOR
95
+ static int
96
+ io_descriptor_fallback(VALUE io)
97
+ {
98
+ rb_io_t *fptr;
99
+ GetOpenFile(io, fptr);
100
+ return fptr->fd;
101
+ }
102
+ #define rb_io_descriptor io_descriptor_fallback
103
+ #endif
104
+
105
+ #ifndef HAVE_RB_IO_PATH
106
+ static VALUE
107
+ io_path_fallback(VALUE io)
108
+ {
109
+ rb_io_t *fptr;
110
+ GetOpenFile(io, fptr);
111
+ return fptr->pathv;
112
+ }
113
+ #define rb_io_path io_path_fallback
114
+ #endif
115
+
116
+ #ifndef HAVE_RB_IO_GET_WRITE_IO
117
+ static VALUE
118
+ io_get_write_io_fallback(VALUE io)
119
+ {
120
+ rb_io_t *fptr;
121
+ GetOpenFile(io, fptr);
122
+ VALUE wio = fptr->tied_io_for_writing;
123
+ return wio ? wio : io;
124
+ }
125
+ #define rb_io_get_write_io io_get_write_io_fallback
126
+ #endif
127
+
128
+ #define sys_fail(io) rb_sys_fail_str(rb_io_path(io))
91
129
 
92
130
  #ifndef HAVE_RB_F_SEND
93
131
  #ifndef RB_PASS_CALLED_KEYWORDS
@@ -112,18 +150,34 @@ rb_f_send(int argc, VALUE *argv, VALUE recv)
112
150
  }
113
151
  #endif
114
152
 
153
+ enum rawmode_opt_ids {
154
+ kwd_min,
155
+ kwd_time,
156
+ kwd_intr,
157
+ rawmode_opt_id_count
158
+ };
159
+ static ID rawmode_opt_ids[rawmode_opt_id_count];
160
+
115
161
  typedef struct {
116
162
  int vmin;
117
163
  int vtime;
118
164
  int intr;
119
165
  } rawmode_arg_t;
120
166
 
167
+ #ifndef UNDEF_P
168
+ # define UNDEF_P(obj) ((obj) == Qundef)
169
+ #endif
170
+ #ifndef NIL_OR_UNDEF_P
171
+ # define NIL_OR_UNDEF_P(obj) (NIL_P(obj) || UNDEF_P(obj))
172
+ #endif
173
+
121
174
  static rawmode_arg_t *
122
175
  rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *opts)
123
176
  {
124
177
  int argc = *argcp;
125
178
  rawmode_arg_t *optp = NULL;
126
179
  VALUE vopts = Qnil;
180
+ VALUE optvals[rawmode_opt_id_count];
127
181
  #ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
128
182
  argc = rb_scan_args(argc, argv, "*:", NULL, &vopts);
129
183
  #else
@@ -138,19 +192,20 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
138
192
  }
139
193
  #endif
140
194
  rb_check_arity(argc, min_argc, max_argc);
141
- if (!NIL_P(vopts)) {
142
- VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
143
- VALUE vtime = rb_hash_aref(vopts, ID2SYM(id_time));
144
- VALUE intr = rb_hash_aref(vopts, ID2SYM(id_intr));
195
+ if (rb_get_kwargs(vopts, rawmode_opt_ids,
196
+ 0, rawmode_opt_id_count, optvals)) {
197
+ VALUE vmin = optvals[kwd_min];
198
+ VALUE vtime = optvals[kwd_time];
199
+ VALUE intr = optvals[kwd_intr];
145
200
  /* default values by `stty raw` */
146
201
  opts->vmin = 1;
147
202
  opts->vtime = 0;
148
203
  opts->intr = 0;
149
- if (!NIL_P(vmin)) {
204
+ if (!NIL_OR_UNDEF_P(vmin)) {
150
205
  opts->vmin = NUM2INT(vmin);
151
206
  optp = opts;
152
207
  }
153
- if (!NIL_P(vtime)) {
208
+ if (!NIL_OR_UNDEF_P(vtime)) {
154
209
  VALUE v10 = INT2FIX(10);
155
210
  vtime = rb_funcall3(vtime, '*', 1, &v10);
156
211
  opts->vtime = NUM2INT(vtime);
@@ -165,6 +220,7 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
165
220
  opts->intr = 0;
166
221
  optp = opts;
167
222
  break;
223
+ case Qundef:
168
224
  case Qnil:
169
225
  break;
170
226
  default:
@@ -275,33 +331,21 @@ set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg)
275
331
  return setattr(fd, &r);
276
332
  }
277
333
 
278
- #define GetReadFD(fptr) ((fptr)->fd)
279
-
280
- static inline int
281
- get_write_fd(const rb_io_t *fptr)
282
- {
283
- VALUE wio = fptr->tied_io_for_writing;
284
- rb_io_t *ofptr;
285
- if (!wio) return fptr->fd;
286
- GetOpenFile(wio, ofptr);
287
- return ofptr->fd;
288
- }
289
- #define GetWriteFD(fptr) get_write_fd(fptr)
334
+ #define GetReadFD(io) rb_io_descriptor(io)
335
+ #define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io))
290
336
 
291
337
  #define FD_PER_IO 2
292
338
 
293
339
  static VALUE
294
340
  ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
295
341
  {
296
- rb_io_t *fptr;
297
342
  int status = -1;
298
343
  int error = 0;
299
344
  int fd[FD_PER_IO];
300
345
  conmode t[FD_PER_IO];
301
346
  VALUE result = Qnil;
302
347
 
303
- GetOpenFile(io, fptr);
304
- fd[0] = GetReadFD(fptr);
348
+ fd[0] = GetReadFD(io);
305
349
  if (fd[0] != -1) {
306
350
  if (set_ttymode(fd[0], t+0, setter, arg)) {
307
351
  status = 0;
@@ -311,7 +355,7 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
311
355
  fd[0] = -1;
312
356
  }
313
357
  }
314
- fd[1] = GetWriteFD(fptr);
358
+ fd[1] = GetWriteFD(io);
315
359
  if (fd[1] != -1 && fd[1] != fd[0]) {
316
360
  if (set_ttymode(fd[1], t+1, setter, arg)) {
317
361
  status = 0;
@@ -324,14 +368,13 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
324
368
  if (status == 0) {
325
369
  result = rb_protect(func, farg, &status);
326
370
  }
327
- GetOpenFile(io, fptr);
328
- if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
371
+ if (fd[0] != -1 && fd[0] == GetReadFD(io)) {
329
372
  if (!setattr(fd[0], t+0)) {
330
373
  error = errno;
331
374
  status = -1;
332
375
  }
333
376
  }
334
- if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(fptr)) {
377
+ if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) {
335
378
  if (!setattr(fd[1], t+1)) {
336
379
  error = errno;
337
380
  status = -1;
@@ -417,15 +460,11 @@ static VALUE
417
460
  console_set_raw(int argc, VALUE *argv, VALUE io)
418
461
  {
419
462
  conmode t;
420
- rb_io_t *fptr;
421
- int fd;
422
463
  rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
423
-
424
- GetOpenFile(io, fptr);
425
- fd = GetReadFD(fptr);
426
- if (!getattr(fd, &t)) sys_fail_fptr(fptr);
464
+ int fd = GetReadFD(io);
465
+ if (!getattr(fd, &t)) sys_fail(io);
427
466
  set_rawmode(&t, optp);
428
- if (!setattr(fd, &t)) sys_fail_fptr(fptr);
467
+ if (!setattr(fd, &t)) sys_fail(io);
429
468
  return io;
430
469
  }
431
470
 
@@ -461,14 +500,10 @@ static VALUE
461
500
  console_set_cooked(VALUE io)
462
501
  {
463
502
  conmode t;
464
- rb_io_t *fptr;
465
- int fd;
466
-
467
- GetOpenFile(io, fptr);
468
- fd = GetReadFD(fptr);
469
- if (!getattr(fd, &t)) sys_fail_fptr(fptr);
503
+ int fd = GetReadFD(io);
504
+ if (!getattr(fd, &t)) sys_fail(io);
470
505
  set_cookedmode(&t, NULL);
471
- if (!setattr(fd, &t)) sys_fail_fptr(fptr);
506
+ if (!setattr(fd, &t)) sys_fail(io);
472
507
  return io;
473
508
  }
474
509
 
@@ -620,17 +655,17 @@ static VALUE
620
655
  console_set_echo(VALUE io, VALUE f)
621
656
  {
622
657
  conmode t;
623
- rb_io_t *fptr;
624
- int fd;
658
+ int fd = GetReadFD(io);
659
+
660
+ if (!getattr(fd, &t)) sys_fail(io);
625
661
 
626
- GetOpenFile(io, fptr);
627
- fd = GetReadFD(fptr);
628
- if (!getattr(fd, &t)) sys_fail_fptr(fptr);
629
662
  if (RTEST(f))
630
- set_echo(&t, NULL);
663
+ set_echo(&t, NULL);
631
664
  else
632
- set_noecho(&t, NULL);
633
- if (!setattr(fd, &t)) sys_fail_fptr(fptr);
665
+ set_noecho(&t, NULL);
666
+
667
+ if (!setattr(fd, &t)) sys_fail(io);
668
+
634
669
  return io;
635
670
  }
636
671
 
@@ -646,12 +681,9 @@ static VALUE
646
681
  console_echo_p(VALUE io)
647
682
  {
648
683
  conmode t;
649
- rb_io_t *fptr;
650
- int fd;
684
+ int fd = GetReadFD(io);
651
685
 
652
- GetOpenFile(io, fptr);
653
- fd = GetReadFD(fptr);
654
- if (!getattr(fd, &t)) sys_fail_fptr(fptr);
686
+ if (!getattr(fd, &t)) sys_fail(io);
655
687
  return echo_p(&t) ? Qtrue : Qfalse;
656
688
  }
657
689
 
@@ -730,12 +762,9 @@ static VALUE
730
762
  console_conmode_get(VALUE io)
731
763
  {
732
764
  conmode t;
733
- rb_io_t *fptr;
734
- int fd;
765
+ int fd = GetReadFD(io);
735
766
 
736
- GetOpenFile(io, fptr);
737
- fd = GetReadFD(fptr);
738
- if (!getattr(fd, &t)) sys_fail_fptr(fptr);
767
+ if (!getattr(fd, &t)) sys_fail(io);
739
768
 
740
769
  return conmode_new(cConmode, &t);
741
770
  }
@@ -752,14 +781,12 @@ static VALUE
752
781
  console_conmode_set(VALUE io, VALUE mode)
753
782
  {
754
783
  conmode *t, r;
755
- rb_io_t *fptr;
756
- int fd;
784
+ int fd = GetReadFD(io);
757
785
 
758
786
  TypedData_Get_Struct(mode, conmode, &conmode_type, t);
759
787
  r = *t;
760
- GetOpenFile(io, fptr);
761
- fd = GetReadFD(fptr);
762
- if (!setattr(fd, &r)) sys_fail_fptr(fptr);
788
+
789
+ if (!setattr(fd, &r)) sys_fail(io);
763
790
 
764
791
  return mode;
765
792
  }
@@ -795,13 +822,9 @@ typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
795
822
  static VALUE
796
823
  console_winsize(VALUE io)
797
824
  {
798
- rb_io_t *fptr;
799
- int fd;
800
825
  rb_console_size_t ws;
801
-
802
- GetOpenFile(io, fptr);
803
- fd = GetWriteFD(fptr);
804
- if (!getwinsize(fd, &ws)) sys_fail_fptr(fptr);
826
+ int fd = GetWriteFD(io);
827
+ if (!getwinsize(fd, &ws)) sys_fail(io);
805
828
  return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
806
829
  }
807
830
 
@@ -817,7 +840,6 @@ console_winsize(VALUE io)
817
840
  static VALUE
818
841
  console_set_winsize(VALUE io, VALUE size)
819
842
  {
820
- rb_io_t *fptr;
821
843
  rb_console_size_t ws;
822
844
  #if defined _WIN32
823
845
  HANDLE wh;
@@ -826,20 +848,17 @@ console_set_winsize(VALUE io, VALUE size)
826
848
  #endif
827
849
  VALUE row, col, xpixel, ypixel;
828
850
  const VALUE *sz;
829
- int fd;
830
851
  long sizelen;
852
+ int fd;
831
853
 
832
- GetOpenFile(io, fptr);
833
854
  size = rb_Array(size);
834
855
  if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
835
- rb_raise(rb_eArgError,
836
- "wrong number of arguments (given %ld, expected 2 or 4)",
837
- sizelen);
856
+ rb_raise(rb_eArgError, "wrong number of arguments (given %ld, expected 2 or 4)", sizelen);
838
857
  }
839
858
  sz = RARRAY_CONST_PTR(size);
840
859
  row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
841
860
  if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
842
- fd = GetWriteFD(fptr);
861
+ fd = GetWriteFD(io);
843
862
  #if defined TIOCSWINSZ
844
863
  ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
845
864
  #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -848,7 +867,7 @@ console_set_winsize(VALUE io, VALUE size)
848
867
  SET(xpixel);
849
868
  SET(ypixel);
850
869
  #undef SET
851
- if (!setwinsize(fd, &ws)) sys_fail_fptr(fptr);
870
+ if (!setwinsize(fd, &ws)) sys_fail(io);
852
871
  #elif defined _WIN32
853
872
  wh = (HANDLE)rb_w32_get_osfhandle(fd);
854
873
  #define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -883,15 +902,23 @@ console_set_winsize(VALUE io, VALUE size)
883
902
  #endif
884
903
 
885
904
  #ifdef _WIN32
905
+ /*
906
+ * call-seq:
907
+ * io.check_winsize_changed { ... } -> io
908
+ *
909
+ * Yields while console input events are queued.
910
+ *
911
+ * This method is Windows only.
912
+ *
913
+ * You must require 'io/console' to use this method.
914
+ */
886
915
  static VALUE
887
916
  console_check_winsize_changed(VALUE io)
888
917
  {
889
- rb_io_t *fptr;
890
918
  HANDLE h;
891
919
  DWORD num;
892
920
 
893
- GetOpenFile(io, fptr);
894
- h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
921
+ h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
895
922
  while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
896
923
  INPUT_RECORD rec;
897
924
  if (ReadConsoleInput(h, &rec, 1, &num)) {
@@ -917,15 +944,11 @@ console_check_winsize_changed(VALUE io)
917
944
  static VALUE
918
945
  console_iflush(VALUE io)
919
946
  {
920
- rb_io_t *fptr;
921
- int fd;
922
-
923
- GetOpenFile(io, fptr);
924
- fd = GetReadFD(fptr);
925
947
  #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
926
- if (tcflush(fd, TCIFLUSH)) sys_fail_fptr(fptr);
948
+ int fd = GetReadFD(io);
949
+ if (tcflush(fd, TCIFLUSH)) sys_fail(io);
927
950
  #endif
928
- (void)fd;
951
+
929
952
  return io;
930
953
  }
931
954
 
@@ -940,13 +963,9 @@ console_iflush(VALUE io)
940
963
  static VALUE
941
964
  console_oflush(VALUE io)
942
965
  {
943
- rb_io_t *fptr;
944
- int fd;
945
-
946
- GetOpenFile(io, fptr);
947
- fd = GetWriteFD(fptr);
966
+ int fd = GetWriteFD(io);
948
967
  #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
949
- if (tcflush(fd, TCOFLUSH)) sys_fail_fptr(fptr);
968
+ if (tcflush(fd, TCOFLUSH)) sys_fail(io);
950
969
  #endif
951
970
  (void)fd;
952
971
  return io;
@@ -963,40 +982,38 @@ console_oflush(VALUE io)
963
982
  static VALUE
964
983
  console_ioflush(VALUE io)
965
984
  {
966
- rb_io_t *fptr;
967
985
  #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
968
- int fd1, fd2;
969
- #endif
986
+ int fd1 = GetReadFD(io);
987
+ int fd2 = GetWriteFD(io);
970
988
 
971
- GetOpenFile(io, fptr);
972
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
973
- fd1 = GetReadFD(fptr);
974
- fd2 = GetWriteFD(fptr);
975
989
  if (fd2 != -1 && fd1 != fd2) {
976
- if (tcflush(fd1, TCIFLUSH)) sys_fail_fptr(fptr);
977
- if (tcflush(fd2, TCOFLUSH)) sys_fail_fptr(fptr);
990
+ if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
991
+ if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
978
992
  }
979
993
  else {
980
- if (tcflush(fd1, TCIOFLUSH)) sys_fail_fptr(fptr);
994
+ if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
981
995
  }
982
996
  #endif
997
+
983
998
  return io;
984
999
  }
985
1000
 
1001
+ /*
1002
+ * call-seq:
1003
+ * io.beep
1004
+ *
1005
+ * Beeps on the output console.
1006
+ *
1007
+ * You must require 'io/console' to use this method.
1008
+ */
986
1009
  static VALUE
987
1010
  console_beep(VALUE io)
988
1011
  {
989
- rb_io_t *fptr;
990
- int fd;
991
-
992
- GetOpenFile(io, fptr);
993
- fd = GetWriteFD(fptr);
994
1012
  #ifdef _WIN32
995
- (void)fd;
996
1013
  MessageBeep(0);
997
1014
  #else
998
- if (write(fd, "\a", 1) < 0)
999
- sys_fail_fptr(fptr);
1015
+ int fd = GetWriteFD(io);
1016
+ if (write(fd, "\a", 1) < 0) sys_fail(io);
1000
1017
  #endif
1001
1018
  return io;
1002
1019
  }
@@ -1017,79 +1034,6 @@ mode_in_range(VALUE val, int high, const char *modename)
1017
1034
  }
1018
1035
 
1019
1036
  #if defined _WIN32
1020
- static VALUE
1021
- console_goto(VALUE io, VALUE y, VALUE x)
1022
- {
1023
- rb_io_t *fptr;
1024
- int fd;
1025
- COORD pos;
1026
-
1027
- GetOpenFile(io, fptr);
1028
- fd = GetWriteFD(fptr);
1029
- pos.X = NUM2UINT(x);
1030
- pos.Y = NUM2UINT(y);
1031
- if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
1032
- rb_syserr_fail(LAST_ERROR, 0);
1033
- }
1034
- return io;
1035
- }
1036
-
1037
- static VALUE
1038
- console_cursor_pos(VALUE io)
1039
- {
1040
- rb_io_t *fptr;
1041
- int fd;
1042
- rb_console_size_t ws;
1043
-
1044
- GetOpenFile(io, fptr);
1045
- fd = GetWriteFD(fptr);
1046
- if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
1047
- rb_syserr_fail(LAST_ERROR, 0);
1048
- }
1049
- return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
1050
- }
1051
-
1052
- static VALUE
1053
- console_move(VALUE io, int y, int x)
1054
- {
1055
- rb_io_t *fptr;
1056
- HANDLE h;
1057
- rb_console_size_t ws;
1058
- COORD *pos = &ws.dwCursorPosition;
1059
-
1060
- GetOpenFile(io, fptr);
1061
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
1062
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
1063
- rb_syserr_fail(LAST_ERROR, 0);
1064
- }
1065
- pos->X += x;
1066
- pos->Y += y;
1067
- if (!SetConsoleCursorPosition(h, *pos)) {
1068
- rb_syserr_fail(LAST_ERROR, 0);
1069
- }
1070
- return io;
1071
- }
1072
-
1073
- static VALUE
1074
- console_goto_column(VALUE io, VALUE val)
1075
- {
1076
- rb_io_t *fptr;
1077
- HANDLE h;
1078
- rb_console_size_t ws;
1079
- COORD *pos = &ws.dwCursorPosition;
1080
-
1081
- GetOpenFile(io, fptr);
1082
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
1083
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
1084
- rb_syserr_fail(LAST_ERROR, 0);
1085
- }
1086
- pos->X = NUM2INT(val);
1087
- if (!SetConsoleCursorPosition(h, *pos)) {
1088
- rb_syserr_fail(LAST_ERROR, 0);
1089
- }
1090
- return io;
1091
- }
1092
-
1093
1037
  static void
1094
1038
  constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
1095
1039
  {
@@ -1099,87 +1043,13 @@ constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
1099
1043
  FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
1100
1044
  }
1101
1045
 
1102
- static VALUE
1103
- console_erase_line(VALUE io, VALUE val)
1104
- {
1105
- rb_io_t *fptr;
1106
- HANDLE h;
1107
- rb_console_size_t ws;
1108
- COORD *pos = &ws.dwCursorPosition;
1109
- DWORD w;
1110
- int mode = mode_in_range(val, 2, "line erase");
1111
-
1112
- GetOpenFile(io, fptr);
1113
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
1114
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
1115
- rb_syserr_fail(LAST_ERROR, 0);
1116
- }
1117
- w = winsize_col(&ws);
1118
- switch (mode) {
1119
- case 0: /* after cursor */
1120
- w -= pos->X;
1121
- break;
1122
- case 1: /* before *and* cursor */
1123
- w = pos->X + 1;
1124
- pos->X = 0;
1125
- break;
1126
- case 2: /* entire line */
1127
- pos->X = 0;
1128
- break;
1129
- }
1130
- constat_clear(h, ws.wAttributes, w, *pos);
1131
- return io;
1132
- }
1133
-
1134
- static VALUE
1135
- console_erase_screen(VALUE io, VALUE val)
1136
- {
1137
- rb_io_t *fptr;
1138
- HANDLE h;
1139
- rb_console_size_t ws;
1140
- COORD *pos = &ws.dwCursorPosition;
1141
- DWORD w;
1142
- int mode = mode_in_range(val, 3, "screen erase");
1143
-
1144
- GetOpenFile(io, fptr);
1145
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
1146
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
1147
- rb_syserr_fail(LAST_ERROR, 0);
1148
- }
1149
- w = winsize_col(&ws);
1150
- switch (mode) {
1151
- case 0: /* erase after cursor */
1152
- w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
1153
- break;
1154
- case 1: /* erase before *and* cursor */
1155
- w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
1156
- pos->X = 0;
1157
- pos->Y = ws.srWindow.Top;
1158
- break;
1159
- case 2: /* erase entire screen */
1160
- w = (w * winsize_row(&ws));
1161
- pos->X = 0;
1162
- pos->Y = ws.srWindow.Top;
1163
- break;
1164
- case 3: /* erase entire screen */
1165
- w = (w * ws.dwSize.Y);
1166
- pos->X = 0;
1167
- pos->Y = 0;
1168
- break;
1169
- }
1170
- constat_clear(h, ws.wAttributes, w, *pos);
1171
- return io;
1172
- }
1173
-
1174
1046
  static VALUE
1175
1047
  console_scroll(VALUE io, int line)
1176
1048
  {
1177
- rb_io_t *fptr;
1178
1049
  HANDLE h;
1179
1050
  rb_console_size_t ws;
1180
1051
 
1181
- GetOpenFile(io, fptr);
1182
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
1052
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1183
1053
  if (!GetConsoleScreenBufferInfo(h, &ws)) {
1184
1054
  rb_syserr_fail(LAST_ERROR, 0);
1185
1055
  }
@@ -1203,6 +1073,17 @@ console_scroll(VALUE io, int line)
1203
1073
 
1204
1074
  #include "win32_vk.inc"
1205
1075
 
1076
+ /*
1077
+ * call-seq:
1078
+ * io.pressed?(key) -> bool
1079
+ *
1080
+ * Returns +true+ if +key+ is pressed. +key+ may be a virtual key
1081
+ * code or its name (String or Symbol) with out "VK_" prefix.
1082
+ *
1083
+ * This method is Windows only.
1084
+ *
1085
+ * You must require 'io/console' to use this method.
1086
+ */
1206
1087
  static VALUE
1207
1088
  console_key_pressed_p(VALUE io, VALUE k)
1208
1089
  {
@@ -1238,23 +1119,11 @@ static int
1238
1119
  direct_query(VALUE io, const struct query_args *query)
1239
1120
  {
1240
1121
  if (RB_TYPE_P(io, T_FILE)) {
1241
- rb_io_t *fptr;
1242
- VALUE wio;
1243
- GetOpenFile(io, fptr);
1244
- wio = fptr->tied_io_for_writing;
1245
- if (wio) {
1246
- VALUE s = rb_str_new_cstr(query->qstr);
1247
- rb_io_write(wio, s);
1248
- rb_io_flush(wio);
1249
- return 1;
1250
- }
1251
- if (write(fptr->fd, query->qstr, strlen(query->qstr)) != -1) {
1252
- return 1;
1253
- }
1254
- if (fptr->fd == 0 &&
1255
- write(1, query->qstr, strlen(query->qstr)) != -1) {
1256
- return 1;
1257
- }
1122
+ VALUE wio = rb_io_get_write_io(io);
1123
+ VALUE s = rb_str_new_cstr(query->qstr);
1124
+ rb_io_write(wio, s);
1125
+ rb_io_flush(wio);
1126
+ return 1;
1258
1127
  }
1259
1128
  return 0;
1260
1129
  }
@@ -1304,9 +1173,41 @@ console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qa
1304
1173
  return ret;
1305
1174
  }
1306
1175
 
1176
+ static VALUE
1177
+ console_scroll(VALUE io, int line)
1178
+ {
1179
+ if (line) {
1180
+ VALUE s = rb_sprintf(CSI "%d%c", line < 0 ? -line : line,
1181
+ line < 0 ? 'T' : 'S');
1182
+ rb_io_write(io, s);
1183
+ }
1184
+ return io;
1185
+ }
1186
+
1187
+ # define console_key_pressed_p rb_f_notimplement
1188
+ #endif
1189
+
1190
+ /*
1191
+ * call-seq:
1192
+ * io.cursor -> [row, column]
1193
+ *
1194
+ * Returns the current cursor position as a two-element array of integers (row, column)
1195
+ *
1196
+ * io.cursor # => [3, 5]
1197
+ *
1198
+ * You must require 'io/console' to use this method.
1199
+ */
1307
1200
  static VALUE
1308
1201
  console_cursor_pos(VALUE io)
1309
1202
  {
1203
+ #ifdef _WIN32
1204
+ rb_console_size_t ws;
1205
+ int fd = GetWriteFD(io);
1206
+ if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
1207
+ rb_syserr_fail(LAST_ERROR, 0);
1208
+ }
1209
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
1210
+ #else
1310
1211
  static const struct query_args query = {"\033[6n", 0};
1311
1212
  VALUE resp = console_vt_response(0, 0, io, &query);
1312
1213
  VALUE row, column, term;
@@ -1323,64 +1224,205 @@ console_cursor_pos(VALUE io)
1323
1224
  RARRAY_ASET(resp, 0, INT2NUM(r));
1324
1225
  RARRAY_ASET(resp, 1, INT2NUM(c));
1325
1226
  return resp;
1227
+ #endif
1326
1228
  }
1327
1229
 
1230
+ /*
1231
+ * call-seq:
1232
+ * io.goto(line, column) -> io
1233
+ *
1234
+ * Set the cursor position at +line+ and +column+.
1235
+ *
1236
+ * You must require 'io/console' to use this method.
1237
+ */
1328
1238
  static VALUE
1329
1239
  console_goto(VALUE io, VALUE y, VALUE x)
1330
1240
  {
1331
- rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
1241
+ #ifdef _WIN32
1242
+ COORD pos;
1243
+ int fd = GetWriteFD(io);
1244
+ pos.X = NUM2UINT(x);
1245
+ pos.Y = NUM2UINT(y);
1246
+ if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
1247
+ rb_syserr_fail(LAST_ERROR, 0);
1248
+ }
1249
+ #else
1250
+ rb_io_write(io, rb_sprintf(CSI "%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
1251
+ #endif
1332
1252
  return io;
1333
1253
  }
1334
1254
 
1335
1255
  static VALUE
1336
1256
  console_move(VALUE io, int y, int x)
1337
1257
  {
1258
+ #ifdef _WIN32
1259
+ HANDLE h;
1260
+ rb_console_size_t ws;
1261
+ COORD *pos = &ws.dwCursorPosition;
1262
+
1263
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1264
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
1265
+ rb_syserr_fail(LAST_ERROR, 0);
1266
+ }
1267
+ pos->X += x;
1268
+ pos->Y += y;
1269
+ if (!SetConsoleCursorPosition(h, *pos)) {
1270
+ rb_syserr_fail(LAST_ERROR, 0);
1271
+ }
1272
+ #else
1338
1273
  if (x || y) {
1339
1274
  VALUE s = rb_str_new_cstr("");
1340
- if (y) rb_str_catf(s, "\x1b[%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
1341
- if (x) rb_str_catf(s, "\x1b[%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
1275
+ if (y) rb_str_catf(s, CSI "%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
1276
+ if (x) rb_str_catf(s, CSI "%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
1342
1277
  rb_io_write(io, s);
1343
1278
  rb_io_flush(io);
1344
1279
  }
1280
+ #endif
1345
1281
  return io;
1346
1282
  }
1347
1283
 
1284
+ /*
1285
+ * call-seq:
1286
+ * io.goto_column(column) -> io
1287
+ *
1288
+ * Set the cursor position at +column+ in the same line of the current
1289
+ * position.
1290
+ *
1291
+ * You must require 'io/console' to use this method.
1292
+ */
1348
1293
  static VALUE
1349
1294
  console_goto_column(VALUE io, VALUE val)
1350
1295
  {
1351
- rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
1296
+ #ifdef _WIN32
1297
+ HANDLE h;
1298
+ rb_console_size_t ws;
1299
+ COORD *pos = &ws.dwCursorPosition;
1300
+
1301
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1302
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
1303
+ rb_syserr_fail(LAST_ERROR, 0);
1304
+ }
1305
+ pos->X = NUM2INT(val);
1306
+ if (!SetConsoleCursorPosition(h, *pos)) {
1307
+ rb_syserr_fail(LAST_ERROR, 0);
1308
+ }
1309
+ #else
1310
+ rb_io_write(io, rb_sprintf(CSI "%dG", NUM2UINT(val)+1));
1311
+ #endif
1352
1312
  return io;
1353
1313
  }
1354
1314
 
1315
+ /*
1316
+ * call-seq:
1317
+ * io.erase_line(mode) -> io
1318
+ *
1319
+ * Erases the line at the cursor corresponding to +mode+.
1320
+ * +mode+ may be either:
1321
+ * 0: after cursor
1322
+ * 1: before and cursor
1323
+ * 2: entire line
1324
+ *
1325
+ * You must require 'io/console' to use this method.
1326
+ */
1355
1327
  static VALUE
1356
1328
  console_erase_line(VALUE io, VALUE val)
1357
1329
  {
1358
1330
  int mode = mode_in_range(val, 2, "line erase");
1359
- rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
1331
+ #ifdef _WIN32
1332
+ HANDLE h;
1333
+ rb_console_size_t ws;
1334
+ COORD *pos = &ws.dwCursorPosition;
1335
+ DWORD w;
1336
+
1337
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1338
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
1339
+ rb_syserr_fail(LAST_ERROR, 0);
1340
+ }
1341
+ w = winsize_col(&ws);
1342
+ switch (mode) {
1343
+ case 0: /* after cursor */
1344
+ w -= pos->X;
1345
+ break;
1346
+ case 1: /* before *and* cursor */
1347
+ w = pos->X + 1;
1348
+ pos->X = 0;
1349
+ break;
1350
+ case 2: /* entire line */
1351
+ pos->X = 0;
1352
+ break;
1353
+ }
1354
+ constat_clear(h, ws.wAttributes, w, *pos);
1355
+ return io;
1356
+ #else
1357
+ rb_io_write(io, rb_sprintf(CSI "%dK", mode));
1358
+ #endif
1360
1359
  return io;
1361
1360
  }
1362
1361
 
1362
+ /*
1363
+ * call-seq:
1364
+ * io.erase_screen(mode) -> io
1365
+ *
1366
+ * Erases the screen at the cursor corresponding to +mode+.
1367
+ * +mode+ may be either:
1368
+ * 0: after cursor
1369
+ * 1: before and cursor
1370
+ * 2: entire screen
1371
+ *
1372
+ * You must require 'io/console' to use this method.
1373
+ */
1363
1374
  static VALUE
1364
1375
  console_erase_screen(VALUE io, VALUE val)
1365
1376
  {
1366
1377
  int mode = mode_in_range(val, 3, "screen erase");
1367
- rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
1368
- return io;
1369
- }
1378
+ #ifdef _WIN32
1379
+ HANDLE h;
1380
+ rb_console_size_t ws;
1381
+ COORD *pos = &ws.dwCursorPosition;
1382
+ DWORD w;
1370
1383
 
1371
- static VALUE
1372
- console_scroll(VALUE io, int line)
1373
- {
1374
- if (line) {
1375
- VALUE s = rb_sprintf("\x1b[%d%c", line < 0 ? -line : line,
1376
- line < 0 ? 'T' : 'S');
1377
- rb_io_write(io, s);
1384
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1385
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
1386
+ rb_syserr_fail(LAST_ERROR, 0);
1387
+ }
1388
+ w = winsize_col(&ws);
1389
+ switch (mode) {
1390
+ case 0: /* erase after cursor */
1391
+ w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
1392
+ break;
1393
+ case 1: /* erase before *and* cursor */
1394
+ w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
1395
+ pos->X = 0;
1396
+ pos->Y = ws.srWindow.Top;
1397
+ break;
1398
+ case 2: /* erase entire screen */
1399
+ w = (w * winsize_row(&ws));
1400
+ pos->X = 0;
1401
+ pos->Y = ws.srWindow.Top;
1402
+ break;
1403
+ case 3: /* erase entire screen */
1404
+ w = (w * ws.dwSize.Y);
1405
+ pos->X = 0;
1406
+ pos->Y = 0;
1407
+ break;
1378
1408
  }
1409
+ constat_clear(h, ws.wAttributes, w, *pos);
1410
+ #else
1411
+ rb_io_write(io, rb_sprintf(CSI "%dJ", mode));
1412
+ #endif
1379
1413
  return io;
1380
1414
  }
1381
- # define console_key_pressed_p rb_f_notimplement
1382
- #endif
1383
1415
 
1416
+ /*
1417
+ * call-seq:
1418
+ * io.cursor = [line, column] -> io
1419
+ *
1420
+ * Same as <tt>io.goto(line, column)</tt>
1421
+ *
1422
+ * See IO#goto.
1423
+ *
1424
+ * You must require 'io/console' to use this method.
1425
+ */
1384
1426
  static VALUE
1385
1427
  console_cursor_set(VALUE io, VALUE cpos)
1386
1428
  {
@@ -1389,42 +1431,98 @@ console_cursor_set(VALUE io, VALUE cpos)
1389
1431
  return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
1390
1432
  }
1391
1433
 
1434
+ /*
1435
+ * call-seq:
1436
+ * io.cursor_up(n) -> io
1437
+ *
1438
+ * Moves the cursor up +n+ lines.
1439
+ *
1440
+ * You must require 'io/console' to use this method.
1441
+ */
1392
1442
  static VALUE
1393
1443
  console_cursor_up(VALUE io, VALUE val)
1394
1444
  {
1395
1445
  return console_move(io, -NUM2INT(val), 0);
1396
1446
  }
1397
1447
 
1448
+ /*
1449
+ * call-seq:
1450
+ * io.cursor_down(n) -> io
1451
+ *
1452
+ * Moves the cursor down +n+ lines.
1453
+ *
1454
+ * You must require 'io/console' to use this method.
1455
+ */
1398
1456
  static VALUE
1399
1457
  console_cursor_down(VALUE io, VALUE val)
1400
1458
  {
1401
1459
  return console_move(io, +NUM2INT(val), 0);
1402
1460
  }
1403
1461
 
1462
+ /*
1463
+ * call-seq:
1464
+ * io.cursor_left(n) -> io
1465
+ *
1466
+ * Moves the cursor left +n+ columns.
1467
+ *
1468
+ * You must require 'io/console' to use this method.
1469
+ */
1404
1470
  static VALUE
1405
1471
  console_cursor_left(VALUE io, VALUE val)
1406
1472
  {
1407
1473
  return console_move(io, 0, -NUM2INT(val));
1408
1474
  }
1409
1475
 
1476
+ /*
1477
+ * call-seq:
1478
+ * io.cursor_right(n) -> io
1479
+ *
1480
+ * Moves the cursor right +n+ columns.
1481
+ *
1482
+ * You must require 'io/console' to use this method.
1483
+ */
1410
1484
  static VALUE
1411
1485
  console_cursor_right(VALUE io, VALUE val)
1412
1486
  {
1413
1487
  return console_move(io, 0, +NUM2INT(val));
1414
1488
  }
1415
1489
 
1490
+ /*
1491
+ * call-seq:
1492
+ * io.scroll_forward(n) -> io
1493
+ *
1494
+ * Scrolls the entire scrolls forward +n+ lines.
1495
+ *
1496
+ * You must require 'io/console' to use this method.
1497
+ */
1416
1498
  static VALUE
1417
1499
  console_scroll_forward(VALUE io, VALUE val)
1418
1500
  {
1419
1501
  return console_scroll(io, +NUM2INT(val));
1420
1502
  }
1421
1503
 
1504
+ /*
1505
+ * call-seq:
1506
+ * io.scroll_backward(n) -> io
1507
+ *
1508
+ * Scrolls the entire scrolls backward +n+ lines.
1509
+ *
1510
+ * You must require 'io/console' to use this method.
1511
+ */
1422
1512
  static VALUE
1423
1513
  console_scroll_backward(VALUE io, VALUE val)
1424
1514
  {
1425
1515
  return console_scroll(io, -NUM2INT(val));
1426
1516
  }
1427
1517
 
1518
+ /*
1519
+ * call-seq:
1520
+ * io.clear_screen -> io
1521
+ *
1522
+ * Clears the entire screen and moves the cursor top-left corner.
1523
+ *
1524
+ * You must require 'io/console' to use this method.
1525
+ */
1428
1526
  static VALUE
1429
1527
  console_clear_screen(VALUE io)
1430
1528
  {
@@ -1433,6 +1531,38 @@ console_clear_screen(VALUE io)
1433
1531
  return io;
1434
1532
  }
1435
1533
 
1534
+ #ifndef HAVE_RB_IO_OPEN_DESCRIPTOR
1535
+ static VALUE
1536
+ io_open_descriptor_fallback(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, void *encoding)
1537
+ {
1538
+ rb_update_max_fd(descriptor);
1539
+
1540
+ VALUE arguments[2] = {
1541
+ INT2NUM(descriptor),
1542
+ INT2FIX(mode),
1543
+ };
1544
+
1545
+ VALUE self = rb_class_new_instance(2, arguments, klass);
1546
+
1547
+ rb_io_t *fptr;
1548
+ GetOpenFile(self, fptr);
1549
+ fptr->pathv = path;
1550
+ fptr->mode |= mode;
1551
+
1552
+ return self;
1553
+ }
1554
+ #define rb_io_open_descriptor io_open_descriptor_fallback
1555
+ #endif
1556
+
1557
+ #ifndef HAVE_RB_IO_CLOSED_P
1558
+ static VALUE
1559
+ rb_io_closed_p(VALUE io)
1560
+ {
1561
+ rb_io_t *fptr = RFILE(io)->fptr;
1562
+ return fptr->fd == -1 ? Qtrue : Qfalse;
1563
+ }
1564
+ #endif
1565
+
1436
1566
  /*
1437
1567
  * call-seq:
1438
1568
  * IO.console -> #<File:/dev/tty>
@@ -1450,34 +1580,37 @@ static VALUE
1450
1580
  console_dev(int argc, VALUE *argv, VALUE klass)
1451
1581
  {
1452
1582
  VALUE con = 0;
1453
- rb_io_t *fptr;
1454
1583
  VALUE sym = 0;
1455
1584
 
1456
1585
  rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
1586
+
1457
1587
  if (argc) {
1458
- Check_Type(sym = argv[0], T_SYMBOL);
1588
+ Check_Type(sym = argv[0], T_SYMBOL);
1459
1589
  }
1590
+
1591
+ // Force the class to be File.
1460
1592
  if (klass == rb_cIO) klass = rb_cFile;
1593
+
1461
1594
  if (rb_const_defined(klass, id_console)) {
1462
- con = rb_const_get(klass, id_console);
1463
- if (!RB_TYPE_P(con, T_FILE) ||
1464
- (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
1465
- rb_const_remove(klass, id_console);
1466
- con = 0;
1467
- }
1595
+ con = rb_const_get(klass, id_console);
1596
+ if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
1597
+ rb_const_remove(klass, id_console);
1598
+ con = 0;
1599
+ }
1468
1600
  }
1601
+
1469
1602
  if (sym) {
1470
- if (sym == ID2SYM(id_close) && argc == 1) {
1471
- if (con) {
1472
- rb_io_close(con);
1473
- rb_const_remove(klass, id_console);
1474
- con = 0;
1475
- }
1476
- return Qnil;
1477
- }
1603
+ if (sym == ID2SYM(id_close) && argc == 1) {
1604
+ if (con) {
1605
+ rb_io_close(con);
1606
+ rb_const_remove(klass, id_console);
1607
+ con = 0;
1608
+ }
1609
+ return Qnil;
1610
+ }
1478
1611
  }
1612
+
1479
1613
  if (!con) {
1480
- VALUE args[2];
1481
1614
  #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
1482
1615
  # define CONSOLE_DEVICE "/dev/tty"
1483
1616
  #elif defined _WIN32
@@ -1489,44 +1622,36 @@ console_dev(int argc, VALUE *argv, VALUE klass)
1489
1622
  # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
1490
1623
  #endif
1491
1624
  #ifdef CONSOLE_DEVICE_FOR_WRITING
1492
- VALUE out;
1493
- rb_io_t *ofptr;
1625
+ VALUE out;
1626
+ rb_io_t *ofptr;
1494
1627
  #endif
1495
- int fd;
1628
+ int fd;
1629
+ VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
1496
1630
 
1497
1631
  #ifdef CONSOLE_DEVICE_FOR_WRITING
1498
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
1499
- if (fd < 0) return Qnil;
1500
- rb_update_max_fd(fd);
1501
- args[1] = INT2FIX(O_WRONLY);
1502
- args[0] = INT2NUM(fd);
1503
- out = rb_class_new_instance(2, args, klass);
1632
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
1633
+ if (fd < 0) return Qnil;
1634
+ out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
1504
1635
  #endif
1505
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
1506
- if (fd < 0) {
1636
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
1637
+ if (fd < 0) {
1507
1638
  #ifdef CONSOLE_DEVICE_FOR_WRITING
1508
- rb_io_close(out);
1639
+ rb_io_close(out);
1509
1640
  #endif
1510
- return Qnil;
1511
- }
1512
- rb_update_max_fd(fd);
1513
- args[1] = INT2FIX(O_RDWR);
1514
- args[0] = INT2NUM(fd);
1515
- con = rb_class_new_instance(2, args, klass);
1516
- GetOpenFile(con, fptr);
1517
- fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
1641
+ return Qnil;
1642
+ }
1643
+
1644
+ con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
1518
1645
  #ifdef CONSOLE_DEVICE_FOR_WRITING
1519
- GetOpenFile(out, ofptr);
1520
- ofptr->pathv = fptr->pathv;
1521
- fptr->tied_io_for_writing = out;
1522
- ofptr->mode |= FMODE_SYNC;
1646
+ rb_io_set_write_io(con, out);
1523
1647
  #endif
1524
- fptr->mode |= FMODE_SYNC;
1525
- rb_const_set(klass, id_console, con);
1648
+ rb_const_set(klass, id_console, con);
1526
1649
  }
1650
+
1527
1651
  if (sym) {
1528
- return rb_f_send(argc, argv, con);
1652
+ return rb_f_send(argc, argv, con);
1529
1653
  }
1654
+
1530
1655
  return con;
1531
1656
  }
1532
1657
 
@@ -1542,13 +1667,18 @@ io_getch(int argc, VALUE *argv, VALUE io)
1542
1667
  return rb_funcallv(io, id_getc, argc, argv);
1543
1668
  }
1544
1669
 
1545
- #if ENABLE_IO_GETPASS
1546
1670
  static VALUE
1547
1671
  puts_call(VALUE io)
1548
1672
  {
1549
1673
  return rb_io_write(io, rb_default_rs);
1550
1674
  }
1551
1675
 
1676
+ static VALUE
1677
+ gets_call(VALUE io)
1678
+ {
1679
+ return rb_funcallv(io, id_gets, 0, 0);
1680
+ }
1681
+
1552
1682
  static VALUE
1553
1683
  getpass_call(VALUE io)
1554
1684
  {
@@ -1569,7 +1699,8 @@ static VALUE
1569
1699
  str_chomp(VALUE str)
1570
1700
  {
1571
1701
  if (!NIL_P(str)) {
1572
- rb_funcallv(str, id_chomp_bang, 0, 0);
1702
+ const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */
1703
+ rb_funcallv(str, id_chomp_bang, 1, &rs);
1573
1704
  }
1574
1705
  return str;
1575
1706
  }
@@ -1586,6 +1717,12 @@ str_chomp(VALUE str)
1586
1717
  * see String#chomp!.
1587
1718
  *
1588
1719
  * You must require 'io/console' to use this method.
1720
+ *
1721
+ * require 'io/console'
1722
+ * IO::console.getpass("Enter password:")
1723
+ * Enter password:
1724
+ * # => "mypassword"
1725
+ *
1589
1726
  */
1590
1727
  static VALUE
1591
1728
  console_getpass(int argc, VALUE *argv, VALUE io)
@@ -1596,6 +1733,7 @@ console_getpass(int argc, VALUE *argv, VALUE io)
1596
1733
  wio = rb_io_get_write_io(io);
1597
1734
  if (wio == io && io == rb_stdin) wio = rb_stderr;
1598
1735
  prompt(argc, argv, wio);
1736
+ rb_io_flush(wio);
1599
1737
  str = rb_ensure(getpass_call, io, puts_call, wio);
1600
1738
  return str_chomp(str);
1601
1739
  }
@@ -1613,11 +1751,10 @@ io_getpass(int argc, VALUE *argv, VALUE io)
1613
1751
 
1614
1752
  rb_check_arity(argc, 0, 1);
1615
1753
  prompt(argc, argv, io);
1616
- str = str_chomp(rb_funcallv(io, id_gets, 0, 0));
1617
- puts_call(io);
1618
- return str;
1754
+ rb_check_funcall(io, id_flush, 0, 0);
1755
+ str = rb_ensure(gets_call, io, puts_call, io);
1756
+ return str_chomp(str);
1619
1757
  }
1620
- #endif
1621
1758
 
1622
1759
  /*
1623
1760
  * IO console methods
@@ -1627,15 +1764,16 @@ Init_console(void)
1627
1764
  {
1628
1765
  #undef rb_intern
1629
1766
  id_getc = rb_intern("getc");
1630
- #if ENABLE_IO_GETPASS
1631
1767
  id_gets = rb_intern("gets");
1768
+ id_flush = rb_intern("flush");
1632
1769
  id_chomp_bang = rb_intern("chomp!");
1633
- #endif
1634
1770
  id_console = rb_intern("console");
1635
1771
  id_close = rb_intern("close");
1636
- id_min = rb_intern("min");
1637
- id_time = rb_intern("time");
1638
- id_intr = rb_intern("intr");
1772
+ #define init_rawmode_opt_id(name) \
1773
+ rawmode_opt_ids[kwd_##name] = rb_intern(#name)
1774
+ init_rawmode_opt_id(min);
1775
+ init_rawmode_opt_id(time);
1776
+ init_rawmode_opt_id(intr);
1639
1777
  #ifndef HAVE_RB_F_SEND
1640
1778
  id___send__ = rb_intern("__send__");
1641
1779
  #endif
@@ -1676,20 +1814,19 @@ InitVM_console(void)
1676
1814
  rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
1677
1815
  rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
1678
1816
  rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
1679
- #if ENABLE_IO_GETPASS
1680
1817
  rb_define_method(rb_cIO, "getpass", console_getpass, -1);
1681
- #endif
1682
1818
  rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
1683
1819
  {
1820
+ /* :stopdoc: */
1684
1821
  VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
1822
+ /* :startdoc: */
1685
1823
  rb_define_method(mReadable, "getch", io_getch, -1);
1686
- #if ENABLE_IO_GETPASS
1687
1824
  rb_define_method(mReadable, "getpass", io_getpass, -1);
1688
- #endif
1689
1825
  }
1690
1826
  {
1691
1827
  /* :stopdoc: */
1692
1828
  cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
1829
+ rb_define_const(cConmode, "VERSION", rb_str_new_cstr(IO_CONSOLE_VERSION));
1693
1830
  rb_define_alloc_func(cConmode, conmode_alloc);
1694
1831
  rb_undef_method(cConmode, "initialize");
1695
1832
  rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: false
2
2
  require 'mkmf'
3
3
 
4
+ have_func("rb_io_path")
5
+ have_func("rb_io_descriptor")
6
+ have_func("rb_io_get_write_io")
7
+ have_func("rb_io_closed_p")
8
+ have_func("rb_io_open_descriptor")
9
+
4
10
  ok = true if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
5
11
  hdr = nil
6
12
  case
@@ -29,7 +35,6 @@ when true
29
35
  elsif have_func("rb_scheduler_timeout") # 3.0
30
36
  have_func("rb_io_wait")
31
37
  end
32
- $defs << "-D""ENABLE_IO_GETPASS=1"
33
38
  create_makefile("io/console") {|conf|
34
39
  conf << "\n""VK_HEADER = #{vk_header}\n"
35
40
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-console
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.11
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobu Nakada
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-29 00:00:00.000000000 Z
11
+ date: 2024-01-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: add console capabilities to IO instances.
14
14
  email: nobu@ruby-lang.org
@@ -17,6 +17,7 @@ extensions:
17
17
  - ext/io/console/extconf.rb
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".document"
20
21
  - LICENSE.txt
21
22
  - README.md
22
23
  - ext/io/console/console.c
@@ -29,6 +30,7 @@ licenses:
29
30
  - BSD-2-Clause
30
31
  metadata:
31
32
  source_code_url: https://github.com/ruby/io-console
33
+ changelog_uri: https://github.com/ruby/io-console/releases
32
34
  post_install_message:
33
35
  rdoc_options: []
34
36
  require_paths:
@@ -44,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
46
  - !ruby/object:Gem::Version
45
47
  version: '0'
46
48
  requirements: []
47
- rubygems_version: 3.2.32
49
+ rubygems_version: 3.6.0.dev
48
50
  signing_key:
49
51
  specification_version: 4
50
52
  summary: Console interface