brakeman 6.2.1 → 6.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +10 -0
  3. data/README.md +0 -1
  4. data/bundle/load.rb +3 -4
  5. data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/Changelog.md +6 -0
  6. data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/Gemfile +1 -0
  7. data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/README.md +3 -0
  8. data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/version.rb +1 -1
  9. data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline.rb +9 -1
  10. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/config.rb +19 -24
  11. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/face.rb +1 -1
  12. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/io/ansi.rb +8 -0
  13. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/io/windows.rb +24 -14
  14. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/line_editor.rb +39 -48
  15. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/terminfo.rb +1 -1
  16. data/bundle/ruby/3.1.0/gems/reline-0.5.10/lib/reline/unicode/east_asian_width.rb +1267 -0
  17. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/unicode.rb +14 -39
  18. data/bundle/ruby/3.1.0/gems/reline-0.5.10/lib/reline/version.rb +3 -0
  19. data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline.rb +7 -4
  20. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/NEWS.md +43 -0
  21. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/attribute.rb +3 -2
  22. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/document.rb +5 -1
  23. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/entity.rb +5 -2
  24. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/baseparser.rb +9 -4
  25. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/pullparser.rb +8 -0
  26. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/sax2parser.rb +10 -0
  27. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/streamparser.rb +8 -0
  28. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/rexml.rb +1 -1
  29. data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/text.rb +5 -3
  30. data/lib/brakeman/checks/check_eol_rails.rb +6 -0
  31. data/lib/brakeman/checks/check_execute.rb +28 -0
  32. data/lib/brakeman/version.rb +1 -1
  33. metadata +115 -133
  34. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/README.md +0 -46
  35. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/Makefile +0 -270
  36. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/console.c +0 -1838
  37. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/console.o +0 -0
  38. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/console.so +0 -0
  39. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/extconf.rb +0 -43
  40. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/ext/io/console/win32_vk.inc +0 -1391
  41. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/lib/io/console/size.rb +0 -23
  42. data/bundle/ruby/3.1.0/gems/io-console-0.7.2/lib/io/console.so +0 -0
  43. data/bundle/ruby/3.1.0/gems/reline-0.5.9/lib/reline/unicode/east_asian_width.rb +0 -1196
  44. data/bundle/ruby/3.1.0/gems/reline-0.5.9/lib/reline/version.rb +0 -3
  45. data/bundle/ruby/3.1.0/gems/rexml-3.3.6/LICENSE.txt +0 -22
  46. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/COPYING +0 -56
  47. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/LICENSE.txt +0 -22
  48. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/ext/strscan/Makefile +0 -268
  49. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/ext/strscan/extconf.rb +0 -10
  50. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/ext/strscan/strscan.c +0 -1741
  51. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/ext/strscan/strscan.o +0 -0
  52. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/ext/strscan/strscan.so +0 -0
  53. data/bundle/ruby/3.1.0/gems/strscan-3.1.0/lib/strscan.so +0 -0
  54. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/AUTHORS +0 -0
  55. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/COPYING +0 -0
  56. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/LICENSE +0 -0
  57. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/TODO +0 -0
  58. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/highline.gemspec +0 -0
  59. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/builtin_styles.rb +0 -0
  60. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/color_scheme.rb +0 -0
  61. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/compatibility.rb +0 -0
  62. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/custom_errors.rb +0 -0
  63. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/import.rb +0 -0
  64. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/io_console_compatible.rb +0 -0
  65. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/list.rb +0 -0
  66. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/list_renderer.rb +0 -0
  67. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/menu/item.rb +0 -0
  68. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/menu.rb +0 -0
  69. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/paginator.rb +0 -0
  70. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/question/answer_converter.rb +0 -0
  71. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/question.rb +0 -0
  72. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/question_asker.rb +0 -0
  73. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/simulate.rb +0 -0
  74. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/statement.rb +0 -0
  75. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/string.rb +0 -0
  76. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/string_extensions.rb +0 -0
  77. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/style.rb +0 -0
  78. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/template_renderer.rb +0 -0
  79. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/terminal/io_console.rb +0 -0
  80. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/terminal/ncurses.rb +0 -0
  81. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/terminal/unix_stty.rb +0 -0
  82. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/terminal.rb +0 -0
  83. /data/bundle/ruby/3.1.0/gems/{highline-3.1.0 → highline-3.1.1}/lib/highline/wrapper.rb +0 -0
  84. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/BSDL +0 -0
  85. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/COPYING +0 -0
  86. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/README.md +0 -0
  87. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/history.rb +0 -0
  88. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/io/dumb.rb +0 -0
  89. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/io.rb +0 -0
  90. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor/base.rb +0 -0
  91. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor/composite.rb +0 -0
  92. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor/emacs.rb +0 -0
  93. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor/vi_command.rb +0 -0
  94. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor/vi_insert.rb +0 -0
  95. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_actor.rb +0 -0
  96. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/key_stroke.rb +0 -0
  97. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/lib/reline/kill_ring.rb +0 -0
  98. /data/bundle/ruby/3.1.0/gems/{reline-0.5.9 → reline-0.5.10}/license_of_rb-readline +0 -0
  99. /data/bundle/ruby/3.1.0/gems/{io-console-0.7.2 → rexml-3.3.8}/LICENSE.txt +0 -0
  100. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/README.md +0 -0
  101. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/attlistdecl.rb +0 -0
  102. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/cdata.rb +0 -0
  103. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/child.rb +0 -0
  104. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/comment.rb +0 -0
  105. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/doctype.rb +0 -0
  106. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/dtd/attlistdecl.rb +0 -0
  107. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/dtd/dtd.rb +0 -0
  108. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/dtd/elementdecl.rb +0 -0
  109. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/dtd/entitydecl.rb +0 -0
  110. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/dtd/notationdecl.rb +0 -0
  111. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/element.rb +0 -0
  112. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/encoding.rb +0 -0
  113. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/formatters/default.rb +0 -0
  114. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/formatters/pretty.rb +0 -0
  115. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/formatters/transitive.rb +0 -0
  116. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/functions.rb +0 -0
  117. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/instruction.rb +0 -0
  118. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/light/node.rb +0 -0
  119. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/namespace.rb +0 -0
  120. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/node.rb +0 -0
  121. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/output.rb +0 -0
  122. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parent.rb +0 -0
  123. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parseexception.rb +0 -0
  124. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/lightparser.rb +0 -0
  125. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/treeparser.rb +0 -0
  126. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/ultralightparser.rb +0 -0
  127. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/parsers/xpathparser.rb +0 -0
  128. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/quickpath.rb +0 -0
  129. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/sax2listener.rb +0 -0
  130. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/security.rb +0 -0
  131. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/source.rb +0 -0
  132. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/streamlistener.rb +0 -0
  133. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/undefinednamespaceexception.rb +0 -0
  134. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/validation/relaxng.rb +0 -0
  135. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/validation/validation.rb +0 -0
  136. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/validation/validationexception.rb +0 -0
  137. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/xmldecl.rb +0 -0
  138. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/xmltokens.rb +0 -0
  139. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/xpath.rb +0 -0
  140. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml/xpath_parser.rb +0 -0
  141. /data/bundle/ruby/3.1.0/gems/{rexml-3.3.6 → rexml-3.3.8}/lib/rexml.rb +0 -0
@@ -1,1838 +0,0 @@
1
- /* -*- c-file-style: "ruby"; indent-tabs-mode: t -*- */
2
- /*
3
- * console IO module
4
- */
5
-
6
- static const char *const
7
- IO_CONSOLE_VERSION = "0.7.2";
8
-
9
- #include "ruby.h"
10
- #include "ruby/io.h"
11
- #include "ruby/thread.h"
12
-
13
- #ifdef HAVE_UNISTD_H
14
- #include <unistd.h>
15
- #endif
16
- #ifdef HAVE_FCNTL_H
17
- #include <fcntl.h>
18
- #endif
19
- #ifdef HAVE_SYS_IOCTL_H
20
- #include <sys/ioctl.h>
21
- #endif
22
-
23
- #if defined HAVE_TERMIOS_H
24
- # include <termios.h>
25
- typedef struct termios conmode;
26
-
27
- static int
28
- setattr(int fd, conmode *t)
29
- {
30
- while (tcsetattr(fd, TCSANOW, t)) {
31
- if (errno != EINTR) return 0;
32
- }
33
- return 1;
34
- }
35
- # define getattr(fd, t) (tcgetattr(fd, t) == 0)
36
- #elif defined HAVE_TERMIO_H
37
- # include <termio.h>
38
- typedef struct termio conmode;
39
- # define setattr(fd, t) (ioctl(fd, TCSETAF, t) == 0)
40
- # define getattr(fd, t) (ioctl(fd, TCGETA, t) == 0)
41
- #elif defined HAVE_SGTTY_H
42
- # include <sgtty.h>
43
- typedef struct sgttyb conmode;
44
- # ifdef HAVE_STTY
45
- # define setattr(fd, t) (stty(fd, t) == 0)
46
- # else
47
- # define setattr(fd, t) (ioctl((fd), TIOCSETP, (t)) == 0)
48
- # endif
49
- # ifdef HAVE_GTTY
50
- # define getattr(fd, t) (gtty(fd, t) == 0)
51
- # else
52
- # define getattr(fd, t) (ioctl((fd), TIOCGETP, (t)) == 0)
53
- # endif
54
- #elif defined _WIN32
55
- #include <winioctl.h>
56
- #include <conio.h>
57
- typedef DWORD conmode;
58
-
59
- #define LAST_ERROR rb_w32_map_errno(GetLastError())
60
- #define SET_LAST_ERROR (errno = LAST_ERROR, 0)
61
-
62
- static int
63
- setattr(int fd, conmode *t)
64
- {
65
- int x = SetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), *t);
66
- if (!x) errno = LAST_ERROR;
67
- return x;
68
- }
69
-
70
- static int
71
- getattr(int fd, conmode *t)
72
- {
73
- int x = GetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), t);
74
- if (!x) errno = LAST_ERROR;
75
- return x;
76
- }
77
- #endif
78
- #ifndef SET_LAST_ERROR
79
- #define SET_LAST_ERROR (0)
80
- #endif
81
-
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;
86
-
87
- #if defined HAVE_RUBY_FIBER_SCHEDULER_H
88
- # include "ruby/fiber/scheduler.h"
89
- #elif defined HAVE_RB_SCHEDULER_TIMEOUT
90
- extern VALUE rb_scheduler_timeout(struct timeval *timeout);
91
- # define rb_fiber_scheduler_make_timeout rb_scheduler_timeout
92
- #endif
93
-
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))
129
-
130
- #ifndef HAVE_RB_F_SEND
131
- #ifndef RB_PASS_CALLED_KEYWORDS
132
- # define rb_funcallv_kw(recv, mid, arg, argv, kw_splat) rb_funcallv(recv, mid, arg, argv)
133
- #endif
134
-
135
- static ID id___send__;
136
-
137
- static VALUE
138
- rb_f_send(int argc, VALUE *argv, VALUE recv)
139
- {
140
- VALUE sym = argv[0];
141
- ID vid = rb_check_id(&sym);
142
- if (vid) {
143
- --argc;
144
- ++argv;
145
- }
146
- else {
147
- vid = id___send__;
148
- }
149
- return rb_funcallv_kw(recv, vid, argc, argv, RB_PASS_CALLED_KEYWORDS);
150
- }
151
- #endif
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
-
161
- typedef struct {
162
- int vmin;
163
- int vtime;
164
- int intr;
165
- } rawmode_arg_t;
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
-
174
- static rawmode_arg_t *
175
- rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *opts)
176
- {
177
- int argc = *argcp;
178
- rawmode_arg_t *optp = NULL;
179
- VALUE vopts = Qnil;
180
- VALUE optvals[rawmode_opt_id_count];
181
- #ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
182
- argc = rb_scan_args(argc, argv, "*:", NULL, &vopts);
183
- #else
184
- if (argc > min_argc) {
185
- vopts = rb_check_hash_type(argv[argc-1]);
186
- if (!NIL_P(vopts)) {
187
- argv[argc-1] = vopts;
188
- vopts = rb_extract_keywords(&argv[argc-1]);
189
- if (!argv[argc-1]) *argcp = --argc;
190
- if (!vopts) vopts = Qnil;
191
- }
192
- }
193
- #endif
194
- rb_check_arity(argc, min_argc, max_argc);
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];
200
- /* default values by `stty raw` */
201
- opts->vmin = 1;
202
- opts->vtime = 0;
203
- opts->intr = 0;
204
- if (!NIL_OR_UNDEF_P(vmin)) {
205
- opts->vmin = NUM2INT(vmin);
206
- optp = opts;
207
- }
208
- if (!NIL_OR_UNDEF_P(vtime)) {
209
- VALUE v10 = INT2FIX(10);
210
- vtime = rb_funcall3(vtime, '*', 1, &v10);
211
- opts->vtime = NUM2INT(vtime);
212
- optp = opts;
213
- }
214
- switch (intr) {
215
- case Qtrue:
216
- opts->intr = 1;
217
- optp = opts;
218
- break;
219
- case Qfalse:
220
- opts->intr = 0;
221
- optp = opts;
222
- break;
223
- case Qundef:
224
- case Qnil:
225
- break;
226
- default:
227
- rb_raise(rb_eArgError, "true or false expected as intr: %"PRIsVALUE,
228
- intr);
229
- }
230
- }
231
- return optp;
232
- }
233
-
234
- static void
235
- set_rawmode(conmode *t, void *arg)
236
- {
237
- #ifdef HAVE_CFMAKERAW
238
- cfmakeraw(t);
239
- t->c_lflag &= ~(ECHOE|ECHOK);
240
- #elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
241
- t->c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL);
242
- t->c_oflag &= ~OPOST;
243
- t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|XCASE);
244
- t->c_cflag &= ~(CSIZE|PARENB);
245
- t->c_cflag |= CS8;
246
- t->c_cc[VMIN] = 1;
247
- t->c_cc[VTIME] = 0;
248
- #elif defined HAVE_SGTTY_H
249
- t->sg_flags &= ~ECHO;
250
- t->sg_flags |= RAW;
251
- #elif defined _WIN32
252
- *t = 0;
253
- #endif
254
- if (arg) {
255
- const rawmode_arg_t *r = arg;
256
- #ifdef VMIN
257
- if (r->vmin >= 0) t->c_cc[VMIN] = r->vmin;
258
- #endif
259
- #ifdef VTIME
260
- if (r->vtime >= 0) t->c_cc[VTIME] = r->vtime;
261
- #endif
262
- #ifdef ISIG
263
- if (r->intr) {
264
- t->c_iflag |= BRKINT;
265
- t->c_lflag |= ISIG;
266
- t->c_oflag |= OPOST;
267
- }
268
- #endif
269
- (void)r;
270
- }
271
- }
272
-
273
- static void
274
- set_cookedmode(conmode *t, void *arg)
275
- {
276
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
277
- t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
278
- t->c_oflag |= OPOST;
279
- t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN);
280
- #elif defined HAVE_SGTTY_H
281
- t->sg_flags |= ECHO;
282
- t->sg_flags &= ~RAW;
283
- #elif defined _WIN32
284
- *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT;
285
- #endif
286
- }
287
-
288
- static void
289
- set_noecho(conmode *t, void *arg)
290
- {
291
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
292
- t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
293
- #elif defined HAVE_SGTTY_H
294
- t->sg_flags &= ~ECHO;
295
- #elif defined _WIN32
296
- *t &= ~ENABLE_ECHO_INPUT;
297
- #endif
298
- }
299
-
300
- static void
301
- set_echo(conmode *t, void *arg)
302
- {
303
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
304
- t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
305
- #elif defined HAVE_SGTTY_H
306
- t->sg_flags |= ECHO;
307
- #elif defined _WIN32
308
- *t |= ENABLE_ECHO_INPUT;
309
- #endif
310
- }
311
-
312
- static int
313
- echo_p(conmode *t)
314
- {
315
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
316
- return (t->c_lflag & (ECHO | ECHONL)) != 0;
317
- #elif defined HAVE_SGTTY_H
318
- return (t->sg_flags & ECHO) != 0;
319
- #elif defined _WIN32
320
- return (*t & ENABLE_ECHO_INPUT) != 0;
321
- #endif
322
- }
323
-
324
- static int
325
- set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg)
326
- {
327
- conmode r;
328
- if (!getattr(fd, t)) return 0;
329
- r = *t;
330
- setter(&r, arg);
331
- return setattr(fd, &r);
332
- }
333
-
334
- #define GetReadFD(io) rb_io_descriptor(io)
335
- #define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io))
336
-
337
- #define FD_PER_IO 2
338
-
339
- static VALUE
340
- ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
341
- {
342
- int status = -1;
343
- int error = 0;
344
- int fd[FD_PER_IO];
345
- conmode t[FD_PER_IO];
346
- VALUE result = Qnil;
347
-
348
- fd[0] = GetReadFD(io);
349
- if (fd[0] != -1) {
350
- if (set_ttymode(fd[0], t+0, setter, arg)) {
351
- status = 0;
352
- }
353
- else {
354
- error = errno;
355
- fd[0] = -1;
356
- }
357
- }
358
- fd[1] = GetWriteFD(io);
359
- if (fd[1] != -1 && fd[1] != fd[0]) {
360
- if (set_ttymode(fd[1], t+1, setter, arg)) {
361
- status = 0;
362
- }
363
- else {
364
- error = errno;
365
- fd[1] = -1;
366
- }
367
- }
368
- if (status == 0) {
369
- result = rb_protect(func, farg, &status);
370
- }
371
- if (fd[0] != -1 && fd[0] == GetReadFD(io)) {
372
- if (!setattr(fd[0], t+0)) {
373
- error = errno;
374
- status = -1;
375
- }
376
- }
377
- if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) {
378
- if (!setattr(fd[1], t+1)) {
379
- error = errno;
380
- status = -1;
381
- }
382
- }
383
- if (status) {
384
- if (status == -1) {
385
- rb_syserr_fail(error, 0);
386
- }
387
- rb_jump_tag(status);
388
- }
389
- return result;
390
- }
391
-
392
- #if !defined _WIN32
393
- struct ttymode_callback_args {
394
- VALUE (*func)(VALUE, VALUE);
395
- VALUE io;
396
- VALUE farg;
397
- };
398
-
399
- static VALUE
400
- ttymode_callback(VALUE args)
401
- {
402
- struct ttymode_callback_args *argp = (struct ttymode_callback_args *)args;
403
- return argp->func(argp->io, argp->farg);
404
- }
405
-
406
- static VALUE
407
- ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
408
- {
409
- struct ttymode_callback_args cargs;
410
- cargs.func = func;
411
- cargs.io = io;
412
- cargs.farg = farg;
413
- return ttymode(io, ttymode_callback, (VALUE)&cargs, setter, arg);
414
- }
415
- #endif
416
-
417
- /*
418
- * call-seq:
419
- * io.raw(min: nil, time: nil, intr: nil) {|io| }
420
- *
421
- * Yields +self+ within raw mode, and returns the result of the block.
422
- *
423
- * STDIN.raw(&:gets)
424
- *
425
- * will read and return a line without echo back and line editing.
426
- *
427
- * The parameter +min+ specifies the minimum number of bytes that
428
- * should be received when a read operation is performed. (default: 1)
429
- *
430
- * The parameter +time+ specifies the timeout in _seconds_ with a
431
- * precision of 1/10 of a second. (default: 0)
432
- *
433
- * If the parameter +intr+ is +true+, enables break, interrupt, quit,
434
- * and suspend special characters.
435
- *
436
- * Refer to the manual page of termios for further details.
437
- *
438
- * You must require 'io/console' to use this method.
439
- */
440
- static VALUE
441
- console_raw(int argc, VALUE *argv, VALUE io)
442
- {
443
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
444
- return ttymode(io, rb_yield, io, set_rawmode, optp);
445
- }
446
-
447
- /*
448
- * call-seq:
449
- * io.raw!(min: nil, time: nil, intr: nil) -> io
450
- *
451
- * Enables raw mode, and returns +io+.
452
- *
453
- * If the terminal mode needs to be back, use <code>io.raw { ... }</code>.
454
- *
455
- * See IO#raw for details on the parameters.
456
- *
457
- * You must require 'io/console' to use this method.
458
- */
459
- static VALUE
460
- console_set_raw(int argc, VALUE *argv, VALUE io)
461
- {
462
- conmode t;
463
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
464
- int fd = GetReadFD(io);
465
- if (!getattr(fd, &t)) sys_fail(io);
466
- set_rawmode(&t, optp);
467
- if (!setattr(fd, &t)) sys_fail(io);
468
- return io;
469
- }
470
-
471
- /*
472
- * call-seq:
473
- * io.cooked {|io| }
474
- *
475
- * Yields +self+ within cooked mode.
476
- *
477
- * STDIN.cooked(&:gets)
478
- *
479
- * will read and return a line with echo back and line editing.
480
- *
481
- * You must require 'io/console' to use this method.
482
- */
483
- static VALUE
484
- console_cooked(VALUE io)
485
- {
486
- return ttymode(io, rb_yield, io, set_cookedmode, NULL);
487
- }
488
-
489
- /*
490
- * call-seq:
491
- * io.cooked!
492
- *
493
- * Enables cooked mode.
494
- *
495
- * If the terminal mode needs to be back, use io.cooked { ... }.
496
- *
497
- * You must require 'io/console' to use this method.
498
- */
499
- static VALUE
500
- console_set_cooked(VALUE io)
501
- {
502
- conmode t;
503
- int fd = GetReadFD(io);
504
- if (!getattr(fd, &t)) sys_fail(io);
505
- set_cookedmode(&t, NULL);
506
- if (!setattr(fd, &t)) sys_fail(io);
507
- return io;
508
- }
509
-
510
- #ifndef _WIN32
511
- static VALUE
512
- getc_call(VALUE io)
513
- {
514
- return rb_funcallv(io, id_getc, 0, 0);
515
- }
516
- #else
517
- static void *
518
- nogvl_getch(void *p)
519
- {
520
- int len = 0;
521
- wint_t *buf = p, c = _getwch();
522
-
523
- switch (c) {
524
- case WEOF:
525
- break;
526
- case 0x00:
527
- case 0xe0:
528
- buf[len++] = c;
529
- c = _getwch();
530
- /* fall through */
531
- default:
532
- buf[len++] = c;
533
- break;
534
- }
535
- return (void *)(VALUE)len;
536
- }
537
- #endif
538
-
539
- /*
540
- * call-seq:
541
- * io.getch(min: nil, time: nil, intr: nil) -> char
542
- *
543
- * Reads and returns a character in raw mode.
544
- *
545
- * See IO#raw for details on the parameters.
546
- *
547
- * You must require 'io/console' to use this method.
548
- */
549
- static VALUE
550
- console_getch(int argc, VALUE *argv, VALUE io)
551
- {
552
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
553
- #ifndef _WIN32
554
- return ttymode(io, getc_call, io, set_rawmode, optp);
555
- #else
556
- rb_io_t *fptr;
557
- VALUE str;
558
- wint_t c;
559
- int len;
560
- char buf[8];
561
- wint_t wbuf[2];
562
- # ifndef HAVE_RB_IO_WAIT
563
- struct timeval *to = NULL, tv;
564
- # else
565
- VALUE timeout = Qnil;
566
- # endif
567
-
568
- GetOpenFile(io, fptr);
569
- if (optp) {
570
- if (optp->vtime) {
571
- # ifndef HAVE_RB_IO_WAIT
572
- to = &tv;
573
- # else
574
- struct timeval tv;
575
- # endif
576
- tv.tv_sec = optp->vtime / 10;
577
- tv.tv_usec = (optp->vtime % 10) * 100000;
578
- # ifdef HAVE_RB_IO_WAIT
579
- timeout = rb_fiber_scheduler_make_timeout(&tv);
580
- # endif
581
- }
582
- switch (optp->vmin) {
583
- case 1: /* default */
584
- break;
585
- case 0: /* return nil when timed out */
586
- if (optp->vtime) break;
587
- /* fallthru */
588
- default:
589
- rb_warning("min option larger than 1 ignored");
590
- }
591
- if (optp->intr) {
592
- # ifndef HAVE_RB_IO_WAIT
593
- int w = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, to);
594
- if (w < 0) rb_eof_error();
595
- if (!(w & RB_WAITFD_IN)) return Qnil;
596
- # else
597
- VALUE result = rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
598
- if (!RTEST(result)) return Qnil;
599
- # endif
600
- }
601
- else if (optp->vtime) {
602
- rb_warning("Non-zero vtime option ignored if intr flag is unset");
603
- }
604
- }
605
- len = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getch, wbuf, RUBY_UBF_IO, 0);
606
- switch (len) {
607
- case 0:
608
- return Qnil;
609
- case 2:
610
- buf[0] = (char)wbuf[0];
611
- c = wbuf[1];
612
- len = 1;
613
- do {
614
- buf[len++] = (unsigned char)c;
615
- } while ((c >>= CHAR_BIT) && len < (int)sizeof(buf));
616
- return rb_str_new(buf, len);
617
- default:
618
- c = wbuf[0];
619
- len = rb_uv_to_utf8(buf, c);
620
- str = rb_utf8_str_new(buf, len);
621
- return rb_str_conv_enc(str, NULL, rb_default_external_encoding());
622
- }
623
- #endif
624
- }
625
-
626
- /*
627
- * call-seq:
628
- * io.noecho {|io| }
629
- *
630
- * Yields +self+ with disabling echo back.
631
- *
632
- * STDIN.noecho(&:gets)
633
- *
634
- * will read and return a line without echo back.
635
- *
636
- * You must require 'io/console' to use this method.
637
- */
638
- static VALUE
639
- console_noecho(VALUE io)
640
- {
641
- return ttymode(io, rb_yield, io, set_noecho, NULL);
642
- }
643
-
644
- /*
645
- * call-seq:
646
- * io.echo = flag
647
- *
648
- * Enables/disables echo back.
649
- * On some platforms, all combinations of this flags and raw/cooked
650
- * mode may not be valid.
651
- *
652
- * You must require 'io/console' to use this method.
653
- */
654
- static VALUE
655
- console_set_echo(VALUE io, VALUE f)
656
- {
657
- conmode t;
658
- int fd = GetReadFD(io);
659
-
660
- if (!getattr(fd, &t)) sys_fail(io);
661
-
662
- if (RTEST(f))
663
- set_echo(&t, NULL);
664
- else
665
- set_noecho(&t, NULL);
666
-
667
- if (!setattr(fd, &t)) sys_fail(io);
668
-
669
- return io;
670
- }
671
-
672
- /*
673
- * call-seq:
674
- * io.echo? -> true or false
675
- *
676
- * Returns +true+ if echo back is enabled.
677
- *
678
- * You must require 'io/console' to use this method.
679
- */
680
- static VALUE
681
- console_echo_p(VALUE io)
682
- {
683
- conmode t;
684
- int fd = GetReadFD(io);
685
-
686
- if (!getattr(fd, &t)) sys_fail(io);
687
- return echo_p(&t) ? Qtrue : Qfalse;
688
- }
689
-
690
- static const rb_data_type_t conmode_type = {
691
- "console-mode",
692
- {0, RUBY_TYPED_DEFAULT_FREE,},
693
- 0, 0,
694
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
695
- };
696
- static VALUE cConmode;
697
-
698
- static VALUE
699
- conmode_alloc(VALUE klass)
700
- {
701
- return rb_data_typed_object_zalloc(klass, sizeof(conmode), &conmode_type);
702
- }
703
-
704
- static VALUE
705
- conmode_new(VALUE klass, const conmode *t)
706
- {
707
- VALUE obj = conmode_alloc(klass);
708
- *(conmode *)DATA_PTR(obj) = *t;
709
- return obj;
710
- }
711
-
712
- static VALUE
713
- conmode_init_copy(VALUE obj, VALUE obj2)
714
- {
715
- conmode *t = rb_check_typeddata(obj, &conmode_type);
716
- conmode *t2 = rb_check_typeddata(obj2, &conmode_type);
717
- *t = *t2;
718
- return obj;
719
- }
720
-
721
- static VALUE
722
- conmode_set_echo(VALUE obj, VALUE f)
723
- {
724
- conmode *t = rb_check_typeddata(obj, &conmode_type);
725
- if (RTEST(f))
726
- set_echo(t, NULL);
727
- else
728
- set_noecho(t, NULL);
729
- return obj;
730
- }
731
-
732
- static VALUE
733
- conmode_set_raw(int argc, VALUE *argv, VALUE obj)
734
- {
735
- conmode *t = rb_check_typeddata(obj, &conmode_type);
736
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
737
-
738
- set_rawmode(t, optp);
739
- return obj;
740
- }
741
-
742
- static VALUE
743
- conmode_raw_new(int argc, VALUE *argv, VALUE obj)
744
- {
745
- conmode *r = rb_check_typeddata(obj, &conmode_type);
746
- conmode t = *r;
747
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
748
-
749
- set_rawmode(&t, optp);
750
- return conmode_new(rb_obj_class(obj), &t);
751
- }
752
-
753
- /*
754
- * call-seq:
755
- * io.console_mode -> mode
756
- *
757
- * Returns a data represents the current console mode.
758
- *
759
- * You must require 'io/console' to use this method.
760
- */
761
- static VALUE
762
- console_conmode_get(VALUE io)
763
- {
764
- conmode t;
765
- int fd = GetReadFD(io);
766
-
767
- if (!getattr(fd, &t)) sys_fail(io);
768
-
769
- return conmode_new(cConmode, &t);
770
- }
771
-
772
- /*
773
- * call-seq:
774
- * io.console_mode = mode
775
- *
776
- * Sets the console mode to +mode+.
777
- *
778
- * You must require 'io/console' to use this method.
779
- */
780
- static VALUE
781
- console_conmode_set(VALUE io, VALUE mode)
782
- {
783
- conmode *t, r;
784
- int fd = GetReadFD(io);
785
-
786
- TypedData_Get_Struct(mode, conmode, &conmode_type, t);
787
- r = *t;
788
-
789
- if (!setattr(fd, &r)) sys_fail(io);
790
-
791
- return mode;
792
- }
793
-
794
- #if defined TIOCGWINSZ
795
- typedef struct winsize rb_console_size_t;
796
- #define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0)
797
- #define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0)
798
- #define winsize_row(buf) (buf)->ws_row
799
- #define winsize_col(buf) (buf)->ws_col
800
- #elif defined _WIN32
801
- typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
802
- #define getwinsize(fd, buf) ( \
803
- GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \
804
- SET_LAST_ERROR)
805
- #define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1)
806
- #define winsize_col(buf) (buf)->dwSize.X
807
- #endif
808
-
809
- #if defined TIOCGWINSZ || defined _WIN32
810
- #define USE_CONSOLE_GETSIZE 1
811
- #endif
812
-
813
- #ifdef USE_CONSOLE_GETSIZE
814
- /*
815
- * call-seq:
816
- * io.winsize -> [rows, columns]
817
- *
818
- * Returns console size.
819
- *
820
- * You must require 'io/console' to use this method.
821
- */
822
- static VALUE
823
- console_winsize(VALUE io)
824
- {
825
- rb_console_size_t ws;
826
- int fd = GetWriteFD(io);
827
- if (!getwinsize(fd, &ws)) sys_fail(io);
828
- return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
829
- }
830
-
831
- /*
832
- * call-seq:
833
- * io.winsize = [rows, columns]
834
- *
835
- * Tries to set console size. The effect depends on the platform and
836
- * the running environment.
837
- *
838
- * You must require 'io/console' to use this method.
839
- */
840
- static VALUE
841
- console_set_winsize(VALUE io, VALUE size)
842
- {
843
- rb_console_size_t ws;
844
- #if defined _WIN32
845
- HANDLE wh;
846
- int newrow, newcol;
847
- BOOL ret;
848
- #endif
849
- VALUE row, col, xpixel, ypixel;
850
- const VALUE *sz;
851
- long sizelen;
852
- int fd;
853
-
854
- size = rb_Array(size);
855
- if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
856
- rb_raise(rb_eArgError, "wrong number of arguments (given %ld, expected 2 or 4)", sizelen);
857
- }
858
- sz = RARRAY_CONST_PTR(size);
859
- row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
860
- if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
861
- fd = GetWriteFD(io);
862
- #if defined TIOCSWINSZ
863
- ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
864
- #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
865
- SET(row);
866
- SET(col);
867
- SET(xpixel);
868
- SET(ypixel);
869
- #undef SET
870
- if (!setwinsize(fd, &ws)) sys_fail(io);
871
- #elif defined _WIN32
872
- wh = (HANDLE)rb_w32_get_osfhandle(fd);
873
- #define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
874
- SET(row);
875
- SET(col);
876
- #undef SET
877
- if (!NIL_P(xpixel)) (void)NUM2UINT(xpixel);
878
- if (!NIL_P(ypixel)) (void)NUM2UINT(ypixel);
879
- if (!GetConsoleScreenBufferInfo(wh, &ws)) {
880
- rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
881
- }
882
- ws.dwSize.X = newcol;
883
- ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
884
- ws.srWindow.Left = 0;
885
- ws.srWindow.Top = 0;
886
- ws.srWindow.Right = newcol-1;
887
- ws.srWindow.Bottom = newrow-1;
888
- if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
889
- rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
890
- }
891
- /* retry when shrinking buffer after shrunk window */
892
- if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
893
- rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
894
- }
895
- /* remove scrollbar if possible */
896
- if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
897
- rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
898
- }
899
- #endif
900
- return io;
901
- }
902
- #endif
903
-
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
- */
915
- static VALUE
916
- console_check_winsize_changed(VALUE io)
917
- {
918
- HANDLE h;
919
- DWORD num;
920
-
921
- h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
922
- while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
923
- INPUT_RECORD rec;
924
- if (ReadConsoleInput(h, &rec, 1, &num)) {
925
- if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
926
- rb_yield(Qnil);
927
- }
928
- }
929
- }
930
- return io;
931
- }
932
- #else
933
- #define console_check_winsize_changed rb_f_notimplement
934
- #endif
935
-
936
- /*
937
- * call-seq:
938
- * io.iflush
939
- *
940
- * Flushes input buffer in kernel.
941
- *
942
- * You must require 'io/console' to use this method.
943
- */
944
- static VALUE
945
- console_iflush(VALUE io)
946
- {
947
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
948
- int fd = GetReadFD(io);
949
- if (tcflush(fd, TCIFLUSH)) sys_fail(io);
950
- #endif
951
-
952
- return io;
953
- }
954
-
955
- /*
956
- * call-seq:
957
- * io.oflush
958
- *
959
- * Flushes output buffer in kernel.
960
- *
961
- * You must require 'io/console' to use this method.
962
- */
963
- static VALUE
964
- console_oflush(VALUE io)
965
- {
966
- int fd = GetWriteFD(io);
967
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
968
- if (tcflush(fd, TCOFLUSH)) sys_fail(io);
969
- #endif
970
- (void)fd;
971
- return io;
972
- }
973
-
974
- /*
975
- * call-seq:
976
- * io.ioflush
977
- *
978
- * Flushes input and output buffers in kernel.
979
- *
980
- * You must require 'io/console' to use this method.
981
- */
982
- static VALUE
983
- console_ioflush(VALUE io)
984
- {
985
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
986
- int fd1 = GetReadFD(io);
987
- int fd2 = GetWriteFD(io);
988
-
989
- if (fd2 != -1 && fd1 != fd2) {
990
- if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
991
- if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
992
- }
993
- else {
994
- if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
995
- }
996
- #endif
997
-
998
- return io;
999
- }
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
- */
1009
- static VALUE
1010
- console_beep(VALUE io)
1011
- {
1012
- #ifdef _WIN32
1013
- MessageBeep(0);
1014
- #else
1015
- int fd = GetWriteFD(io);
1016
- if (write(fd, "\a", 1) < 0) sys_fail(io);
1017
- #endif
1018
- return io;
1019
- }
1020
-
1021
- static int
1022
- mode_in_range(VALUE val, int high, const char *modename)
1023
- {
1024
- int mode;
1025
- if (NIL_P(val)) return 0;
1026
- if (!RB_INTEGER_TYPE_P(val)) {
1027
- wrong_value:
1028
- rb_raise(rb_eArgError, "wrong %s mode: %"PRIsVALUE, modename, val);
1029
- }
1030
- if ((mode = NUM2INT(val)) < 0 || mode > high) {
1031
- goto wrong_value;
1032
- }
1033
- return mode;
1034
- }
1035
-
1036
- #if defined _WIN32
1037
- static void
1038
- constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
1039
- {
1040
- DWORD written;
1041
-
1042
- FillConsoleOutputAttribute(handle, attr, len, pos, &written);
1043
- FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
1044
- }
1045
-
1046
- static VALUE
1047
- console_scroll(VALUE io, int line)
1048
- {
1049
- HANDLE h;
1050
- rb_console_size_t ws;
1051
-
1052
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
1053
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
1054
- rb_syserr_fail(LAST_ERROR, 0);
1055
- }
1056
- if (line) {
1057
- SMALL_RECT scroll;
1058
- COORD destination;
1059
- CHAR_INFO fill;
1060
- scroll.Left = 0;
1061
- scroll.Top = line > 0 ? line : 0;
1062
- scroll.Right = winsize_col(&ws) - 1;
1063
- scroll.Bottom = winsize_row(&ws) - 1 + (line < 0 ? line : 0);
1064
- destination.X = 0;
1065
- destination.Y = line < 0 ? -line : 0;
1066
- fill.Char.UnicodeChar = L' ';
1067
- fill.Attributes = ws.wAttributes;
1068
-
1069
- ScrollConsoleScreenBuffer(h, &scroll, NULL, destination, &fill);
1070
- }
1071
- return io;
1072
- }
1073
-
1074
- #include "win32_vk.inc"
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
- */
1087
- static VALUE
1088
- console_key_pressed_p(VALUE io, VALUE k)
1089
- {
1090
- int vk = -1;
1091
-
1092
- if (FIXNUM_P(k)) {
1093
- vk = NUM2UINT(k);
1094
- }
1095
- else {
1096
- const struct vktable *t;
1097
- const char *kn;
1098
- if (SYMBOL_P(k)) {
1099
- k = rb_sym2str(k);
1100
- kn = RSTRING_PTR(k);
1101
- }
1102
- else {
1103
- kn = StringValuePtr(k);
1104
- }
1105
- t = console_win32_vk(kn, RSTRING_LEN(k));
1106
- if (!t || (vk = (short)t->vk) == -1) {
1107
- rb_raise(rb_eArgError, "unknown virtual key code: % "PRIsVALUE, k);
1108
- }
1109
- }
1110
- return GetKeyState(vk) & 0x80 ? Qtrue : Qfalse;
1111
- }
1112
- #else
1113
- struct query_args {
1114
- char qstr[6];
1115
- unsigned char opt;
1116
- };
1117
-
1118
- static int
1119
- direct_query(VALUE io, const struct query_args *query)
1120
- {
1121
- if (RB_TYPE_P(io, T_FILE)) {
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;
1127
- }
1128
- return 0;
1129
- }
1130
-
1131
- static VALUE
1132
- read_vt_response(VALUE io, VALUE query)
1133
- {
1134
- struct query_args *qargs = (struct query_args *)query;
1135
- VALUE result, b;
1136
- int opt = 0;
1137
- int num = 0;
1138
- if (qargs) {
1139
- opt = qargs->opt;
1140
- if (!direct_query(io, qargs)) return Qnil;
1141
- }
1142
- if (rb_io_getbyte(io) != INT2FIX(0x1b)) return Qnil;
1143
- if (rb_io_getbyte(io) != INT2FIX('[')) return Qnil;
1144
- result = rb_ary_new();
1145
- while (!NIL_P(b = rb_io_getbyte(io))) {
1146
- int c = NUM2UINT(b);
1147
- if (c == ';') {
1148
- rb_ary_push(result, INT2NUM(num));
1149
- num = 0;
1150
- }
1151
- else if (ISDIGIT(c)) {
1152
- num = num * 10 + c - '0';
1153
- }
1154
- else if (opt && c == opt) {
1155
- opt = 0;
1156
- }
1157
- else {
1158
- char last = (char)c;
1159
- rb_ary_push(result, INT2NUM(num));
1160
- b = rb_str_new(&last, 1);
1161
- break;
1162
- }
1163
- }
1164
- return rb_ary_push(result, b);
1165
- }
1166
-
1167
- static VALUE
1168
- console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qargs)
1169
- {
1170
- rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 1, &opts);
1171
- VALUE query = (VALUE)qargs;
1172
- VALUE ret = ttymode_with_io(io, read_vt_response, query, set_rawmode, optp);
1173
- return ret;
1174
- }
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
- */
1200
- static VALUE
1201
- console_cursor_pos(VALUE io)
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
1211
- static const struct query_args query = {"\033[6n", 0};
1212
- VALUE resp = console_vt_response(0, 0, io, &query);
1213
- VALUE row, column, term;
1214
- unsigned int r, c;
1215
- if (!RB_TYPE_P(resp, T_ARRAY) || RARRAY_LEN(resp) != 3) return Qnil;
1216
- term = RARRAY_AREF(resp, 2);
1217
- if (!RB_TYPE_P(term, T_STRING) || RSTRING_LEN(term) != 1) return Qnil;
1218
- if (RSTRING_PTR(term)[0] != 'R') return Qnil;
1219
- row = RARRAY_AREF(resp, 0);
1220
- column = RARRAY_AREF(resp, 1);
1221
- rb_ary_resize(resp, 2);
1222
- r = NUM2UINT(row) - 1;
1223
- c = NUM2UINT(column) - 1;
1224
- RARRAY_ASET(resp, 0, INT2NUM(r));
1225
- RARRAY_ASET(resp, 1, INT2NUM(c));
1226
- return resp;
1227
- #endif
1228
- }
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
- */
1238
- static VALUE
1239
- console_goto(VALUE io, VALUE y, VALUE x)
1240
- {
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
1252
- return io;
1253
- }
1254
-
1255
- static VALUE
1256
- console_move(VALUE io, int y, int x)
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
1273
- if (x || y) {
1274
- VALUE s = rb_str_new_cstr("");
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');
1277
- rb_io_write(io, s);
1278
- rb_io_flush(io);
1279
- }
1280
- #endif
1281
- return io;
1282
- }
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
- */
1293
- static VALUE
1294
- console_goto_column(VALUE io, VALUE val)
1295
- {
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
1312
- return io;
1313
- }
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
- */
1327
- static VALUE
1328
- console_erase_line(VALUE io, VALUE val)
1329
- {
1330
- int mode = mode_in_range(val, 2, "line erase");
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
1359
- return io;
1360
- }
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
- */
1374
- static VALUE
1375
- console_erase_screen(VALUE io, VALUE val)
1376
- {
1377
- int mode = mode_in_range(val, 3, "screen erase");
1378
- #ifdef _WIN32
1379
- HANDLE h;
1380
- rb_console_size_t ws;
1381
- COORD *pos = &ws.dwCursorPosition;
1382
- DWORD w;
1383
-
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;
1408
- }
1409
- constat_clear(h, ws.wAttributes, w, *pos);
1410
- #else
1411
- rb_io_write(io, rb_sprintf(CSI "%dJ", mode));
1412
- #endif
1413
- return io;
1414
- }
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
- */
1426
- static VALUE
1427
- console_cursor_set(VALUE io, VALUE cpos)
1428
- {
1429
- cpos = rb_convert_type(cpos, T_ARRAY, "Array", "to_ary");
1430
- if (RARRAY_LEN(cpos) != 2) rb_raise(rb_eArgError, "expected 2D coordinate");
1431
- return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
1432
- }
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
- */
1442
- static VALUE
1443
- console_cursor_up(VALUE io, VALUE val)
1444
- {
1445
- return console_move(io, -NUM2INT(val), 0);
1446
- }
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
- */
1456
- static VALUE
1457
- console_cursor_down(VALUE io, VALUE val)
1458
- {
1459
- return console_move(io, +NUM2INT(val), 0);
1460
- }
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
- */
1470
- static VALUE
1471
- console_cursor_left(VALUE io, VALUE val)
1472
- {
1473
- return console_move(io, 0, -NUM2INT(val));
1474
- }
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
- */
1484
- static VALUE
1485
- console_cursor_right(VALUE io, VALUE val)
1486
- {
1487
- return console_move(io, 0, +NUM2INT(val));
1488
- }
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
- */
1498
- static VALUE
1499
- console_scroll_forward(VALUE io, VALUE val)
1500
- {
1501
- return console_scroll(io, +NUM2INT(val));
1502
- }
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
- */
1512
- static VALUE
1513
- console_scroll_backward(VALUE io, VALUE val)
1514
- {
1515
- return console_scroll(io, -NUM2INT(val));
1516
- }
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
- */
1526
- static VALUE
1527
- console_clear_screen(VALUE io)
1528
- {
1529
- console_erase_screen(io, INT2FIX(2));
1530
- console_goto(io, INT2FIX(0), INT2FIX(0));
1531
- return io;
1532
- }
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
-
1566
- /*
1567
- * call-seq:
1568
- * IO.console -> #<File:/dev/tty>
1569
- * IO.console(sym, *args)
1570
- *
1571
- * Returns an File instance opened console.
1572
- *
1573
- * If +sym+ is given, it will be sent to the opened console with
1574
- * +args+ and the result will be returned instead of the console IO
1575
- * itself.
1576
- *
1577
- * You must require 'io/console' to use this method.
1578
- */
1579
- static VALUE
1580
- console_dev(int argc, VALUE *argv, VALUE klass)
1581
- {
1582
- VALUE con = 0;
1583
- VALUE sym = 0;
1584
-
1585
- rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
1586
-
1587
- if (argc) {
1588
- Check_Type(sym = argv[0], T_SYMBOL);
1589
- }
1590
-
1591
- // Force the class to be File.
1592
- if (klass == rb_cIO) klass = rb_cFile;
1593
-
1594
- if (rb_const_defined(klass, id_console)) {
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
- }
1600
- }
1601
-
1602
- if (sym) {
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
- }
1611
- }
1612
-
1613
- if (!con) {
1614
- #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
1615
- # define CONSOLE_DEVICE "/dev/tty"
1616
- #elif defined _WIN32
1617
- # define CONSOLE_DEVICE "con$"
1618
- # define CONSOLE_DEVICE_FOR_READING "conin$"
1619
- # define CONSOLE_DEVICE_FOR_WRITING "conout$"
1620
- #endif
1621
- #ifndef CONSOLE_DEVICE_FOR_READING
1622
- # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
1623
- #endif
1624
- #ifdef CONSOLE_DEVICE_FOR_WRITING
1625
- VALUE out;
1626
- rb_io_t *ofptr;
1627
- #endif
1628
- int fd;
1629
- VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
1630
-
1631
- #ifdef CONSOLE_DEVICE_FOR_WRITING
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);
1635
- #endif
1636
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
1637
- if (fd < 0) {
1638
- #ifdef CONSOLE_DEVICE_FOR_WRITING
1639
- rb_io_close(out);
1640
- #endif
1641
- return Qnil;
1642
- }
1643
-
1644
- con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
1645
- #ifdef CONSOLE_DEVICE_FOR_WRITING
1646
- rb_io_set_write_io(con, out);
1647
- #endif
1648
- rb_const_set(klass, id_console, con);
1649
- }
1650
-
1651
- if (sym) {
1652
- return rb_f_send(argc, argv, con);
1653
- }
1654
-
1655
- return con;
1656
- }
1657
-
1658
- /*
1659
- * call-seq:
1660
- * io.getch(min: nil, time: nil, intr: nil) -> char
1661
- *
1662
- * See IO#getch.
1663
- */
1664
- static VALUE
1665
- io_getch(int argc, VALUE *argv, VALUE io)
1666
- {
1667
- return rb_funcallv(io, id_getc, argc, argv);
1668
- }
1669
-
1670
- static VALUE
1671
- puts_call(VALUE io)
1672
- {
1673
- return rb_io_write(io, rb_default_rs);
1674
- }
1675
-
1676
- static VALUE
1677
- gets_call(VALUE io)
1678
- {
1679
- return rb_funcallv(io, id_gets, 0, 0);
1680
- }
1681
-
1682
- static VALUE
1683
- getpass_call(VALUE io)
1684
- {
1685
- return ttymode(io, rb_io_gets, io, set_noecho, NULL);
1686
- }
1687
-
1688
- static void
1689
- prompt(int argc, VALUE *argv, VALUE io)
1690
- {
1691
- if (argc > 0 && !NIL_P(argv[0])) {
1692
- VALUE str = argv[0];
1693
- StringValueCStr(str);
1694
- rb_io_write(io, str);
1695
- }
1696
- }
1697
-
1698
- static VALUE
1699
- str_chomp(VALUE str)
1700
- {
1701
- if (!NIL_P(str)) {
1702
- const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */
1703
- rb_funcallv(str, id_chomp_bang, 1, &rs);
1704
- }
1705
- return str;
1706
- }
1707
-
1708
- /*
1709
- * call-seq:
1710
- * io.getpass(prompt=nil) -> string
1711
- *
1712
- * Reads and returns a line without echo back.
1713
- * Prints +prompt+ unless it is +nil+.
1714
- *
1715
- * The newline character that terminates the
1716
- * read line is removed from the returned string,
1717
- * see String#chomp!.
1718
- *
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
- *
1726
- */
1727
- static VALUE
1728
- console_getpass(int argc, VALUE *argv, VALUE io)
1729
- {
1730
- VALUE str, wio;
1731
-
1732
- rb_check_arity(argc, 0, 1);
1733
- wio = rb_io_get_write_io(io);
1734
- if (wio == io && io == rb_stdin) wio = rb_stderr;
1735
- prompt(argc, argv, wio);
1736
- rb_io_flush(wio);
1737
- str = rb_ensure(getpass_call, io, puts_call, wio);
1738
- return str_chomp(str);
1739
- }
1740
-
1741
- /*
1742
- * call-seq:
1743
- * io.getpass(prompt=nil) -> string
1744
- *
1745
- * See IO#getpass.
1746
- */
1747
- static VALUE
1748
- io_getpass(int argc, VALUE *argv, VALUE io)
1749
- {
1750
- VALUE str;
1751
-
1752
- rb_check_arity(argc, 0, 1);
1753
- prompt(argc, argv, io);
1754
- rb_check_funcall(io, id_flush, 0, 0);
1755
- str = rb_ensure(gets_call, io, puts_call, io);
1756
- return str_chomp(str);
1757
- }
1758
-
1759
- /*
1760
- * IO console methods
1761
- */
1762
- void
1763
- Init_console(void)
1764
- {
1765
- #undef rb_intern
1766
- id_getc = rb_intern("getc");
1767
- id_gets = rb_intern("gets");
1768
- id_flush = rb_intern("flush");
1769
- id_chomp_bang = rb_intern("chomp!");
1770
- id_console = rb_intern("console");
1771
- id_close = rb_intern("close");
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);
1777
- #ifndef HAVE_RB_F_SEND
1778
- id___send__ = rb_intern("__send__");
1779
- #endif
1780
- InitVM(console);
1781
- }
1782
-
1783
- void
1784
- InitVM_console(void)
1785
- {
1786
- rb_define_method(rb_cIO, "raw", console_raw, -1);
1787
- rb_define_method(rb_cIO, "raw!", console_set_raw, -1);
1788
- rb_define_method(rb_cIO, "cooked", console_cooked, 0);
1789
- rb_define_method(rb_cIO, "cooked!", console_set_cooked, 0);
1790
- rb_define_method(rb_cIO, "getch", console_getch, -1);
1791
- rb_define_method(rb_cIO, "echo=", console_set_echo, 1);
1792
- rb_define_method(rb_cIO, "echo?", console_echo_p, 0);
1793
- rb_define_method(rb_cIO, "console_mode", console_conmode_get, 0);
1794
- rb_define_method(rb_cIO, "console_mode=", console_conmode_set, 1);
1795
- rb_define_method(rb_cIO, "noecho", console_noecho, 0);
1796
- rb_define_method(rb_cIO, "winsize", console_winsize, 0);
1797
- rb_define_method(rb_cIO, "winsize=", console_set_winsize, 1);
1798
- rb_define_method(rb_cIO, "iflush", console_iflush, 0);
1799
- rb_define_method(rb_cIO, "oflush", console_oflush, 0);
1800
- rb_define_method(rb_cIO, "ioflush", console_ioflush, 0);
1801
- rb_define_method(rb_cIO, "beep", console_beep, 0);
1802
- rb_define_method(rb_cIO, "goto", console_goto, 2);
1803
- rb_define_method(rb_cIO, "cursor", console_cursor_pos, 0);
1804
- rb_define_method(rb_cIO, "cursor=", console_cursor_set, 1);
1805
- rb_define_method(rb_cIO, "cursor_up", console_cursor_up, 1);
1806
- rb_define_method(rb_cIO, "cursor_down", console_cursor_down, 1);
1807
- rb_define_method(rb_cIO, "cursor_left", console_cursor_left, 1);
1808
- rb_define_method(rb_cIO, "cursor_right", console_cursor_right, 1);
1809
- rb_define_method(rb_cIO, "goto_column", console_goto_column, 1);
1810
- rb_define_method(rb_cIO, "erase_line", console_erase_line, 1);
1811
- rb_define_method(rb_cIO, "erase_screen", console_erase_screen, 1);
1812
- rb_define_method(rb_cIO, "scroll_forward", console_scroll_forward, 1);
1813
- rb_define_method(rb_cIO, "scroll_backward", console_scroll_backward, 1);
1814
- rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
1815
- rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
1816
- rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
1817
- rb_define_method(rb_cIO, "getpass", console_getpass, -1);
1818
- rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
1819
- {
1820
- /* :stopdoc: */
1821
- VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
1822
- /* :startdoc: */
1823
- rb_define_method(mReadable, "getch", io_getch, -1);
1824
- rb_define_method(mReadable, "getpass", io_getpass, -1);
1825
- }
1826
- {
1827
- /* :stopdoc: */
1828
- cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
1829
- rb_define_const(cConmode, "VERSION", rb_str_new_cstr(IO_CONSOLE_VERSION));
1830
- rb_define_alloc_func(cConmode, conmode_alloc);
1831
- rb_undef_method(cConmode, "initialize");
1832
- rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
1833
- rb_define_method(cConmode, "echo=", conmode_set_echo, 1);
1834
- rb_define_method(cConmode, "raw!", conmode_set_raw, -1);
1835
- rb_define_method(cConmode, "raw", conmode_raw_new, -1);
1836
- /* :startdoc: */
1837
- }
1838
- }