Alien-uv

 view release on metacpan or  search on metacpan

libuv/src/win/tty.c  view on Meta::CPAN

                         &handle,
                         0,
                         FALSE,
                         DUPLICATE_SAME_ACCESS))
      return uv_translate_sys_error(GetLastError());
    fd = -1;
  }

  readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
  if (!readable) {
    /* Obtain the screen buffer info with the output handle. */
    if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
      return uv_translate_sys_error(GetLastError());
    }

    /* Obtain the tty_output_lock because the virtual window state is shared
     * between all uv_tty_t handles. */
    uv_sem_wait(&uv_tty_output_lock);

    if (uv__vterm_state == UV_UNCHECKED)
      uv__determine_vterm_state(handle);

    /* Remember the original console text attributes. */
    uv_tty_capture_initial_style(&screen_buffer_info);

    uv_tty_update_virtual_window(&screen_buffer_info);

    uv_sem_post(&uv_tty_output_lock);
  }


  uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
  uv_connection_init((uv_stream_t*) tty);

  tty->handle = handle;
  tty->u.fd = fd;
  tty->reqs_pending = 0;
  tty->flags |= UV_HANDLE_BOUND;

  if (readable) {
    /* Initialize TTY input specific fields. */
    tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
    /* TODO: remove me in v2.x. */
    tty->tty.rd.unused_ = NULL;
    tty->tty.rd.read_line_buffer = uv_null_buf_;
    tty->tty.rd.read_raw_wait = NULL;

    /* Init keycode-to-vt100 mapper state. */
    tty->tty.rd.last_key_len = 0;
    tty->tty.rd.last_key_offset = 0;
    tty->tty.rd.last_utf16_high_surrogate = 0;
    memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
  } else {
    /* TTY output specific fields. */
    tty->flags |= UV_HANDLE_WRITABLE;

    /* Init utf8-to-utf16 conversion state. */
    tty->tty.wr.utf8_bytes_left = 0;
    tty->tty.wr.utf8_codepoint = 0;

    /* Initialize eol conversion state */
    tty->tty.wr.previous_eol = 0;

    /* Init ANSI parser state. */
    tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
  }

  return 0;
}


/* Set the default console text attributes based on how the console was
 * configured when libuv started.
 */
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
  static int style_captured = 0;

  /* Only do this once.
     Assumption: Caller has acquired uv_tty_output_lock. */
  if (style_captured)
    return;

  /* Save raw win32 attributes. */
  uv_tty_default_text_attributes = info->wAttributes;

  /* Convert black text on black background to use white text. */
  if (uv_tty_default_text_attributes == 0)
    uv_tty_default_text_attributes = 7;

  /* Convert Win32 attributes to ANSI colors. */
  uv_tty_default_fg_color = 0;
  uv_tty_default_bg_color = 0;
  uv_tty_default_fg_bright = 0;
  uv_tty_default_bg_bright = 0;
  uv_tty_default_inverse = 0;

  if (uv_tty_default_text_attributes & FOREGROUND_RED)
    uv_tty_default_fg_color |= 1;

  if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
    uv_tty_default_fg_color |= 2;

  if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
    uv_tty_default_fg_color |= 4;

  if (uv_tty_default_text_attributes & BACKGROUND_RED)
    uv_tty_default_bg_color |= 1;

  if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
    uv_tty_default_bg_color |= 2;

  if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
    uv_tty_default_bg_color |= 4;

  if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
    uv_tty_default_fg_bright = 1;

  if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
    uv_tty_default_bg_bright = 1;

  if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
    uv_tty_default_inverse = 1;

libuv/src/win/tty.c  view on Meta::CPAN

}

static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
                                        BOOL visible,
                                        DWORD* error) {
  CONSOLE_CURSOR_INFO cursor_info;

  if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
    *error = GetLastError();
    return -1;
  }

  cursor_info.bVisible = visible;

  if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
    *error = GetLastError();
    return -1;
  }

  return 0;
}

static int uv_tty_write_bufs(uv_tty_t* handle,
                             const uv_buf_t bufs[],
                             unsigned int nbufs,
                             DWORD* error) {
  /* We can only write 8k characters at a time. Windows can't handle much more
   * characters in a single console write anyway. */
  WCHAR utf16_buf[MAX_CONSOLE_CHAR];
  WCHAR* utf16_buffer;
  DWORD utf16_buf_used = 0;
  unsigned int i, len, max_len, pos;
  int allocate = 0;

#define FLUSH_TEXT()                                                 \
  do {                                                               \
    pos = 0;                                                         \
    do {                                                             \
      len = utf16_buf_used - pos;                                    \
      if (len > MAX_CONSOLE_CHAR)                                    \
        len = MAX_CONSOLE_CHAR;                                      \
      uv_tty_emit_text(handle, &utf16_buffer[pos], len, error);      \
      pos += len;                                                    \
    } while (pos < utf16_buf_used);                                  \
    if (allocate) {                                                  \
      uv__free(utf16_buffer);                                        \
      allocate = 0;                                                  \
      utf16_buffer = utf16_buf;                                      \
    }                                                                \
    utf16_buf_used = 0;                                              \
 } while (0)

#define ENSURE_BUFFER_SPACE(wchars_needed)                          \
  if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
    FLUSH_TEXT();                                                   \
  }

  /* Cache for fast access */
  unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
  unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
  unsigned char previous_eol = handle->tty.wr.previous_eol;
  unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;

  /* Store the error here. If we encounter an error, stop trying to do i/o but
   * keep parsing the buffer so we leave the parser in a consistent state. */
  *error = ERROR_SUCCESS;

  utf16_buffer = utf16_buf;

  uv_sem_wait(&uv_tty_output_lock);

  for (i = 0; i < nbufs; i++) {
    uv_buf_t buf = bufs[i];
    unsigned int j;

    if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
      utf16_buf_used = MultiByteToWideChar(CP_UTF8,
                                           0,
                                           buf.base,
                                           buf.len,
                                           NULL,
                                           0);

      if (utf16_buf_used == 0) {
        *error = GetLastError();
        break;
      }

      max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
      allocate = max_len > MAX_CONSOLE_CHAR;
      if (allocate)
        utf16_buffer = uv__malloc(max_len);
      if (!MultiByteToWideChar(CP_UTF8,
                               0,
                               buf.base,
                               buf.len,
                               utf16_buffer,
                               utf16_buf_used)) {
        if (allocate)
          uv__free(utf16_buffer);
        *error = GetLastError();
        break;
      }

      FLUSH_TEXT();

      continue;
    }

    for (j = 0; j < buf.len; j++) {
      unsigned char c = buf.base[j];

      /* Run the character through the utf8 decoder We happily accept non
       * shortest form encodings and invalid code points - there's no real harm
       * that can be done. */
      if (utf8_bytes_left == 0) {
        /* Read utf-8 start byte */
        DWORD first_zero_bit;
        unsigned char not_c = ~c;
#ifdef _MSC_VER /* msvc */
        if (_BitScanReverse(&first_zero_bit, not_c)) {

libuv/src/win/tty.c  view on Meta::CPAN

          } else {
            /* We don't support commands that use private mode characters or
             * intermediaries. Ignore the rest of the sequence. */
            ansi_parser_state |= ANSI_IGNORE;
            continue;
          }
        } else {
          /* We're ignoring this command. Stop only on command character. */
          if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
            ansi_parser_state = ANSI_NORMAL;
          }
          continue;
        }

      } else if (ansi_parser_state & ANSI_ST_CONTROL) {
        /* Unsupported control code.
         * Ignore everything until we see `BEL` or `ESC \`. */
        if (ansi_parser_state & ANSI_IN_STRING) {
          if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
            if (utf8_codepoint == '"') {
              ansi_parser_state &= ~ANSI_IN_STRING;
            } else if (utf8_codepoint == '\\') {
              ansi_parser_state |= ANSI_BACKSLASH_SEEN;
            }
          } else {
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
          }
        } else {
          if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
              (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
            /* End of sequence */
            ansi_parser_state = ANSI_NORMAL;
          } else if (utf8_codepoint == '\033') {
            /* Escape character */
            ansi_parser_state |= ANSI_ESCAPE_SEEN;
          } else if (utf8_codepoint == '"') {
             /* String starting */
            ansi_parser_state |= ANSI_IN_STRING;
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
            ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
          } else {
            ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
          }
        }
        continue;
      } else {
        /* Inconsistent state */
        abort();
      }

      /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
       * console doesn't really support UTF-16, so just emit the replacement
       * character. */
      if (utf8_codepoint > 0xffff) {
        utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
      }

      if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
        /* EOL conversion - emit \r\n when we see \n. */

        if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
          /* \n was not preceded by \r; print \r\n. */
          ENSURE_BUFFER_SPACE(2);
          utf16_buf[utf16_buf_used++] = L'\r';
          utf16_buf[utf16_buf_used++] = L'\n';
        } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
          /* \n was followed by \r; do not print the \r, since the source was
           * either \r\n\r (so the second \r is redundant) or was \n\r (so the
           * \n was processed by the last case and an \r automatically
           * inserted). */
        } else {
          /* \r without \n; print \r as-is. */
          ENSURE_BUFFER_SPACE(1);
          utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
        }

        previous_eol = (char) utf8_codepoint;

      } else if (utf8_codepoint <= 0xffff) {
        /* Encode character into utf-16 buffer. */
        ENSURE_BUFFER_SPACE(1);
        utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
        previous_eol = 0;
      }
    }
  }

  /* Flush remaining characters */
  FLUSH_TEXT();

  /* Copy cached values back to struct. */
  handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
  handle->tty.wr.utf8_codepoint = utf8_codepoint;
  handle->tty.wr.previous_eol = previous_eol;
  handle->tty.wr.ansi_parser_state = ansi_parser_state;

  uv_sem_post(&uv_tty_output_lock);

  if (*error == STATUS_SUCCESS) {
    return 0;
  } else {
    return -1;
  }

#undef FLUSH_TEXT
}


int uv_tty_write(uv_loop_t* loop,
                 uv_write_t* req,
                 uv_tty_t* handle,
                 const uv_buf_t bufs[],
                 unsigned int nbufs,
                 uv_write_cb cb) {
  DWORD error;

  UV_REQ_INIT(req, UV_WRITE);
  req->handle = (uv_stream_t*) handle;
  req->cb = cb;

  handle->reqs_pending++;
  handle->stream.conn.write_reqs_pending++;
  REGISTER_HANDLE_REQ(loop, handle, req);

  req->u.io.queued_bytes = 0;

  if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
    SET_REQ_SUCCESS(req);
  } else {
    SET_REQ_ERROR(req, error);
  }

  uv_insert_pending_req(loop, (uv_req_t*) req);

  return 0;
}


int uv__tty_try_write(uv_tty_t* handle,
                      const uv_buf_t bufs[],
                      unsigned int nbufs) {
  DWORD error;

  if (handle->stream.conn.write_reqs_pending > 0)
    return UV_EAGAIN;

  if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
    return uv_translate_sys_error(error);

  return uv__count_bufs(bufs, nbufs);
}


void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,



( run in 0.629 second using v1.01-cache-2.11-cpan-5a3173703d6 )