Blame src/win/tty.c

Packit Service 7c31a4
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit Service 7c31a4
 * of this software and associated documentation files (the "Software"), to
Packit Service 7c31a4
 * deal in the Software without restriction, including without limitation the
Packit Service 7c31a4
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit Service 7c31a4
 * sell copies of the Software, and to permit persons to whom the Software is
Packit Service 7c31a4
 * furnished to do so, subject to the following conditions:
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * The above copyright notice and this permission notice shall be included in
Packit Service 7c31a4
 * all copies or substantial portions of the Software.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service 7c31a4
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service 7c31a4
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit Service 7c31a4
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service 7c31a4
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Service 7c31a4
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit Service 7c31a4
 * IN THE SOFTWARE.
Packit Service 7c31a4
 */
Packit Service 7c31a4
Packit Service 7c31a4
#include <assert.h>
Packit Service 7c31a4
#include <io.h>
Packit Service 7c31a4
#include <string.h>
Packit Service 7c31a4
#include <stdlib.h>
Packit Service 7c31a4
Packit Service 7c31a4
#if defined(_MSC_VER) && _MSC_VER < 1600
Packit Service 7c31a4
# include "uv/stdint-msvc2008.h"
Packit Service 7c31a4
#else
Packit Service 7c31a4
# include <stdint.h>
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
#ifndef COMMON_LVB_REVERSE_VIDEO
Packit Service 7c31a4
# define COMMON_LVB_REVERSE_VIDEO 0x4000
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
#include "uv.h"
Packit Service 7c31a4
#include "internal.h"
Packit Service 7c31a4
#include "handle-inl.h"
Packit Service 7c31a4
#include "stream-inl.h"
Packit Service 7c31a4
#include "req-inl.h"
Packit Service 7c31a4
Packit Service 7c31a4
#ifndef InterlockedOr
Packit Service 7c31a4
# define InterlockedOr _InterlockedOr
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
Packit Service 7c31a4
Packit Service 7c31a4
#define ANSI_NORMAL           0x0000
Packit Service 7c31a4
#define ANSI_ESCAPE_SEEN      0x0002
Packit Service 7c31a4
#define ANSI_CSI              0x0004
Packit Service 7c31a4
#define ANSI_ST_CONTROL       0x0008
Packit Service 7c31a4
#define ANSI_IGNORE           0x0010
Packit Service 7c31a4
#define ANSI_IN_ARG           0x0020
Packit Service 7c31a4
#define ANSI_IN_STRING        0x0040
Packit Service 7c31a4
#define ANSI_BACKSLASH_SEEN   0x0080
Packit Service 7c31a4
#define ANSI_EXTENSION        0x0100
Packit Service 7c31a4
#define ANSI_DECSCUSR         0x0200
Packit Service 7c31a4
Packit Service 7c31a4
#define MAX_INPUT_BUFFER_LENGTH 8192
Packit Service 7c31a4
#define MAX_CONSOLE_CHAR 8192
Packit Service 7c31a4
Packit Service 7c31a4
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
Packit Service 7c31a4
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
#define CURSOR_SIZE_SMALL     25
Packit Service 7c31a4
#define CURSOR_SIZE_LARGE     100
Packit Service 7c31a4
Packit Service 7c31a4
static void uv_tty_capture_initial_style(
Packit Service 7c31a4
    CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
Packit Service 7c31a4
    CONSOLE_CURSOR_INFO* cursor_info);
Packit Service 7c31a4
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
Packit Service 7c31a4
static int uv__cancel_read_console(uv_tty_t* handle);
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/* Null uv_buf_t */
Packit Service 7c31a4
static const uv_buf_t uv_null_buf_ = { 0, NULL };
Packit Service 7c31a4
Packit Service 7c31a4
enum uv__read_console_status_e {
Packit Service 7c31a4
  NOT_STARTED,
Packit Service 7c31a4
  IN_PROGRESS,
Packit Service 7c31a4
  TRAP_REQUESTED,
Packit Service 7c31a4
  COMPLETED
Packit Service 7c31a4
};
Packit Service 7c31a4
Packit Service 7c31a4
static volatile LONG uv__read_console_status = NOT_STARTED;
Packit Service 7c31a4
static volatile LONG uv__restore_screen_state;
Packit Service 7c31a4
static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/*
Packit Service 7c31a4
 * The console virtual window.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * Normally cursor movement in windows is relative to the console screen buffer,
Packit Service 7c31a4
 * e.g. the application is allowed to overwrite the 'history'. This is very
Packit Service 7c31a4
 * inconvenient, it makes absolute cursor movement pretty useless. There is
Packit Service 7c31a4
 * also the concept of 'client rect' which is defined by the actual size of
Packit Service 7c31a4
 * the console window and the scroll position of the screen buffer, but it's
Packit Service 7c31a4
 * very volatile because it changes when the user scrolls.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * To make cursor movement behave sensibly we define a virtual window to which
Packit Service 7c31a4
 * cursor movement is confined. The virtual window is always as wide as the
Packit Service 7c31a4
 * console screen buffer, but it's height is defined by the size of the
Packit Service 7c31a4
 * console window. The top of the virtual window aligns with the position
Packit Service 7c31a4
 * of the caret when the first stdout/err handle is created, unless that would
Packit Service 7c31a4
 * mean that it would extend beyond the bottom of the screen buffer -  in that
Packit Service 7c31a4
 * that case it's located as far down as possible.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * When the user writes a long text or many newlines, such that the output
Packit Service 7c31a4
 * reaches beyond the bottom of the virtual window, the virtual window is
Packit Service 7c31a4
 * shifted downwards, but not resized.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * Since all tty i/o happens on the same console, this window is shared
Packit Service 7c31a4
 * between all stdout/stderr handles.
Packit Service 7c31a4
 */
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_virtual_offset = -1;
Packit Service 7c31a4
static int uv_tty_virtual_height = -1;
Packit Service 7c31a4
static int uv_tty_virtual_width = -1;
Packit Service 7c31a4
Packit Service 7c31a4
/* The console window size
Packit Service 7c31a4
 * We keep this separate from uv_tty_virtual_*. We use those values to only
Packit Service 7c31a4
 * handle signalling SIGWINCH
Packit Service 7c31a4
 */
Packit Service 7c31a4
Packit Service 7c31a4
static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
Packit Service 7c31a4
static int uv__tty_console_height = -1;
Packit Service 7c31a4
static int uv__tty_console_width = -1;
Packit Service 7c31a4
static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
Packit Service 7c31a4
static uv_mutex_t uv__tty_console_resize_mutex;
Packit Service 7c31a4
Packit Service 7c31a4
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
Packit Service 7c31a4
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
Packit Service 7c31a4
                                                  DWORD event,
Packit Service 7c31a4
                                                  HWND hwnd,
Packit Service 7c31a4
                                                  LONG idObject,
Packit Service 7c31a4
                                                  LONG idChild,
Packit Service 7c31a4
                                                  DWORD dwEventThread,
Packit Service 7c31a4
                                                  DWORD dwmsEventTime);
Packit Service 7c31a4
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param);
Packit Service 7c31a4
static void uv__tty_console_signal_resize(void);
Packit Service 7c31a4
Packit Service 7c31a4
/* We use a semaphore rather than a mutex or critical section because in some
Packit Service 7c31a4
   cases (uv__cancel_read_console) we need take the lock in the main thread and
Packit Service 7c31a4
   release it in another thread. Using a semaphore ensures that in such
Packit Service 7c31a4
   scenario the main thread will still block when trying to acquire the lock. */
Packit Service 7c31a4
static uv_sem_t uv_tty_output_lock;
Packit Service 7c31a4
Packit Service 7c31a4
static WORD uv_tty_default_text_attributes =
Packit Service 7c31a4
    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
Packit Service 7c31a4
Packit Service 7c31a4
static char uv_tty_default_fg_color = 7;
Packit Service 7c31a4
static char uv_tty_default_bg_color = 0;
Packit Service 7c31a4
static char uv_tty_default_fg_bright = 0;
Packit Service 7c31a4
static char uv_tty_default_bg_bright = 0;
Packit Service 7c31a4
static char uv_tty_default_inverse = 0;
Packit Service 7c31a4
Packit Service 7c31a4
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
Packit Service 7c31a4
Packit Service 7c31a4
/* Determine whether or not ANSI support is enabled. */
Packit Service 7c31a4
static BOOL uv__need_check_vterm_state = TRUE;
Packit Service 7c31a4
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
Packit Service 7c31a4
static void uv__determine_vterm_state(HANDLE handle);
Packit Service 7c31a4
Packit Service 7c31a4
void uv_console_init(void) {
Packit Service 7c31a4
  if (uv_sem_init(&uv_tty_output_lock, 1))
Packit Service 7c31a4
    abort();
Packit Service 7c31a4
  uv__tty_console_handle = CreateFileW(L"CONOUT$",
Packit Service 7c31a4
                                       GENERIC_READ | GENERIC_WRITE,
Packit Service 7c31a4
                                       FILE_SHARE_WRITE,
Packit Service 7c31a4
                                       0,
Packit Service 7c31a4
                                       OPEN_EXISTING,
Packit Service 7c31a4
                                       0,
Packit Service 7c31a4
                                       0);
Packit Service 7c31a4
  if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
Packit Service 7c31a4
    CONSOLE_SCREEN_BUFFER_INFO sb_info;
Packit Service 7c31a4
    QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
Packit Service 7c31a4
                      NULL,
Packit Service 7c31a4
                      WT_EXECUTELONGFUNCTION);
Packit Service 7c31a4
    uv_mutex_init(&uv__tty_console_resize_mutex);
Packit Service 7c31a4
    if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
Packit Service 7c31a4
      uv__tty_console_width = sb_info.dwSize.X;
Packit Service 7c31a4
      uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
Packit Service 7c31a4
  BOOL readable;
Packit Service 7c31a4
  DWORD NumberOfEvents;
Packit Service 7c31a4
  HANDLE handle;
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
Packit Service 7c31a4
  CONSOLE_CURSOR_INFO cursor_info;
Packit Service 7c31a4
  (void)unused;
Packit Service 7c31a4
Packit Service 7c31a4
  uv__once_init();
Packit Service 7c31a4
  handle = (HANDLE) uv__get_osfhandle(fd);
Packit Service 7c31a4
  if (handle == INVALID_HANDLE_VALUE)
Packit Service 7c31a4
    return UV_EBADF;
Packit Service 7c31a4
Packit Service 7c31a4
  if (fd <= 2) {
Packit Service 7c31a4
    /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
Packit Service 7c31a4
     * underlying OS handle and forget about the original fd.
Packit Service 7c31a4
     * We could also opt to use the original OS handle and just never close it,
Packit Service 7c31a4
     * but then there would be no reliable way to cancel pending read operations
Packit Service 7c31a4
     * upon close.
Packit Service 7c31a4
     */
Packit Service 7c31a4
    if (!DuplicateHandle(INVALID_HANDLE_VALUE,
Packit Service 7c31a4
                         handle,
Packit Service 7c31a4
                         INVALID_HANDLE_VALUE,
Packit Service 7c31a4
                         &handle,
Packit Service 7c31a4
                         0,
Packit Service 7c31a4
                         FALSE,
Packit Service 7c31a4
                         DUPLICATE_SAME_ACCESS))
Packit Service 7c31a4
      return uv_translate_sys_error(GetLastError());
Packit Service 7c31a4
    fd = -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
Packit Service 7c31a4
  if (!readable) {
Packit Service 7c31a4
    /* Obtain the screen buffer info with the output handle. */
Packit Service 7c31a4
    if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
Packit Service 7c31a4
      return uv_translate_sys_error(GetLastError());
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    /* Obtain the cursor info with the output handle. */
Packit Service 7c31a4
    if (!GetConsoleCursorInfo(handle, &cursor_info)) {
Packit Service 7c31a4
      return uv_translate_sys_error(GetLastError());
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    /* Obtain the tty_output_lock because the virtual window state is shared
Packit Service 7c31a4
     * between all uv_tty_t handles. */
Packit Service 7c31a4
    uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
Packit Service 7c31a4
    if (uv__need_check_vterm_state)
Packit Service 7c31a4
      uv__determine_vterm_state(handle);
Packit Service 7c31a4
Packit Service 7c31a4
    /* Remember the original console text attributes and cursor info. */
Packit Service 7c31a4
    uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
Packit Service 7c31a4
Packit Service 7c31a4
    uv_tty_update_virtual_window(&screen_buffer_info);
Packit Service 7c31a4
Packit Service 7c31a4
    uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
  uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
Packit Service 7c31a4
  uv_connection_init((uv_stream_t*) tty);
Packit Service 7c31a4
Packit Service 7c31a4
  tty->handle = handle;
Packit Service 7c31a4
  tty->u.fd = fd;
Packit Service 7c31a4
  tty->reqs_pending = 0;
Packit Service 7c31a4
  tty->flags |= UV_HANDLE_BOUND;
Packit Service 7c31a4
Packit Service 7c31a4
  if (readable) {
Packit Service 7c31a4
    /* Initialize TTY input specific fields. */
Packit Service 7c31a4
    tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
Packit Service 7c31a4
    /* TODO: remove me in v2.x. */
Packit Service 7c31a4
    tty->tty.rd.unused_ = NULL;
Packit Service 7c31a4
    tty->tty.rd.read_line_buffer = uv_null_buf_;
Packit Service 7c31a4
    tty->tty.rd.read_raw_wait = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
    /* Init keycode-to-vt100 mapper state. */
Packit Service 7c31a4
    tty->tty.rd.last_key_len = 0;
Packit Service 7c31a4
    tty->tty.rd.last_key_offset = 0;
Packit Service 7c31a4
    tty->tty.rd.last_utf16_high_surrogate = 0;
Packit Service 7c31a4
    memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    /* TTY output specific fields. */
Packit Service 7c31a4
    tty->flags |= UV_HANDLE_WRITABLE;
Packit Service 7c31a4
Packit Service 7c31a4
    /* Init utf8-to-utf16 conversion state. */
Packit Service 7c31a4
    tty->tty.wr.utf8_bytes_left = 0;
Packit Service 7c31a4
    tty->tty.wr.utf8_codepoint = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    /* Initialize eol conversion state */
Packit Service 7c31a4
    tty->tty.wr.previous_eol = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    /* Init ANSI parser state. */
Packit Service 7c31a4
    tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/* Set the default console text attributes based on how the console was
Packit Service 7c31a4
 * configured when libuv started.
Packit Service 7c31a4
 */
Packit Service 7c31a4
static void uv_tty_capture_initial_style(
Packit Service 7c31a4
    CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
Packit Service 7c31a4
    CONSOLE_CURSOR_INFO* cursor_info) {
Packit Service 7c31a4
  static int style_captured = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Only do this once.
Packit Service 7c31a4
     Assumption: Caller has acquired uv_tty_output_lock. */
Packit Service 7c31a4
  if (style_captured)
Packit Service 7c31a4
    return;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Save raw win32 attributes. */
Packit Service 7c31a4
  uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Convert black text on black background to use white text. */
Packit Service 7c31a4
  if (uv_tty_default_text_attributes == 0)
Packit Service 7c31a4
    uv_tty_default_text_attributes = 7;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Convert Win32 attributes to ANSI colors. */
Packit Service 7c31a4
  uv_tty_default_fg_color = 0;
Packit Service 7c31a4
  uv_tty_default_bg_color = 0;
Packit Service 7c31a4
  uv_tty_default_fg_bright = 0;
Packit Service 7c31a4
  uv_tty_default_bg_bright = 0;
Packit Service 7c31a4
  uv_tty_default_inverse = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & FOREGROUND_RED)
Packit Service 7c31a4
    uv_tty_default_fg_color |= 1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
Packit Service 7c31a4
    uv_tty_default_fg_color |= 2;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
Packit Service 7c31a4
    uv_tty_default_fg_color |= 4;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & BACKGROUND_RED)
Packit Service 7c31a4
    uv_tty_default_bg_color |= 1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
Packit Service 7c31a4
    uv_tty_default_bg_color |= 2;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
Packit Service 7c31a4
    uv_tty_default_bg_color |= 4;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
Packit Service 7c31a4
    uv_tty_default_fg_bright = 1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
Packit Service 7c31a4
    uv_tty_default_bg_bright = 1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
Packit Service 7c31a4
    uv_tty_default_inverse = 1;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Save the cursor size and the cursor state. */
Packit Service 7c31a4
  uv_tty_default_cursor_info = *cursor_info;
Packit Service 7c31a4
Packit Service 7c31a4
  style_captured = 1;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
Packit Service 7c31a4
  DWORD flags;
Packit Service 7c31a4
  unsigned char was_reading;
Packit Service 7c31a4
  uv_alloc_cb alloc_cb;
Packit Service 7c31a4
  uv_read_cb read_cb;
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
Packit Service 7c31a4
    return UV_EINVAL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  switch (mode) {
Packit Service 7c31a4
    case UV_TTY_MODE_NORMAL:
Packit Service 7c31a4
      flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
Packit Service 7c31a4
      break;
Packit Service 7c31a4
    case UV_TTY_MODE_RAW:
Packit Service 7c31a4
      flags = ENABLE_WINDOW_INPUT;
Packit Service 7c31a4
      break;
Packit Service 7c31a4
    case UV_TTY_MODE_IO:
Packit Service 7c31a4
      return UV_ENOTSUP;
Packit Service 7c31a4
    default:
Packit Service 7c31a4
      return UV_EINVAL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* If currently reading, stop, and restart reading. */
Packit Service 7c31a4
  if (tty->flags & UV_HANDLE_READING) {
Packit Service 7c31a4
    was_reading = 1;
Packit Service 7c31a4
    alloc_cb = tty->alloc_cb;
Packit Service 7c31a4
    read_cb = tty->read_cb;
Packit Service 7c31a4
    err = uv_tty_read_stop(tty);
Packit Service 7c31a4
    if (err) {
Packit Service 7c31a4
      return uv_translate_sys_error(err);
Packit Service 7c31a4
    }
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    was_reading = 0;
Packit Service 7c31a4
    alloc_cb = NULL;
Packit Service 7c31a4
    read_cb = NULL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
  if (!SetConsoleMode(tty->handle, flags)) {
Packit Service 7c31a4
    err = uv_translate_sys_error(GetLastError());
Packit Service 7c31a4
    uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
Packit Service 7c31a4
  /* Update flag. */
Packit Service 7c31a4
  tty->flags &= ~UV_HANDLE_TTY_RAW;
Packit Service 7c31a4
  tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
Packit Service 7c31a4
Packit Service 7c31a4
  /* If we just stopped reading, restart. */
Packit Service 7c31a4
  if (was_reading) {
Packit Service 7c31a4
    err = uv_tty_read_start(tty, alloc_cb, read_cb);
Packit Service 7c31a4
    if (err) {
Packit Service 7c31a4
      return uv_translate_sys_error(err);
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
Packit Service 7c31a4
    return uv_translate_sys_error(GetLastError());
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
  uv_tty_update_virtual_window(&info;;
Packit Service 7c31a4
  uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
Packit Service 7c31a4
  *width = uv_tty_virtual_width;
Packit Service 7c31a4
  *height = uv_tty_virtual_height;
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
Packit Service 7c31a4
  uv_loop_t* loop;
Packit Service 7c31a4
  uv_tty_t* handle;
Packit Service 7c31a4
  uv_req_t* req;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(data);
Packit Service 7c31a4
  assert(!didTimeout);
Packit Service 7c31a4
Packit Service 7c31a4
  req = (uv_req_t*) data;
Packit Service 7c31a4
  handle = (uv_tty_t*) req->data;
Packit Service 7c31a4
  loop = handle->loop;
Packit Service 7c31a4
Packit Service 7c31a4
  UnregisterWait(handle->tty.rd.read_raw_wait);
Packit Service 7c31a4
  handle->tty.rd.read_raw_wait = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
  SET_REQ_SUCCESS(req);
Packit Service 7c31a4
  POST_COMPLETION_FOR_REQ(loop, req);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
Packit Service 7c31a4
  uv_read_t* req;
Packit Service 7c31a4
  BOOL r;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->flags & UV_HANDLE_READING);
Packit Service 7c31a4
  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
Packit Service 7c31a4
Packit Service 7c31a4
  handle->tty.rd.read_line_buffer = uv_null_buf_;
Packit Service 7c31a4
Packit Service 7c31a4
  req = &handle->read_req;
Packit Service 7c31a4
  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
Packit Service 7c31a4
Packit Service 7c31a4
  r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
Packit Service 7c31a4
                                  handle->handle,
Packit Service 7c31a4
                                  uv_tty_post_raw_read,
Packit Service 7c31a4
                                  (void*) req,
Packit Service 7c31a4
                                  INFINITE,
Packit Service 7c31a4
                                  WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
Packit Service 7c31a4
  if (!r) {
Packit Service 7c31a4
    handle->tty.rd.read_raw_wait = NULL;
Packit Service 7c31a4
    SET_REQ_ERROR(req, GetLastError());
Packit Service 7c31a4
    uv_insert_pending_req(loop, (uv_req_t*)req);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  handle->flags |= UV_HANDLE_READ_PENDING;
Packit Service 7c31a4
  handle->reqs_pending++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
Packit Service 7c31a4
  uv_loop_t* loop;
Packit Service 7c31a4
  uv_tty_t* handle;
Packit Service 7c31a4
  uv_req_t* req;
Packit Service 7c31a4
  DWORD bytes, read_bytes;
Packit Service 7c31a4
  WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
Packit Service 7c31a4
  DWORD chars, read_chars;
Packit Service 7c31a4
  LONG status;
Packit Service 7c31a4
  COORD pos;
Packit Service 7c31a4
  BOOL read_console_success;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(data);
Packit Service 7c31a4
Packit Service 7c31a4
  req = (uv_req_t*) data;
Packit Service 7c31a4
  handle = (uv_tty_t*) req->data;
Packit Service 7c31a4
  loop = handle->loop;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->tty.rd.read_line_buffer.base != NULL);
Packit Service 7c31a4
  assert(handle->tty.rd.read_line_buffer.len > 0);
Packit Service 7c31a4
Packit Service 7c31a4
  /* ReadConsole can't handle big buffers. */
Packit Service 7c31a4
  if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
Packit Service 7c31a4
    bytes = handle->tty.rd.read_line_buffer.len;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    bytes = MAX_INPUT_BUFFER_LENGTH;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
Packit Service 7c31a4
   * codeunits to encode. */
Packit Service 7c31a4
  chars = bytes / 3;
Packit Service 7c31a4
Packit Service 7c31a4
  status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
Packit Service 7c31a4
  if (status == TRAP_REQUESTED) {
Packit Service 7c31a4
    SET_REQ_SUCCESS(req);
Packit Service e2ebee
    InterlockedExchange(&uv__read_console_status, COMPLETED);
Packit Service 7c31a4
    req->u.io.overlapped.InternalHigh = 0;
Packit Service 7c31a4
    POST_COMPLETION_FOR_REQ(loop, req);
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  read_console_success = ReadConsoleW(handle->handle,
Packit Service 7c31a4
                                      (void*) utf16,
Packit Service 7c31a4
                                      chars,
Packit Service 7c31a4
                                      &read_chars,
Packit Service 7c31a4
                                      NULL);
Packit Service 7c31a4
Packit Service 7c31a4
  if (read_console_success) {
Packit Service 7c31a4
    read_bytes = WideCharToMultiByte(CP_UTF8,
Packit Service 7c31a4
                                     0,
Packit Service 7c31a4
                                     utf16,
Packit Service 7c31a4
                                     read_chars,
Packit Service 7c31a4
                                     handle->tty.rd.read_line_buffer.base,
Packit Service 7c31a4
                                     bytes,
Packit Service 7c31a4
                                     NULL,
Packit Service 7c31a4
                                     NULL);
Packit Service 7c31a4
    SET_REQ_SUCCESS(req);
Packit Service 7c31a4
    req->u.io.overlapped.InternalHigh = read_bytes;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    SET_REQ_ERROR(req, GetLastError());
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  status = InterlockedExchange(&uv__read_console_status, COMPLETED);
Packit Service 7c31a4
Packit Service 7c31a4
  if (status ==  TRAP_REQUESTED) {
Packit Service 7c31a4
    /* If we canceled the read by sending a VK_RETURN event, restore the
Packit Service 7c31a4
       screen state to undo the visual effect of the VK_RETURN */
Packit Service 7c31a4
    if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
Packit Service 7c31a4
      HANDLE active_screen_buffer;
Packit Service 7c31a4
      active_screen_buffer = CreateFileA("conout$",
Packit Service 7c31a4
                                         GENERIC_READ | GENERIC_WRITE,
Packit Service 7c31a4
                                         FILE_SHARE_READ | FILE_SHARE_WRITE,
Packit Service 7c31a4
                                         NULL,
Packit Service 7c31a4
                                         OPEN_EXISTING,
Packit Service 7c31a4
                                         FILE_ATTRIBUTE_NORMAL,
Packit Service 7c31a4
                                         NULL);
Packit Service 7c31a4
      if (active_screen_buffer != INVALID_HANDLE_VALUE) {
Packit Service 7c31a4
        pos = uv__saved_screen_state.dwCursorPosition;
Packit Service 7c31a4
Packit Service 7c31a4
        /* If the cursor was at the bottom line of the screen buffer, the
Packit Service 7c31a4
           VK_RETURN would have caused the buffer contents to scroll up by one
Packit Service 7c31a4
           line. The right position to reset the cursor to is therefore one line
Packit Service 7c31a4
           higher */
Packit Service 7c31a4
        if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
Packit Service 7c31a4
          pos.Y--;
Packit Service 7c31a4
Packit Service 7c31a4
        SetConsoleCursorPosition(active_screen_buffer, pos);
Packit Service 7c31a4
        CloseHandle(active_screen_buffer);
Packit Service 7c31a4
      }
Packit Service 7c31a4
    }
Packit Service 7c31a4
    uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
  }
Packit Service 7c31a4
  POST_COMPLETION_FOR_REQ(loop, req);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
Packit Service 7c31a4
  uv_read_t* req;
Packit Service 7c31a4
  BOOL r;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->flags & UV_HANDLE_READING);
Packit Service 7c31a4
  assert(!(handle->flags & UV_HANDLE_READ_PENDING));
Packit Service 7c31a4
  assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
Packit Service 7c31a4
Packit Service 7c31a4
  req = &handle->read_req;
Packit Service 7c31a4
  memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
Packit Service 7c31a4
Packit Service 7c31a4
  handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
Packit Service 7c31a4
  handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
Packit Service 7c31a4
  if (handle->tty.rd.read_line_buffer.base == NULL ||
Packit Service 7c31a4
      handle->tty.rd.read_line_buffer.len == 0) {
Packit Service 7c31a4
    handle->read_cb((uv_stream_t*) handle,
Packit Service 7c31a4
                    UV_ENOBUFS,
Packit Service 7c31a4
                    &handle->tty.rd.read_line_buffer);
Packit Service 7c31a4
    return;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  assert(handle->tty.rd.read_line_buffer.base != NULL);
Packit Service 7c31a4
Packit Service 7c31a4
  /* Reset flags  No locking is required since there cannot be a line read
Packit Service 7c31a4
     in progress. We are also relying on the memory barrier provided by
Packit Service 7c31a4
     QueueUserWorkItem*/
Packit Service 7c31a4
  uv__restore_screen_state = FALSE;
Packit Service 7c31a4
  uv__read_console_status = NOT_STARTED;
Packit Service 7c31a4
  r = QueueUserWorkItem(uv_tty_line_read_thread,
Packit Service 7c31a4
                        (void*) req,
Packit Service 7c31a4
                        WT_EXECUTELONGFUNCTION);
Packit Service 7c31a4
  if (!r) {
Packit Service 7c31a4
    SET_REQ_ERROR(req, GetLastError());
Packit Service 7c31a4
    uv_insert_pending_req(loop, (uv_req_t*)req);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  handle->flags |= UV_HANDLE_READ_PENDING;
Packit Service 7c31a4
  handle->reqs_pending++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_TTY_RAW) {
Packit Service 7c31a4
    uv_tty_queue_read_raw(loop, handle);
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    uv_tty_queue_read_line(loop, handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
Packit Service 7c31a4
    size_t* len) {
Packit Service 7c31a4
#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str)          \
Packit Service 7c31a4
    case (vk):                                                                \
Packit Service 7c31a4
      if (shift && ctrl) {                                                    \
Packit Service 7c31a4
        *len = sizeof shift_ctrl_str;                                         \
Packit Service 7c31a4
        return "\033" shift_ctrl_str;                                         \
Packit Service 7c31a4
      } else if (shift) {                                                     \
Packit Service 7c31a4
        *len = sizeof shift_str ;                                             \
Packit Service 7c31a4
        return "\033" shift_str;                                              \
Packit Service 7c31a4
      } else if (ctrl) {                                                      \
Packit Service 7c31a4
        *len = sizeof ctrl_str;                                               \
Packit Service 7c31a4
        return "\033" ctrl_str;                                               \
Packit Service 7c31a4
      } else {                                                                \
Packit Service 7c31a4
        *len = sizeof normal_str;                                             \
Packit Service 7c31a4
        return "\033" normal_str;                                             \
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
  switch (code) {
Packit Service 7c31a4
    /* These mappings are the same as Cygwin's. Unmodified and alt-modified
Packit Service 7c31a4
     * keypad keys comply with linux console, modifiers comply with xterm
Packit Service 7c31a4
     * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
Packit Service 7c31a4
     * f12 with and without modifiers comply with rxvt. */
Packit Service 7c31a4
    VK_CASE(VK_INSERT,  "[2~",  "[2;2~", "[2;5~", "[2;6~")
Packit Service 7c31a4
    VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
Packit Service 7c31a4
    VK_CASE(VK_DOWN,    "[B",   "[1;2B", "[1;5B", "[1;6B")
Packit Service 7c31a4
    VK_CASE(VK_NEXT,    "[6~",  "[6;2~", "[6;5~", "[6;6~")
Packit Service 7c31a4
    VK_CASE(VK_LEFT,    "[D",   "[1;2D", "[1;5D", "[1;6D")
Packit Service 7c31a4
    VK_CASE(VK_CLEAR,   "[G",   "[1;2G", "[1;5G", "[1;6G")
Packit Service 7c31a4
    VK_CASE(VK_RIGHT,   "[C",   "[1;2C", "[1;5C", "[1;6C")
Packit Service 7c31a4
    VK_CASE(VK_UP,      "[A",   "[1;2A", "[1;5A", "[1;6A")
Packit Service 7c31a4
    VK_CASE(VK_HOME,    "[1~",  "[1;2~", "[1;5~", "[1;6~")
Packit Service 7c31a4
    VK_CASE(VK_PRIOR,   "[5~",  "[5;2~", "[5;5~", "[5;6~")
Packit Service 7c31a4
    VK_CASE(VK_DELETE,  "[3~",  "[3;2~", "[3;5~", "[3;6~")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD0, "[2~",  "[2;2~", "[2;5~", "[2;6~")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD1, "[4~",  "[4;2~", "[4;5~", "[4;6~")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD2, "[B",   "[1;2B", "[1;5B", "[1;6B")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD3, "[6~",  "[6;2~", "[6;5~", "[6;6~")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD4, "[D",   "[1;2D", "[1;5D", "[1;6D")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD5, "[G",   "[1;2G", "[1;5G", "[1;6G")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD6, "[C",   "[1;2C", "[1;5C", "[1;6C")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD7, "[A",   "[1;2A", "[1;5A", "[1;6A")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD8, "[1~",  "[1;2~", "[1;5~", "[1;6~")
Packit Service 7c31a4
    VK_CASE(VK_NUMPAD9, "[5~",  "[5;2~", "[5;5~", "[5;6~")
Packit Service 7c31a4
    VK_CASE(VK_DECIMAL, "[3~",  "[3;2~", "[3;5~", "[3;6~")
Packit Service 7c31a4
    VK_CASE(VK_F1,      "[[A",  "[23~",  "[11^",  "[23^" )
Packit Service 7c31a4
    VK_CASE(VK_F2,      "[[B",  "[24~",  "[12^",  "[24^" )
Packit Service 7c31a4
    VK_CASE(VK_F3,      "[[C",  "[25~",  "[13^",  "[25^" )
Packit Service 7c31a4
    VK_CASE(VK_F4,      "[[D",  "[26~",  "[14^",  "[26^" )
Packit Service 7c31a4
    VK_CASE(VK_F5,      "[[E",  "[28~",  "[15^",  "[28^" )
Packit Service 7c31a4
    VK_CASE(VK_F6,      "[17~", "[29~",  "[17^",  "[29^" )
Packit Service 7c31a4
    VK_CASE(VK_F7,      "[18~", "[31~",  "[18^",  "[31^" )
Packit Service 7c31a4
    VK_CASE(VK_F8,      "[19~", "[32~",  "[19^",  "[32^" )
Packit Service 7c31a4
    VK_CASE(VK_F9,      "[20~", "[33~",  "[20^",  "[33^" )
Packit Service 7c31a4
    VK_CASE(VK_F10,     "[21~", "[34~",  "[21^",  "[34^" )
Packit Service 7c31a4
    VK_CASE(VK_F11,     "[23~", "[23$",  "[23^",  "[23@" )
Packit Service 7c31a4
    VK_CASE(VK_F12,     "[24~", "[24$",  "[24^",  "[24@" )
Packit Service 7c31a4
Packit Service 7c31a4
    default:
Packit Service 7c31a4
      *len = 0;
Packit Service 7c31a4
      return NULL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
#undef VK_CASE
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
    uv_req_t* req) {
Packit Service 7c31a4
  /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
Packit Service 7c31a4
#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
Packit Service 7c31a4
Packit Service 7c31a4
  DWORD records_left, records_read;
Packit Service 7c31a4
  uv_buf_t buf;
Packit Service 7c31a4
  off_t buf_used;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->type == UV_TTY);
Packit Service 7c31a4
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit Service 7c31a4
  handle->flags &= ~UV_HANDLE_READ_PENDING;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(handle->flags & UV_HANDLE_READING) ||
Packit Service 7c31a4
      !(handle->flags & UV_HANDLE_TTY_RAW)) {
Packit Service 7c31a4
    goto out;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!REQ_SUCCESS(req)) {
Packit Service 7c31a4
    /* An error occurred while waiting for the event. */
Packit Service 7c31a4
    if ((handle->flags & UV_HANDLE_READING)) {
Packit Service 7c31a4
      handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
      handle->read_cb((uv_stream_t*)handle,
Packit Service 7c31a4
                      uv_translate_sys_error(GET_REQ_ERROR(req)),
Packit Service 7c31a4
                      &uv_null_buf_);
Packit Service 7c31a4
    }
Packit Service 7c31a4
    goto out;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Fetch the number of events  */
Packit Service 7c31a4
  if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
Packit Service 7c31a4
    handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
    DECREASE_ACTIVE_COUNT(loop, handle);
Packit Service 7c31a4
    handle->read_cb((uv_stream_t*)handle,
Packit Service 7c31a4
                    uv_translate_sys_error(GetLastError()),
Packit Service 7c31a4
                    &uv_null_buf_);
Packit Service 7c31a4
    goto out;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Windows sends a lot of events that we're not interested in, so buf will be
Packit Service 7c31a4
   * allocated on demand, when there's actually something to emit. */
Packit Service 7c31a4
  buf = uv_null_buf_;
Packit Service 7c31a4
  buf_used = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
Packit Service 7c31a4
         (handle->flags & UV_HANDLE_READING)) {
Packit Service 7c31a4
    if (handle->tty.rd.last_key_len == 0) {
Packit Service 7c31a4
      /* Read the next input record */
Packit Service 7c31a4
      if (!ReadConsoleInputW(handle->handle,
Packit Service 7c31a4
                             &handle->tty.rd.last_input_record,
Packit Service 7c31a4
                             1,
Packit Service 7c31a4
                             &records_read)) {
Packit Service 7c31a4
        handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
        DECREASE_ACTIVE_COUNT(loop, handle);
Packit Service 7c31a4
        handle->read_cb((uv_stream_t*) handle,
Packit Service 7c31a4
                        uv_translate_sys_error(GetLastError()),
Packit Service 7c31a4
                        &buf;;
Packit Service 7c31a4
        goto out;
Packit Service 7c31a4
      }
Packit Service 7c31a4
      records_left--;
Packit Service 7c31a4
Packit Service 7c31a4
      /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
Packit Service 7c31a4
       * running under some TTY emulator that does not send those events. */
Packit Service 7c31a4
      if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
Packit Service 7c31a4
        uv__tty_console_signal_resize();
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Ignore other events that are not key events. */
Packit Service 7c31a4
      if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Ignore keyup events, unless the left alt key was held and a valid
Packit Service 7c31a4
       * unicode character was emitted. */
Packit Service 7c31a4
      if (!KEV.bKeyDown &&
Packit Service 7c31a4
          (KEV.wVirtualKeyCode != VK_MENU ||
Packit Service 7c31a4
           KEV.uChar.UnicodeChar == 0)) {
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Ignore keypresses to numpad number keys if the left alt is held
Packit Service 7c31a4
       * because the user is composing a character, or windows simulating this.
Packit Service 7c31a4
       */
Packit Service 7c31a4
      if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
Packit Service 7c31a4
          !(KEV.dwControlKeyState & ENHANCED_KEY) &&
Packit Service 7c31a4
          (KEV.wVirtualKeyCode == VK_INSERT ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_END ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_DOWN ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NEXT ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_LEFT ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_CLEAR ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_RIGHT ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_HOME ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_UP ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_PRIOR ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD0 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD1 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD2 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD3 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD4 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD5 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD6 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD7 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD8 ||
Packit Service 7c31a4
          KEV.wVirtualKeyCode == VK_NUMPAD9)) {
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      if (KEV.uChar.UnicodeChar != 0) {
Packit Service 7c31a4
        int prefix_len, char_len;
Packit Service 7c31a4
Packit Service 7c31a4
        /* Character key pressed */
Packit Service 7c31a4
        if (KEV.uChar.UnicodeChar >= 0xD800 &&
Packit Service 7c31a4
            KEV.uChar.UnicodeChar < 0xDC00) {
Packit Service 7c31a4
          /* UTF-16 high surrogate */
Packit Service 7c31a4
          handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        /* Prefix with \u033 if alt was held, but alt was not used as part a
Packit Service 7c31a4
         * compose sequence. */
Packit Service 7c31a4
        if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
Packit Service 7c31a4
            && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
Packit Service 7c31a4
            RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
Packit Service 7c31a4
          handle->tty.rd.last_key[0] = '\033';
Packit Service 7c31a4
          prefix_len = 1;
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          prefix_len = 0;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        if (KEV.uChar.UnicodeChar >= 0xDC00 &&
Packit Service 7c31a4
            KEV.uChar.UnicodeChar < 0xE000) {
Packit Service 7c31a4
          /* UTF-16 surrogate pair */
Packit Service 7c31a4
          WCHAR utf16_buffer[2];
Packit Service 7c31a4
          utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
Packit Service 7c31a4
          utf16_buffer[1] = KEV.uChar.UnicodeChar;
Packit Service 7c31a4
          char_len = WideCharToMultiByte(CP_UTF8,
Packit Service 7c31a4
                                         0,
Packit Service 7c31a4
                                         utf16_buffer,
Packit Service 7c31a4
                                         2,
Packit Service 7c31a4
                                         &handle->tty.rd.last_key[prefix_len],
Packit Service 7c31a4
                                         sizeof handle->tty.rd.last_key,
Packit Service 7c31a4
                                         NULL,
Packit Service 7c31a4
                                         NULL);
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          /* Single UTF-16 character */
Packit Service 7c31a4
          char_len = WideCharToMultiByte(CP_UTF8,
Packit Service 7c31a4
                                         0,
Packit Service 7c31a4
                                         &KEV.uChar.UnicodeChar,
Packit Service 7c31a4
                                         1,
Packit Service 7c31a4
                                         &handle->tty.rd.last_key[prefix_len],
Packit Service 7c31a4
                                         sizeof handle->tty.rd.last_key,
Packit Service 7c31a4
                                         NULL,
Packit Service 7c31a4
                                         NULL);
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        /* Whatever happened, the last character wasn't a high surrogate. */
Packit Service 7c31a4
        handle->tty.rd.last_utf16_high_surrogate = 0;
Packit Service 7c31a4
Packit Service 7c31a4
        /* If the utf16 character(s) couldn't be converted something must be
Packit Service 7c31a4
         * wrong. */
Packit Service 7c31a4
        if (!char_len) {
Packit Service 7c31a4
          handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
          DECREASE_ACTIVE_COUNT(loop, handle);
Packit Service 7c31a4
          handle->read_cb((uv_stream_t*) handle,
Packit Service 7c31a4
                          uv_translate_sys_error(GetLastError()),
Packit Service 7c31a4
                          &buf;;
Packit Service 7c31a4
          goto out;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
Packit Service 7c31a4
        handle->tty.rd.last_key_offset = 0;
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
Packit Service 7c31a4
      } else {
Packit Service 7c31a4
        /* Function key pressed */
Packit Service 7c31a4
        const char* vt100;
Packit Service 7c31a4
        size_t prefix_len, vt100_len;
Packit Service 7c31a4
Packit Service 7c31a4
        vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
Packit Service 7c31a4
                                  !!(KEV.dwControlKeyState & SHIFT_PRESSED),
Packit Service 7c31a4
                                  !!(KEV.dwControlKeyState & (
Packit Service 7c31a4
                                    LEFT_CTRL_PRESSED |
Packit Service 7c31a4
                                    RIGHT_CTRL_PRESSED)),
Packit Service 7c31a4
                                  &vt100_len);
Packit Service 7c31a4
Packit Service 7c31a4
        /* If we were unable to map to a vt100 sequence, just ignore. */
Packit Service 7c31a4
        if (!vt100) {
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        /* Prefix with \x033 when the alt key was held. */
Packit Service 7c31a4
        if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
Packit Service 7c31a4
          handle->tty.rd.last_key[0] = '\033';
Packit Service 7c31a4
          prefix_len = 1;
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          prefix_len = 0;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        /* Copy the vt100 sequence to the handle buffer. */
Packit Service 7c31a4
        assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
Packit Service 7c31a4
        memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
Packit Service 7c31a4
Packit Service 7c31a4
        handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
Packit Service 7c31a4
        handle->tty.rd.last_key_offset = 0;
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      /* Copy any bytes left from the last keypress to the user buffer. */
Packit Service 7c31a4
      if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
Packit Service 7c31a4
        /* Allocate a buffer if needed */
Packit Service 7c31a4
        if (buf_used == 0) {
Packit Service 7c31a4
          buf = uv_buf_init(NULL, 0);
Packit Service 7c31a4
          handle->alloc_cb((uv_handle_t*) handle, 1024, &buf;;
Packit Service 7c31a4
          if (buf.base == NULL || buf.len == 0) {
Packit Service 7c31a4
            handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf;;
Packit Service 7c31a4
            goto out;
Packit Service 7c31a4
          }
Packit Service 7c31a4
          assert(buf.base != NULL);
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
Packit Service 7c31a4
Packit Service 7c31a4
        /* If the buffer is full, emit it */
Packit Service 7c31a4
        if ((size_t) buf_used == buf.len) {
Packit Service 7c31a4
          handle->read_cb((uv_stream_t*) handle, buf_used, &buf;;
Packit Service 7c31a4
          buf = uv_null_buf_;
Packit Service 7c31a4
          buf_used = 0;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Apply dwRepeat from the last input record. */
Packit Service 7c31a4
      if (--KEV.wRepeatCount > 0) {
Packit Service 7c31a4
        handle->tty.rd.last_key_offset = 0;
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      handle->tty.rd.last_key_len = 0;
Packit Service 7c31a4
      continue;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Send the buffer back to the user */
Packit Service 7c31a4
  if (buf_used > 0) {
Packit Service 7c31a4
    handle->read_cb((uv_stream_t*) handle, buf_used, &buf;;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
 out:
Packit Service 7c31a4
  /* Wait for more input events. */
Packit Service 7c31a4
  if ((handle->flags & UV_HANDLE_READING) &&
Packit Service 7c31a4
      !(handle->flags & UV_HANDLE_READ_PENDING)) {
Packit Service 7c31a4
    uv_tty_queue_read(loop, handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  DECREASE_PENDING_REQ_COUNT(handle);
Packit Service 7c31a4
Packit Service 7c31a4
#undef KEV
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
    uv_req_t* req) {
Packit Service 7c31a4
  uv_buf_t buf;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->type == UV_TTY);
Packit Service 7c31a4
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit Service 7c31a4
Packit Service 7c31a4
  buf = handle->tty.rd.read_line_buffer;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->flags &= ~UV_HANDLE_READ_PENDING;
Packit Service 7c31a4
  handle->tty.rd.read_line_buffer = uv_null_buf_;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!REQ_SUCCESS(req)) {
Packit Service 7c31a4
    /* Read was not successful */
Packit Service 7c31a4
    if (handle->flags & UV_HANDLE_READING) {
Packit Service 7c31a4
      /* Real error */
Packit Service 7c31a4
      handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
      DECREASE_ACTIVE_COUNT(loop, handle);
Packit Service 7c31a4
      handle->read_cb((uv_stream_t*) handle,
Packit Service 7c31a4
                      uv_translate_sys_error(GET_REQ_ERROR(req)),
Packit Service 7c31a4
                      &buf;;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
Packit Service 7c31a4
        req->u.io.overlapped.InternalHigh != 0) {
Packit Service 7c31a4
      /* Read successful. TODO: read unicode, convert to utf-8 */
Packit Service 7c31a4
      DWORD bytes = req->u.io.overlapped.InternalHigh;
Packit Service 7c31a4
      handle->read_cb((uv_stream_t*) handle, bytes, &buf;;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Wait for more input events. */
Packit Service 7c31a4
  if ((handle->flags & UV_HANDLE_READING) &&
Packit Service 7c31a4
      !(handle->flags & UV_HANDLE_READ_PENDING)) {
Packit Service 7c31a4
    uv_tty_queue_read(loop, handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  DECREASE_PENDING_REQ_COUNT(handle);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
    uv_req_t* req) {
Packit Service 7c31a4
  assert(handle->type == UV_TTY);
Packit Service 7c31a4
  assert(handle->flags & UV_HANDLE_TTY_READABLE);
Packit Service 7c31a4
Packit Service 7c31a4
  /* If the read_line_buffer member is zero, it must have been an raw read.
Packit Service 7c31a4
   * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
Packit Service 7c31a4
   * flag or something. */
Packit Service 7c31a4
  if (handle->tty.rd.read_line_buffer.len == 0) {
Packit Service 7c31a4
    uv_process_tty_read_raw_req(loop, handle, req);
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    uv_process_tty_read_line_req(loop, handle, req);
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
Packit Service 7c31a4
    uv_read_cb read_cb) {
Packit Service 7c31a4
  uv_loop_t* loop = handle->loop;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
Packit Service 7c31a4
    return ERROR_INVALID_PARAMETER;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  handle->flags |= UV_HANDLE_READING;
Packit Service 7c31a4
  INCREASE_ACTIVE_COUNT(loop, handle);
Packit Service 7c31a4
  handle->read_cb = read_cb;
Packit Service 7c31a4
  handle->alloc_cb = alloc_cb;
Packit Service 7c31a4
Packit Service 7c31a4
  /* If reading was stopped and then started again, there could still be a read
Packit Service 7c31a4
   * request pending. */
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_READ_PENDING) {
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Maybe the user stopped reading half-way while processing key events.
Packit Service 7c31a4
   * Short-circuit if this could be the case. */
Packit Service 7c31a4
  if (handle->tty.rd.last_key_len > 0) {
Packit Service 7c31a4
    SET_REQ_SUCCESS(&handle->read_req);
Packit Service 7c31a4
    uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
Packit Service 7c31a4
    /* Make sure no attempt is made to insert it again until it's handled. */
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_READ_PENDING;
Packit Service 7c31a4
    handle->reqs_pending++;
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_tty_queue_read(loop, handle);
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_read_stop(uv_tty_t* handle) {
Packit Service 7c31a4
  INPUT_RECORD record;
Packit Service 7c31a4
  DWORD written, err;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->flags &= ~UV_HANDLE_READING;
Packit Service 7c31a4
  DECREASE_ACTIVE_COUNT(handle->loop, handle);
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(handle->flags & UV_HANDLE_READ_PENDING))
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_TTY_RAW) {
Packit Service 7c31a4
    /* Cancel raw read. Write some bullshit event to force the console wait to
Packit Service 7c31a4
     * return. */
Packit Service 7c31a4
    memset(&record, 0, sizeof record);
Packit Service 7c31a4
    record.EventType = FOCUS_EVENT;
Packit Service 7c31a4
    if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
Packit Service 7c31a4
      return GetLastError();
Packit Service 7c31a4
    }
Packit Service 7c31a4
  } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
Packit Service 7c31a4
    /* Cancel line-buffered read if not already pending */
Packit Service 7c31a4
    err = uv__cancel_read_console(handle);
Packit Service 7c31a4
    if (err)
Packit Service 7c31a4
      return err;
Packit Service 7c31a4
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int uv__cancel_read_console(uv_tty_t* handle) {
Packit Service 7c31a4
  HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
Packit Service 7c31a4
  INPUT_RECORD record;
Packit Service 7c31a4
  DWORD written;
Packit Service 7c31a4
  DWORD err = 0;
Packit Service 7c31a4
  LONG status;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
Packit Service 7c31a4
Packit Service 7c31a4
  /* Hold the output lock during the cancellation, to ensure that further
Packit Service 7c31a4
     writes don't interfere with the screen state. It will be the ReadConsole
Packit Service 7c31a4
     thread's responsibility to release the lock. */
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
  status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
Packit Service 7c31a4
  if (status != IN_PROGRESS) {
Packit Service 7c31a4
    /* Either we have managed to set a trap for the other thread before
Packit Service 7c31a4
       ReadConsole is called, or ReadConsole has returned because the user
Packit Service 7c31a4
       has pressed ENTER. In either case, there is nothing else to do. */
Packit Service 7c31a4
    uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Save screen state before sending the VK_RETURN event */
Packit Service 7c31a4
  active_screen_buffer = CreateFileA("conout$",
Packit Service 7c31a4
                                     GENERIC_READ | GENERIC_WRITE,
Packit Service 7c31a4
                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
Packit Service 7c31a4
                                     NULL,
Packit Service 7c31a4
                                     OPEN_EXISTING,
Packit Service 7c31a4
                                     FILE_ATTRIBUTE_NORMAL,
Packit Service 7c31a4
                                     NULL);
Packit Service 7c31a4
Packit Service 7c31a4
  if (active_screen_buffer != INVALID_HANDLE_VALUE &&
Packit Service 7c31a4
      GetConsoleScreenBufferInfo(active_screen_buffer,
Packit Service 7c31a4
                                 &uv__saved_screen_state)) {
Packit Service 7c31a4
    InterlockedOr(&uv__restore_screen_state, 1);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Write enter key event to force the console wait to return. */
Packit Service 7c31a4
  record.EventType = KEY_EVENT;
Packit Service 7c31a4
  record.Event.KeyEvent.bKeyDown = TRUE;
Packit Service 7c31a4
  record.Event.KeyEvent.wRepeatCount = 1;
Packit Service 7c31a4
  record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
Packit Service 7c31a4
  record.Event.KeyEvent.wVirtualScanCode =
Packit Service 7c31a4
    MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
Packit Service 7c31a4
  record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
Packit Service 7c31a4
  record.Event.KeyEvent.dwControlKeyState = 0;
Packit Service 7c31a4
  if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
Packit Service 7c31a4
    err = GetLastError();
Packit Service 7c31a4
Packit Service 7c31a4
  if (active_screen_buffer != INVALID_HANDLE_VALUE)
Packit Service 7c31a4
    CloseHandle(active_screen_buffer);
Packit Service 7c31a4
Packit Service 7c31a4
  return err;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
Packit Service 7c31a4
  uv_tty_virtual_width = info->dwSize.X;
Packit Service 7c31a4
  uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Recompute virtual window offset row. */
Packit Service 7c31a4
  if (uv_tty_virtual_offset == -1) {
Packit Service 7c31a4
    uv_tty_virtual_offset = info->dwCursorPosition.Y;
Packit Service 7c31a4
  } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
Packit Service 7c31a4
             uv_tty_virtual_height + 1) {
Packit Service 7c31a4
    /* If suddenly find the cursor outside of the virtual window, it must have
Packit Service 7c31a4
     * somehow scrolled. Update the virtual window offset. */
Packit Service 7c31a4
    uv_tty_virtual_offset = info->dwCursorPosition.Y -
Packit Service 7c31a4
                            uv_tty_virtual_height + 1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
Packit Service 7c31a4
    uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  if (uv_tty_virtual_offset < 0) {
Packit Service 7c31a4
    uv_tty_virtual_offset = 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static COORD uv_tty_make_real_coord(uv_tty_t* handle,
Packit Service 7c31a4
    CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
Packit Service 7c31a4
    unsigned char y_relative) {
Packit Service 7c31a4
  COORD result;
Packit Service 7c31a4
Packit Service 7c31a4
  uv_tty_update_virtual_window(info);
Packit Service 7c31a4
Packit Service 7c31a4
  /* Adjust y position */
Packit Service 7c31a4
  if (y_relative) {
Packit Service 7c31a4
    y = info->dwCursorPosition.Y + y;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    y = uv_tty_virtual_offset + y;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  /* Clip y to virtual client rectangle */
Packit Service 7c31a4
  if (y < uv_tty_virtual_offset) {
Packit Service 7c31a4
    y = uv_tty_virtual_offset;
Packit Service 7c31a4
  } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
Packit Service 7c31a4
    y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Adjust x */
Packit Service 7c31a4
  if (x_relative) {
Packit Service 7c31a4
    x = info->dwCursorPosition.X + x;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  /* Clip x */
Packit Service 7c31a4
  if (x < 0) {
Packit Service 7c31a4
    x = 0;
Packit Service 7c31a4
  } else if (x >= uv_tty_virtual_width) {
Packit Service 7c31a4
    x = uv_tty_virtual_width - 1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  result.X = (unsigned short) x;
Packit Service 7c31a4
  result.Y = (unsigned short) y;
Packit Service 7c31a4
  return result;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
Packit Service 7c31a4
    DWORD* error) {
Packit Service 7c31a4
  DWORD written;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!WriteConsoleW(handle->handle,
Packit Service 7c31a4
                     (void*) buffer,
Packit Service 7c31a4
                     length,
Packit Service 7c31a4
                     &written,
Packit Service 7c31a4
                     NULL)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
Packit Service 7c31a4
    int y, unsigned char y_relative, DWORD* error) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
  COORD pos;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
 retry:
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
Packit Service 7c31a4
Packit Service 7c31a4
  if (!SetConsoleCursorPosition(handle->handle, pos)) {
Packit Service 7c31a4
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit Service 7c31a4
      /* The console may be resized - retry */
Packit Service 7c31a4
      goto retry;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      *error = GetLastError();
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
Packit Service 7c31a4
  const COORD origin = {0, 0};
Packit Service 7c31a4
  const WORD char_attrs = uv_tty_default_text_attributes;
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
Packit Service 7c31a4
  DWORD count, written;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Reset original text attributes. */
Packit Service 7c31a4
  if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Move the cursor position to (0, 0). */
Packit Service 7c31a4
  if (!SetConsoleCursorPosition(handle->handle, origin)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Clear the screen buffer. */
Packit Service 7c31a4
 retry:
Packit Service 7c31a4
   if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
Packit Service 7c31a4
     *error = GetLastError();
Packit Service 7c31a4
     return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(FillConsoleOutputCharacterW(handle->handle,
Packit Service 7c31a4
                                    L'\x20',
Packit Service 7c31a4
                                    count,
Packit Service 7c31a4
                                    origin,
Packit Service 7c31a4
                                    &written) &&
Packit Service 7c31a4
        FillConsoleOutputAttribute(handle->handle,
Packit Service 7c31a4
                                   char_attrs,
Packit Service 7c31a4
                                   written,
Packit Service 7c31a4
                                   origin,
Packit Service 7c31a4
                                   &written))) {
Packit Service 7c31a4
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit Service 7c31a4
      /* The console may be resized - retry */
Packit Service 7c31a4
      goto retry;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      *error = GetLastError();
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Move the virtual window up to the top. */
Packit Service 7c31a4
  uv_tty_virtual_offset = 0;
Packit Service 7c31a4
  uv_tty_update_virtual_window(&screen_buffer_info);
Packit Service 7c31a4
Packit Service 7c31a4
  /* Reset the cursor size and the cursor state. */
Packit Service 7c31a4
  if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
Packit Service 7c31a4
    DWORD* error) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
  COORD start, end;
Packit Service 7c31a4
  DWORD count, written;
Packit Service 7c31a4
Packit Service 7c31a4
  int x1, x2, y1, y2;
Packit Service 7c31a4
  int x1r, x2r, y1r, y2r;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (dir == 0) {
Packit Service 7c31a4
    /* Clear from current position */
Packit Service 7c31a4
    x1 = 0;
Packit Service 7c31a4
    x1r = 1;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    /* Clear from column 0 */
Packit Service 7c31a4
    x1 = 0;
Packit Service 7c31a4
    x1r = 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (dir == 1) {
Packit Service 7c31a4
    /* Clear to current position */
Packit Service 7c31a4
    x2 = 0;
Packit Service 7c31a4
    x2r = 1;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    /* Clear to end of row. We pretend the console is 65536 characters wide,
Packit Service 7c31a4
     * uv_tty_make_real_coord will clip it to the actual console width. */
Packit Service 7c31a4
    x2 = 0xffff;
Packit Service 7c31a4
    x2r = 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!entire_screen) {
Packit Service 7c31a4
    /* Stay on our own row */
Packit Service 7c31a4
    y1 = y2 = 0;
Packit Service 7c31a4
    y1r = y2r = 1;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    /* Apply columns direction to row */
Packit Service 7c31a4
    y1 = x1;
Packit Service 7c31a4
    y1r = x1r;
Packit Service 7c31a4
    y2 = x2;
Packit Service 7c31a4
    y2r = x2r;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
 retry:
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
Packit Service 7c31a4
  end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
Packit Service 7c31a4
  count = (end.Y * info.dwSize.X + end.X) -
Packit Service 7c31a4
          (start.Y * info.dwSize.X + start.X) + 1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!(FillConsoleOutputCharacterW(handle->handle,
Packit Service 7c31a4
                              L'\x20',
Packit Service 7c31a4
                              count,
Packit Service 7c31a4
                              start,
Packit Service 7c31a4
                              &written) &&
Packit Service 7c31a4
        FillConsoleOutputAttribute(handle->handle,
Packit Service 7c31a4
                                   info.wAttributes,
Packit Service 7c31a4
                                   written,
Packit Service 7c31a4
                                   start,
Packit Service 7c31a4
                                   &written))) {
Packit Service 7c31a4
    if (GetLastError() == ERROR_INVALID_PARAMETER) {
Packit Service 7c31a4
      /* The console may be resized - retry */
Packit Service 7c31a4
      goto retry;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      *error = GetLastError();
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
#define FLIP_FGBG                                                             \
Packit Service 7c31a4
    do {                                                                      \
Packit Service 7c31a4
      WORD fg = info.wAttributes & 0xF;                                       \
Packit Service 7c31a4
      WORD bg = info.wAttributes & 0xF0;                                      \
Packit Service 7c31a4
      info.wAttributes &= 0xFF00;                                             \
Packit Service 7c31a4
      info.wAttributes |= fg << 4;                                            \
Packit Service 7c31a4
      info.wAttributes |= bg >> 4;                                            \
Packit Service 7c31a4
    } while (0)
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
Packit Service 7c31a4
  unsigned short argc = handle->tty.wr.ansi_csi_argc;
Packit Service 7c31a4
  unsigned short* argv = handle->tty.wr.ansi_csi_argv;
Packit Service 7c31a4
  int i;
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
Packit Service 7c31a4
  char fg_color = -1, bg_color = -1;
Packit Service 7c31a4
  char fg_bright = -1, bg_bright = -1;
Packit Service 7c31a4
  char inverse = -1;
Packit Service 7c31a4
Packit Service 7c31a4
  if (argc == 0) {
Packit Service 7c31a4
    /* Reset mode */
Packit Service 7c31a4
    fg_color = uv_tty_default_fg_color;
Packit Service 7c31a4
    bg_color = uv_tty_default_bg_color;
Packit Service 7c31a4
    fg_bright = uv_tty_default_fg_bright;
Packit Service 7c31a4
    bg_bright = uv_tty_default_bg_bright;
Packit Service 7c31a4
    inverse = uv_tty_default_inverse;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  for (i = 0; i < argc; i++) {
Packit Service 7c31a4
    short arg = argv[i];
Packit Service 7c31a4
Packit Service 7c31a4
    if (arg == 0) {
Packit Service 7c31a4
      /* Reset mode */
Packit Service 7c31a4
      fg_color = uv_tty_default_fg_color;
Packit Service 7c31a4
      bg_color = uv_tty_default_bg_color;
Packit Service 7c31a4
      fg_bright = uv_tty_default_fg_bright;
Packit Service 7c31a4
      bg_bright = uv_tty_default_bg_bright;
Packit Service 7c31a4
      inverse = uv_tty_default_inverse;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 1) {
Packit Service 7c31a4
      /* Foreground bright on */
Packit Service 7c31a4
      fg_bright = 1;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 2) {
Packit Service 7c31a4
      /* Both bright off */
Packit Service 7c31a4
      fg_bright = 0;
Packit Service 7c31a4
      bg_bright = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 5) {
Packit Service 7c31a4
      /* Background bright on */
Packit Service 7c31a4
      bg_bright = 1;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 7) {
Packit Service 7c31a4
      /* Inverse: on */
Packit Service 7c31a4
      inverse = 1;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 21 || arg == 22) {
Packit Service 7c31a4
      /* Foreground bright off */
Packit Service 7c31a4
      fg_bright = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 25) {
Packit Service 7c31a4
      /* Background bright off */
Packit Service 7c31a4
      bg_bright = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 27) {
Packit Service 7c31a4
      /* Inverse: off */
Packit Service 7c31a4
      inverse = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg >= 30 && arg <= 37) {
Packit Service 7c31a4
      /* Set foreground color */
Packit Service 7c31a4
      fg_color = arg - 30;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg == 39) {
Packit Service 7c31a4
      /* Default text color */
Packit Service 7c31a4
      fg_color = uv_tty_default_fg_color;
Packit Service 7c31a4
      fg_bright = uv_tty_default_fg_bright;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg >= 40 && arg <= 47) {
Packit Service 7c31a4
      /* Set background color */
Packit Service 7c31a4
      bg_color = arg - 40;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg ==  49) {
Packit Service 7c31a4
      /* Default background color */
Packit Service 7c31a4
      bg_color = uv_tty_default_bg_color;
Packit Service 7c31a4
      bg_bright = uv_tty_default_bg_bright;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg >= 90 && arg <= 97) {
Packit Service 7c31a4
      /* Set bold foreground color */
Packit Service 7c31a4
      fg_bright = 1;
Packit Service 7c31a4
      fg_color = arg - 90;
Packit Service 7c31a4
Packit Service 7c31a4
    } else if (arg >= 100 && arg <= 107) {
Packit Service 7c31a4
      /* Set bold background color */
Packit Service 7c31a4
      bg_bright = 1;
Packit Service 7c31a4
      bg_color = arg - 100;
Packit Service 7c31a4
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
Packit Service 7c31a4
      bg_bright == -1 && inverse == -1) {
Packit Service 7c31a4
    /* Nothing changed */
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
Packit Service 7c31a4
    FLIP_FGBG;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (fg_color != -1) {
Packit Service 7c31a4
    info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
Packit Service 7c31a4
    if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
Packit Service 7c31a4
    if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
Packit Service 7c31a4
    if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (fg_bright != -1) {
Packit Service 7c31a4
    if (fg_bright) {
Packit Service 7c31a4
      info.wAttributes |= FOREGROUND_INTENSITY;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      info.wAttributes &= ~FOREGROUND_INTENSITY;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (bg_color != -1) {
Packit Service 7c31a4
    info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
Packit Service 7c31a4
    if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
Packit Service 7c31a4
    if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
Packit Service 7c31a4
    if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (bg_bright != -1) {
Packit Service 7c31a4
    if (bg_bright) {
Packit Service 7c31a4
      info.wAttributes |= BACKGROUND_INTENSITY;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      info.wAttributes &= ~BACKGROUND_INTENSITY;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (inverse != -1) {
Packit Service 7c31a4
    if (inverse) {
Packit Service 7c31a4
      info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
Packit Service 7c31a4
    } else {
Packit Service 7c31a4
      info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
Packit Service 7c31a4
    FLIP_FGBG;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
Packit Service 7c31a4
    DWORD* error) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_tty_update_virtual_window(&info;;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
Packit Service 7c31a4
  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
Packit Service 7c31a4
  handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
Packit Service 7c31a4
Packit Service 7c31a4
  if (save_attributes) {
Packit Service 7c31a4
    handle->tty.wr.saved_attributes = info.wAttributes &
Packit Service 7c31a4
        (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_restore_state(uv_tty_t* handle,
Packit Service 7c31a4
    unsigned char restore_attributes, DWORD* error) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO info;
Packit Service 7c31a4
  WORD new_attributes;
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error != ERROR_SUCCESS) {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
Packit Service 7c31a4
    if (uv_tty_move_caret(handle,
Packit Service 7c31a4
                          handle->tty.wr.saved_position.X,
Packit Service 7c31a4
                          0,
Packit Service 7c31a4
                          handle->tty.wr.saved_position.Y,
Packit Service 7c31a4
                          0,
Packit Service 7c31a4
                          error) != 0) {
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (restore_attributes &&
Packit Service 7c31a4
      (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
Packit Service 7c31a4
    if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
Packit Service 7c31a4
      *error = GetLastError();
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    new_attributes = info.wAttributes;
Packit Service 7c31a4
    new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
Packit Service 7c31a4
    new_attributes |= handle->tty.wr.saved_attributes;
Packit Service 7c31a4
Packit Service 7c31a4
    if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
Packit Service 7c31a4
      *error = GetLastError();
Packit Service 7c31a4
      return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
Packit Service 7c31a4
                                        BOOL visible,
Packit Service 7c31a4
                                        DWORD* error) {
Packit Service 7c31a4
  CONSOLE_CURSOR_INFO cursor_info;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  cursor_info.bVisible = visible;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
Packit Service 7c31a4
  CONSOLE_CURSOR_INFO cursor_info;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (style == 0) {
Packit Service 7c31a4
    cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
Packit Service 7c31a4
  } else if (style <= 2) {
Packit Service 7c31a4
    cursor_info.dwSize = CURSOR_SIZE_LARGE;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    cursor_info.dwSize = CURSOR_SIZE_SMALL;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
Packit Service 7c31a4
    *error = GetLastError();
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int uv_tty_write_bufs(uv_tty_t* handle,
Packit Service 7c31a4
                             const uv_buf_t bufs[],
Packit Service 7c31a4
                             unsigned int nbufs,
Packit Service 7c31a4
                             DWORD* error) {
Packit Service 7c31a4
  /* We can only write 8k characters at a time. Windows can't handle much more
Packit Service 7c31a4
   * characters in a single console write anyway. */
Packit Service 7c31a4
  WCHAR utf16_buf[MAX_CONSOLE_CHAR];
Packit Service 7c31a4
  DWORD utf16_buf_used = 0;
Packit Service 7c31a4
  unsigned int i;
Packit Service 7c31a4
Packit Service 7c31a4
#define FLUSH_TEXT()                                                \
Packit Service 7c31a4
  do {                                                              \
Packit Service 7c31a4
    if (utf16_buf_used > 0) {                                       \
Packit Service 7c31a4
      uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);   \
Packit Service 7c31a4
      utf16_buf_used = 0;                                           \
Packit Service 7c31a4
    }                                                               \
Packit Service 7c31a4
  } while (0)
Packit Service 7c31a4
Packit Service 7c31a4
#define ENSURE_BUFFER_SPACE(wchars_needed)                          \
Packit Service 7c31a4
  if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
Packit Service 7c31a4
    FLUSH_TEXT();                                                   \
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Cache for fast access */
Packit Service 7c31a4
  unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
Packit Service 7c31a4
  unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
Packit Service 7c31a4
  unsigned char previous_eol = handle->tty.wr.previous_eol;
Packit Service 7c31a4
  unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Store the error here. If we encounter an error, stop trying to do i/o but
Packit Service 7c31a4
   * keep parsing the buffer so we leave the parser in a consistent state. */
Packit Service 7c31a4
  *error = ERROR_SUCCESS;
Packit Service 7c31a4
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
Packit Service 7c31a4
  for (i = 0; i < nbufs; i++) {
Packit Service 7c31a4
    uv_buf_t buf = bufs[i];
Packit Service 7c31a4
    unsigned int j;
Packit Service 7c31a4
Packit Service 7c31a4
    for (j = 0; j < buf.len; j++) {
Packit Service 7c31a4
      unsigned char c = buf.base[j];
Packit Service 7c31a4
Packit Service 7c31a4
      /* Run the character through the utf8 decoder We happily accept non
Packit Service 7c31a4
       * shortest form encodings and invalid code points - there's no real harm
Packit Service 7c31a4
       * that can be done. */
Packit Service 7c31a4
      if (utf8_bytes_left == 0) {
Packit Service 7c31a4
        /* Read utf-8 start byte */
Packit Service 7c31a4
        DWORD first_zero_bit;
Packit Service 7c31a4
        unsigned char not_c = ~c;
Packit Service 7c31a4
#ifdef _MSC_VER /* msvc */
Packit Service 7c31a4
        if (_BitScanReverse(&first_zero_bit, not_c)) {
Packit Service 7c31a4
#else /* assume gcc */
Packit Service 7c31a4
        if (c != 0) {
Packit Service 7c31a4
          first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
Packit Service 7c31a4
#endif
Packit Service 7c31a4
          if (first_zero_bit == 7) {
Packit Service 7c31a4
            /* Ascii - pass right through */
Packit Service 7c31a4
            utf8_codepoint = (unsigned int) c;
Packit Service 7c31a4
Packit Service 7c31a4
          } else if (first_zero_bit <= 5) {
Packit Service 7c31a4
            /* Multibyte sequence */
Packit Service 7c31a4
            utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
Packit Service 7c31a4
            utf8_bytes_left = (char) (6 - first_zero_bit);
Packit Service 7c31a4
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            /* Invalid continuation */
Packit Service 7c31a4
            utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit Service 7c31a4
          }
Packit Service 7c31a4
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          /* 0xff -- invalid */
Packit Service 7c31a4
          utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
      } else if ((c & 0xc0) == 0x80) {
Packit Service 7c31a4
        /* Valid continuation of utf-8 multibyte sequence */
Packit Service 7c31a4
        utf8_bytes_left--;
Packit Service 7c31a4
        utf8_codepoint <<= 6;
Packit Service 7c31a4
        utf8_codepoint |= ((unsigned int) c & 0x3f);
Packit Service 7c31a4
Packit Service 7c31a4
      } else {
Packit Service 7c31a4
        /* Start byte where continuation was expected. */
Packit Service 7c31a4
        utf8_bytes_left = 0;
Packit Service 7c31a4
        utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
Packit Service 7c31a4
        /* Patch buf offset so this character will be parsed again as a start
Packit Service 7c31a4
         * byte. */
Packit Service 7c31a4
        j--;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Maybe we need to parse more bytes to find a character. */
Packit Service 7c31a4
      if (utf8_bytes_left != 0) {
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Parse vt100/ansi escape codes */
Packit Service 7c31a4
      if (uv__vterm_state == UV_TTY_SUPPORTED) {
Packit Service 7c31a4
        /* Pass through escape codes if conhost supports them. */
Packit Service 7c31a4
      } else if (ansi_parser_state == ANSI_NORMAL) {
Packit Service 7c31a4
        switch (utf8_codepoint) {
Packit Service 7c31a4
          case '\033':
Packit Service 7c31a4
            ansi_parser_state = ANSI_ESCAPE_SEEN;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case 0233:
Packit Service 7c31a4
            ansi_parser_state = ANSI_CSI;
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argc = 0;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
Packit Service 7c31a4
        switch (utf8_codepoint) {
Packit Service 7c31a4
          case '[':
Packit Service 7c31a4
            ansi_parser_state = ANSI_CSI;
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argc = 0;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case '^':
Packit Service 7c31a4
          case '_':
Packit Service 7c31a4
          case 'P':
Packit Service 7c31a4
          case ']':
Packit Service 7c31a4
            /* Not supported, but we'll have to parse until we see a stop code,
Packit Service 7c31a4
             * e. g. ESC \ or BEL. */
Packit Service 7c31a4
            ansi_parser_state = ANSI_ST_CONTROL;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case '\033':
Packit Service 7c31a4
            /* Ignore double escape. */
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case 'c':
Packit Service 7c31a4
            /* Full console reset. */
Packit Service 7c31a4
            FLUSH_TEXT();
Packit Service 7c31a4
            uv_tty_reset(handle, error);
Packit Service 7c31a4
            ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case '7':
Packit Service 7c31a4
            /* Save the cursor position and text attributes. */
Packit Service 7c31a4
            FLUSH_TEXT();
Packit Service 7c31a4
            uv_tty_save_state(handle, 1, error);
Packit Service 7c31a4
            ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          case '8':
Packit Service 7c31a4
            /* Restore the cursor position and text attributes */
Packit Service 7c31a4
            FLUSH_TEXT();
Packit Service 7c31a4
            uv_tty_restore_state(handle, 1, error);
Packit Service 7c31a4
            ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          default:
Packit Service 7c31a4
            if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
Packit Service 7c31a4
              /* Single-char control. */
Packit Service 7c31a4
              ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
              continue;
Packit Service 7c31a4
            } else {
Packit Service 7c31a4
              /* Invalid - proceed as normal, */
Packit Service 7c31a4
              ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
            }
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (ansi_parser_state == ANSI_IGNORE) {
Packit Service 7c31a4
        /* We're ignoring this command. Stop only on command character. */
Packit Service 7c31a4
        if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service 7c31a4
          ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (ansi_parser_state == ANSI_DECSCUSR) {
Packit Service 7c31a4
        /* So far we've the sequence `ESC [ arg space`, and we're waiting for
Packit Service 7c31a4
         * the final command byte. */
Packit Service 7c31a4
        if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service 7c31a4
          /* Command byte */
Packit Service 7c31a4
          if (utf8_codepoint == 'q') {
Packit Service 7c31a4
            /* Change the cursor shape */
Packit Service 7c31a4
            int style = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
              ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit Service 7c31a4
            if (style >= 0 && style <= 6) {
Packit Service 7c31a4
              FLUSH_TEXT();
Packit Service 7c31a4
              uv_tty_set_cursor_shape(handle, style, error);
Packit Service 7c31a4
            }
Packit Service 7c31a4
          }
Packit Service 7c31a4
Packit Service 7c31a4
          /* Sequence ended - go back to normal state. */
Packit Service 7c31a4
          ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        /* Unexpected character, but sequence hasn't ended yet. Ignore the rest
Packit Service 7c31a4
         * of the sequence. */
Packit Service 7c31a4
        ansi_parser_state = ANSI_IGNORE;
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (ansi_parser_state & ANSI_CSI) {
Packit Service 7c31a4
        /* So far we've seen `ESC [`, and we may or may not have already parsed
Packit Service 7c31a4
         * some of the arguments that follow. */
Packit Service 7c31a4
Packit Service 7c31a4
        if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
Packit Service 7c31a4
          /* Parse a numerical argument. */
Packit Service 7c31a4
          if (!(ansi_parser_state & ANSI_IN_ARG)) {
Packit Service 7c31a4
            /* We were not currently parsing a number, add a new one. */
Packit Service 7c31a4
            /* Check for that there are too many arguments. */
Packit Service 7c31a4
            if (handle->tty.wr.ansi_csi_argc >=
Packit Service 7c31a4
                ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
Packit Service 7c31a4
              ansi_parser_state = ANSI_IGNORE;
Packit Service 7c31a4
              continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
            ansi_parser_state |= ANSI_IN_ARG;
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argc++;
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
Packit Service 7c31a4
                (unsigned short) utf8_codepoint - '0';
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            /* We were already parsing a number. Parse next digit. */
Packit Service 7c31a4
            uint32_t value = 10 *
Packit Service 7c31a4
                handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
Packit Service 7c31a4
Packit Service 7c31a4
            /* Check for overflow. */
Packit Service 7c31a4
            if (value > UINT16_MAX) {
Packit Service 7c31a4
              ansi_parser_state = ANSI_IGNORE;
Packit Service 7c31a4
              continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
Packit Service 7c31a4
                (unsigned short) value + (utf8_codepoint - '0');
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
          }
Packit Service 7c31a4
Packit Service 7c31a4
        } else if (utf8_codepoint == ';') {
Packit Service 7c31a4
          /* Denotes the end of an argument. */
Packit Service 7c31a4
          if (ansi_parser_state & ANSI_IN_ARG) {
Packit Service 7c31a4
            ansi_parser_state &= ~ANSI_IN_ARG;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            /* If ANSI_IN_ARG is not set, add another argument and default
Packit Service 7c31a4
             * it to 0. */
Packit Service 7c31a4
Packit Service 7c31a4
            /* Check for too many arguments */
Packit Service 7c31a4
            if (handle->tty.wr.ansi_csi_argc >=
Packit Service 7c31a4
Packit Service 7c31a4
                ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
Packit Service 7c31a4
              ansi_parser_state = ANSI_IGNORE;
Packit Service 7c31a4
              continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argc++;
Packit Service 7c31a4
            handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
          }
Packit Service 7c31a4
Packit Service 7c31a4
        } else if (utf8_codepoint == '?' &&
Packit Service 7c31a4
                   !(ansi_parser_state & ANSI_IN_ARG) &&
Packit Service 7c31a4
                   !(ansi_parser_state & ANSI_EXTENSION) &&
Packit Service 7c31a4
                   handle->tty.wr.ansi_csi_argc == 0) {
Packit Service 7c31a4
          /* Pass through '?' if it is the first character after CSI */
Packit Service 7c31a4
          /* This is an extension character from the VT100 codeset */
Packit Service 7c31a4
          /* that is supported and used by most ANSI terminals today. */
Packit Service 7c31a4
          ansi_parser_state |= ANSI_EXTENSION;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
Packit Service 7c31a4
        } else if (utf8_codepoint == ' ' &&
Packit Service 7c31a4
                   !(ansi_parser_state & ANSI_EXTENSION)) {
Packit Service 7c31a4
          /* We expect a command byte to follow after this space. The only
Packit Service 7c31a4
           * command that we current support is 'set cursor style'. */
Packit Service 7c31a4
          ansi_parser_state = ANSI_DECSCUSR;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
Packit Service 7c31a4
        } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
Packit Service 7c31a4
          /* Command byte */
Packit Service 7c31a4
          if (ansi_parser_state & ANSI_EXTENSION) {
Packit Service 7c31a4
            /* Sequence is `ESC [ ? args command`. */
Packit Service 7c31a4
            switch (utf8_codepoint) {
Packit Service 7c31a4
              case 'l':
Packit Service 7c31a4
                /* Hide the cursor */
Packit Service 7c31a4
                if (handle->tty.wr.ansi_csi_argc == 1 &&
Packit Service 7c31a4
                    handle->tty.wr.ansi_csi_argv[0] == 25) {
Packit Service 7c31a4
                  FLUSH_TEXT();
Packit Service 7c31a4
                  uv_tty_set_cursor_visibility(handle, 0, error);
Packit Service 7c31a4
                }
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'h':
Packit Service 7c31a4
                /* Show the cursor */
Packit Service 7c31a4
                if (handle->tty.wr.ansi_csi_argc == 1 &&
Packit Service 7c31a4
                    handle->tty.wr.ansi_csi_argv[0] == 25) {
Packit Service 7c31a4
                  FLUSH_TEXT();
Packit Service 7c31a4
                  uv_tty_set_cursor_visibility(handle, 1, error);
Packit Service 7c31a4
                }
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            /* Sequence is `ESC [ args command`. */
Packit Service 7c31a4
            int x, y, d;
Packit Service 7c31a4
            switch (utf8_codepoint) {
Packit Service 7c31a4
              case 'A':
Packit Service 7c31a4
                /* cursor up */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                y = -(handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit Service 7c31a4
                uv_tty_move_caret(handle, 0, 1, y, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'B':
Packit Service 7c31a4
                /* cursor down */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                y = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit Service 7c31a4
                uv_tty_move_caret(handle, 0, 1, y, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'C':
Packit Service 7c31a4
                /* cursor forward */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                x = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit Service 7c31a4
                uv_tty_move_caret(handle, x, 1, 0, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'D':
Packit Service 7c31a4
                /* cursor back */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                x = -(handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit Service 7c31a4
                uv_tty_move_caret(handle, x, 1, 0, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'E':
Packit Service 7c31a4
                /* cursor next line */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                y = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1;
Packit Service 7c31a4
                uv_tty_move_caret(handle, 0, 0, y, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'F':
Packit Service 7c31a4
                /* cursor previous line */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                y = -(handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 1);
Packit Service 7c31a4
                uv_tty_move_caret(handle, 0, 0, y, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'G':
Packit Service 7c31a4
                /* cursor horizontal move absolute */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                x = (handle->tty.wr.ansi_csi_argc >= 1 &&
Packit Service 7c31a4
                     handle->tty.wr.ansi_csi_argv[0])
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
Packit Service 7c31a4
                uv_tty_move_caret(handle, x, 0, 0, 1, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'H':
Packit Service 7c31a4
              case 'f':
Packit Service 7c31a4
                /* cursor move absolute */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                y = (handle->tty.wr.ansi_csi_argc >= 1 &&
Packit Service 7c31a4
                     handle->tty.wr.ansi_csi_argv[0])
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
Packit Service 7c31a4
                x = (handle->tty.wr.ansi_csi_argc >= 2 &&
Packit Service 7c31a4
                     handle->tty.wr.ansi_csi_argv[1])
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
Packit Service 7c31a4
                uv_tty_move_caret(handle, x, 0, y, 0, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'J':
Packit Service 7c31a4
                /* Erase screen */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                d = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 0;
Packit Service 7c31a4
                if (d >= 0 && d <= 2) {
Packit Service 7c31a4
                  uv_tty_clear(handle, d, 1, error);
Packit Service 7c31a4
                }
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'K':
Packit Service 7c31a4
                /* Erase line */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                d = handle->tty.wr.ansi_csi_argc
Packit Service 7c31a4
                  ? handle->tty.wr.ansi_csi_argv[0] : 0;
Packit Service 7c31a4
                if (d >= 0 && d <= 2) {
Packit Service 7c31a4
                  uv_tty_clear(handle, d, 0, error);
Packit Service 7c31a4
                }
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'm':
Packit Service 7c31a4
                /* Set style */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                uv_tty_set_style(handle, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 's':
Packit Service 7c31a4
                /* Save the cursor position. */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                uv_tty_save_state(handle, 0, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
Packit Service 7c31a4
              case 'u':
Packit Service 7c31a4
                /* Restore the cursor position */
Packit Service 7c31a4
                FLUSH_TEXT();
Packit Service 7c31a4
                uv_tty_restore_state(handle, 0, error);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
          }
Packit Service 7c31a4
Packit Service 7c31a4
          /* Sequence ended - go back to normal state. */
Packit Service 7c31a4
          ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          /* We don't support commands that use private mode characters or
Packit Service 7c31a4
           * intermediaries. Ignore the rest of the sequence. */
Packit Service 7c31a4
          ansi_parser_state = ANSI_IGNORE;
Packit Service 7c31a4
          continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (ansi_parser_state & ANSI_ST_CONTROL) {
Packit Service 7c31a4
        /* Unsupported control code.
Packit Service 7c31a4
         * Ignore everything until we see `BEL` or `ESC \`. */
Packit Service 7c31a4
        if (ansi_parser_state & ANSI_IN_STRING) {
Packit Service 7c31a4
          if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
Packit Service 7c31a4
            if (utf8_codepoint == '"') {
Packit Service 7c31a4
              ansi_parser_state &= ~ANSI_IN_STRING;
Packit Service 7c31a4
            } else if (utf8_codepoint == '\\') {
Packit Service 7c31a4
              ansi_parser_state |= ANSI_BACKSLASH_SEEN;
Packit Service 7c31a4
            }
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
Packit Service 7c31a4
          }
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
Packit Service 7c31a4
              (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
Packit Service 7c31a4
            /* End of sequence */
Packit Service 7c31a4
            ansi_parser_state = ANSI_NORMAL;
Packit Service 7c31a4
          } else if (utf8_codepoint == '\033') {
Packit Service 7c31a4
            /* Escape character */
Packit Service 7c31a4
            ansi_parser_state |= ANSI_ESCAPE_SEEN;
Packit Service 7c31a4
          } else if (utf8_codepoint == '"') {
Packit Service 7c31a4
             /* String starting */
Packit Service 7c31a4
            ansi_parser_state |= ANSI_IN_STRING;
Packit Service 7c31a4
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
Packit Service 7c31a4
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
Packit Service 7c31a4
          } else {
Packit Service 7c31a4
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
Packit Service 7c31a4
          }
Packit Service 7c31a4
        }
Packit Service 7c31a4
        continue;
Packit Service 7c31a4
      } else {
Packit Service 7c31a4
        /* Inconsistent state */
Packit Service 7c31a4
        abort();
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
Packit Service 7c31a4
        /* EOL conversion - emit \r\n when we see \n. */
Packit Service 7c31a4
Packit Service 7c31a4
        if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
Packit Service 7c31a4
          /* \n was not preceded by \r; print \r\n. */
Packit Service 7c31a4
          ENSURE_BUFFER_SPACE(2);
Packit Service 7c31a4
          utf16_buf[utf16_buf_used++] = L'\r';
Packit Service 7c31a4
          utf16_buf[utf16_buf_used++] = L'\n';
Packit Service 7c31a4
        } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
Packit Service 7c31a4
          /* \n was followed by \r; do not print the \r, since the source was
Packit Service 7c31a4
           * either \r\n\r (so the second \r is redundant) or was \n\r (so the
Packit Service 7c31a4
           * \n was processed by the last case and an \r automatically
Packit Service 7c31a4
           * inserted). */
Packit Service 7c31a4
        } else {
Packit Service 7c31a4
          /* \r without \n; print \r as-is. */
Packit Service 7c31a4
          ENSURE_BUFFER_SPACE(1);
Packit Service 7c31a4
          utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        previous_eol = (char) utf8_codepoint;
Packit Service 7c31a4
Packit Service 7c31a4
      } else if (utf8_codepoint <= 0xffff) {
Packit Service 7c31a4
        /* Encode character into utf-16 buffer. */
Packit Service 7c31a4
        ENSURE_BUFFER_SPACE(1);
Packit Service 7c31a4
        utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
Packit Service 7c31a4
        previous_eol = 0;
Packit Service e2ebee
      } else {
Packit Service e2ebee
        ENSURE_BUFFER_SPACE(2);
Packit Service e2ebee
        utf8_codepoint -= 0x10000;
Packit Service e2ebee
        utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800);
Packit Service e2ebee
        utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00);
Packit Service e2ebee
        previous_eol = 0;
Packit Service 7c31a4
      }
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Flush remaining characters */
Packit Service 7c31a4
  FLUSH_TEXT();
Packit Service 7c31a4
Packit Service 7c31a4
  /* Copy cached values back to struct. */
Packit Service 7c31a4
  handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
Packit Service 7c31a4
  handle->tty.wr.utf8_codepoint = utf8_codepoint;
Packit Service 7c31a4
  handle->tty.wr.previous_eol = previous_eol;
Packit Service 7c31a4
  handle->tty.wr.ansi_parser_state = ansi_parser_state;
Packit Service 7c31a4
Packit Service 7c31a4
  uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
Packit Service 7c31a4
  if (*error == STATUS_SUCCESS) {
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    return -1;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
#undef FLUSH_TEXT
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_write(uv_loop_t* loop,
Packit Service 7c31a4
                 uv_write_t* req,
Packit Service 7c31a4
                 uv_tty_t* handle,
Packit Service 7c31a4
                 const uv_buf_t bufs[],
Packit Service 7c31a4
                 unsigned int nbufs,
Packit Service 7c31a4
                 uv_write_cb cb) {
Packit Service 7c31a4
  DWORD error;
Packit Service 7c31a4
Packit Service 7c31a4
  UV_REQ_INIT(req, UV_WRITE);
Packit Service 7c31a4
  req->handle = (uv_stream_t*) handle;
Packit Service 7c31a4
  req->cb = cb;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->reqs_pending++;
Packit Service 7c31a4
  handle->stream.conn.write_reqs_pending++;
Packit Service 7c31a4
  REGISTER_HANDLE_REQ(loop, handle, req);
Packit Service 7c31a4
Packit Service 7c31a4
  req->u.io.queued_bytes = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
Packit Service 7c31a4
    SET_REQ_SUCCESS(req);
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    SET_REQ_ERROR(req, error);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_insert_pending_req(loop, (uv_req_t*) req);
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv__tty_try_write(uv_tty_t* handle,
Packit Service 7c31a4
                      const uv_buf_t bufs[],
Packit Service 7c31a4
                      unsigned int nbufs) {
Packit Service 7c31a4
  DWORD error;
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->stream.conn.write_reqs_pending > 0)
Packit Service 7c31a4
    return UV_EAGAIN;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
Packit Service 7c31a4
    return uv_translate_sys_error(error);
Packit Service 7c31a4
Packit Service 7c31a4
  return uv__count_bufs(bufs, nbufs);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
  uv_write_t* req) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->write_queue_size -= req->u.io.queued_bytes;
Packit Service 7c31a4
  UNREGISTER_HANDLE_REQ(loop, handle, req);
Packit Service 7c31a4
Packit Service 7c31a4
  if (req->cb) {
Packit Service 7c31a4
    err = GET_REQ_ERROR(req);
Packit Service 7c31a4
    req->cb(req, uv_translate_sys_error(err));
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  handle->stream.conn.write_reqs_pending--;
Packit Service 7c31a4
  if (handle->stream.conn.shutdown_req != NULL &&
Packit Service 7c31a4
      handle->stream.conn.write_reqs_pending == 0) {
Packit Service 7c31a4
    uv_want_endgame(loop, (uv_handle_t*)handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  DECREASE_PENDING_REQ_COUNT(handle);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_tty_close(uv_tty_t* handle) {
Packit Service 7c31a4
  assert(handle->u.fd == -1 || handle->u.fd > 2);
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_READING)
Packit Service 7c31a4
    uv_tty_read_stop(handle);
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->u.fd == -1)
Packit Service 7c31a4
    CloseHandle(handle->handle);
Packit Service 7c31a4
  else
Packit Service 7c31a4
    close(handle->u.fd);
Packit Service 7c31a4
Packit Service 7c31a4
  handle->u.fd = -1;
Packit Service 7c31a4
  handle->handle = INVALID_HANDLE_VALUE;
Packit Service 7c31a4
  handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
Packit Service 7c31a4
  uv__handle_closing(handle);
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->reqs_pending == 0) {
Packit Service 7c31a4
    uv_want_endgame(handle->loop, (uv_handle_t*) handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
Packit Service 7c31a4
  if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
Packit Service 7c31a4
      handle->stream.conn.shutdown_req != NULL &&
Packit Service 7c31a4
      handle->stream.conn.write_reqs_pending == 0) {
Packit Service 7c31a4
    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
Packit Service 7c31a4
Packit Service 7c31a4
    /* TTY shutdown is really just a no-op */
Packit Service 7c31a4
    if (handle->stream.conn.shutdown_req->cb) {
Packit Service 7c31a4
      if (handle->flags & UV_HANDLE_CLOSING) {
Packit Service 7c31a4
        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
Packit Service 7c31a4
      } else {
Packit Service 7c31a4
        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
Packit Service 7c31a4
      }
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    handle->stream.conn.shutdown_req = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
    DECREASE_PENDING_REQ_COUNT(handle);
Packit Service 7c31a4
    return;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_CLOSING &&
Packit Service 7c31a4
      handle->reqs_pending == 0) {
Packit Service 7c31a4
    /* The wait handle used for raw reading should be unregistered when the
Packit Service 7c31a4
     * wait callback runs. */
Packit Service 7c31a4
    assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
Packit Service 7c31a4
           handle->tty.rd.read_raw_wait == NULL);
Packit Service 7c31a4
Packit Service 7c31a4
    assert(!(handle->flags & UV_HANDLE_CLOSED));
Packit Service 7c31a4
    uv__handle_close(handle);
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/*
Packit Service 7c31a4
 * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
Packit Service 7c31a4
 * TODO: find a way to remove it
Packit Service 7c31a4
 */
Packit Service 7c31a4
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
    uv_req_t* raw_req) {
Packit Service 7c31a4
  abort();
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/*
Packit Service 7c31a4
 * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
Packit Service 7c31a4
 * TODO: find a way to remove it
Packit Service 7c31a4
 */
Packit Service 7c31a4
void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
Packit Service 7c31a4
    uv_connect_t* req) {
Packit Service 7c31a4
  abort();
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_reset_mode(void) {
Packit Service 7c31a4
  /* Not necessary to do anything. */
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
/* Determine whether or not this version of windows supports
Packit Service 7c31a4
 * proper ANSI color codes. Should be supported as of windows
Packit Service 7c31a4
 * 10 version 1511, build number 10.0.10586.
Packit Service 7c31a4
 */
Packit Service 7c31a4
static void uv__determine_vterm_state(HANDLE handle) {
Packit Service 7c31a4
  DWORD dwMode = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  uv__need_check_vterm_state = FALSE;
Packit Service 7c31a4
  if (!GetConsoleMode(handle, &dwMode)) {
Packit Service 7c31a4
    return;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
Packit Service 7c31a4
  if (!SetConsoleMode(handle, dwMode)) {
Packit Service 7c31a4
    return;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv__vterm_state = UV_TTY_SUPPORTED;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
Packit Service 7c31a4
  NTSTATUS status;
Packit Service 7c31a4
  ULONG_PTR conhost_pid;
Packit Service 7c31a4
  MSG msg;
Packit Service 7c31a4
Packit Service 7c31a4
  if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
Packit Service 7c31a4
  status = pNtQueryInformationProcess(GetCurrentProcess(),
Packit Service 7c31a4
                                      ProcessConsoleHostProcess,
Packit Service 7c31a4
                                      &conhost_pid,
Packit Service 7c31a4
                                      sizeof(conhost_pid),
Packit Service 7c31a4
                                      NULL);
Packit Service 7c31a4
Packit Service 7c31a4
  if (!NT_SUCCESS(status)) {
Packit Service 7c31a4
    /* We couldn't retrieve our console host process, probably because this
Packit Service 7c31a4
     * is a 32-bit process running on 64-bit Windows. Fall back to receiving
Packit Service 7c31a4
     * console events from the input stream only. */
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
Packit Service 7c31a4
  conhost_pid &= ~(ULONG_PTR)0x3;
Packit Service 7c31a4
Packit Service 7c31a4
  uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit Service 7c31a4
  if (uv__tty_console_resized == NULL)
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread,
Packit Service 7c31a4
                        NULL,
Packit Service 7c31a4
                        WT_EXECUTELONGFUNCTION) == 0)
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
Packit Service 7c31a4
                        EVENT_CONSOLE_LAYOUT,
Packit Service 7c31a4
                        NULL,
Packit Service 7c31a4
                        uv__tty_console_resize_event,
Packit Service 7c31a4
                        (DWORD)conhost_pid,
Packit Service 7c31a4
                        0,
Packit Service 7c31a4
                        WINEVENT_OUTOFCONTEXT))
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
Packit Service 7c31a4
  while (GetMessage(&msg, NULL, 0, 0)) {
Packit Service 7c31a4
    TranslateMessage(&msg;;
Packit Service 7c31a4
    DispatchMessage(&msg;;
Packit Service 7c31a4
  }
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
Packit Service 7c31a4
                                                  DWORD event,
Packit Service 7c31a4
                                                  HWND hwnd,
Packit Service 7c31a4
                                                  LONG idObject,
Packit Service 7c31a4
                                                  LONG idChild,
Packit Service 7c31a4
                                                  DWORD dwEventThread,
Packit Service 7c31a4
                                                  DWORD dwmsEventTime) {
Packit Service 7c31a4
  SetEvent(uv__tty_console_resized);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
Packit Service 7c31a4
  for (;;) {
Packit Service 7c31a4
    /* Make sure to not overwhelm the system with resize events */
Packit Service 7c31a4
    Sleep(33);
Packit Service 7c31a4
    WaitForSingleObject(uv__tty_console_resized, INFINITE);
Packit Service 7c31a4
    uv__tty_console_signal_resize();
Packit Service 7c31a4
    ResetEvent(uv__tty_console_resized);
Packit Service 7c31a4
  }
Packit Service e2ebee
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static void uv__tty_console_signal_resize(void) {
Packit Service 7c31a4
  CONSOLE_SCREEN_BUFFER_INFO sb_info;
Packit Service 7c31a4
  int width, height;
Packit Service 7c31a4
Packit Service 7c31a4
  if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
Packit Service 7c31a4
    return;
Packit Service 7c31a4
Packit Service 7c31a4
  width = sb_info.dwSize.X;
Packit Service 7c31a4
  height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
Packit Service 7c31a4
Packit Service 7c31a4
  uv_mutex_lock(&uv__tty_console_resize_mutex);
Packit Service 7c31a4
  assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
Packit Service 7c31a4
  if (width != uv__tty_console_width || height != uv__tty_console_height) {
Packit Service 7c31a4
    uv__tty_console_width = width;
Packit Service 7c31a4
    uv__tty_console_height = height;
Packit Service 7c31a4
    uv_mutex_unlock(&uv__tty_console_resize_mutex);
Packit Service 7c31a4
    uv__signal_dispatch(SIGWINCH);
Packit Service 7c31a4
  } else {
Packit Service 7c31a4
    uv_mutex_unlock(&uv__tty_console_resize_mutex);
Packit Service 7c31a4
  }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
  uv__need_check_vterm_state = FALSE;
Packit Service 7c31a4
  uv__vterm_state = state;
Packit Service 7c31a4
  uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
Packit Service 7c31a4
  uv_sem_wait(&uv_tty_output_lock);
Packit Service 7c31a4
  *state = uv__vterm_state;
Packit Service 7c31a4
  uv_sem_post(&uv_tty_output_lock);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}