racer 0.1.3

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