Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmlibuv / src / win / tty.c
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 <stdlib.h>
26
27 #if defined(_MSC_VER) && _MSC_VER < 1600
28 # include "uv/stdint-msvc2008.h"
29 #else
30 # include <stdint.h>
31 #endif
32
33 #ifndef COMMON_LVB_REVERSE_VIDEO
34 # define COMMON_LVB_REVERSE_VIDEO 0x4000
35 #endif
36
37 #include "uv.h"
38 #include "internal.h"
39 #include "handle-inl.h"
40 #include "stream-inl.h"
41 #include "req-inl.h"
42
43 #ifndef InterlockedOr
44 # define InterlockedOr _InterlockedOr
45 #endif
46
47 #define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
48
49 #define ANSI_NORMAL           0x0000
50 #define ANSI_ESCAPE_SEEN      0x0002
51 #define ANSI_CSI              0x0004
52 #define ANSI_ST_CONTROL       0x0008
53 #define ANSI_IGNORE           0x0010
54 #define ANSI_IN_ARG           0x0020
55 #define ANSI_IN_STRING        0x0040
56 #define ANSI_BACKSLASH_SEEN   0x0080
57 #define ANSI_EXTENSION        0x0100
58 #define ANSI_DECSCUSR         0x0200
59
60 #define MAX_INPUT_BUFFER_LENGTH 8192
61 #define MAX_CONSOLE_CHAR 8192
62
63 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
64 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
65 #endif
66
67 #define CURSOR_SIZE_SMALL     25
68 #define CURSOR_SIZE_LARGE     100
69
70 static void uv__tty_capture_initial_style(
71     CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
72     CONSOLE_CURSOR_INFO* cursor_info);
73 static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
74 static int uv__cancel_read_console(uv_tty_t* handle);
75
76
77 /* Null uv_buf_t */
78 static const uv_buf_t uv_null_buf_ = { 0, NULL };
79
80 enum uv__read_console_status_e {
81   NOT_STARTED,
82   IN_PROGRESS,
83   TRAP_REQUESTED,
84   COMPLETED
85 };
86
87 static volatile LONG uv__read_console_status = NOT_STARTED;
88 static volatile LONG uv__restore_screen_state;
89 static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
90
91
92 /*
93  * The console virtual window.
94  *
95  * Normally cursor movement in windows is relative to the console screen buffer,
96  * e.g. the application is allowed to overwrite the 'history'. This is very
97  * inconvenient, it makes absolute cursor movement pretty useless. There is
98  * also the concept of 'client rect' which is defined by the actual size of
99  * the console window and the scroll position of the screen buffer, but it's
100  * very volatile because it changes when the user scrolls.
101  *
102  * To make cursor movement behave sensibly we define a virtual window to which
103  * cursor movement is confined. The virtual window is always as wide as the
104  * console screen buffer, but it's height is defined by the size of the
105  * console window. The top of the virtual window aligns with the position
106  * of the caret when the first stdout/err handle is created, unless that would
107  * mean that it would extend beyond the bottom of the screen buffer -  in that
108  * that case it's located as far down as possible.
109  *
110  * When the user writes a long text or many newlines, such that the output
111  * reaches beyond the bottom of the virtual window, the virtual window is
112  * shifted downwards, but not resized.
113  *
114  * Since all tty i/o happens on the same console, this window is shared
115  * between all stdout/stderr handles.
116  */
117
118 static int uv_tty_virtual_offset = -1;
119 static int uv_tty_virtual_height = -1;
120 static int uv_tty_virtual_width = -1;
121
122 /* The console window size
123  * We keep this separate from uv_tty_virtual_*. We use those values to only
124  * handle signalling SIGWINCH
125  */
126
127 static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
128 static int uv__tty_console_height = -1;
129 static int uv__tty_console_width = -1;
130 static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
131 static uv_mutex_t uv__tty_console_resize_mutex;
132
133 static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
134 static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
135                                                   DWORD event,
136                                                   HWND hwnd,
137                                                   LONG idObject,
138                                                   LONG idChild,
139                                                   DWORD dwEventThread,
140                                                   DWORD dwmsEventTime);
141 static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param);
142 static void uv__tty_console_signal_resize(void);
143
144 /* We use a semaphore rather than a mutex or critical section because in some
145    cases (uv__cancel_read_console) we need take the lock in the main thread and
146    release it in another thread. Using a semaphore ensures that in such
147    scenario the main thread will still block when trying to acquire the lock. */
148 static uv_sem_t uv_tty_output_lock;
149
150 static WORD uv_tty_default_text_attributes =
151     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
152
153 static char uv_tty_default_fg_color = 7;
154 static char uv_tty_default_bg_color = 0;
155 static char uv_tty_default_fg_bright = 0;
156 static char uv_tty_default_bg_bright = 0;
157 static char uv_tty_default_inverse = 0;
158
159 static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
160
161 /* Determine whether or not ANSI support is enabled. */
162 static BOOL uv__need_check_vterm_state = TRUE;
163 static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
164 static void uv__determine_vterm_state(HANDLE handle);
165
166 void uv__console_init(void) {
167   if (uv_sem_init(&uv_tty_output_lock, 1))
168     abort();
169   uv__tty_console_handle = CreateFileW(L"CONOUT$",
170                                        GENERIC_READ | GENERIC_WRITE,
171                                        FILE_SHARE_WRITE,
172                                        0,
173                                        OPEN_EXISTING,
174                                        0,
175                                        0);
176   if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
177     CONSOLE_SCREEN_BUFFER_INFO sb_info;
178     QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
179                       NULL,
180                       WT_EXECUTELONGFUNCTION);
181     uv_mutex_init(&uv__tty_console_resize_mutex);
182     if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
183       uv__tty_console_width = sb_info.dwSize.X;
184       uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
185     }
186   }
187 }
188
189
190 int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
191   BOOL readable;
192   DWORD NumberOfEvents;
193   HANDLE handle;
194   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
195   CONSOLE_CURSOR_INFO cursor_info;
196   (void)unused;
197
198   uv__once_init();
199   handle = (HANDLE) uv__get_osfhandle(fd);
200   if (handle == INVALID_HANDLE_VALUE)
201     return UV_EBADF;
202
203   if (fd <= 2) {
204     /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
205      * underlying OS handle and forget about the original fd.
206      * We could also opt to use the original OS handle and just never close it,
207      * but then there would be no reliable way to cancel pending read operations
208      * upon close.
209      */
210     if (!DuplicateHandle(INVALID_HANDLE_VALUE,
211                          handle,
212                          INVALID_HANDLE_VALUE,
213                          &handle,
214                          0,
215                          FALSE,
216                          DUPLICATE_SAME_ACCESS))
217       return uv_translate_sys_error(GetLastError());
218     fd = -1;
219   }
220
221   readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
222   if (!readable) {
223     /* Obtain the screen buffer info with the output handle. */
224     if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
225       return uv_translate_sys_error(GetLastError());
226     }
227
228     /* Obtain the cursor info with the output handle. */
229     if (!GetConsoleCursorInfo(handle, &cursor_info)) {
230       return uv_translate_sys_error(GetLastError());
231     }
232
233     /* Obtain the tty_output_lock because the virtual window state is shared
234      * between all uv_tty_t handles. */
235     uv_sem_wait(&uv_tty_output_lock);
236
237     if (uv__need_check_vterm_state)
238       uv__determine_vterm_state(handle);
239
240     /* Remember the original console text attributes and cursor info. */
241     uv__tty_capture_initial_style(&screen_buffer_info, &cursor_info);
242
243     uv__tty_update_virtual_window(&screen_buffer_info);
244
245     uv_sem_post(&uv_tty_output_lock);
246   }
247
248
249   uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
250   uv__connection_init((uv_stream_t*) tty);
251
252   tty->handle = handle;
253   tty->u.fd = fd;
254   tty->reqs_pending = 0;
255   tty->flags |= UV_HANDLE_BOUND;
256
257   if (readable) {
258     /* Initialize TTY input specific fields. */
259     tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
260     /* TODO: remove me in v2.x. */
261     tty->tty.rd.unused_ = NULL;
262     tty->tty.rd.read_line_buffer = uv_null_buf_;
263     tty->tty.rd.read_raw_wait = NULL;
264
265     /* Init keycode-to-vt100 mapper state. */
266     tty->tty.rd.last_key_len = 0;
267     tty->tty.rd.last_key_offset = 0;
268     tty->tty.rd.last_utf16_high_surrogate = 0;
269     memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
270   } else {
271     /* TTY output specific fields. */
272     tty->flags |= UV_HANDLE_WRITABLE;
273
274     /* Init utf8-to-utf16 conversion state. */
275     tty->tty.wr.utf8_bytes_left = 0;
276     tty->tty.wr.utf8_codepoint = 0;
277
278     /* Initialize eol conversion state */
279     tty->tty.wr.previous_eol = 0;
280
281     /* Init ANSI parser state. */
282     tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
283   }
284
285   return 0;
286 }
287
288
289 /* Set the default console text attributes based on how the console was
290  * configured when libuv started.
291  */
292 static void uv__tty_capture_initial_style(
293     CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
294     CONSOLE_CURSOR_INFO* cursor_info) {
295   static int style_captured = 0;
296
297   /* Only do this once.
298      Assumption: Caller has acquired uv_tty_output_lock. */
299   if (style_captured)
300     return;
301
302   /* Save raw win32 attributes. */
303   uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
304
305   /* Convert black text on black background to use white text. */
306   if (uv_tty_default_text_attributes == 0)
307     uv_tty_default_text_attributes = 7;
308
309   /* Convert Win32 attributes to ANSI colors. */
310   uv_tty_default_fg_color = 0;
311   uv_tty_default_bg_color = 0;
312   uv_tty_default_fg_bright = 0;
313   uv_tty_default_bg_bright = 0;
314   uv_tty_default_inverse = 0;
315
316   if (uv_tty_default_text_attributes & FOREGROUND_RED)
317     uv_tty_default_fg_color |= 1;
318
319   if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
320     uv_tty_default_fg_color |= 2;
321
322   if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
323     uv_tty_default_fg_color |= 4;
324
325   if (uv_tty_default_text_attributes & BACKGROUND_RED)
326     uv_tty_default_bg_color |= 1;
327
328   if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
329     uv_tty_default_bg_color |= 2;
330
331   if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
332     uv_tty_default_bg_color |= 4;
333
334   if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
335     uv_tty_default_fg_bright = 1;
336
337   if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
338     uv_tty_default_bg_bright = 1;
339
340   if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
341     uv_tty_default_inverse = 1;
342
343   /* Save the cursor size and the cursor state. */
344   uv_tty_default_cursor_info = *cursor_info;
345
346   style_captured = 1;
347 }
348
349
350 int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
351   DWORD flags;
352   unsigned char was_reading;
353   uv_alloc_cb alloc_cb;
354   uv_read_cb read_cb;
355   int err;
356
357   if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
358     return UV_EINVAL;
359   }
360
361   if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
362     return 0;
363   }
364
365   switch (mode) {
366     case UV_TTY_MODE_NORMAL:
367       flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
368       break;
369     case UV_TTY_MODE_RAW:
370       flags = ENABLE_WINDOW_INPUT;
371       break;
372     case UV_TTY_MODE_IO:
373       return UV_ENOTSUP;
374     default:
375       return UV_EINVAL;
376   }
377
378   /* If currently reading, stop, and restart reading. */
379   if (tty->flags & UV_HANDLE_READING) {
380     was_reading = 1;
381     alloc_cb = tty->alloc_cb;
382     read_cb = tty->read_cb;
383     err = uv__tty_read_stop(tty);
384     if (err) {
385       return uv_translate_sys_error(err);
386     }
387   } else {
388     was_reading = 0;
389     alloc_cb = NULL;
390     read_cb = NULL;
391   }
392
393   uv_sem_wait(&uv_tty_output_lock);
394   if (!SetConsoleMode(tty->handle, flags)) {
395     err = uv_translate_sys_error(GetLastError());
396     uv_sem_post(&uv_tty_output_lock);
397     return err;
398   }
399   uv_sem_post(&uv_tty_output_lock);
400
401   /* Update flag. */
402   tty->flags &= ~UV_HANDLE_TTY_RAW;
403   tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
404
405   /* If we just stopped reading, restart. */
406   if (was_reading) {
407     err = uv__tty_read_start(tty, alloc_cb, read_cb);
408     if (err) {
409       return uv_translate_sys_error(err);
410     }
411   }
412
413   return 0;
414 }
415
416
417 int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
418   CONSOLE_SCREEN_BUFFER_INFO info;
419
420   if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
421     return uv_translate_sys_error(GetLastError());
422   }
423
424   uv_sem_wait(&uv_tty_output_lock);
425   uv__tty_update_virtual_window(&info);
426   uv_sem_post(&uv_tty_output_lock);
427
428   *width = uv_tty_virtual_width;
429   *height = uv_tty_virtual_height;
430
431   return 0;
432 }
433
434
435 static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
436   uv_loop_t* loop;
437   uv_tty_t* handle;
438   uv_req_t* req;
439
440   assert(data);
441   assert(!didTimeout);
442
443   req = (uv_req_t*) data;
444   handle = (uv_tty_t*) req->data;
445   loop = handle->loop;
446
447   UnregisterWait(handle->tty.rd.read_raw_wait);
448   handle->tty.rd.read_raw_wait = NULL;
449
450   SET_REQ_SUCCESS(req);
451   POST_COMPLETION_FOR_REQ(loop, req);
452 }
453
454
455 static void uv__tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
456   uv_read_t* req;
457   BOOL r;
458
459   assert(handle->flags & UV_HANDLE_READING);
460   assert(!(handle->flags & UV_HANDLE_READ_PENDING));
461
462   assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
463
464   handle->tty.rd.read_line_buffer = uv_null_buf_;
465
466   req = &handle->read_req;
467   memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
468
469   r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
470                                   handle->handle,
471                                   uv_tty_post_raw_read,
472                                   (void*) req,
473                                   INFINITE,
474                                   WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
475   if (!r) {
476     handle->tty.rd.read_raw_wait = NULL;
477     SET_REQ_ERROR(req, GetLastError());
478     uv__insert_pending_req(loop, (uv_req_t*)req);
479   }
480
481   handle->flags |= UV_HANDLE_READ_PENDING;
482   handle->reqs_pending++;
483 }
484
485
486 static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
487   uv_loop_t* loop;
488   uv_tty_t* handle;
489   uv_req_t* req;
490   DWORD bytes, read_bytes;
491   WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
492   DWORD chars, read_chars;
493   LONG status;
494   COORD pos;
495   BOOL read_console_success;
496
497   assert(data);
498
499   req = (uv_req_t*) data;
500   handle = (uv_tty_t*) req->data;
501   loop = handle->loop;
502
503   assert(handle->tty.rd.read_line_buffer.base != NULL);
504   assert(handle->tty.rd.read_line_buffer.len > 0);
505
506   /* ReadConsole can't handle big buffers. */
507   if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
508     bytes = handle->tty.rd.read_line_buffer.len;
509   } else {
510     bytes = MAX_INPUT_BUFFER_LENGTH;
511   }
512
513   /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
514    * codeunits to encode. */
515   chars = bytes / 3;
516
517   status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
518   if (status == TRAP_REQUESTED) {
519     SET_REQ_SUCCESS(req);
520     InterlockedExchange(&uv__read_console_status, COMPLETED);
521     req->u.io.overlapped.InternalHigh = 0;
522     POST_COMPLETION_FOR_REQ(loop, req);
523     return 0;
524   }
525
526   read_console_success = ReadConsoleW(handle->handle,
527                                       (void*) utf16,
528                                       chars,
529                                       &read_chars,
530                                       NULL);
531
532   if (read_console_success) {
533     read_bytes = WideCharToMultiByte(CP_UTF8,
534                                      0,
535                                      utf16,
536                                      read_chars,
537                                      handle->tty.rd.read_line_buffer.base,
538                                      bytes,
539                                      NULL,
540                                      NULL);
541     SET_REQ_SUCCESS(req);
542     req->u.io.overlapped.InternalHigh = read_bytes;
543   } else {
544     SET_REQ_ERROR(req, GetLastError());
545   }
546
547   status = InterlockedExchange(&uv__read_console_status, COMPLETED);
548
549   if (status ==  TRAP_REQUESTED) {
550     /* If we canceled the read by sending a VK_RETURN event, restore the
551        screen state to undo the visual effect of the VK_RETURN */
552     if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
553       HANDLE active_screen_buffer;
554       active_screen_buffer = CreateFileA("conout$",
555                                          GENERIC_READ | GENERIC_WRITE,
556                                          FILE_SHARE_READ | FILE_SHARE_WRITE,
557                                          NULL,
558                                          OPEN_EXISTING,
559                                          FILE_ATTRIBUTE_NORMAL,
560                                          NULL);
561       if (active_screen_buffer != INVALID_HANDLE_VALUE) {
562         pos = uv__saved_screen_state.dwCursorPosition;
563
564         /* If the cursor was at the bottom line of the screen buffer, the
565            VK_RETURN would have caused the buffer contents to scroll up by one
566            line. The right position to reset the cursor to is therefore one line
567            higher */
568         if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
569           pos.Y--;
570
571         SetConsoleCursorPosition(active_screen_buffer, pos);
572         CloseHandle(active_screen_buffer);
573       }
574     }
575     uv_sem_post(&uv_tty_output_lock);
576   }
577   POST_COMPLETION_FOR_REQ(loop, req);
578   return 0;
579 }
580
581
582 static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
583   uv_read_t* req;
584   BOOL r;
585
586   assert(handle->flags & UV_HANDLE_READING);
587   assert(!(handle->flags & UV_HANDLE_READ_PENDING));
588   assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
589
590   req = &handle->read_req;
591   memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
592
593   handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
594   handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
595   if (handle->tty.rd.read_line_buffer.base == NULL ||
596       handle->tty.rd.read_line_buffer.len == 0) {
597     handle->read_cb((uv_stream_t*) handle,
598                     UV_ENOBUFS,
599                     &handle->tty.rd.read_line_buffer);
600     return;
601   }
602   assert(handle->tty.rd.read_line_buffer.base != NULL);
603
604   /* Reset flags  No locking is required since there cannot be a line read
605      in progress. We are also relying on the memory barrier provided by
606      QueueUserWorkItem*/
607   uv__restore_screen_state = FALSE;
608   uv__read_console_status = NOT_STARTED;
609   r = QueueUserWorkItem(uv_tty_line_read_thread,
610                         (void*) req,
611                         WT_EXECUTELONGFUNCTION);
612   if (!r) {
613     SET_REQ_ERROR(req, GetLastError());
614     uv__insert_pending_req(loop, (uv_req_t*)req);
615   }
616
617   handle->flags |= UV_HANDLE_READ_PENDING;
618   handle->reqs_pending++;
619 }
620
621
622 static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
623   if (handle->flags & UV_HANDLE_TTY_RAW) {
624     uv__tty_queue_read_raw(loop, handle);
625   } else {
626     uv__tty_queue_read_line(loop, handle);
627   }
628 }
629
630
631 static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
632     size_t* len) {
633 #define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str)          \
634     case (vk):                                                                \
635       if (shift && ctrl) {                                                    \
636         *len = sizeof shift_ctrl_str;                                         \
637         return "\033" shift_ctrl_str;                                         \
638       } else if (shift) {                                                     \
639         *len = sizeof shift_str ;                                             \
640         return "\033" shift_str;                                              \
641       } else if (ctrl) {                                                      \
642         *len = sizeof ctrl_str;                                               \
643         return "\033" ctrl_str;                                               \
644       } else {                                                                \
645         *len = sizeof normal_str;                                             \
646         return "\033" normal_str;                                             \
647       }
648
649   switch (code) {
650     /* These mappings are the same as Cygwin's. Unmodified and alt-modified
651      * keypad keys comply with linux console, modifiers comply with xterm
652      * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
653      * f12 with and without modifiers comply with rxvt. */
654     VK_CASE(VK_INSERT,  "[2~",  "[2;2~", "[2;5~", "[2;6~")
655     VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
656     VK_CASE(VK_DOWN,    "[B",   "[1;2B", "[1;5B", "[1;6B")
657     VK_CASE(VK_NEXT,    "[6~",  "[6;2~", "[6;5~", "[6;6~")
658     VK_CASE(VK_LEFT,    "[D",   "[1;2D", "[1;5D", "[1;6D")
659     VK_CASE(VK_CLEAR,   "[G",   "[1;2G", "[1;5G", "[1;6G")
660     VK_CASE(VK_RIGHT,   "[C",   "[1;2C", "[1;5C", "[1;6C")
661     VK_CASE(VK_UP,      "[A",   "[1;2A", "[1;5A", "[1;6A")
662     VK_CASE(VK_HOME,    "[1~",  "[1;2~", "[1;5~", "[1;6~")
663     VK_CASE(VK_PRIOR,   "[5~",  "[5;2~", "[5;5~", "[5;6~")
664     VK_CASE(VK_DELETE,  "[3~",  "[3;2~", "[3;5~", "[3;6~")
665     VK_CASE(VK_NUMPAD0, "[2~",  "[2;2~", "[2;5~", "[2;6~")
666     VK_CASE(VK_NUMPAD1, "[4~",  "[4;2~", "[4;5~", "[4;6~")
667     VK_CASE(VK_NUMPAD2, "[B",   "[1;2B", "[1;5B", "[1;6B")
668     VK_CASE(VK_NUMPAD3, "[6~",  "[6;2~", "[6;5~", "[6;6~")
669     VK_CASE(VK_NUMPAD4, "[D",   "[1;2D", "[1;5D", "[1;6D")
670     VK_CASE(VK_NUMPAD5, "[G",   "[1;2G", "[1;5G", "[1;6G")
671     VK_CASE(VK_NUMPAD6, "[C",   "[1;2C", "[1;5C", "[1;6C")
672     VK_CASE(VK_NUMPAD7, "[A",   "[1;2A", "[1;5A", "[1;6A")
673     VK_CASE(VK_NUMPAD8, "[1~",  "[1;2~", "[1;5~", "[1;6~")
674     VK_CASE(VK_NUMPAD9, "[5~",  "[5;2~", "[5;5~", "[5;6~")
675     VK_CASE(VK_DECIMAL, "[3~",  "[3;2~", "[3;5~", "[3;6~")
676     VK_CASE(VK_F1,      "[[A",  "[23~",  "[11^",  "[23^" )
677     VK_CASE(VK_F2,      "[[B",  "[24~",  "[12^",  "[24^" )
678     VK_CASE(VK_F3,      "[[C",  "[25~",  "[13^",  "[25^" )
679     VK_CASE(VK_F4,      "[[D",  "[26~",  "[14^",  "[26^" )
680     VK_CASE(VK_F5,      "[[E",  "[28~",  "[15^",  "[28^" )
681     VK_CASE(VK_F6,      "[17~", "[29~",  "[17^",  "[29^" )
682     VK_CASE(VK_F7,      "[18~", "[31~",  "[18^",  "[31^" )
683     VK_CASE(VK_F8,      "[19~", "[32~",  "[19^",  "[32^" )
684     VK_CASE(VK_F9,      "[20~", "[33~",  "[20^",  "[33^" )
685     VK_CASE(VK_F10,     "[21~", "[34~",  "[21^",  "[34^" )
686     VK_CASE(VK_F11,     "[23~", "[23$",  "[23^",  "[23@" )
687     VK_CASE(VK_F12,     "[24~", "[24$",  "[24^",  "[24@" )
688
689     default:
690       *len = 0;
691       return NULL;
692   }
693 #undef VK_CASE
694 }
695
696
697 void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
698     uv_req_t* req) {
699   /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
700 #define KEV handle->tty.rd.last_input_record.Event.KeyEvent
701
702   DWORD records_left, records_read;
703   uv_buf_t buf;
704   off_t buf_used;
705
706   assert(handle->type == UV_TTY);
707   assert(handle->flags & UV_HANDLE_TTY_READABLE);
708   handle->flags &= ~UV_HANDLE_READ_PENDING;
709
710   if (!(handle->flags & UV_HANDLE_READING) ||
711       !(handle->flags & UV_HANDLE_TTY_RAW)) {
712     goto out;
713   }
714
715   if (!REQ_SUCCESS(req)) {
716     /* An error occurred while waiting for the event. */
717     if ((handle->flags & UV_HANDLE_READING)) {
718       handle->flags &= ~UV_HANDLE_READING;
719       handle->read_cb((uv_stream_t*)handle,
720                       uv_translate_sys_error(GET_REQ_ERROR(req)),
721                       &uv_null_buf_);
722     }
723     goto out;
724   }
725
726   /* Fetch the number of events  */
727   if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
728     handle->flags &= ~UV_HANDLE_READING;
729     DECREASE_ACTIVE_COUNT(loop, handle);
730     handle->read_cb((uv_stream_t*)handle,
731                     uv_translate_sys_error(GetLastError()),
732                     &uv_null_buf_);
733     goto out;
734   }
735
736   /* Windows sends a lot of events that we're not interested in, so buf will be
737    * allocated on demand, when there's actually something to emit. */
738   buf = uv_null_buf_;
739   buf_used = 0;
740
741   while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
742          (handle->flags & UV_HANDLE_READING)) {
743     if (handle->tty.rd.last_key_len == 0) {
744       /* Read the next input record */
745       if (!ReadConsoleInputW(handle->handle,
746                              &handle->tty.rd.last_input_record,
747                              1,
748                              &records_read)) {
749         handle->flags &= ~UV_HANDLE_READING;
750         DECREASE_ACTIVE_COUNT(loop, handle);
751         handle->read_cb((uv_stream_t*) handle,
752                         uv_translate_sys_error(GetLastError()),
753                         &buf);
754         goto out;
755       }
756       records_left--;
757
758       /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
759        * running under some TTY emulator that does not send those events. */
760       if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
761         uv__tty_console_signal_resize();
762       }
763
764       /* Ignore other events that are not key events. */
765       if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
766         continue;
767       }
768
769       /* Ignore keyup events, unless the left alt key was held and a valid
770        * unicode character was emitted. */
771       if (!KEV.bKeyDown &&
772           (KEV.wVirtualKeyCode != VK_MENU ||
773            KEV.uChar.UnicodeChar == 0)) {
774         continue;
775       }
776
777       /* Ignore keypresses to numpad number keys if the left alt is held
778        * because the user is composing a character, or windows simulating this.
779        */
780       if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
781           !(KEV.dwControlKeyState & ENHANCED_KEY) &&
782           (KEV.wVirtualKeyCode == VK_INSERT ||
783           KEV.wVirtualKeyCode == VK_END ||
784           KEV.wVirtualKeyCode == VK_DOWN ||
785           KEV.wVirtualKeyCode == VK_NEXT ||
786           KEV.wVirtualKeyCode == VK_LEFT ||
787           KEV.wVirtualKeyCode == VK_CLEAR ||
788           KEV.wVirtualKeyCode == VK_RIGHT ||
789           KEV.wVirtualKeyCode == VK_HOME ||
790           KEV.wVirtualKeyCode == VK_UP ||
791           KEV.wVirtualKeyCode == VK_PRIOR ||
792           KEV.wVirtualKeyCode == VK_NUMPAD0 ||
793           KEV.wVirtualKeyCode == VK_NUMPAD1 ||
794           KEV.wVirtualKeyCode == VK_NUMPAD2 ||
795           KEV.wVirtualKeyCode == VK_NUMPAD3 ||
796           KEV.wVirtualKeyCode == VK_NUMPAD4 ||
797           KEV.wVirtualKeyCode == VK_NUMPAD5 ||
798           KEV.wVirtualKeyCode == VK_NUMPAD6 ||
799           KEV.wVirtualKeyCode == VK_NUMPAD7 ||
800           KEV.wVirtualKeyCode == VK_NUMPAD8 ||
801           KEV.wVirtualKeyCode == VK_NUMPAD9)) {
802         continue;
803       }
804
805       if (KEV.uChar.UnicodeChar != 0) {
806         int prefix_len, char_len;
807
808         /* Character key pressed */
809         if (KEV.uChar.UnicodeChar >= 0xD800 &&
810             KEV.uChar.UnicodeChar < 0xDC00) {
811           /* UTF-16 high surrogate */
812           handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
813           continue;
814         }
815
816         /* Prefix with \u033 if alt was held, but alt was not used as part a
817          * compose sequence. */
818         if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
819             && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
820             RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
821           handle->tty.rd.last_key[0] = '\033';
822           prefix_len = 1;
823         } else {
824           prefix_len = 0;
825         }
826
827         if (KEV.uChar.UnicodeChar >= 0xDC00 &&
828             KEV.uChar.UnicodeChar < 0xE000) {
829           /* UTF-16 surrogate pair */
830           WCHAR utf16_buffer[2];
831           utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
832           utf16_buffer[1] = KEV.uChar.UnicodeChar;
833           char_len = WideCharToMultiByte(CP_UTF8,
834                                          0,
835                                          utf16_buffer,
836                                          2,
837                                          &handle->tty.rd.last_key[prefix_len],
838                                          sizeof handle->tty.rd.last_key,
839                                          NULL,
840                                          NULL);
841         } else {
842           /* Single UTF-16 character */
843           char_len = WideCharToMultiByte(CP_UTF8,
844                                          0,
845                                          &KEV.uChar.UnicodeChar,
846                                          1,
847                                          &handle->tty.rd.last_key[prefix_len],
848                                          sizeof handle->tty.rd.last_key,
849                                          NULL,
850                                          NULL);
851         }
852
853         /* Whatever happened, the last character wasn't a high surrogate. */
854         handle->tty.rd.last_utf16_high_surrogate = 0;
855
856         /* If the utf16 character(s) couldn't be converted something must be
857          * wrong. */
858         if (!char_len) {
859           handle->flags &= ~UV_HANDLE_READING;
860           DECREASE_ACTIVE_COUNT(loop, handle);
861           handle->read_cb((uv_stream_t*) handle,
862                           uv_translate_sys_error(GetLastError()),
863                           &buf);
864           goto out;
865         }
866
867         handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
868         handle->tty.rd.last_key_offset = 0;
869         continue;
870
871       } else {
872         /* Function key pressed */
873         const char* vt100;
874         size_t prefix_len, vt100_len;
875
876         vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
877                                   !!(KEV.dwControlKeyState & SHIFT_PRESSED),
878                                   !!(KEV.dwControlKeyState & (
879                                     LEFT_CTRL_PRESSED |
880                                     RIGHT_CTRL_PRESSED)),
881                                   &vt100_len);
882
883         /* If we were unable to map to a vt100 sequence, just ignore. */
884         if (!vt100) {
885           continue;
886         }
887
888         /* Prefix with \x033 when the alt key was held. */
889         if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
890           handle->tty.rd.last_key[0] = '\033';
891           prefix_len = 1;
892         } else {
893           prefix_len = 0;
894         }
895
896         /* Copy the vt100 sequence to the handle buffer. */
897         assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
898         memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
899
900         handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
901         handle->tty.rd.last_key_offset = 0;
902         continue;
903       }
904     } else {
905       /* Copy any bytes left from the last keypress to the user buffer. */
906       if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
907         /* Allocate a buffer if needed */
908         if (buf_used == 0) {
909           buf = uv_buf_init(NULL, 0);
910           handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
911           if (buf.base == NULL || buf.len == 0) {
912             handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
913             goto out;
914           }
915           assert(buf.base != NULL);
916         }
917
918         buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
919
920         /* If the buffer is full, emit it */
921         if ((size_t) buf_used == buf.len) {
922           handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
923           buf = uv_null_buf_;
924           buf_used = 0;
925         }
926
927         continue;
928       }
929
930       /* Apply dwRepeat from the last input record. */
931       if (--KEV.wRepeatCount > 0) {
932         handle->tty.rd.last_key_offset = 0;
933         continue;
934       }
935
936       handle->tty.rd.last_key_len = 0;
937       continue;
938     }
939   }
940
941   /* Send the buffer back to the user */
942   if (buf_used > 0) {
943     handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
944   }
945
946  out:
947   /* Wait for more input events. */
948   if ((handle->flags & UV_HANDLE_READING) &&
949       !(handle->flags & UV_HANDLE_READ_PENDING)) {
950     uv__tty_queue_read(loop, handle);
951   }
952
953   DECREASE_PENDING_REQ_COUNT(handle);
954
955 #undef KEV
956 }
957
958
959
960 void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
961     uv_req_t* req) {
962   uv_buf_t buf;
963
964   assert(handle->type == UV_TTY);
965   assert(handle->flags & UV_HANDLE_TTY_READABLE);
966
967   buf = handle->tty.rd.read_line_buffer;
968
969   handle->flags &= ~UV_HANDLE_READ_PENDING;
970   handle->tty.rd.read_line_buffer = uv_null_buf_;
971
972   if (!REQ_SUCCESS(req)) {
973     /* Read was not successful */
974     if (handle->flags & UV_HANDLE_READING) {
975       /* Real error */
976       handle->flags &= ~UV_HANDLE_READING;
977       DECREASE_ACTIVE_COUNT(loop, handle);
978       handle->read_cb((uv_stream_t*) handle,
979                       uv_translate_sys_error(GET_REQ_ERROR(req)),
980                       &buf);
981     }
982   } else {
983     if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
984         req->u.io.overlapped.InternalHigh != 0) {
985       /* Read successful. TODO: read unicode, convert to utf-8 */
986       DWORD bytes = req->u.io.overlapped.InternalHigh;
987       handle->read_cb((uv_stream_t*) handle, bytes, &buf);
988     }
989     handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
990   }
991
992   /* Wait for more input events. */
993   if ((handle->flags & UV_HANDLE_READING) &&
994       !(handle->flags & UV_HANDLE_READ_PENDING)) {
995     uv__tty_queue_read(loop, handle);
996   }
997
998   DECREASE_PENDING_REQ_COUNT(handle);
999 }
1000
1001
1002 void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
1003     uv_req_t* req) {
1004   assert(handle->type == UV_TTY);
1005   assert(handle->flags & UV_HANDLE_TTY_READABLE);
1006
1007   /* If the read_line_buffer member is zero, it must have been an raw read.
1008    * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
1009    * flag or something. */
1010   if (handle->tty.rd.read_line_buffer.len == 0) {
1011     uv_process_tty_read_raw_req(loop, handle, req);
1012   } else {
1013     uv_process_tty_read_line_req(loop, handle, req);
1014   }
1015 }
1016
1017
1018 int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
1019     uv_read_cb read_cb) {
1020   uv_loop_t* loop = handle->loop;
1021
1022   if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
1023     return ERROR_INVALID_PARAMETER;
1024   }
1025
1026   handle->flags |= UV_HANDLE_READING;
1027   INCREASE_ACTIVE_COUNT(loop, handle);
1028   handle->read_cb = read_cb;
1029   handle->alloc_cb = alloc_cb;
1030
1031   /* If reading was stopped and then started again, there could still be a read
1032    * request pending. */
1033   if (handle->flags & UV_HANDLE_READ_PENDING) {
1034     return 0;
1035   }
1036
1037   /* Maybe the user stopped reading half-way while processing key events.
1038    * Short-circuit if this could be the case. */
1039   if (handle->tty.rd.last_key_len > 0) {
1040     SET_REQ_SUCCESS(&handle->read_req);
1041     uv__insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
1042     /* Make sure no attempt is made to insert it again until it's handled. */
1043     handle->flags |= UV_HANDLE_READ_PENDING;
1044     handle->reqs_pending++;
1045     return 0;
1046   }
1047
1048   uv__tty_queue_read(loop, handle);
1049
1050   return 0;
1051 }
1052
1053
1054 int uv__tty_read_stop(uv_tty_t* handle) {
1055   INPUT_RECORD record;
1056   DWORD written, err;
1057
1058   handle->flags &= ~UV_HANDLE_READING;
1059   DECREASE_ACTIVE_COUNT(handle->loop, handle);
1060
1061   if (!(handle->flags & UV_HANDLE_READ_PENDING))
1062     return 0;
1063
1064   if (handle->flags & UV_HANDLE_TTY_RAW) {
1065     /* Cancel raw read. Write some bullshit event to force the console wait to
1066      * return. */
1067     memset(&record, 0, sizeof record);
1068     record.EventType = FOCUS_EVENT;
1069     if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
1070       return GetLastError();
1071     }
1072   } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
1073     /* Cancel line-buffered read if not already pending */
1074     err = uv__cancel_read_console(handle);
1075     if (err)
1076       return err;
1077
1078     handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
1079   }
1080
1081   return 0;
1082 }
1083
1084 static int uv__cancel_read_console(uv_tty_t* handle) {
1085   HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
1086   INPUT_RECORD record;
1087   DWORD written;
1088   DWORD err = 0;
1089   LONG status;
1090
1091   assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
1092
1093   /* Hold the output lock during the cancellation, to ensure that further
1094      writes don't interfere with the screen state. It will be the ReadConsole
1095      thread's responsibility to release the lock. */
1096   uv_sem_wait(&uv_tty_output_lock);
1097   status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
1098   if (status != IN_PROGRESS) {
1099     /* Either we have managed to set a trap for the other thread before
1100        ReadConsole is called, or ReadConsole has returned because the user
1101        has pressed ENTER. In either case, there is nothing else to do. */
1102     uv_sem_post(&uv_tty_output_lock);
1103     return 0;
1104   }
1105
1106   /* Save screen state before sending the VK_RETURN event */
1107   active_screen_buffer = CreateFileA("conout$",
1108                                      GENERIC_READ | GENERIC_WRITE,
1109                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
1110                                      NULL,
1111                                      OPEN_EXISTING,
1112                                      FILE_ATTRIBUTE_NORMAL,
1113                                      NULL);
1114
1115   if (active_screen_buffer != INVALID_HANDLE_VALUE &&
1116       GetConsoleScreenBufferInfo(active_screen_buffer,
1117                                  &uv__saved_screen_state)) {
1118     InterlockedOr(&uv__restore_screen_state, 1);
1119   }
1120
1121   /* Write enter key event to force the console wait to return. */
1122   record.EventType = KEY_EVENT;
1123   record.Event.KeyEvent.bKeyDown = TRUE;
1124   record.Event.KeyEvent.wRepeatCount = 1;
1125   record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1126   record.Event.KeyEvent.wVirtualScanCode =
1127     MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
1128   record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
1129   record.Event.KeyEvent.dwControlKeyState = 0;
1130   if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
1131     err = GetLastError();
1132
1133   if (active_screen_buffer != INVALID_HANDLE_VALUE)
1134     CloseHandle(active_screen_buffer);
1135
1136   return err;
1137 }
1138
1139
1140 static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
1141   uv_tty_virtual_width = info->dwSize.X;
1142   uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
1143
1144   /* Recompute virtual window offset row. */
1145   if (uv_tty_virtual_offset == -1) {
1146     uv_tty_virtual_offset = info->dwCursorPosition.Y;
1147   } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
1148              uv_tty_virtual_height + 1) {
1149     /* If suddenly find the cursor outside of the virtual window, it must have
1150      * somehow scrolled. Update the virtual window offset. */
1151     uv_tty_virtual_offset = info->dwCursorPosition.Y -
1152                             uv_tty_virtual_height + 1;
1153   }
1154   if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
1155     uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
1156   }
1157   if (uv_tty_virtual_offset < 0) {
1158     uv_tty_virtual_offset = 0;
1159   }
1160 }
1161
1162
1163 static COORD uv__tty_make_real_coord(uv_tty_t* handle,
1164     CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
1165     unsigned char y_relative) {
1166   COORD result;
1167
1168   uv__tty_update_virtual_window(info);
1169
1170   /* Adjust y position */
1171   if (y_relative) {
1172     y = info->dwCursorPosition.Y + y;
1173   } else {
1174     y = uv_tty_virtual_offset + y;
1175   }
1176   /* Clip y to virtual client rectangle */
1177   if (y < uv_tty_virtual_offset) {
1178     y = uv_tty_virtual_offset;
1179   } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
1180     y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
1181   }
1182
1183   /* Adjust x */
1184   if (x_relative) {
1185     x = info->dwCursorPosition.X + x;
1186   }
1187   /* Clip x */
1188   if (x < 0) {
1189     x = 0;
1190   } else if (x >= uv_tty_virtual_width) {
1191     x = uv_tty_virtual_width - 1;
1192   }
1193
1194   result.X = (unsigned short) x;
1195   result.Y = (unsigned short) y;
1196   return result;
1197 }
1198
1199
1200 static int uv__tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
1201     DWORD* error) {
1202   DWORD written;
1203
1204   if (*error != ERROR_SUCCESS) {
1205     return -1;
1206   }
1207
1208   if (!WriteConsoleW(handle->handle,
1209                      (void*) buffer,
1210                      length,
1211                      &written,
1212                      NULL)) {
1213     *error = GetLastError();
1214     return -1;
1215   }
1216
1217   return 0;
1218 }
1219
1220
1221 static int uv__tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
1222     int y, unsigned char y_relative, DWORD* error) {
1223   CONSOLE_SCREEN_BUFFER_INFO info;
1224   COORD pos;
1225
1226   if (*error != ERROR_SUCCESS) {
1227     return -1;
1228   }
1229
1230  retry:
1231   if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1232     *error = GetLastError();
1233   }
1234
1235   pos = uv__tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
1236
1237   if (!SetConsoleCursorPosition(handle->handle, pos)) {
1238     if (GetLastError() == ERROR_INVALID_PARAMETER) {
1239       /* The console may be resized - retry */
1240       goto retry;
1241     } else {
1242       *error = GetLastError();
1243       return -1;
1244     }
1245   }
1246
1247   return 0;
1248 }
1249
1250
1251 static int uv__tty_reset(uv_tty_t* handle, DWORD* error) {
1252   const COORD origin = {0, 0};
1253   const WORD char_attrs = uv_tty_default_text_attributes;
1254   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
1255   DWORD count, written;
1256
1257   if (*error != ERROR_SUCCESS) {
1258     return -1;
1259   }
1260
1261   /* Reset original text attributes. */
1262   if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
1263     *error = GetLastError();
1264     return -1;
1265   }
1266
1267   /* Move the cursor position to (0, 0). */
1268   if (!SetConsoleCursorPosition(handle->handle, origin)) {
1269     *error = GetLastError();
1270     return -1;
1271   }
1272
1273   /* Clear the screen buffer. */
1274  retry:
1275    if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
1276      *error = GetLastError();
1277      return -1;
1278   }
1279
1280   count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
1281
1282   if (!(FillConsoleOutputCharacterW(handle->handle,
1283                                     L'\x20',
1284                                     count,
1285                                     origin,
1286                                     &written) &&
1287         FillConsoleOutputAttribute(handle->handle,
1288                                    char_attrs,
1289                                    written,
1290                                    origin,
1291                                    &written))) {
1292     if (GetLastError() == ERROR_INVALID_PARAMETER) {
1293       /* The console may be resized - retry */
1294       goto retry;
1295     } else {
1296       *error = GetLastError();
1297       return -1;
1298     }
1299   }
1300
1301   /* Move the virtual window up to the top. */
1302   uv_tty_virtual_offset = 0;
1303   uv__tty_update_virtual_window(&screen_buffer_info);
1304
1305   /* Reset the cursor size and the cursor state. */
1306   if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
1307     *error = GetLastError();
1308     return -1;
1309   }
1310
1311   return 0;
1312 }
1313
1314
1315 static int uv__tty_clear(uv_tty_t* handle, int dir, char entire_screen,
1316     DWORD* error) {
1317   CONSOLE_SCREEN_BUFFER_INFO info;
1318   COORD start, end;
1319   DWORD count, written;
1320
1321   int x1, x2, y1, y2;
1322   int x1r, x2r, y1r, y2r;
1323
1324   if (*error != ERROR_SUCCESS) {
1325     return -1;
1326   }
1327
1328   if (dir == 0) {
1329     /* Clear from current position */
1330     x1 = 0;
1331     x1r = 1;
1332   } else {
1333     /* Clear from column 0 */
1334     x1 = 0;
1335     x1r = 0;
1336   }
1337
1338   if (dir == 1) {
1339     /* Clear to current position */
1340     x2 = 0;
1341     x2r = 1;
1342   } else {
1343     /* Clear to end of row. We pretend the console is 65536 characters wide,
1344      * uv__tty_make_real_coord will clip it to the actual console width. */
1345     x2 = 0xffff;
1346     x2r = 0;
1347   }
1348
1349   if (!entire_screen) {
1350     /* Stay on our own row */
1351     y1 = y2 = 0;
1352     y1r = y2r = 1;
1353   } else {
1354     /* Apply columns direction to row */
1355     y1 = x1;
1356     y1r = x1r;
1357     y2 = x2;
1358     y2r = x2r;
1359   }
1360
1361  retry:
1362   if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1363     *error = GetLastError();
1364     return -1;
1365   }
1366
1367   start = uv__tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
1368   end = uv__tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
1369   count = (end.Y * info.dwSize.X + end.X) -
1370           (start.Y * info.dwSize.X + start.X) + 1;
1371
1372   if (!(FillConsoleOutputCharacterW(handle->handle,
1373                               L'\x20',
1374                               count,
1375                               start,
1376                               &written) &&
1377         FillConsoleOutputAttribute(handle->handle,
1378                                    info.wAttributes,
1379                                    written,
1380                                    start,
1381                                    &written))) {
1382     if (GetLastError() == ERROR_INVALID_PARAMETER) {
1383       /* The console may be resized - retry */
1384       goto retry;
1385     } else {
1386       *error = GetLastError();
1387       return -1;
1388     }
1389   }
1390
1391   return 0;
1392 }
1393
1394 #define FLIP_FGBG                                                             \
1395     do {                                                                      \
1396       WORD fg = info.wAttributes & 0xF;                                       \
1397       WORD bg = info.wAttributes & 0xF0;                                      \
1398       info.wAttributes &= 0xFF00;                                             \
1399       info.wAttributes |= fg << 4;                                            \
1400       info.wAttributes |= bg >> 4;                                            \
1401     } while (0)
1402
1403 static int uv__tty_set_style(uv_tty_t* handle, DWORD* error) {
1404   unsigned short argc = handle->tty.wr.ansi_csi_argc;
1405   unsigned short* argv = handle->tty.wr.ansi_csi_argv;
1406   int i;
1407   CONSOLE_SCREEN_BUFFER_INFO info;
1408
1409   char fg_color = -1, bg_color = -1;
1410   char fg_bright = -1, bg_bright = -1;
1411   char inverse = -1;
1412
1413   if (argc == 0) {
1414     /* Reset mode */
1415     fg_color = uv_tty_default_fg_color;
1416     bg_color = uv_tty_default_bg_color;
1417     fg_bright = uv_tty_default_fg_bright;
1418     bg_bright = uv_tty_default_bg_bright;
1419     inverse = uv_tty_default_inverse;
1420   }
1421
1422   for (i = 0; i < argc; i++) {
1423     short arg = argv[i];
1424
1425     if (arg == 0) {
1426       /* Reset mode */
1427       fg_color = uv_tty_default_fg_color;
1428       bg_color = uv_tty_default_bg_color;
1429       fg_bright = uv_tty_default_fg_bright;
1430       bg_bright = uv_tty_default_bg_bright;
1431       inverse = uv_tty_default_inverse;
1432
1433     } else if (arg == 1) {
1434       /* Foreground bright on */
1435       fg_bright = 1;
1436
1437     } else if (arg == 2) {
1438       /* Both bright off */
1439       fg_bright = 0;
1440       bg_bright = 0;
1441
1442     } else if (arg == 5) {
1443       /* Background bright on */
1444       bg_bright = 1;
1445
1446     } else if (arg == 7) {
1447       /* Inverse: on */
1448       inverse = 1;
1449
1450     } else if (arg == 21 || arg == 22) {
1451       /* Foreground bright off */
1452       fg_bright = 0;
1453
1454     } else if (arg == 25) {
1455       /* Background bright off */
1456       bg_bright = 0;
1457
1458     } else if (arg == 27) {
1459       /* Inverse: off */
1460       inverse = 0;
1461
1462     } else if (arg >= 30 && arg <= 37) {
1463       /* Set foreground color */
1464       fg_color = arg - 30;
1465
1466     } else if (arg == 39) {
1467       /* Default text color */
1468       fg_color = uv_tty_default_fg_color;
1469       fg_bright = uv_tty_default_fg_bright;
1470
1471     } else if (arg >= 40 && arg <= 47) {
1472       /* Set background color */
1473       bg_color = arg - 40;
1474
1475     } else if (arg ==  49) {
1476       /* Default background color */
1477       bg_color = uv_tty_default_bg_color;
1478       bg_bright = uv_tty_default_bg_bright;
1479
1480     } else if (arg >= 90 && arg <= 97) {
1481       /* Set bold foreground color */
1482       fg_bright = 1;
1483       fg_color = arg - 90;
1484
1485     } else if (arg >= 100 && arg <= 107) {
1486       /* Set bold background color */
1487       bg_bright = 1;
1488       bg_color = arg - 100;
1489
1490     }
1491   }
1492
1493   if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
1494       bg_bright == -1 && inverse == -1) {
1495     /* Nothing changed */
1496     return 0;
1497   }
1498
1499   if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1500     *error = GetLastError();
1501     return -1;
1502   }
1503
1504   if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
1505     FLIP_FGBG;
1506   }
1507
1508   if (fg_color != -1) {
1509     info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1510     if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
1511     if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
1512     if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
1513   }
1514
1515   if (fg_bright != -1) {
1516     if (fg_bright) {
1517       info.wAttributes |= FOREGROUND_INTENSITY;
1518     } else {
1519       info.wAttributes &= ~FOREGROUND_INTENSITY;
1520     }
1521   }
1522
1523   if (bg_color != -1) {
1524     info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
1525     if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
1526     if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
1527     if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
1528   }
1529
1530   if (bg_bright != -1) {
1531     if (bg_bright) {
1532       info.wAttributes |= BACKGROUND_INTENSITY;
1533     } else {
1534       info.wAttributes &= ~BACKGROUND_INTENSITY;
1535     }
1536   }
1537
1538   if (inverse != -1) {
1539     if (inverse) {
1540       info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
1541     } else {
1542       info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
1543     }
1544   }
1545
1546   if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
1547     FLIP_FGBG;
1548   }
1549
1550   if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
1551     *error = GetLastError();
1552     return -1;
1553   }
1554
1555   return 0;
1556 }
1557
1558
1559 static int uv__tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
1560     DWORD* error) {
1561   CONSOLE_SCREEN_BUFFER_INFO info;
1562
1563   if (*error != ERROR_SUCCESS) {
1564     return -1;
1565   }
1566
1567   if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1568     *error = GetLastError();
1569     return -1;
1570   }
1571
1572   uv__tty_update_virtual_window(&info);
1573
1574   handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
1575   handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y -
1576         uv_tty_virtual_offset;
1577   handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
1578
1579   if (save_attributes) {
1580     handle->tty.wr.saved_attributes = info.wAttributes &
1581         (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1582     handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
1583   }
1584
1585   return 0;
1586 }
1587
1588
1589 static int uv__tty_restore_state(uv_tty_t* handle,
1590     unsigned char restore_attributes, DWORD* error) {
1591   CONSOLE_SCREEN_BUFFER_INFO info;
1592   WORD new_attributes;
1593
1594   if (*error != ERROR_SUCCESS) {
1595     return -1;
1596   }
1597
1598   if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
1599     if (uv__tty_move_caret(handle,
1600                           handle->tty.wr.saved_position.X,
1601                           0,
1602                           handle->tty.wr.saved_position.Y,
1603                           0,
1604                           error) != 0) {
1605       return -1;
1606     }
1607   }
1608
1609   if (restore_attributes &&
1610       (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
1611     if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
1612       *error = GetLastError();
1613       return -1;
1614     }
1615
1616     new_attributes = info.wAttributes;
1617     new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
1618     new_attributes |= handle->tty.wr.saved_attributes;
1619
1620     if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
1621       *error = GetLastError();
1622       return -1;
1623     }
1624   }
1625
1626   return 0;
1627 }
1628
1629 static int uv__tty_set_cursor_visibility(uv_tty_t* handle,
1630                                         BOOL visible,
1631                                         DWORD* error) {
1632   CONSOLE_CURSOR_INFO cursor_info;
1633
1634   if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
1635     *error = GetLastError();
1636     return -1;
1637   }
1638
1639   cursor_info.bVisible = visible;
1640
1641   if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
1642     *error = GetLastError();
1643     return -1;
1644   }
1645
1646   return 0;
1647 }
1648
1649 static int uv__tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
1650   CONSOLE_CURSOR_INFO cursor_info;
1651
1652   if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
1653     *error = GetLastError();
1654     return -1;
1655   }
1656
1657   if (style == 0) {
1658     cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
1659   } else if (style <= 2) {
1660     cursor_info.dwSize = CURSOR_SIZE_LARGE;
1661   } else {
1662     cursor_info.dwSize = CURSOR_SIZE_SMALL;
1663   }
1664
1665   if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
1666     *error = GetLastError();
1667     return -1;
1668   }
1669
1670   return 0;
1671 }
1672
1673
1674 static int uv__tty_write_bufs(uv_tty_t* handle,
1675                              const uv_buf_t bufs[],
1676                              unsigned int nbufs,
1677                              DWORD* error) {
1678   /* We can only write 8k characters at a time. Windows can't handle much more
1679    * characters in a single console write anyway. */
1680   WCHAR utf16_buf[MAX_CONSOLE_CHAR];
1681   DWORD utf16_buf_used = 0;
1682   unsigned int i;
1683
1684 #define FLUSH_TEXT()                                                \
1685   do {                                                              \
1686     if (utf16_buf_used > 0) {                                       \
1687       uv__tty_emit_text(handle, utf16_buf, utf16_buf_used, error);  \
1688       utf16_buf_used = 0;                                           \
1689     }                                                               \
1690   } while (0)
1691
1692 #define ENSURE_BUFFER_SPACE(wchars_needed)                          \
1693   if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
1694     FLUSH_TEXT();                                                   \
1695   }
1696
1697   /* Cache for fast access */
1698   unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
1699   unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
1700   unsigned char previous_eol = handle->tty.wr.previous_eol;
1701   unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
1702
1703   /* Store the error here. If we encounter an error, stop trying to do i/o but
1704    * keep parsing the buffer so we leave the parser in a consistent state. */
1705   *error = ERROR_SUCCESS;
1706
1707   uv_sem_wait(&uv_tty_output_lock);
1708
1709   for (i = 0; i < nbufs; i++) {
1710     uv_buf_t buf = bufs[i];
1711     unsigned int j;
1712
1713     for (j = 0; j < buf.len; j++) {
1714       unsigned char c = buf.base[j];
1715
1716       /* Run the character through the utf8 decoder We happily accept non
1717        * shortest form encodings and invalid code points - there's no real harm
1718        * that can be done. */
1719       if (utf8_bytes_left == 0) {
1720         /* Read utf-8 start byte */
1721         DWORD first_zero_bit;
1722         unsigned char not_c = ~c;
1723 #ifdef _MSC_VER /* msvc */
1724         if (_BitScanReverse(&first_zero_bit, not_c)) {
1725 #else /* assume gcc */
1726         if (c != 0) {
1727           first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
1728 #endif
1729           if (first_zero_bit == 7) {
1730             /* Ascii - pass right through */
1731             utf8_codepoint = (unsigned int) c;
1732
1733           } else if (first_zero_bit <= 5) {
1734             /* Multibyte sequence */
1735             utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
1736             utf8_bytes_left = (char) (6 - first_zero_bit);
1737
1738           } else {
1739             /* Invalid continuation */
1740             utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1741           }
1742
1743         } else {
1744           /* 0xff -- invalid */
1745           utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1746         }
1747
1748       } else if ((c & 0xc0) == 0x80) {
1749         /* Valid continuation of utf-8 multibyte sequence */
1750         utf8_bytes_left--;
1751         utf8_codepoint <<= 6;
1752         utf8_codepoint |= ((unsigned int) c & 0x3f);
1753
1754       } else {
1755         /* Start byte where continuation was expected. */
1756         utf8_bytes_left = 0;
1757         utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
1758         /* Patch buf offset so this character will be parsed again as a start
1759          * byte. */
1760         j--;
1761       }
1762
1763       /* Maybe we need to parse more bytes to find a character. */
1764       if (utf8_bytes_left != 0) {
1765         continue;
1766       }
1767
1768       /* Parse vt100/ansi escape codes */
1769       if (uv__vterm_state == UV_TTY_SUPPORTED) {
1770         /* Pass through escape codes if conhost supports them. */
1771       } else if (ansi_parser_state == ANSI_NORMAL) {
1772         switch (utf8_codepoint) {
1773           case '\033':
1774             ansi_parser_state = ANSI_ESCAPE_SEEN;
1775             continue;
1776
1777           case 0233:
1778             ansi_parser_state = ANSI_CSI;
1779             handle->tty.wr.ansi_csi_argc = 0;
1780             continue;
1781         }
1782
1783       } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
1784         switch (utf8_codepoint) {
1785           case '[':
1786             ansi_parser_state = ANSI_CSI;
1787             handle->tty.wr.ansi_csi_argc = 0;
1788             continue;
1789
1790           case '^':
1791           case '_':
1792           case 'P':
1793           case ']':
1794             /* Not supported, but we'll have to parse until we see a stop code,
1795              * e. g. ESC \ or BEL. */
1796             ansi_parser_state = ANSI_ST_CONTROL;
1797             continue;
1798
1799           case '\033':
1800             /* Ignore double escape. */
1801             continue;
1802
1803           case 'c':
1804             /* Full console reset. */
1805             FLUSH_TEXT();
1806             uv__tty_reset(handle, error);
1807             ansi_parser_state = ANSI_NORMAL;
1808             continue;
1809
1810           case '7':
1811             /* Save the cursor position and text attributes. */
1812             FLUSH_TEXT();
1813             uv__tty_save_state(handle, 1, error);
1814             ansi_parser_state = ANSI_NORMAL;
1815             continue;
1816
1817           case '8':
1818             /* Restore the cursor position and text attributes */
1819             FLUSH_TEXT();
1820             uv__tty_restore_state(handle, 1, error);
1821             ansi_parser_state = ANSI_NORMAL;
1822             continue;
1823
1824           default:
1825             if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
1826               /* Single-char control. */
1827               ansi_parser_state = ANSI_NORMAL;
1828               continue;
1829             } else {
1830               /* Invalid - proceed as normal, */
1831               ansi_parser_state = ANSI_NORMAL;
1832             }
1833         }
1834
1835       } else if (ansi_parser_state == ANSI_IGNORE) {
1836         /* We're ignoring this command. Stop only on command character. */
1837         if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1838           ansi_parser_state = ANSI_NORMAL;
1839         }
1840         continue;
1841
1842       } else if (ansi_parser_state == ANSI_DECSCUSR) {
1843         /* So far we've the sequence `ESC [ arg space`, and we're waiting for
1844          * the final command byte. */
1845         if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1846           /* Command byte */
1847           if (utf8_codepoint == 'q') {
1848             /* Change the cursor shape */
1849             int style = handle->tty.wr.ansi_csi_argc
1850               ? handle->tty.wr.ansi_csi_argv[0] : 1;
1851             if (style >= 0 && style <= 6) {
1852               FLUSH_TEXT();
1853               uv__tty_set_cursor_shape(handle, style, error);
1854             }
1855           }
1856
1857           /* Sequence ended - go back to normal state. */
1858           ansi_parser_state = ANSI_NORMAL;
1859           continue;
1860         }
1861         /* Unexpected character, but sequence hasn't ended yet. Ignore the rest
1862          * of the sequence. */
1863         ansi_parser_state = ANSI_IGNORE;
1864
1865       } else if (ansi_parser_state & ANSI_CSI) {
1866         /* So far we've seen `ESC [`, and we may or may not have already parsed
1867          * some of the arguments that follow. */
1868
1869         if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
1870           /* Parse a numerical argument. */
1871           if (!(ansi_parser_state & ANSI_IN_ARG)) {
1872             /* We were not currently parsing a number, add a new one. */
1873             /* Check for that there are too many arguments. */
1874             if (handle->tty.wr.ansi_csi_argc >=
1875                 ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
1876               ansi_parser_state = ANSI_IGNORE;
1877               continue;
1878             }
1879             ansi_parser_state |= ANSI_IN_ARG;
1880             handle->tty.wr.ansi_csi_argc++;
1881             handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
1882                 (unsigned short) utf8_codepoint - '0';
1883             continue;
1884
1885           } else {
1886             /* We were already parsing a number. Parse next digit. */
1887             uint32_t value = 10 *
1888                 handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
1889
1890             /* Check for overflow. */
1891             if (value > UINT16_MAX) {
1892               ansi_parser_state = ANSI_IGNORE;
1893               continue;
1894             }
1895
1896             handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
1897                 (unsigned short) value + (utf8_codepoint - '0');
1898             continue;
1899           }
1900
1901         } else if (utf8_codepoint == ';') {
1902           /* Denotes the end of an argument. */
1903           if (ansi_parser_state & ANSI_IN_ARG) {
1904             ansi_parser_state &= ~ANSI_IN_ARG;
1905             continue;
1906
1907           } else {
1908             /* If ANSI_IN_ARG is not set, add another argument and default
1909              * it to 0. */
1910
1911             /* Check for too many arguments */
1912             if (handle->tty.wr.ansi_csi_argc >=
1913
1914                 ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
1915               ansi_parser_state = ANSI_IGNORE;
1916               continue;
1917             }
1918
1919             handle->tty.wr.ansi_csi_argc++;
1920             handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
1921             continue;
1922           }
1923
1924         } else if (utf8_codepoint == '?' &&
1925                    !(ansi_parser_state & ANSI_IN_ARG) &&
1926                    !(ansi_parser_state & ANSI_EXTENSION) &&
1927                    handle->tty.wr.ansi_csi_argc == 0) {
1928           /* Pass through '?' if it is the first character after CSI */
1929           /* This is an extension character from the VT100 codeset */
1930           /* that is supported and used by most ANSI terminals today. */
1931           ansi_parser_state |= ANSI_EXTENSION;
1932           continue;
1933
1934         } else if (utf8_codepoint == ' ' &&
1935                    !(ansi_parser_state & ANSI_EXTENSION)) {
1936           /* We expect a command byte to follow after this space. The only
1937            * command that we current support is 'set cursor style'. */
1938           ansi_parser_state = ANSI_DECSCUSR;
1939           continue;
1940
1941         } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
1942           /* Command byte */
1943           if (ansi_parser_state & ANSI_EXTENSION) {
1944             /* Sequence is `ESC [ ? args command`. */
1945             switch (utf8_codepoint) {
1946               case 'l':
1947                 /* Hide the cursor */
1948                 if (handle->tty.wr.ansi_csi_argc == 1 &&
1949                     handle->tty.wr.ansi_csi_argv[0] == 25) {
1950                   FLUSH_TEXT();
1951                   uv__tty_set_cursor_visibility(handle, 0, error);
1952                 }
1953                 break;
1954
1955               case 'h':
1956                 /* Show the cursor */
1957                 if (handle->tty.wr.ansi_csi_argc == 1 &&
1958                     handle->tty.wr.ansi_csi_argv[0] == 25) {
1959                   FLUSH_TEXT();
1960                   uv__tty_set_cursor_visibility(handle, 1, error);
1961                 }
1962                 break;
1963             }
1964
1965           } else {
1966             /* Sequence is `ESC [ args command`. */
1967             int x, y, d;
1968             switch (utf8_codepoint) {
1969               case 'A':
1970                 /* cursor up */
1971                 FLUSH_TEXT();
1972                 y = -(handle->tty.wr.ansi_csi_argc
1973                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
1974                 uv__tty_move_caret(handle, 0, 1, y, 1, error);
1975                 break;
1976
1977               case 'B':
1978                 /* cursor down */
1979                 FLUSH_TEXT();
1980                 y = handle->tty.wr.ansi_csi_argc
1981                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
1982                 uv__tty_move_caret(handle, 0, 1, y, 1, error);
1983                 break;
1984
1985               case 'C':
1986                 /* cursor forward */
1987                 FLUSH_TEXT();
1988                 x = handle->tty.wr.ansi_csi_argc
1989                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
1990                 uv__tty_move_caret(handle, x, 1, 0, 1, error);
1991                 break;
1992
1993               case 'D':
1994                 /* cursor back */
1995                 FLUSH_TEXT();
1996                 x = -(handle->tty.wr.ansi_csi_argc
1997                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
1998                 uv__tty_move_caret(handle, x, 1, 0, 1, error);
1999                 break;
2000
2001               case 'E':
2002                 /* cursor next line */
2003                 FLUSH_TEXT();
2004                 y = handle->tty.wr.ansi_csi_argc
2005                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
2006                 uv__tty_move_caret(handle, 0, 0, y, 1, error);
2007                 break;
2008
2009               case 'F':
2010                 /* cursor previous line */
2011                 FLUSH_TEXT();
2012                 y = -(handle->tty.wr.ansi_csi_argc
2013                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
2014                 uv__tty_move_caret(handle, 0, 0, y, 1, error);
2015                 break;
2016
2017               case 'G':
2018                 /* cursor horizontal move absolute */
2019                 FLUSH_TEXT();
2020                 x = (handle->tty.wr.ansi_csi_argc >= 1 &&
2021                      handle->tty.wr.ansi_csi_argv[0])
2022                   ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
2023                 uv__tty_move_caret(handle, x, 0, 0, 1, error);
2024                 break;
2025
2026               case 'H':
2027               case 'f':
2028                 /* cursor move absolute */
2029                 FLUSH_TEXT();
2030                 y = (handle->tty.wr.ansi_csi_argc >= 1 &&
2031                      handle->tty.wr.ansi_csi_argv[0])
2032                   ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
2033                 x = (handle->tty.wr.ansi_csi_argc >= 2 &&
2034                      handle->tty.wr.ansi_csi_argv[1])
2035                   ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
2036                 uv__tty_move_caret(handle, x, 0, y, 0, error);
2037                 break;
2038
2039               case 'J':
2040                 /* Erase screen */
2041                 FLUSH_TEXT();
2042                 d = handle->tty.wr.ansi_csi_argc
2043                   ? handle->tty.wr.ansi_csi_argv[0] : 0;
2044                 if (d >= 0 && d <= 2) {
2045                   uv__tty_clear(handle, d, 1, error);
2046                 }
2047                 break;
2048
2049               case 'K':
2050                 /* Erase line */
2051                 FLUSH_TEXT();
2052                 d = handle->tty.wr.ansi_csi_argc
2053                   ? handle->tty.wr.ansi_csi_argv[0] : 0;
2054                 if (d >= 0 && d <= 2) {
2055                   uv__tty_clear(handle, d, 0, error);
2056                 }
2057                 break;
2058
2059               case 'm':
2060                 /* Set style */
2061                 FLUSH_TEXT();
2062                 uv__tty_set_style(handle, error);
2063                 break;
2064
2065               case 's':
2066                 /* Save the cursor position. */
2067                 FLUSH_TEXT();
2068                 uv__tty_save_state(handle, 0, error);
2069                 break;
2070
2071               case 'u':
2072                 /* Restore the cursor position */
2073                 FLUSH_TEXT();
2074                 uv__tty_restore_state(handle, 0, error);
2075                 break;
2076             }
2077           }
2078
2079           /* Sequence ended - go back to normal state. */
2080           ansi_parser_state = ANSI_NORMAL;
2081           continue;
2082
2083         } else {
2084           /* We don't support commands that use private mode characters or
2085            * intermediaries. Ignore the rest of the sequence. */
2086           ansi_parser_state = ANSI_IGNORE;
2087           continue;
2088         }
2089
2090       } else if (ansi_parser_state & ANSI_ST_CONTROL) {
2091         /* Unsupported control code.
2092          * Ignore everything until we see `BEL` or `ESC \`. */
2093         if (ansi_parser_state & ANSI_IN_STRING) {
2094           if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
2095             if (utf8_codepoint == '"') {
2096               ansi_parser_state &= ~ANSI_IN_STRING;
2097             } else if (utf8_codepoint == '\\') {
2098               ansi_parser_state |= ANSI_BACKSLASH_SEEN;
2099             }
2100           } else {
2101             ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
2102           }
2103         } else {
2104           if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
2105               (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
2106             /* End of sequence */
2107             ansi_parser_state = ANSI_NORMAL;
2108           } else if (utf8_codepoint == '\033') {
2109             /* Escape character */
2110             ansi_parser_state |= ANSI_ESCAPE_SEEN;
2111           } else if (utf8_codepoint == '"') {
2112              /* String starting */
2113             ansi_parser_state |= ANSI_IN_STRING;
2114             ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
2115             ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
2116           } else {
2117             ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
2118           }
2119         }
2120         continue;
2121       } else {
2122         /* Inconsistent state */
2123         abort();
2124       }
2125
2126       if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
2127         /* EOL conversion - emit \r\n when we see \n. */
2128
2129         if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
2130           /* \n was not preceded by \r; print \r\n. */
2131           ENSURE_BUFFER_SPACE(2);
2132           utf16_buf[utf16_buf_used++] = L'\r';
2133           utf16_buf[utf16_buf_used++] = L'\n';
2134         } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
2135           /* \n was followed by \r; do not print the \r, since the source was
2136            * either \r\n\r (so the second \r is redundant) or was \n\r (so the
2137            * \n was processed by the last case and an \r automatically
2138            * inserted). */
2139         } else {
2140           /* \r without \n; print \r as-is. */
2141           ENSURE_BUFFER_SPACE(1);
2142           utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
2143         }
2144
2145         previous_eol = (char) utf8_codepoint;
2146
2147       } else if (utf8_codepoint <= 0xffff) {
2148         /* Encode character into utf-16 buffer. */
2149         ENSURE_BUFFER_SPACE(1);
2150         utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
2151         previous_eol = 0;
2152       } else {
2153         ENSURE_BUFFER_SPACE(2);
2154         utf8_codepoint -= 0x10000;
2155         utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800);
2156         utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00);
2157         previous_eol = 0;
2158       }
2159     }
2160   }
2161
2162   /* Flush remaining characters */
2163   FLUSH_TEXT();
2164
2165   /* Copy cached values back to struct. */
2166   handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
2167   handle->tty.wr.utf8_codepoint = utf8_codepoint;
2168   handle->tty.wr.previous_eol = previous_eol;
2169   handle->tty.wr.ansi_parser_state = ansi_parser_state;
2170
2171   uv_sem_post(&uv_tty_output_lock);
2172
2173   if (*error == STATUS_SUCCESS) {
2174     return 0;
2175   } else {
2176     return -1;
2177   }
2178
2179 #undef FLUSH_TEXT
2180 }
2181
2182
2183 int uv__tty_write(uv_loop_t* loop,
2184                  uv_write_t* req,
2185                  uv_tty_t* handle,
2186                  const uv_buf_t bufs[],
2187                  unsigned int nbufs,
2188                  uv_write_cb cb) {
2189   DWORD error;
2190
2191   UV_REQ_INIT(req, UV_WRITE);
2192   req->handle = (uv_stream_t*) handle;
2193   req->cb = cb;
2194
2195   handle->reqs_pending++;
2196   handle->stream.conn.write_reqs_pending++;
2197   REGISTER_HANDLE_REQ(loop, handle, req);
2198
2199   req->u.io.queued_bytes = 0;
2200
2201   if (!uv__tty_write_bufs(handle, bufs, nbufs, &error)) {
2202     SET_REQ_SUCCESS(req);
2203   } else {
2204     SET_REQ_ERROR(req, error);
2205   }
2206
2207   uv__insert_pending_req(loop, (uv_req_t*) req);
2208
2209   return 0;
2210 }
2211
2212
2213 int uv__tty_try_write(uv_tty_t* handle,
2214                       const uv_buf_t bufs[],
2215                       unsigned int nbufs) {
2216   DWORD error;
2217
2218   if (handle->stream.conn.write_reqs_pending > 0)
2219     return UV_EAGAIN;
2220
2221   if (uv__tty_write_bufs(handle, bufs, nbufs, &error))
2222     return uv_translate_sys_error(error);
2223
2224   return uv__count_bufs(bufs, nbufs);
2225 }
2226
2227
2228 void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
2229   uv_write_t* req) {
2230   int err;
2231
2232   handle->write_queue_size -= req->u.io.queued_bytes;
2233   UNREGISTER_HANDLE_REQ(loop, handle, req);
2234
2235   if (req->cb) {
2236     err = GET_REQ_ERROR(req);
2237     req->cb(req, uv_translate_sys_error(err));
2238   }
2239
2240
2241   handle->stream.conn.write_reqs_pending--;
2242   if (handle->stream.conn.write_reqs_pending == 0)
2243     if (handle->flags & UV_HANDLE_SHUTTING)
2244       uv__process_tty_shutdown_req(loop,
2245                                    handle,
2246                                    handle->stream.conn.shutdown_req);
2247
2248   DECREASE_PENDING_REQ_COUNT(handle);
2249 }
2250
2251
2252 void uv__tty_close(uv_tty_t* handle) {
2253   assert(handle->u.fd == -1 || handle->u.fd > 2);
2254   if (handle->flags & UV_HANDLE_READING)
2255     uv__tty_read_stop(handle);
2256
2257   if (handle->u.fd == -1)
2258     CloseHandle(handle->handle);
2259   else
2260     close(handle->u.fd);
2261
2262   handle->u.fd = -1;
2263   handle->handle = INVALID_HANDLE_VALUE;
2264   handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
2265   uv__handle_closing(handle);
2266
2267   if (handle->reqs_pending == 0)
2268     uv__want_endgame(handle->loop, (uv_handle_t*) handle);
2269 }
2270
2271
2272 void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) {
2273   assert(stream->stream.conn.write_reqs_pending == 0);
2274   assert(req);
2275
2276   stream->stream.conn.shutdown_req = NULL;
2277   stream->flags &= ~UV_HANDLE_SHUTTING;
2278   UNREGISTER_HANDLE_REQ(loop, stream, req);
2279
2280   /* TTY shutdown is really just a no-op */
2281   if (req->cb) {
2282     if (stream->flags & UV_HANDLE_CLOSING) {
2283       req->cb(req, UV_ECANCELED);
2284     } else {
2285       req->cb(req, 0);
2286     }
2287   }
2288
2289   DECREASE_PENDING_REQ_COUNT(stream);
2290 }
2291
2292
2293 void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
2294   assert(handle->flags & UV_HANDLE_CLOSING);
2295   assert(handle->reqs_pending == 0);
2296
2297   /* The wait handle used for raw reading should be unregistered when the
2298    * wait callback runs. */
2299   assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
2300          handle->tty.rd.read_raw_wait == NULL);
2301
2302   assert(!(handle->flags & UV_HANDLE_CLOSED));
2303   uv__handle_close(handle);
2304 }
2305
2306
2307 /*
2308  * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
2309  * TODO: find a way to remove it
2310  */
2311 void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
2312     uv_req_t* raw_req) {
2313   abort();
2314 }
2315
2316
2317 /*
2318  * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
2319  * TODO: find a way to remove it
2320  */
2321 void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
2322     uv_connect_t* req) {
2323   abort();
2324 }
2325
2326
2327 int uv_tty_reset_mode(void) {
2328   /* Not necessary to do anything. */
2329   return 0;
2330 }
2331
2332 /* Determine whether or not this version of windows supports
2333  * proper ANSI color codes. Should be supported as of windows
2334  * 10 version 1511, build number 10.0.10586.
2335  */
2336 static void uv__determine_vterm_state(HANDLE handle) {
2337   DWORD dwMode = 0;
2338
2339   uv__need_check_vterm_state = FALSE;
2340   if (!GetConsoleMode(handle, &dwMode)) {
2341     return;
2342   }
2343
2344   dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
2345   if (!SetConsoleMode(handle, dwMode)) {
2346     return;
2347   }
2348
2349   uv__vterm_state = UV_TTY_SUPPORTED;
2350 }
2351
2352 static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
2353   NTSTATUS status;
2354   ULONG_PTR conhost_pid;
2355   MSG msg;
2356
2357   if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
2358     return 0;
2359
2360   status = pNtQueryInformationProcess(GetCurrentProcess(),
2361                                       ProcessConsoleHostProcess,
2362                                       &conhost_pid,
2363                                       sizeof(conhost_pid),
2364                                       NULL);
2365
2366   if (!NT_SUCCESS(status)) {
2367     /* We couldn't retrieve our console host process, probably because this
2368      * is a 32-bit process running on 64-bit Windows. Fall back to receiving
2369      * console events from the input stream only. */
2370     return 0;
2371   }
2372
2373   /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
2374   conhost_pid &= ~(ULONG_PTR)0x3;
2375
2376   uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL);
2377   if (uv__tty_console_resized == NULL)
2378     return 0;
2379   if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread,
2380                         NULL,
2381                         WT_EXECUTELONGFUNCTION) == 0)
2382     return 0;
2383
2384   if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
2385                         EVENT_CONSOLE_LAYOUT,
2386                         NULL,
2387                         uv__tty_console_resize_event,
2388                         (DWORD)conhost_pid,
2389                         0,
2390                         WINEVENT_OUTOFCONTEXT))
2391     return 0;
2392
2393   while (GetMessage(&msg, NULL, 0, 0)) {
2394     TranslateMessage(&msg);
2395     DispatchMessage(&msg);
2396   }
2397   return 0;
2398 }
2399
2400 static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
2401                                                   DWORD event,
2402                                                   HWND hwnd,
2403                                                   LONG idObject,
2404                                                   LONG idChild,
2405                                                   DWORD dwEventThread,
2406                                                   DWORD dwmsEventTime) {
2407   SetEvent(uv__tty_console_resized);
2408 }
2409
2410 static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
2411   for (;;) {
2412     /* Make sure to not overwhelm the system with resize events */
2413     Sleep(33);
2414     WaitForSingleObject(uv__tty_console_resized, INFINITE);
2415     uv__tty_console_signal_resize();
2416     ResetEvent(uv__tty_console_resized);
2417   }
2418   return 0;
2419 }
2420
2421 static void uv__tty_console_signal_resize(void) {
2422   CONSOLE_SCREEN_BUFFER_INFO sb_info;
2423   int width, height;
2424
2425   if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
2426     return;
2427
2428   width = sb_info.dwSize.X;
2429   height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
2430
2431   uv_mutex_lock(&uv__tty_console_resize_mutex);
2432   assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
2433   if (width != uv__tty_console_width || height != uv__tty_console_height) {
2434     uv__tty_console_width = width;
2435     uv__tty_console_height = height;
2436     uv_mutex_unlock(&uv__tty_console_resize_mutex);
2437     uv__signal_dispatch(SIGWINCH);
2438   } else {
2439     uv_mutex_unlock(&uv__tty_console_resize_mutex);
2440   }
2441 }
2442
2443 void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
2444   uv_sem_wait(&uv_tty_output_lock);
2445   uv__need_check_vterm_state = FALSE;
2446   uv__vterm_state = state;
2447   uv_sem_post(&uv_tty_output_lock);
2448 }
2449
2450 int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
2451   uv_sem_wait(&uv_tty_output_lock);
2452   *state = uv__vterm_state;
2453   uv_sem_post(&uv_tty_output_lock);
2454   return 0;
2455 }