brakeman 6.2.1 → 6.2.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.
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
- }