noderb 0.0.10 → 0.0.11

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