foolio 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +21 -0
  6. data/examples/timer.rb +20 -0
  7. data/ext/foolio/extconf.rb +34 -0
  8. data/ext/foolio/foolio_ext.c +921 -0
  9. data/ext/foolio/gen.rb +50 -0
  10. data/ext/foolio/make_table.rb +12 -0
  11. data/ext/foolio/templ +243 -0
  12. data/ext/libuv/.gitignore +33 -0
  13. data/ext/libuv/.mailmap +13 -0
  14. data/ext/libuv/.travis.yml +9 -0
  15. data/ext/libuv/AUTHORS +61 -0
  16. data/ext/libuv/LICENSE +44 -0
  17. data/ext/libuv/Makefile +71 -0
  18. data/ext/libuv/README.md +90 -0
  19. data/ext/libuv/common.gypi +178 -0
  20. data/ext/libuv/gyp_uv +73 -0
  21. data/ext/libuv/include/uv-private/eio.h +403 -0
  22. data/ext/libuv/include/uv-private/ev.h +838 -0
  23. data/ext/libuv/include/uv-private/ngx-queue.h +108 -0
  24. data/ext/libuv/include/uv-private/tree.h +768 -0
  25. data/ext/libuv/include/uv-private/uv-unix.h +324 -0
  26. data/ext/libuv/include/uv-private/uv-win.h +517 -0
  27. data/ext/libuv/include/uv.h +1838 -0
  28. data/ext/libuv/src/fs-poll.c +235 -0
  29. data/ext/libuv/src/inet.c +293 -0
  30. data/ext/libuv/src/unix/async.c +148 -0
  31. data/ext/libuv/src/unix/core.c +696 -0
  32. data/ext/libuv/src/unix/cygwin.c +83 -0
  33. data/ext/libuv/src/unix/darwin.c +342 -0
  34. data/ext/libuv/src/unix/dl.c +83 -0
  35. data/ext/libuv/src/unix/eio/Changes +63 -0
  36. data/ext/libuv/src/unix/eio/LICENSE +36 -0
  37. data/ext/libuv/src/unix/eio/Makefile.am +15 -0
  38. data/ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
  39. data/ext/libuv/src/unix/eio/autogen.sh +3 -0
  40. data/ext/libuv/src/unix/eio/config.h.in +86 -0
  41. data/ext/libuv/src/unix/eio/config_cygwin.h +80 -0
  42. data/ext/libuv/src/unix/eio/config_darwin.h +141 -0
  43. data/ext/libuv/src/unix/eio/config_freebsd.h +81 -0
  44. data/ext/libuv/src/unix/eio/config_linux.h +94 -0
  45. data/ext/libuv/src/unix/eio/config_netbsd.h +81 -0
  46. data/ext/libuv/src/unix/eio/config_openbsd.h +137 -0
  47. data/ext/libuv/src/unix/eio/config_sunos.h +84 -0
  48. data/ext/libuv/src/unix/eio/configure.ac +22 -0
  49. data/ext/libuv/src/unix/eio/demo.c +194 -0
  50. data/ext/libuv/src/unix/eio/ecb.h +370 -0
  51. data/ext/libuv/src/unix/eio/eio.3 +3428 -0
  52. data/ext/libuv/src/unix/eio/eio.c +2593 -0
  53. data/ext/libuv/src/unix/eio/eio.pod +969 -0
  54. data/ext/libuv/src/unix/eio/libeio.m4 +195 -0
  55. data/ext/libuv/src/unix/eio/xthread.h +164 -0
  56. data/ext/libuv/src/unix/error.c +105 -0
  57. data/ext/libuv/src/unix/ev/Changes +388 -0
  58. data/ext/libuv/src/unix/ev/LICENSE +36 -0
  59. data/ext/libuv/src/unix/ev/Makefile.am +18 -0
  60. data/ext/libuv/src/unix/ev/Makefile.in +771 -0
  61. data/ext/libuv/src/unix/ev/README +58 -0
  62. data/ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
  63. data/ext/libuv/src/unix/ev/autogen.sh +6 -0
  64. data/ext/libuv/src/unix/ev/config.guess +1526 -0
  65. data/ext/libuv/src/unix/ev/config.h.in +125 -0
  66. data/ext/libuv/src/unix/ev/config.sub +1658 -0
  67. data/ext/libuv/src/unix/ev/config_cygwin.h +123 -0
  68. data/ext/libuv/src/unix/ev/config_darwin.h +122 -0
  69. data/ext/libuv/src/unix/ev/config_freebsd.h +120 -0
  70. data/ext/libuv/src/unix/ev/config_linux.h +141 -0
  71. data/ext/libuv/src/unix/ev/config_netbsd.h +120 -0
  72. data/ext/libuv/src/unix/ev/config_openbsd.h +126 -0
  73. data/ext/libuv/src/unix/ev/config_sunos.h +122 -0
  74. data/ext/libuv/src/unix/ev/configure +13037 -0
  75. data/ext/libuv/src/unix/ev/configure.ac +18 -0
  76. data/ext/libuv/src/unix/ev/depcomp +630 -0
  77. data/ext/libuv/src/unix/ev/ev++.h +816 -0
  78. data/ext/libuv/src/unix/ev/ev.3 +5311 -0
  79. data/ext/libuv/src/unix/ev/ev.c +3925 -0
  80. data/ext/libuv/src/unix/ev/ev.pod +5243 -0
  81. data/ext/libuv/src/unix/ev/ev_epoll.c +266 -0
  82. data/ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
  83. data/ext/libuv/src/unix/ev/ev_poll.c +148 -0
  84. data/ext/libuv/src/unix/ev/ev_port.c +179 -0
  85. data/ext/libuv/src/unix/ev/ev_select.c +310 -0
  86. data/ext/libuv/src/unix/ev/ev_vars.h +203 -0
  87. data/ext/libuv/src/unix/ev/ev_win32.c +153 -0
  88. data/ext/libuv/src/unix/ev/ev_wrap.h +196 -0
  89. data/ext/libuv/src/unix/ev/event.c +402 -0
  90. data/ext/libuv/src/unix/ev/event.h +170 -0
  91. data/ext/libuv/src/unix/ev/install-sh +294 -0
  92. data/ext/libuv/src/unix/ev/libev.m4 +39 -0
  93. data/ext/libuv/src/unix/ev/ltmain.sh +8413 -0
  94. data/ext/libuv/src/unix/ev/missing +336 -0
  95. data/ext/libuv/src/unix/ev/mkinstalldirs +111 -0
  96. data/ext/libuv/src/unix/freebsd.c +326 -0
  97. data/ext/libuv/src/unix/fs.c +739 -0
  98. data/ext/libuv/src/unix/internal.h +188 -0
  99. data/ext/libuv/src/unix/kqueue.c +120 -0
  100. data/ext/libuv/src/unix/linux/inotify.c +239 -0
  101. data/ext/libuv/src/unix/linux/linux-core.c +557 -0
  102. data/ext/libuv/src/unix/linux/syscalls.c +388 -0
  103. data/ext/libuv/src/unix/linux/syscalls.h +124 -0
  104. data/ext/libuv/src/unix/loop-watcher.c +62 -0
  105. data/ext/libuv/src/unix/loop.c +94 -0
  106. data/ext/libuv/src/unix/netbsd.c +108 -0
  107. data/ext/libuv/src/unix/openbsd.c +295 -0
  108. data/ext/libuv/src/unix/pipe.c +259 -0
  109. data/ext/libuv/src/unix/poll.c +114 -0
  110. data/ext/libuv/src/unix/process.c +495 -0
  111. data/ext/libuv/src/unix/signal.c +269 -0
  112. data/ext/libuv/src/unix/stream.c +990 -0
  113. data/ext/libuv/src/unix/sunos.c +481 -0
  114. data/ext/libuv/src/unix/tcp.c +393 -0
  115. data/ext/libuv/src/unix/thread.c +251 -0
  116. data/ext/libuv/src/unix/timer.c +136 -0
  117. data/ext/libuv/src/unix/tty.c +145 -0
  118. data/ext/libuv/src/unix/udp.c +659 -0
  119. data/ext/libuv/src/unix/uv-eio.c +107 -0
  120. data/ext/libuv/src/unix/uv-eio.h +13 -0
  121. data/ext/libuv/src/uv-common.c +380 -0
  122. data/ext/libuv/src/uv-common.h +170 -0
  123. data/ext/libuv/src/win/async.c +100 -0
  124. data/ext/libuv/src/win/atomicops-inl.h +56 -0
  125. data/ext/libuv/src/win/core.c +278 -0
  126. data/ext/libuv/src/win/dl.c +86 -0
  127. data/ext/libuv/src/win/error.c +155 -0
  128. data/ext/libuv/src/win/fs-event.c +510 -0
  129. data/ext/libuv/src/win/fs.c +1948 -0
  130. data/ext/libuv/src/win/getaddrinfo.c +365 -0
  131. data/ext/libuv/src/win/handle-inl.h +149 -0
  132. data/ext/libuv/src/win/handle.c +154 -0
  133. data/ext/libuv/src/win/internal.h +343 -0
  134. data/ext/libuv/src/win/loop-watcher.c +122 -0
  135. data/ext/libuv/src/win/pipe.c +1672 -0
  136. data/ext/libuv/src/win/poll.c +616 -0
  137. data/ext/libuv/src/win/process-stdio.c +500 -0
  138. data/ext/libuv/src/win/process.c +1013 -0
  139. data/ext/libuv/src/win/req-inl.h +220 -0
  140. data/ext/libuv/src/win/req.c +25 -0
  141. data/ext/libuv/src/win/signal.c +57 -0
  142. data/ext/libuv/src/win/stream-inl.h +67 -0
  143. data/ext/libuv/src/win/stream.c +167 -0
  144. data/ext/libuv/src/win/tcp.c +1394 -0
  145. data/ext/libuv/src/win/thread.c +372 -0
  146. data/ext/libuv/src/win/threadpool.c +74 -0
  147. data/ext/libuv/src/win/timer.c +224 -0
  148. data/ext/libuv/src/win/tty.c +1799 -0
  149. data/ext/libuv/src/win/udp.c +716 -0
  150. data/ext/libuv/src/win/util.c +864 -0
  151. data/ext/libuv/src/win/winapi.c +132 -0
  152. data/ext/libuv/src/win/winapi.h +4452 -0
  153. data/ext/libuv/src/win/winsock.c +557 -0
  154. data/ext/libuv/src/win/winsock.h +171 -0
  155. data/ext/libuv/test/benchmark-async-pummel.c +97 -0
  156. data/ext/libuv/test/benchmark-async.c +137 -0
  157. data/ext/libuv/test/benchmark-fs-stat.c +135 -0
  158. data/ext/libuv/test/benchmark-getaddrinfo.c +94 -0
  159. data/ext/libuv/test/benchmark-list.h +127 -0
  160. data/ext/libuv/test/benchmark-loop-count.c +88 -0
  161. data/ext/libuv/test/benchmark-million-timers.c +65 -0
  162. data/ext/libuv/test/benchmark-ping-pongs.c +213 -0
  163. data/ext/libuv/test/benchmark-pound.c +324 -0
  164. data/ext/libuv/test/benchmark-pump.c +462 -0
  165. data/ext/libuv/test/benchmark-sizes.c +44 -0
  166. data/ext/libuv/test/benchmark-spawn.c +162 -0
  167. data/ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
  168. data/ext/libuv/test/benchmark-thread.c +64 -0
  169. data/ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
  170. data/ext/libuv/test/blackhole-server.c +118 -0
  171. data/ext/libuv/test/dns-server.c +321 -0
  172. data/ext/libuv/test/echo-server.c +378 -0
  173. data/ext/libuv/test/fixtures/empty_file +0 -0
  174. data/ext/libuv/test/fixtures/load_error.node +1 -0
  175. data/ext/libuv/test/run-benchmarks.c +64 -0
  176. data/ext/libuv/test/run-tests.c +138 -0
  177. data/ext/libuv/test/runner-unix.c +295 -0
  178. data/ext/libuv/test/runner-unix.h +36 -0
  179. data/ext/libuv/test/runner-win.c +285 -0
  180. data/ext/libuv/test/runner-win.h +42 -0
  181. data/ext/libuv/test/runner.c +355 -0
  182. data/ext/libuv/test/runner.h +159 -0
  183. data/ext/libuv/test/task.h +112 -0
  184. data/ext/libuv/test/test-async.c +118 -0
  185. data/ext/libuv/test/test-callback-order.c +76 -0
  186. data/ext/libuv/test/test-callback-stack.c +203 -0
  187. data/ext/libuv/test/test-connection-fail.c +148 -0
  188. data/ext/libuv/test/test-cwd-and-chdir.c +64 -0
  189. data/ext/libuv/test/test-delayed-accept.c +188 -0
  190. data/ext/libuv/test/test-dlerror.c +58 -0
  191. data/ext/libuv/test/test-error.c +59 -0
  192. data/ext/libuv/test/test-fail-always.c +29 -0
  193. data/ext/libuv/test/test-fs-event.c +474 -0
  194. data/ext/libuv/test/test-fs-poll.c +146 -0
  195. data/ext/libuv/test/test-fs.c +1843 -0
  196. data/ext/libuv/test/test-get-currentexe.c +63 -0
  197. data/ext/libuv/test/test-get-loadavg.c +36 -0
  198. data/ext/libuv/test/test-get-memory.c +38 -0
  199. data/ext/libuv/test/test-getaddrinfo.c +122 -0
  200. data/ext/libuv/test/test-getsockname.c +342 -0
  201. data/ext/libuv/test/test-hrtime.c +54 -0
  202. data/ext/libuv/test/test-idle.c +81 -0
  203. data/ext/libuv/test/test-ipc-send-recv.c +209 -0
  204. data/ext/libuv/test/test-ipc.c +620 -0
  205. data/ext/libuv/test/test-list.h +427 -0
  206. data/ext/libuv/test/test-loop-handles.c +336 -0
  207. data/ext/libuv/test/test-multiple-listen.c +102 -0
  208. data/ext/libuv/test/test-mutexes.c +63 -0
  209. data/ext/libuv/test/test-pass-always.c +28 -0
  210. data/ext/libuv/test/test-ping-pong.c +253 -0
  211. data/ext/libuv/test/test-pipe-bind-error.c +140 -0
  212. data/ext/libuv/test/test-pipe-connect-error.c +96 -0
  213. data/ext/libuv/test/test-platform-output.c +87 -0
  214. data/ext/libuv/test/test-poll-close.c +72 -0
  215. data/ext/libuv/test/test-poll.c +573 -0
  216. data/ext/libuv/test/test-process-title.c +49 -0
  217. data/ext/libuv/test/test-ref.c +338 -0
  218. data/ext/libuv/test/test-run-once.c +48 -0
  219. data/ext/libuv/test/test-semaphore.c +111 -0
  220. data/ext/libuv/test/test-shutdown-close.c +103 -0
  221. data/ext/libuv/test/test-shutdown-eof.c +183 -0
  222. data/ext/libuv/test/test-signal.c +162 -0
  223. data/ext/libuv/test/test-spawn.c +863 -0
  224. data/ext/libuv/test/test-stdio-over-pipes.c +246 -0
  225. data/ext/libuv/test/test-tcp-bind-error.c +191 -0
  226. data/ext/libuv/test/test-tcp-bind6-error.c +154 -0
  227. data/ext/libuv/test/test-tcp-close-while-connecting.c +80 -0
  228. data/ext/libuv/test/test-tcp-close.c +129 -0
  229. data/ext/libuv/test/test-tcp-connect-error-after-write.c +95 -0
  230. data/ext/libuv/test/test-tcp-connect-error.c +70 -0
  231. data/ext/libuv/test/test-tcp-connect-timeout.c +85 -0
  232. data/ext/libuv/test/test-tcp-connect6-error.c +68 -0
  233. data/ext/libuv/test/test-tcp-flags.c +51 -0
  234. data/ext/libuv/test/test-tcp-shutdown-after-write.c +131 -0
  235. data/ext/libuv/test/test-tcp-unexpected-read.c +113 -0
  236. data/ext/libuv/test/test-tcp-write-error.c +168 -0
  237. data/ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
  238. data/ext/libuv/test/test-tcp-writealot.c +170 -0
  239. data/ext/libuv/test/test-thread.c +183 -0
  240. data/ext/libuv/test/test-threadpool.c +57 -0
  241. data/ext/libuv/test/test-timer-again.c +141 -0
  242. data/ext/libuv/test/test-timer.c +152 -0
  243. data/ext/libuv/test/test-tty.c +110 -0
  244. data/ext/libuv/test/test-udp-dgram-too-big.c +86 -0
  245. data/ext/libuv/test/test-udp-ipv6.c +156 -0
  246. data/ext/libuv/test/test-udp-multicast-join.c +139 -0
  247. data/ext/libuv/test/test-udp-multicast-ttl.c +86 -0
  248. data/ext/libuv/test/test-udp-options.c +86 -0
  249. data/ext/libuv/test/test-udp-send-and-recv.c +208 -0
  250. data/ext/libuv/test/test-util.c +97 -0
  251. data/ext/libuv/test/test-walk-handles.c +77 -0
  252. data/ext/libuv/uv.gyp +375 -0
  253. data/ext/libuv/vcbuild.bat +105 -0
  254. data/foolio.gemspec +18 -0
  255. data/lib/foolio.rb +9 -0
  256. data/lib/foolio/handle.rb +27 -0
  257. data/lib/foolio/listener.rb +26 -0
  258. data/lib/foolio/loop.rb +79 -0
  259. data/lib/foolio/stream.rb +109 -0
  260. data/lib/foolio/version.rb +3 -0
  261. metadata +309 -0
@@ -0,0 +1,1799 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+
22
+ #include <assert.h>
23
+ #include <io.h>
24
+ #include <string.h>
25
+ #include <stdint.h>
26
+
27
+ #include "uv.h"
28
+ #include "internal.h"
29
+ #include "handle-inl.h"
30
+ #include "stream-inl.h"
31
+ #include "req-inl.h"
32
+
33
+
34
+ #define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
35
+
36
+ #define ANSI_NORMAL 0x00
37
+ #define ANSI_ESCAPE_SEEN 0x02
38
+ #define ANSI_CSI 0x04
39
+ #define ANSI_ST_CONTROL 0x08
40
+ #define ANSI_IGNORE 0x10
41
+ #define ANSI_IN_ARG 0x20
42
+ #define ANSI_IN_STRING 0x40
43
+ #define ANSI_BACKSLASH_SEEN 0x80
44
+
45
+
46
+ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
47
+
48
+
49
+ /* Null uv_buf_t */
50
+ static const uv_buf_t uv_null_buf_ = { 0, NULL };
51
+
52
+
53
+ /*
54
+ * The console virtual window.
55
+ *
56
+ * Normally cursor movement in windows is relative to the console screen buffer,
57
+ * e.g. the application is allowed to overwrite the 'history'. This is very
58
+ * inconvenient, it makes absolute cursor movement pretty useless. There is
59
+ * also the concept of 'client rect' which is defined by the actual size of
60
+ * the console window and the scroll position of the screen buffer, but it's
61
+ * very volatile because it changes when the user scrolls.
62
+ *
63
+ * To make cursor movement behave sensibly we define a virtual window to which
64
+ * cursor movement is confined. The virtual window is always as wide as the
65
+ * console screen buffer, but it's height is defined by the size of the
66
+ * console window. The top of the virtual window aligns with the position
67
+ * of the caret when the first stdout/err handle is created, unless that would
68
+ * mean that it would extend beyond the bottom of the screen buffer - in that
69
+ * that case it's located as far down as possible.
70
+ *
71
+ * When the user writes a long text or many newlines, such that the output
72
+ * reaches beyond the bottom of the virtual window, the virtual window is
73
+ * shifted downwards, but not resized.
74
+ *
75
+ * Since all tty i/o happens on the same console, this window is shared
76
+ * between all stdout/stderr handles.
77
+ */
78
+
79
+ static int uv_tty_virtual_offset = -1;
80
+ static int uv_tty_virtual_height = -1;
81
+ static int uv_tty_virtual_width = -1;
82
+
83
+ static CRITICAL_SECTION uv_tty_output_lock;
84
+
85
+
86
+ void uv_console_init() {
87
+ InitializeCriticalSection(&uv_tty_output_lock);
88
+ }
89
+
90
+
91
+ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
92
+ HANDLE win_handle;
93
+ CONSOLE_SCREEN_BUFFER_INFO info;
94
+
95
+ win_handle = (HANDLE) _get_osfhandle(fd);
96
+ if (win_handle == INVALID_HANDLE_VALUE) {
97
+ uv__set_sys_error(loop, ERROR_INVALID_HANDLE);
98
+ return -1;
99
+ }
100
+
101
+ if (!GetConsoleMode(win_handle, &tty->original_console_mode)) {
102
+ uv__set_sys_error(loop, GetLastError());
103
+ return -1;
104
+ }
105
+
106
+ /* Initialize virtual window size; if it fails, assume that this is stdin. */
107
+ if (GetConsoleScreenBufferInfo(win_handle, &info)) {
108
+ EnterCriticalSection(&uv_tty_output_lock);
109
+ uv_tty_update_virtual_window(&info);
110
+ LeaveCriticalSection(&uv_tty_output_lock);
111
+ }
112
+
113
+ uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
114
+ uv_connection_init((uv_stream_t*) tty);
115
+
116
+ tty->handle = win_handle;
117
+ tty->read_line_handle = NULL;
118
+ tty->read_line_buffer = uv_null_buf_;
119
+ tty->read_raw_wait = NULL;
120
+ tty->reqs_pending = 0;
121
+ tty->flags |= UV_HANDLE_BOUND;
122
+
123
+ /* Init keycode-to-vt100 mapper state. */
124
+ tty->last_key_len = 0;
125
+ tty->last_key_offset = 0;
126
+ tty->last_utf16_high_surrogate = 0;
127
+ memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
128
+
129
+ /* Init utf8-to-utf16 conversion state. */
130
+ tty->utf8_bytes_left = 0;
131
+ tty->utf8_codepoint = 0;
132
+
133
+ /* Initialize eol conversion state */
134
+ tty->previous_eol = 0;
135
+
136
+ /* Init ANSI parser state. */
137
+ tty->ansi_parser_state = ANSI_NORMAL;
138
+
139
+ return 0;
140
+ }
141
+
142
+
143
+ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
144
+ DWORD flags = 0;
145
+ unsigned char was_reading;
146
+ uv_alloc_cb alloc_cb;
147
+ uv_read_cb read_cb;
148
+
149
+ if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
150
+ return 0;
151
+ }
152
+
153
+ if (tty->original_console_mode & ENABLE_QUICK_EDIT_MODE) {
154
+ flags = ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS;
155
+ }
156
+
157
+ if (mode) {
158
+ /* Raw input */
159
+ flags |= ENABLE_WINDOW_INPUT;
160
+ } else {
161
+ /* Line-buffered mode. */
162
+ flags |= ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
163
+ ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT;
164
+ }
165
+
166
+ if (!SetConsoleMode(tty->handle, flags)) {
167
+ uv__set_sys_error(tty->loop, GetLastError());
168
+ return -1;
169
+ }
170
+
171
+ /* If currently reading, stop, and restart reading. */
172
+ if (tty->flags & UV_HANDLE_READING) {
173
+ was_reading = 1;
174
+ alloc_cb = tty->alloc_cb;
175
+ read_cb = tty->read_cb;
176
+
177
+ if (was_reading && uv_tty_read_stop(tty) != 0) {
178
+ return -1;
179
+ }
180
+ } else {
181
+ was_reading = 0;
182
+ }
183
+
184
+ /* Update flag. */
185
+ tty->flags &= ~UV_HANDLE_TTY_RAW;
186
+ tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
187
+
188
+ /* If we just stopped reading, restart. */
189
+ if (was_reading && uv_tty_read_start(tty, alloc_cb, read_cb) != 0) {
190
+ return -1;
191
+ }
192
+
193
+ return 0;
194
+ }
195
+
196
+
197
+ int uv_is_tty(uv_file file) {
198
+ DWORD result;
199
+ return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
200
+ }
201
+
202
+
203
+ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
204
+ CONSOLE_SCREEN_BUFFER_INFO info;
205
+
206
+ if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
207
+ uv__set_sys_error(tty->loop, GetLastError());
208
+ return -1;
209
+ }
210
+
211
+ EnterCriticalSection(&uv_tty_output_lock);
212
+ uv_tty_update_virtual_window(&info);
213
+ LeaveCriticalSection(&uv_tty_output_lock);
214
+
215
+ *width = uv_tty_virtual_width;
216
+ *height = uv_tty_virtual_height;
217
+
218
+ return 0;
219
+ }
220
+
221
+
222
+ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
223
+ uv_loop_t* loop;
224
+ uv_tty_t* handle;
225
+ uv_req_t* req;
226
+
227
+ assert(data);
228
+ assert(!didTimeout);
229
+
230
+ req = (uv_req_t*) data;
231
+ handle = (uv_tty_t*) req->data;
232
+ loop = handle->loop;
233
+
234
+ UnregisterWait(handle->read_raw_wait);
235
+ handle->read_raw_wait = NULL;
236
+
237
+ SET_REQ_SUCCESS(req);
238
+ POST_COMPLETION_FOR_REQ(loop, req);
239
+ }
240
+
241
+
242
+ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
243
+ uv_read_t* req;
244
+ BOOL r;
245
+
246
+ assert(handle->flags & UV_HANDLE_READING);
247
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
248
+
249
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
250
+
251
+ handle->read_line_buffer = uv_null_buf_;
252
+
253
+ req = &handle->read_req;
254
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
255
+
256
+ r = RegisterWaitForSingleObject(&handle->read_raw_wait,
257
+ handle->handle,
258
+ uv_tty_post_raw_read,
259
+ (void*) req,
260
+ INFINITE,
261
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
262
+ if (!r) {
263
+ handle->read_raw_wait = NULL;
264
+ SET_REQ_ERROR(req, GetLastError());
265
+ uv_insert_pending_req(loop, (uv_req_t*)req);
266
+ }
267
+
268
+ handle->flags |= UV_HANDLE_READ_PENDING;
269
+ handle->reqs_pending++;
270
+ }
271
+
272
+
273
+ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
274
+ uv_loop_t* loop;
275
+ uv_tty_t* handle;
276
+ uv_req_t* req;
277
+ DWORD bytes, read_bytes;
278
+
279
+ assert(data);
280
+
281
+ req = (uv_req_t*) data;
282
+ handle = (uv_tty_t*) req->data;
283
+ loop = handle->loop;
284
+
285
+ assert(handle->read_line_buffer.base != NULL);
286
+ assert(handle->read_line_buffer.len > 0);
287
+
288
+ /* ReadConsole can't handle big buffers. */
289
+ if (handle->read_line_buffer.len < 8192) {
290
+ bytes = handle->read_line_buffer.len;
291
+ } else {
292
+ bytes = 8192;
293
+ }
294
+
295
+ /* Todo: Unicode */
296
+ if (ReadConsoleA(handle->read_line_handle,
297
+ (void*) handle->read_line_buffer.base,
298
+ bytes,
299
+ &read_bytes,
300
+ NULL)) {
301
+ SET_REQ_SUCCESS(req);
302
+ req->overlapped.InternalHigh = read_bytes;
303
+ } else {
304
+ SET_REQ_ERROR(req, GetLastError());
305
+ }
306
+
307
+ POST_COMPLETION_FOR_REQ(loop, req);
308
+ return 0;
309
+ }
310
+
311
+
312
+ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
313
+ uv_read_t* req;
314
+ BOOL r;
315
+
316
+ assert(handle->flags & UV_HANDLE_READING);
317
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
318
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
319
+
320
+ req = &handle->read_req;
321
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
322
+
323
+ handle->read_line_buffer = handle->alloc_cb((uv_handle_t*) handle, 8192);
324
+ assert(handle->read_line_buffer.base != NULL);
325
+ assert(handle->read_line_buffer.len > 0);
326
+
327
+ /* Duplicate the console handle, so if we want to cancel the read, we can */
328
+ /* just close this handle duplicate. */
329
+ if (handle->read_line_handle == NULL) {
330
+ HANDLE this_process = GetCurrentProcess();
331
+ r = DuplicateHandle(this_process,
332
+ handle->handle,
333
+ this_process,
334
+ &handle->read_line_handle,
335
+ 0,
336
+ 0,
337
+ DUPLICATE_SAME_ACCESS);
338
+ if (!r) {
339
+ handle->read_line_handle = NULL;
340
+ SET_REQ_ERROR(req, GetLastError());
341
+ uv_insert_pending_req(loop, (uv_req_t*)req);
342
+ goto out;
343
+ }
344
+ }
345
+
346
+ r = QueueUserWorkItem(uv_tty_line_read_thread,
347
+ (void*) req,
348
+ WT_EXECUTELONGFUNCTION);
349
+ if (!r) {
350
+ SET_REQ_ERROR(req, GetLastError());
351
+ uv_insert_pending_req(loop, (uv_req_t*)req);
352
+ }
353
+
354
+ out:
355
+ handle->flags |= UV_HANDLE_READ_PENDING;
356
+ handle->reqs_pending++;
357
+ }
358
+
359
+
360
+ static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
361
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
362
+ uv_tty_queue_read_raw(loop, handle);
363
+ } else {
364
+ uv_tty_queue_read_line(loop, handle);
365
+ }
366
+ }
367
+
368
+
369
+ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
370
+ size_t* len) {
371
+ #define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
372
+ case (vk): \
373
+ if (shift && ctrl) { \
374
+ *len = sizeof shift_ctrl_str; \
375
+ return "\033" shift_ctrl_str; \
376
+ } else if (shift) { \
377
+ *len = sizeof shift_str ; \
378
+ return "\033" shift_str; \
379
+ } else if (ctrl) { \
380
+ *len = sizeof ctrl_str; \
381
+ return "\033" ctrl_str; \
382
+ } else { \
383
+ *len = sizeof normal_str; \
384
+ return "\033" normal_str; \
385
+ }
386
+
387
+ switch (code) {
388
+ /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
389
+ /* keypad keys comply with linux console, modifiers comply with xterm */
390
+ /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
391
+ /* f6..f12 with and without modifiers comply with rxvt. */
392
+ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
393
+ VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
394
+ VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
395
+ VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
396
+ VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
397
+ VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
398
+ VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
399
+ VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
400
+ VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
401
+ VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
402
+ VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
403
+ VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
404
+ VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
405
+ VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
406
+ VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
407
+ VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
408
+ VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
409
+ VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
410
+ VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
411
+ VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
412
+ VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
413
+ VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
414
+ VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
415
+ VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
416
+ VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
417
+ VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
418
+ VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
419
+ VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
420
+ VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
421
+ VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
422
+ VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
423
+ VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
424
+ VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
425
+ VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
426
+
427
+ default:
428
+ *len = 0;
429
+ return NULL;
430
+ }
431
+ #undef VK_CASE
432
+ }
433
+
434
+
435
+ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
436
+ uv_req_t* req) {
437
+ /* Shortcut for handle->last_input_record.Event.KeyEvent. */
438
+ #define KEV handle->last_input_record.Event.KeyEvent
439
+
440
+ DWORD records_left, records_read;
441
+ uv_buf_t buf;
442
+ off_t buf_used;
443
+
444
+ assert(handle->type == UV_TTY);
445
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
446
+
447
+ if (!(handle->flags & UV_HANDLE_READING) ||
448
+ !(handle->flags & UV_HANDLE_TTY_RAW)) {
449
+ goto out;
450
+ }
451
+
452
+ if (!REQ_SUCCESS(req)) {
453
+ /* An error occurred while waiting for the event. */
454
+ if ((handle->flags & UV_HANDLE_READING)) {
455
+ handle->flags &= ~UV_HANDLE_READING;
456
+ uv__set_sys_error(loop, GET_REQ_ERROR(req));
457
+ handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_);
458
+ }
459
+ goto out;
460
+ }
461
+
462
+ /* Fetch the number of events */
463
+ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
464
+ uv__set_sys_error(loop, GetLastError());
465
+ handle->flags &= ~UV_HANDLE_READING;
466
+ DECREASE_ACTIVE_COUNT(loop, handle);
467
+ handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_);
468
+ goto out;
469
+ }
470
+
471
+ /* Windows sends a lot of events that we're not interested in, so buf */
472
+ /* will be allocated on demand, when there's actually something to emit. */
473
+ buf = uv_null_buf_;
474
+ buf_used = 0;
475
+
476
+ while ((records_left > 0 || handle->last_key_len > 0) &&
477
+ (handle->flags & UV_HANDLE_READING)) {
478
+ if (handle->last_key_len == 0) {
479
+ /* Read the next input record */
480
+ if (!ReadConsoleInputW(handle->handle,
481
+ &handle->last_input_record,
482
+ 1,
483
+ &records_read)) {
484
+ uv__set_sys_error(loop, GetLastError());
485
+ handle->flags &= ~UV_HANDLE_READING;
486
+ DECREASE_ACTIVE_COUNT(loop, handle);
487
+ handle->read_cb((uv_stream_t*) handle, -1, buf);
488
+ goto out;
489
+ }
490
+ records_left--;
491
+
492
+ /* Ignore events that are not keyboard events */
493
+ if (handle->last_input_record.EventType != KEY_EVENT) {
494
+ continue;
495
+ }
496
+
497
+ /* Ignore keyup events, unless the left alt key was held and a valid */
498
+ /* unicode character was emitted. */
499
+ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
500
+ KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
501
+ continue;
502
+ }
503
+
504
+ /* Ignore keypresses to numpad number keys if the left alt is held */
505
+ /* because the user is composing a character, or windows simulating */
506
+ /* this. */
507
+ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
508
+ !(KEV.dwControlKeyState & ENHANCED_KEY) &&
509
+ (KEV.wVirtualKeyCode == VK_INSERT ||
510
+ KEV.wVirtualKeyCode == VK_END ||
511
+ KEV.wVirtualKeyCode == VK_DOWN ||
512
+ KEV.wVirtualKeyCode == VK_NEXT ||
513
+ KEV.wVirtualKeyCode == VK_LEFT ||
514
+ KEV.wVirtualKeyCode == VK_CLEAR ||
515
+ KEV.wVirtualKeyCode == VK_RIGHT ||
516
+ KEV.wVirtualKeyCode == VK_HOME ||
517
+ KEV.wVirtualKeyCode == VK_UP ||
518
+ KEV.wVirtualKeyCode == VK_PRIOR ||
519
+ KEV.wVirtualKeyCode == VK_NUMPAD0 ||
520
+ KEV.wVirtualKeyCode == VK_NUMPAD1 ||
521
+ KEV.wVirtualKeyCode == VK_NUMPAD2 ||
522
+ KEV.wVirtualKeyCode == VK_NUMPAD3 ||
523
+ KEV.wVirtualKeyCode == VK_NUMPAD4 ||
524
+ KEV.wVirtualKeyCode == VK_NUMPAD5 ||
525
+ KEV.wVirtualKeyCode == VK_NUMPAD6 ||
526
+ KEV.wVirtualKeyCode == VK_NUMPAD7 ||
527
+ KEV.wVirtualKeyCode == VK_NUMPAD8 ||
528
+ KEV.wVirtualKeyCode == VK_NUMPAD9)) {
529
+ continue;
530
+ }
531
+
532
+ if (KEV.uChar.UnicodeChar != 0) {
533
+ int prefix_len, char_len;
534
+
535
+ /* Character key pressed */
536
+ if (KEV.uChar.UnicodeChar >= 0xD800 &&
537
+ KEV.uChar.UnicodeChar < 0xDC00) {
538
+ /* UTF-16 high surrogate */
539
+ handle->last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
540
+ continue;
541
+ }
542
+
543
+ /* Prefix with \u033 if alt was held, but alt was not used as part */
544
+ /* a compose sequence. */
545
+ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
546
+ && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
547
+ RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
548
+ handle->last_key[0] = '\033';
549
+ prefix_len = 1;
550
+ } else {
551
+ prefix_len = 0;
552
+ }
553
+
554
+ if (KEV.uChar.UnicodeChar >= 0xDC00 &&
555
+ KEV.uChar.UnicodeChar < 0xE000) {
556
+ /* UTF-16 surrogate pair */
557
+ WCHAR utf16_buffer[2] = { handle->last_utf16_high_surrogate,
558
+ KEV.uChar.UnicodeChar};
559
+ char_len = WideCharToMultiByte(CP_UTF8,
560
+ 0,
561
+ utf16_buffer,
562
+ 2,
563
+ &handle->last_key[prefix_len],
564
+ sizeof handle->last_key,
565
+ NULL,
566
+ NULL);
567
+ } else {
568
+ /* Single UTF-16 character */
569
+ char_len = WideCharToMultiByte(CP_UTF8,
570
+ 0,
571
+ &KEV.uChar.UnicodeChar,
572
+ 1,
573
+ &handle->last_key[prefix_len],
574
+ sizeof handle->last_key,
575
+ NULL,
576
+ NULL);
577
+ }
578
+
579
+ /* Whatever happened, the last character wasn't a high surrogate. */
580
+ handle->last_utf16_high_surrogate = 0;
581
+
582
+ /* If the utf16 character(s) couldn't be converted something must */
583
+ /* be wrong. */
584
+ if (!char_len) {
585
+ uv__set_sys_error(loop, GetLastError());
586
+ handle->flags &= ~UV_HANDLE_READING;
587
+ DECREASE_ACTIVE_COUNT(loop, handle);
588
+ handle->read_cb((uv_stream_t*) handle, -1, buf);
589
+ goto out;
590
+ }
591
+
592
+ handle->last_key_len = (unsigned char) (prefix_len + char_len);
593
+ handle->last_key_offset = 0;
594
+ continue;
595
+
596
+ } else {
597
+ /* Function key pressed */
598
+ const char* vt100;
599
+ size_t prefix_len, vt100_len;
600
+
601
+ vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
602
+ !!(KEV.dwControlKeyState & SHIFT_PRESSED),
603
+ !!(KEV.dwControlKeyState & (
604
+ LEFT_CTRL_PRESSED |
605
+ RIGHT_CTRL_PRESSED)),
606
+ &vt100_len);
607
+
608
+ /* If we were unable to map to a vt100 sequence, just ignore. */
609
+ if (!vt100) {
610
+ continue;
611
+ }
612
+
613
+ /* Prefix with \x033 when the alt key was held. */
614
+ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
615
+ handle->last_key[0] = '\033';
616
+ prefix_len = 1;
617
+ } else {
618
+ prefix_len = 0;
619
+ }
620
+
621
+ /* Copy the vt100 sequence to the handle buffer. */
622
+ assert(prefix_len + vt100_len < sizeof handle->last_key);
623
+ memcpy(&handle->last_key[prefix_len], vt100, vt100_len);
624
+
625
+ handle->last_key_len = (unsigned char) (prefix_len + vt100_len);
626
+ handle->last_key_offset = 0;
627
+ continue;
628
+ }
629
+ } else {
630
+ /* Copy any bytes left from the last keypress to the user buffer. */
631
+ if (handle->last_key_offset < handle->last_key_len) {
632
+ /* Allocate a buffer if needed */
633
+ if (buf_used == 0) {
634
+ buf = handle->alloc_cb((uv_handle_t*) handle, 1024);
635
+ }
636
+
637
+ buf.base[buf_used++] = handle->last_key[handle->last_key_offset++];
638
+
639
+ /* If the buffer is full, emit it */
640
+ if (buf_used == buf.len) {
641
+ handle->read_cb((uv_stream_t*) handle, buf_used, buf);
642
+ buf = uv_null_buf_;
643
+ buf_used = 0;
644
+ }
645
+
646
+ continue;
647
+ }
648
+
649
+ /* Apply dwRepeat from the last input record. */
650
+ if (--KEV.wRepeatCount > 0) {
651
+ handle->last_key_offset = 0;
652
+ continue;
653
+ }
654
+
655
+ handle->last_key_len = 0;
656
+ continue;
657
+ }
658
+ }
659
+
660
+ /* Send the buffer back to the user */
661
+ if (buf_used > 0) {
662
+ handle->read_cb((uv_stream_t*) handle, buf_used, buf);
663
+ }
664
+
665
+ out:
666
+ /* Wait for more input events. */
667
+ if ((handle->flags & UV_HANDLE_READING) &&
668
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
669
+ uv_tty_queue_read(loop, handle);
670
+ }
671
+
672
+ DECREASE_PENDING_REQ_COUNT(handle);
673
+
674
+ #undef KEV
675
+ }
676
+
677
+
678
+
679
+ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
680
+ uv_req_t* req) {
681
+ uv_buf_t buf;
682
+
683
+ assert(handle->type == UV_TTY);
684
+
685
+ buf = handle->read_line_buffer;
686
+
687
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
688
+ handle->read_line_buffer = uv_null_buf_;
689
+
690
+ if (!REQ_SUCCESS(req)) {
691
+ /* Read was not successful */
692
+ if ((handle->flags & UV_HANDLE_READING) &&
693
+ handle->read_line_handle != NULL) {
694
+ /* Real error */
695
+ handle->flags &= ~UV_HANDLE_READING;
696
+ DECREASE_ACTIVE_COUNT(loop, handle);
697
+ uv__set_sys_error(loop, GET_REQ_ERROR(req));
698
+ handle->read_cb((uv_stream_t*) handle, -1, buf);
699
+ } else {
700
+ /* The read was cancelled, or whatever we don't care */
701
+ uv__set_sys_error(loop, WSAEWOULDBLOCK); /* maps to UV_EAGAIN */
702
+ handle->read_cb((uv_stream_t*) handle, 0, buf);
703
+ }
704
+
705
+ } else {
706
+ /* Read successful */
707
+ /* TODO: read unicode, convert to utf-8 */
708
+ DWORD bytes = req->overlapped.InternalHigh;
709
+ if (bytes == 0) {
710
+ uv__set_sys_error(loop, WSAEWOULDBLOCK); /* maps to UV_EAGAIN */
711
+ }
712
+ handle->read_cb((uv_stream_t*) handle, bytes, buf);
713
+ }
714
+
715
+ /* Wait for more input events. */
716
+ if ((handle->flags & UV_HANDLE_READING) &&
717
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
718
+ uv_tty_queue_read(loop, handle);
719
+ }
720
+
721
+ DECREASE_PENDING_REQ_COUNT(handle);
722
+ }
723
+
724
+
725
+ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
726
+ uv_req_t* req) {
727
+
728
+ /* If the read_line_buffer member is zero, it must have been an raw read. */
729
+ /* Otherwise it was a line-buffered read. */
730
+ /* FIXME: This is quite obscure. Use a flag or something. */
731
+ if (handle->read_line_buffer.len == 0) {
732
+ uv_process_tty_read_raw_req(loop, handle, req);
733
+ } else {
734
+ uv_process_tty_read_line_req(loop, handle, req);
735
+ }
736
+ }
737
+
738
+
739
+ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
740
+ uv_read_cb read_cb) {
741
+ uv_loop_t* loop = handle->loop;
742
+
743
+ handle->flags |= UV_HANDLE_READING;
744
+ INCREASE_ACTIVE_COUNT(loop, handle);
745
+ handle->read_cb = read_cb;
746
+ handle->alloc_cb = alloc_cb;
747
+
748
+ /* If reading was stopped and then started again, there could still be a */
749
+ /* read request pending. */
750
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
751
+ return 0;
752
+ }
753
+
754
+ /* Maybe the user stopped reading half-way while processing key events. */
755
+ /* Short-circuit if this could be the case. */
756
+ if (handle->last_key_len > 0) {
757
+ SET_REQ_SUCCESS(&handle->read_req);
758
+ uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
759
+ return -1;
760
+ }
761
+
762
+ uv_tty_queue_read(loop, handle);
763
+
764
+ return 0;
765
+ }
766
+
767
+
768
+ int uv_tty_read_stop(uv_tty_t* handle) {
769
+ uv_loop_t* loop = handle->loop;
770
+
771
+ if (handle->flags & UV_HANDLE_READING) {
772
+ handle->flags &= ~UV_HANDLE_READING;
773
+ DECREASE_ACTIVE_COUNT(loop, handle);
774
+ }
775
+
776
+ /* Cancel raw read */
777
+ if ((handle->flags & UV_HANDLE_READ_PENDING) &&
778
+ (handle->flags & UV_HANDLE_TTY_RAW)) {
779
+ /* Write some bullshit event to force the console wait to return. */
780
+ INPUT_RECORD record;
781
+ DWORD written;
782
+ memset(&record, 0, sizeof record);
783
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
784
+ uv__set_sys_error(loop, GetLastError());
785
+ return -1;
786
+ }
787
+ }
788
+
789
+ /* Cancel line-buffered read */
790
+ if (handle->read_line_handle != NULL) {
791
+ /* Closing this handle will cancel the ReadConsole operation */
792
+ CloseHandle(handle->read_line_handle);
793
+ handle->read_line_handle = NULL;
794
+ }
795
+
796
+
797
+ return 0;
798
+ }
799
+
800
+
801
+ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
802
+ uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
803
+ uv_tty_virtual_width = info->dwSize.X;
804
+
805
+ /* Recompute virtual window offset row. */
806
+ if (uv_tty_virtual_offset == -1) {
807
+ uv_tty_virtual_offset = info->dwCursorPosition.Y;
808
+ } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
809
+ uv_tty_virtual_height + 1) {
810
+ /* If suddenly find the cursor outside of the virtual window, it must */
811
+ /* have somehow scrolled. Update the virtual window offset. */
812
+ uv_tty_virtual_offset = info->dwCursorPosition.Y -
813
+ uv_tty_virtual_height + 1;
814
+ }
815
+ if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
816
+ uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
817
+ }
818
+ if (uv_tty_virtual_offset < 0) {
819
+ uv_tty_virtual_offset = 0;
820
+ }
821
+ }
822
+
823
+
824
+ static COORD uv_tty_make_real_coord(uv_tty_t* handle,
825
+ CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
826
+ unsigned char y_relative) {
827
+ COORD result;
828
+
829
+ uv_tty_update_virtual_window(info);
830
+
831
+ /* Adjust y position */
832
+ if (y_relative) {
833
+ y = info->dwCursorPosition.Y + y;
834
+ } else {
835
+ y = uv_tty_virtual_offset + y;
836
+ }
837
+ /* Clip y to virtual client rectangle */
838
+ if (y < uv_tty_virtual_offset) {
839
+ y = uv_tty_virtual_offset;
840
+ } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
841
+ y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
842
+ }
843
+
844
+ /* Adjust x */
845
+ if (x_relative) {
846
+ x = info->dwCursorPosition.X + x;
847
+ }
848
+ /* Clip x */
849
+ if (x < 0) {
850
+ x = 0;
851
+ } else if (x >= uv_tty_virtual_width) {
852
+ x = uv_tty_virtual_width - 1;
853
+ }
854
+
855
+ result.X = (unsigned short) x;
856
+ result.Y = (unsigned short) y;
857
+ return result;
858
+ }
859
+
860
+
861
+ static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
862
+ DWORD* error) {
863
+ DWORD written;
864
+
865
+ if (*error != ERROR_SUCCESS) {
866
+ return -1;
867
+ }
868
+
869
+ if (!WriteConsoleW(handle->handle,
870
+ (void*) buffer,
871
+ length,
872
+ &written,
873
+ NULL)) {
874
+ *error = GetLastError();
875
+ return -1;
876
+ }
877
+
878
+ return 0;
879
+ }
880
+
881
+
882
+ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
883
+ int y, unsigned char y_relative, DWORD* error) {
884
+ CONSOLE_SCREEN_BUFFER_INFO info;
885
+ COORD pos;
886
+
887
+ if (*error != ERROR_SUCCESS) {
888
+ return -1;
889
+ }
890
+
891
+ retry:
892
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
893
+ *error = GetLastError();
894
+ }
895
+
896
+ pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
897
+
898
+ if (!SetConsoleCursorPosition(handle->handle, pos)) {
899
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
900
+ /* The console may be resized - retry */
901
+ goto retry;
902
+ } else {
903
+ *error = GetLastError();
904
+ return -1;
905
+ }
906
+ }
907
+
908
+ return 0;
909
+ }
910
+
911
+
912
+ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
913
+ const COORD origin = {0, 0};
914
+ const WORD char_attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_RED;
915
+ CONSOLE_SCREEN_BUFFER_INFO info;
916
+ DWORD count, written;
917
+
918
+ if (*error != ERROR_SUCCESS) {
919
+ return -1;
920
+ }
921
+
922
+ /* Reset original text attributes. */
923
+ if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
924
+ *error = GetLastError();
925
+ return -1;
926
+ }
927
+
928
+ /* Move the cursor position to (0, 0). */
929
+ if (!SetConsoleCursorPosition(handle->handle, origin)) {
930
+ *error = GetLastError();
931
+ return -1;
932
+ }
933
+
934
+ /* Clear the screen buffer. */
935
+ retry:
936
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
937
+ *error = GetLastError();
938
+ return -1;
939
+ }
940
+
941
+ count = info.dwSize.X * info.dwSize.Y;
942
+
943
+ if (!(FillConsoleOutputCharacterW(handle->handle,
944
+ L'\x20',
945
+ count,
946
+ origin,
947
+ &written) &&
948
+ FillConsoleOutputAttribute(handle->handle,
949
+ char_attrs,
950
+ written,
951
+ origin,
952
+ &written))) {
953
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
954
+ /* The console may be resized - retry */
955
+ goto retry;
956
+ } else {
957
+ *error = GetLastError();
958
+ return -1;
959
+ }
960
+ }
961
+
962
+ /* Move the virtual window up to the top. */
963
+ uv_tty_virtual_offset = 0;
964
+ uv_tty_update_virtual_window(&info);
965
+
966
+ return 0;
967
+ }
968
+
969
+
970
+ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
971
+ DWORD* error) {
972
+ CONSOLE_SCREEN_BUFFER_INFO info;
973
+ COORD start, end;
974
+ DWORD count, written;
975
+
976
+ int x1, x2, y1, y2;
977
+ int x1r, x2r, y1r, y2r;
978
+
979
+ if (*error != ERROR_SUCCESS) {
980
+ return -1;
981
+ }
982
+
983
+ if (dir == 0) {
984
+ /* Clear from current position */
985
+ x1 = 0;
986
+ x1r = 1;
987
+ } else {
988
+ /* Clear from column 0 */
989
+ x1 = 0;
990
+ x1r = 0;
991
+ }
992
+
993
+ if (dir == 1) {
994
+ /* Clear to current position */
995
+ x2 = 0;
996
+ x2r = 1;
997
+ } else {
998
+ /* Clear to end of row. We pretend the console is 65536 characters wide, */
999
+ /* uv_tty_make_real_coord will clip it to the actual console width. */
1000
+ x2 = 0xffff;
1001
+ x2r = 0;
1002
+ }
1003
+
1004
+ if (!entire_screen) {
1005
+ /* Stay on our own row */
1006
+ y1 = y2 = 0;
1007
+ y1r = y2r = 1;
1008
+ } else {
1009
+ /* Apply columns direction to row */
1010
+ y1 = x1;
1011
+ y1r = x1r;
1012
+ y2 = x2;
1013
+ y2r = x2r;
1014
+ }
1015
+
1016
+ retry:
1017
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1018
+ *error = GetLastError();
1019
+ return -1;
1020
+ }
1021
+
1022
+ start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
1023
+ end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
1024
+ count = (end.Y * info.dwSize.X + end.X) -
1025
+ (start.Y * info.dwSize.X + start.X) + 1;
1026
+
1027
+ if (!(FillConsoleOutputCharacterW(handle->handle,
1028
+ L'\x20',
1029
+ count,
1030
+ start,
1031
+ &written) &&
1032
+ FillConsoleOutputAttribute(handle->handle,
1033
+ info.wAttributes,
1034
+ written,
1035
+ start,
1036
+ &written))) {
1037
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
1038
+ /* The console may be resized - retry */
1039
+ goto retry;
1040
+ } else {
1041
+ *error = GetLastError();
1042
+ return -1;
1043
+ }
1044
+ }
1045
+
1046
+ return 0;
1047
+ }
1048
+
1049
+
1050
+ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
1051
+ unsigned short argc = handle->ansi_csi_argc;
1052
+ unsigned short* argv = handle->ansi_csi_argv;
1053
+ int i;
1054
+ CONSOLE_SCREEN_BUFFER_INFO info;
1055
+
1056
+ char fg_color = -1, bg_color = -1;
1057
+ char fg_bright = -1, bg_bright = -1;
1058
+
1059
+ if (argc == 0) {
1060
+ /* Reset mode */
1061
+ fg_color = 7;
1062
+ bg_color = 0;
1063
+ fg_bright = 0;
1064
+ bg_bright = 0;
1065
+ }
1066
+
1067
+ for (i = 0; i < argc; i++) {
1068
+ short arg = argv[i];
1069
+
1070
+ if (arg == 0) {
1071
+ /* Reset mode */
1072
+ fg_color = 7;
1073
+ bg_color = 0;
1074
+ fg_bright = 0;
1075
+ bg_bright = 0;
1076
+
1077
+ } else if (arg == 1) {
1078
+ /* Foreground bright on */
1079
+ fg_bright = 1;
1080
+
1081
+ } else if (arg == 2) {
1082
+ /* Both bright off */
1083
+ fg_bright = 0;
1084
+ bg_bright = 0;
1085
+
1086
+ } else if (arg == 5) {
1087
+ /* Background bright on */
1088
+ bg_bright = 1;
1089
+
1090
+ } else if (arg == 21 || arg == 22) {
1091
+ /* Foreground bright off */
1092
+ fg_bright = 0;
1093
+
1094
+ } else if (arg == 25) {
1095
+ /* Background bright off */
1096
+ bg_bright = 0;
1097
+
1098
+ } else if (arg >= 30 && arg <= 37) {
1099
+ /* Set foreground color */
1100
+ fg_color = arg - 30;
1101
+
1102
+ } else if (arg == 39) {
1103
+ /* Default text color */
1104
+ fg_color = 7;
1105
+ fg_bright = 0;
1106
+
1107
+ } else if (arg >= 40 && arg <= 47) {
1108
+ /* Set background color */
1109
+ bg_color = arg - 40;
1110
+
1111
+ } else if (arg == 49) {
1112
+ /* Default background color */
1113
+ bg_color = 0;
1114
+
1115
+ } else if (arg >= 90 && arg <= 97) {
1116
+ /* Set bold foreground color */
1117
+ fg_bright = 1;
1118
+ fg_color = arg - 90;
1119
+
1120
+ } else if (arg >= 100 && arg <= 107) {
1121
+ /* Set bold background color */
1122
+ bg_bright = 1;
1123
+ bg_color = arg - 100;
1124
+
1125
+ }
1126
+ }
1127
+
1128
+ if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
1129
+ bg_bright == -1) {
1130
+ /* Nothing changed */
1131
+ return 0;
1132
+ }
1133
+
1134
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1135
+ *error = GetLastError();
1136
+ return -1;
1137
+ }
1138
+
1139
+ if (fg_color != -1) {
1140
+ info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1141
+ if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
1142
+ if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
1143
+ if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
1144
+ }
1145
+
1146
+ if (fg_bright != -1) {
1147
+ if (fg_bright) {
1148
+ info.wAttributes |= FOREGROUND_INTENSITY;
1149
+ } else {
1150
+ info.wAttributes &= ~FOREGROUND_INTENSITY;
1151
+ }
1152
+ }
1153
+
1154
+ if (bg_color != -1) {
1155
+ info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
1156
+ if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
1157
+ if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
1158
+ if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
1159
+ }
1160
+
1161
+ if (bg_bright != -1) {
1162
+ if (bg_bright) {
1163
+ info.wAttributes |= BACKGROUND_INTENSITY;
1164
+ } else {
1165
+ info.wAttributes &= ~BACKGROUND_INTENSITY;
1166
+ }
1167
+ }
1168
+
1169
+ if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
1170
+ *error = GetLastError();
1171
+ return -1;
1172
+ }
1173
+
1174
+ return 0;
1175
+ }
1176
+
1177
+
1178
+ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
1179
+ DWORD* error) {
1180
+ CONSOLE_SCREEN_BUFFER_INFO info;
1181
+
1182
+ if (*error != ERROR_SUCCESS) {
1183
+ return -1;
1184
+ }
1185
+
1186
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1187
+ *error = GetLastError();
1188
+ return -1;
1189
+ }
1190
+
1191
+ uv_tty_update_virtual_window(&info);
1192
+
1193
+ handle->saved_position.X = info.dwCursorPosition.X;
1194
+ handle->saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
1195
+ handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
1196
+
1197
+ if (save_attributes) {
1198
+ handle->saved_attributes = info.wAttributes &
1199
+ (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1200
+ handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
1201
+ }
1202
+
1203
+ return 0;
1204
+ }
1205
+
1206
+
1207
+ static int uv_tty_restore_state(uv_tty_t* handle,
1208
+ unsigned char restore_attributes, DWORD* error) {
1209
+ CONSOLE_SCREEN_BUFFER_INFO info;
1210
+ WORD new_attributes;
1211
+
1212
+ if (*error != ERROR_SUCCESS) {
1213
+ return -1;
1214
+ }
1215
+
1216
+ if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
1217
+ if (uv_tty_move_caret(handle,
1218
+ handle->saved_position.X,
1219
+ 0,
1220
+ handle->saved_position.Y,
1221
+ 0,
1222
+ error) != 0) {
1223
+ return -1;
1224
+ }
1225
+ }
1226
+
1227
+ if (restore_attributes &&
1228
+ (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
1229
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1230
+ *error = GetLastError();
1231
+ return -1;
1232
+ }
1233
+
1234
+ new_attributes = info.wAttributes;
1235
+ new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1236
+ new_attributes |= handle->saved_attributes;
1237
+
1238
+ if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
1239
+ *error = GetLastError();
1240
+ return -1;
1241
+ }
1242
+ }
1243
+
1244
+ return 0;
1245
+ }
1246
+
1247
+
1248
+ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t bufs[], int bufcnt,
1249
+ DWORD* error) {
1250
+ /* We can only write 8k characters at a time. Windows can't handle */
1251
+ /* much more characters in a single console write anyway. */
1252
+ WCHAR utf16_buf[8192];
1253
+ DWORD utf16_buf_used = 0;
1254
+ int i;
1255
+
1256
+ #define FLUSH_TEXT() \
1257
+ do { \
1258
+ if (utf16_buf_used > 0) { \
1259
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
1260
+ utf16_buf_used = 0; \
1261
+ } \
1262
+ } while (0)
1263
+
1264
+ /* Cache for fast access */
1265
+ unsigned char utf8_bytes_left = handle->utf8_bytes_left;
1266
+ unsigned int utf8_codepoint = handle->utf8_codepoint;
1267
+ unsigned char previous_eol = handle->previous_eol;
1268
+ unsigned char ansi_parser_state = handle->ansi_parser_state;
1269
+
1270
+ /* Store the error here. If we encounter an error, stop trying to do i/o */
1271
+ /* but keep parsing the buffer so we leave the parser in a consistent */
1272
+ /* state. */
1273
+ *error = ERROR_SUCCESS;
1274
+
1275
+ EnterCriticalSection(&uv_tty_output_lock);
1276
+
1277
+ for (i = 0; i < bufcnt; i++) {
1278
+ uv_buf_t buf = bufs[i];
1279
+ unsigned int j;
1280
+
1281
+ for (j = 0; j < buf.len; j++) {
1282
+ unsigned char c = buf.base[j];
1283
+
1284
+ /* Run the character through the utf8 decoder We happily accept non */
1285
+ /* shortest form encodings and invalid code points - there's no real */
1286
+ /* harm that can be done. */
1287
+ if (utf8_bytes_left == 0) {
1288
+ /* Read utf-8 start byte */
1289
+ DWORD first_zero_bit;
1290
+ unsigned char not_c = ~c;
1291
+ #ifdef _MSC_VER /* msvc */
1292
+ if (_BitScanReverse(&first_zero_bit, not_c)) {
1293
+ #else /* assume gcc */
1294
+ if (c != 0) {
1295
+ first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
1296
+ #endif
1297
+ if (first_zero_bit == 7) {
1298
+ /* Ascii - pass right through */
1299
+ utf8_codepoint = (unsigned int) c;
1300
+
1301
+ } else if (first_zero_bit <= 5) {
1302
+ /* Multibyte sequence */
1303
+ utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
1304
+ utf8_bytes_left = (char) (6 - first_zero_bit);
1305
+
1306
+ } else {
1307
+ /* Invalid continuation */
1308
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1309
+ }
1310
+
1311
+ } else {
1312
+ /* 0xff -- invalid */
1313
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1314
+ }
1315
+
1316
+ } else if ((c & 0xc0) == 0x80) {
1317
+ /* Valid continuation of utf-8 multibyte sequence */
1318
+ utf8_bytes_left--;
1319
+ utf8_codepoint <<= 6;
1320
+ utf8_codepoint |= ((unsigned int) c & 0x3f);
1321
+
1322
+ } else {
1323
+ /* Start byte where continuation was expected. */
1324
+ utf8_bytes_left = 0;
1325
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1326
+ /* Patch buf offset so this character will be parsed again as a */
1327
+ /* start byte. */
1328
+ j--;
1329
+ }
1330
+
1331
+ /* Maybe we need to parse more bytes to find a character. */
1332
+ if (utf8_bytes_left != 0) {
1333
+ continue;
1334
+ }
1335
+
1336
+ /* Parse vt100/ansi escape codes */
1337
+ if (ansi_parser_state == ANSI_NORMAL) {
1338
+ switch (utf8_codepoint) {
1339
+ case '\033':
1340
+ ansi_parser_state = ANSI_ESCAPE_SEEN;
1341
+ continue;
1342
+
1343
+ case 0233:
1344
+ ansi_parser_state = ANSI_CSI;
1345
+ handle->ansi_csi_argc = 0;
1346
+ continue;
1347
+ }
1348
+
1349
+ } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
1350
+ switch (utf8_codepoint) {
1351
+ case '[':
1352
+ ansi_parser_state = ANSI_CSI;
1353
+ handle->ansi_csi_argc = 0;
1354
+ continue;
1355
+
1356
+ case '^':
1357
+ case '_':
1358
+ case 'P':
1359
+ case ']':
1360
+ /* Not supported, but we'll have to parse until we see a stop */
1361
+ /* code, e.g. ESC \ or BEL. */
1362
+ ansi_parser_state = ANSI_ST_CONTROL;
1363
+ continue;
1364
+
1365
+ case '\033':
1366
+ /* Ignore double escape. */
1367
+ continue;
1368
+
1369
+ case 'c':
1370
+ /* Full console reset. */
1371
+ FLUSH_TEXT();
1372
+ uv_tty_reset(handle, error);
1373
+ ansi_parser_state = ANSI_NORMAL;
1374
+ continue;
1375
+
1376
+ case '7':
1377
+ /* Save the cursor position and text attributes. */
1378
+ FLUSH_TEXT();
1379
+ uv_tty_save_state(handle, 1, error);
1380
+ ansi_parser_state = ANSI_NORMAL;
1381
+ continue;
1382
+
1383
+ case '8':
1384
+ /* Restore the cursor position and text attributes */
1385
+ FLUSH_TEXT();
1386
+ uv_tty_restore_state(handle, 1, error);
1387
+ ansi_parser_state = ANSI_NORMAL;
1388
+ continue;
1389
+
1390
+ default:
1391
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
1392
+ /* Single-char control. */
1393
+ ansi_parser_state = ANSI_NORMAL;
1394
+ continue;
1395
+ } else {
1396
+ /* Invalid - proceed as normal, */
1397
+ ansi_parser_state = ANSI_NORMAL;
1398
+ }
1399
+ }
1400
+
1401
+ } else if (ansi_parser_state & ANSI_CSI) {
1402
+ if (!(ansi_parser_state & ANSI_IGNORE)) {
1403
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
1404
+ /* Parsing a numerical argument */
1405
+
1406
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
1407
+ /* We were not currently parsing a number */
1408
+
1409
+ /* Check for too many arguments */
1410
+ if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) {
1411
+ ansi_parser_state |= ANSI_IGNORE;
1412
+ continue;
1413
+ }
1414
+
1415
+ ansi_parser_state |= ANSI_IN_ARG;
1416
+ handle->ansi_csi_argc++;
1417
+ handle->ansi_csi_argv[handle->ansi_csi_argc - 1] =
1418
+ (unsigned short) utf8_codepoint - '0';
1419
+ continue;
1420
+ } else {
1421
+ /* We were already parsing a number. Parse next digit. */
1422
+ uint32_t value = 10 *
1423
+ handle->ansi_csi_argv[handle->ansi_csi_argc - 1];
1424
+
1425
+ /* Check for overflow. */
1426
+ if (value > UINT16_MAX) {
1427
+ ansi_parser_state |= ANSI_IGNORE;
1428
+ continue;
1429
+ }
1430
+
1431
+ handle->ansi_csi_argv[handle->ansi_csi_argc - 1] =
1432
+ (unsigned short) value + (utf8_codepoint - '0');
1433
+ continue;
1434
+ }
1435
+
1436
+ } else if (utf8_codepoint == ';') {
1437
+ /* Denotes the end of an argument. */
1438
+ if (ansi_parser_state & ANSI_IN_ARG) {
1439
+ ansi_parser_state &= ~ANSI_IN_ARG;
1440
+ continue;
1441
+
1442
+ } else {
1443
+ /* If ANSI_IN_ARG is not set, add another argument and */
1444
+ /* default it to 0. */
1445
+ /* Check for too many arguments */
1446
+ if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) {
1447
+ ansi_parser_state |= ANSI_IGNORE;
1448
+ continue;
1449
+ }
1450
+
1451
+ handle->ansi_csi_argc++;
1452
+ handle->ansi_csi_argv[handle->ansi_csi_argc - 1] = 0;
1453
+ continue;
1454
+ }
1455
+
1456
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
1457
+ (handle->ansi_csi_argc > 0 || utf8_codepoint != '[')) {
1458
+ int x, y, d;
1459
+
1460
+ /* Command byte */
1461
+ switch (utf8_codepoint) {
1462
+ case 'A':
1463
+ /* cursor up */
1464
+ FLUSH_TEXT();
1465
+ y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
1466
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
1467
+ break;
1468
+
1469
+ case 'B':
1470
+ /* cursor down */
1471
+ FLUSH_TEXT();
1472
+ y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
1473
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
1474
+ break;
1475
+
1476
+ case 'C':
1477
+ /* cursor forward */
1478
+ FLUSH_TEXT();
1479
+ x = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
1480
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
1481
+ break;
1482
+
1483
+ case 'D':
1484
+ /* cursor back */
1485
+ FLUSH_TEXT();
1486
+ x = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
1487
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
1488
+ break;
1489
+
1490
+ case 'E':
1491
+ /* cursor next line */
1492
+ FLUSH_TEXT();
1493
+ y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1;
1494
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
1495
+ break;
1496
+
1497
+ case 'F':
1498
+ /* cursor previous line */
1499
+ FLUSH_TEXT();
1500
+ y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1);
1501
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
1502
+ break;
1503
+
1504
+ case 'G':
1505
+ /* cursor horizontal move absolute */
1506
+ FLUSH_TEXT();
1507
+ x = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0])
1508
+ ? handle->ansi_csi_argv[0] - 1 : 0;
1509
+ uv_tty_move_caret(handle, x, 0, 0, 1, error);
1510
+ break;
1511
+
1512
+ case 'H':
1513
+ case 'f':
1514
+ /* cursor move absolute */
1515
+ FLUSH_TEXT();
1516
+ y = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0])
1517
+ ? handle->ansi_csi_argv[0] - 1 : 0;
1518
+ x = (handle->ansi_csi_argc >= 2 && handle->ansi_csi_argv[1])
1519
+ ? handle->ansi_csi_argv[1] - 1 : 0;
1520
+ uv_tty_move_caret(handle, x, 0, y, 0, error);
1521
+ break;
1522
+
1523
+ case 'J':
1524
+ /* Erase screen */
1525
+ FLUSH_TEXT();
1526
+ d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0;
1527
+ if (d >= 0 && d <= 2) {
1528
+ uv_tty_clear(handle, d, 1, error);
1529
+ }
1530
+ break;
1531
+
1532
+ case 'K':
1533
+ /* Erase line */
1534
+ FLUSH_TEXT();
1535
+ d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0;
1536
+ if (d >= 0 && d <= 2) {
1537
+ uv_tty_clear(handle, d, 0, error);
1538
+ }
1539
+ break;
1540
+
1541
+ case 'm':
1542
+ /* Set style */
1543
+ FLUSH_TEXT();
1544
+ uv_tty_set_style(handle, error);
1545
+ break;
1546
+
1547
+ case 's':
1548
+ /* Save the cursor position. */
1549
+ FLUSH_TEXT();
1550
+ uv_tty_save_state(handle, 0, error);
1551
+ break;
1552
+
1553
+ case 'u':
1554
+ /* Restore the cursor position */
1555
+ FLUSH_TEXT();
1556
+ uv_tty_restore_state(handle, 0, error);
1557
+ break;
1558
+ }
1559
+
1560
+ /* Sequence ended - go back to normal state. */
1561
+ ansi_parser_state = ANSI_NORMAL;
1562
+ continue;
1563
+
1564
+ } else {
1565
+ /* We don't support commands that use private mode characters or */
1566
+ /* intermediaries. Ignore the rest of the sequence. */
1567
+ ansi_parser_state |= ANSI_IGNORE;
1568
+ continue;
1569
+ }
1570
+ } else {
1571
+ /* We're ignoring this command. Stop only on command character. */
1572
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1573
+ ansi_parser_state = ANSI_NORMAL;
1574
+ }
1575
+ continue;
1576
+ }
1577
+
1578
+ } else if (ansi_parser_state & ANSI_ST_CONTROL) {
1579
+ /* Unsupported control code */
1580
+ /* Ignore everything until we see BEL or ESC \ */
1581
+ if (ansi_parser_state & ANSI_IN_STRING) {
1582
+ if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
1583
+ if (utf8_codepoint == '"') {
1584
+ ansi_parser_state &= ~ANSI_IN_STRING;
1585
+ } else if (utf8_codepoint == '\\') {
1586
+ ansi_parser_state |= ANSI_BACKSLASH_SEEN;
1587
+ }
1588
+ } else {
1589
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
1590
+ }
1591
+ } else {
1592
+ if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
1593
+ (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
1594
+ /* End of sequence */
1595
+ ansi_parser_state = ANSI_NORMAL;
1596
+ } else if (utf8_codepoint == '\033') {
1597
+ /* Escape character */
1598
+ ansi_parser_state |= ANSI_ESCAPE_SEEN;
1599
+ } else if (utf8_codepoint == '"') {
1600
+ /* String starting */
1601
+ ansi_parser_state |= ANSI_IN_STRING;
1602
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
1603
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
1604
+ } else {
1605
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
1606
+ }
1607
+ }
1608
+ continue;
1609
+ } else {
1610
+ /* Inconsistent state */
1611
+ abort();
1612
+ }
1613
+
1614
+ /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
1615
+ /* windows console doesn't really support UTF-16, so just emit the */
1616
+ /* replacement character. */
1617
+ if (utf8_codepoint > 0xffff) {
1618
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1619
+ }
1620
+
1621
+ if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
1622
+ /* EOL conversion - emit \r\n, when we see either \r or \n. */
1623
+ /* If a \n immediately follows a \r or vice versa, ignore it. */
1624
+ if (previous_eol == 0 || utf8_codepoint == previous_eol) {
1625
+ /* If there's no room in the utf16 buf, flush it first. */
1626
+ if (2 > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {
1627
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);
1628
+ utf16_buf_used = 0;
1629
+ }
1630
+
1631
+ utf16_buf[utf16_buf_used++] = L'\r';
1632
+ utf16_buf[utf16_buf_used++] = L'\n';
1633
+ previous_eol = (char) utf8_codepoint;
1634
+ } else {
1635
+ /* Ignore this newline, but don't ignore later ones. */
1636
+ previous_eol = 0;
1637
+ }
1638
+
1639
+ } else if (utf8_codepoint <= 0xffff) {
1640
+ /* Encode character into utf-16 buffer. */
1641
+
1642
+ /* If there's no room in the utf16 buf, flush it first. */
1643
+ if (1 > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {
1644
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);
1645
+ utf16_buf_used = 0;
1646
+ }
1647
+
1648
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
1649
+ previous_eol = 0;
1650
+ }
1651
+ }
1652
+ }
1653
+
1654
+ /* Flush remaining characters */
1655
+ FLUSH_TEXT();
1656
+
1657
+ /* Copy cached values back to struct. */
1658
+ handle->utf8_bytes_left = utf8_bytes_left;
1659
+ handle->utf8_codepoint = utf8_codepoint;
1660
+ handle->previous_eol = previous_eol;
1661
+ handle->ansi_parser_state = ansi_parser_state;
1662
+
1663
+ LeaveCriticalSection(&uv_tty_output_lock);
1664
+
1665
+ if (*error == STATUS_SUCCESS) {
1666
+ return 0;
1667
+ } else {
1668
+ return -1;
1669
+ }
1670
+
1671
+ #undef FLUSH_TEXT
1672
+ }
1673
+
1674
+
1675
+ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
1676
+ uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
1677
+ DWORD error;
1678
+
1679
+ if ((handle->flags & UV_HANDLE_SHUTTING) ||
1680
+ (handle->flags & UV_HANDLE_CLOSING)) {
1681
+ uv__set_sys_error(loop, WSAESHUTDOWN);
1682
+ return -1;
1683
+ }
1684
+
1685
+ uv_req_init(loop, (uv_req_t*) req);
1686
+ req->type = UV_WRITE;
1687
+ req->handle = (uv_stream_t*) handle;
1688
+ req->cb = cb;
1689
+
1690
+ handle->reqs_pending++;
1691
+ handle->write_reqs_pending++;
1692
+ REGISTER_HANDLE_REQ(loop, handle, req);
1693
+
1694
+ req->queued_bytes = 0;
1695
+
1696
+ if (!uv_tty_write_bufs(handle, bufs, bufcnt, &error)) {
1697
+ SET_REQ_SUCCESS(req);
1698
+ } else {
1699
+ SET_REQ_ERROR(req, error);
1700
+ }
1701
+
1702
+ uv_insert_pending_req(loop, (uv_req_t*) req);
1703
+
1704
+ return 0;
1705
+ }
1706
+
1707
+
1708
+ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
1709
+ uv_write_t* req) {
1710
+
1711
+ handle->write_queue_size -= req->queued_bytes;
1712
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
1713
+
1714
+ if (req->cb) {
1715
+ uv__set_sys_error(loop, GET_REQ_ERROR(req));
1716
+ ((uv_write_cb)req->cb)(req, loop->last_err.code == UV_OK ? 0 : -1);
1717
+ }
1718
+
1719
+ handle->write_reqs_pending--;
1720
+ if (handle->flags & UV_HANDLE_SHUTTING &&
1721
+ handle->write_reqs_pending == 0) {
1722
+ uv_want_endgame(loop, (uv_handle_t*)handle);
1723
+ }
1724
+
1725
+ DECREASE_PENDING_REQ_COUNT(handle);
1726
+ }
1727
+
1728
+
1729
+ void uv_tty_close(uv_tty_t* handle) {
1730
+ handle->flags |= UV_HANDLE_SHUTTING;
1731
+
1732
+ uv_tty_read_stop(handle);
1733
+ CloseHandle(handle->handle);
1734
+
1735
+ uv__handle_start(handle);
1736
+
1737
+ if (handle->reqs_pending == 0) {
1738
+ uv_want_endgame(handle->loop, (uv_handle_t*) handle);
1739
+ }
1740
+ }
1741
+
1742
+
1743
+ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
1744
+ if ((handle->flags && UV_HANDLE_CONNECTION) &&
1745
+ handle->shutdown_req != NULL &&
1746
+ handle->write_reqs_pending == 0) {
1747
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
1748
+
1749
+ /* TTY shutdown is really just a no-op */
1750
+ if (handle->shutdown_req->cb) {
1751
+ if (handle->flags & UV_HANDLE_CLOSING) {
1752
+ uv__set_artificial_error(loop, UV_ECANCELED);
1753
+ handle->shutdown_req->cb(handle->shutdown_req, -1);
1754
+ } else {
1755
+ handle->shutdown_req->cb(handle->shutdown_req, 0);
1756
+ }
1757
+ }
1758
+
1759
+ handle->shutdown_req = NULL;
1760
+
1761
+ DECREASE_PENDING_REQ_COUNT(handle);
1762
+ return;
1763
+ }
1764
+
1765
+ if (handle->flags & UV_HANDLE_CLOSING &&
1766
+ handle->reqs_pending == 0) {
1767
+ /* The console handle duplicate used for line reading should be destroyed */
1768
+ /* by uv_tty_read_stop. */
1769
+ assert(handle->read_line_handle == NULL);
1770
+
1771
+ /* The wait handle used for raw reading should be unregistered when the */
1772
+ /* wait callback runs. */
1773
+ assert(handle->read_raw_wait == NULL);
1774
+
1775
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
1776
+ uv__handle_stop(handle);
1777
+ uv__handle_close(handle);
1778
+ }
1779
+ }
1780
+
1781
+
1782
+ /* TODO: remove me */
1783
+ void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
1784
+ uv_req_t* raw_req) {
1785
+ abort();
1786
+ }
1787
+
1788
+
1789
+ /* TODO: remove me */
1790
+ void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
1791
+ uv_connect_t* req) {
1792
+ abort();
1793
+ }
1794
+
1795
+
1796
+ void uv_tty_reset_mode() {
1797
+ /* Not necessary to do anything. */
1798
+ ;
1799
+ }