text: // This is an open source non-commercial project. Dear PVS-Studio, please check
  // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  
  #include <uv.h>
  
  #include "nvim/os/os.h"
  #include "nvim/os/pty_conpty_win.h"
  #include "nvim/vim.h"
  
  #ifndef EXTENDED_STARTUPINFO_PRESENT
  # define EXTENDED_STARTUPINFO_PRESENT 0x00080000
  #endif
  #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
  # define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
  #endif
  
  HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *);
  HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD);
  void (WINAPI *pClosePseudoConsole)(HPCON);
  
  bool os_has_conpty_working(void)
  {
    static TriState has_conpty = kNone;
    if (has_conpty == kNone) {
      has_conpty = os_dyn_conpty_init();
    }
  
    return has_conpty == kTrue;
  }
  
  TriState os_dyn_conpty_init(void)
  {
    uv_lib_t kernel;
    if (uv_dlopen("kernel32.dll", &kernel)) {
      uv_dlclose(&kernel);
      return kFalse;
    }
    static struct {
      char *name;
      FARPROC *ptr;
    } conpty_entry[] = {
      { "CreatePseudoConsole", (FARPROC *)&pCreatePseudoConsole },
      { "ResizePseudoConsole", (FARPROC *)&pResizePseudoConsole },
      { "ClosePseudoConsole", (FARPROC *)&pClosePseudoConsole },
      { NULL, NULL }
    };
    for (int i = 0;
         conpty_entry[i].name != NULL && conpty_entry[i].ptr != NULL; i++) {
      if (uv_dlsym(&kernel, conpty_entry[i].name, (void **)conpty_entry[i].ptr)) {
        uv_dlclose(&kernel);
        return kFalse;
      }
    }
    return kTrue;
  }
  
  conpty_t *os_conpty_init(char **in_name, char **out_name, uint16_t width, uint16_t height)
  {
    static int count = 0;
    conpty_t *conpty_object = xcalloc(1, sizeof(*conpty_object));
    const char *emsg = NULL;
    HANDLE in_read = INVALID_HANDLE_VALUE;
    HANDLE out_write = INVALID_HANDLE_VALUE;
    char buf[MAXPATHL];
    SECURITY_ATTRIBUTES sa = { 0 };
    const DWORD mode = PIPE_ACCESS_INBOUND
                       | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE;
  
    sa.nLength = sizeof(sa);
    snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-in-%d-%d",
             os_get_pid(), count);
    *in_name = xstrdup(buf);
    if ((in_read = CreateNamedPipeA(*in_name,
                                    mode,
                                    PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                                    1,
                                    0,
                                    0,
                                    30000,
                                    &sa)) == INVALID_HANDLE_VALUE) {
      emsg = "create input pipe failed";
      goto failed;
    }
    snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-out-%d-%d",
             os_get_pid(), count);
    *out_name = xstrdup(buf);
    if ((out_write = CreateNamedPipeA(*out_name,
                                      mode,
                                      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                                      1,
                                      0,
                                      0,
                                      30000,
                                      &sa)) == INVALID_HANDLE_VALUE) {
      emsg = "create output pipe failed";
      goto failed;
    }
    assert(width <= SHRT_MAX);
    assert(height <=  SHRT_MAX);
    COORD size = { (int16_t)width, (int16_t)height };
    HRESULT hr;
    hr = pCreatePseudoConsole(size, in_read, out_write, 0, &conpty_object->pty);
    if (FAILED(hr)) {
      emsg = "create pseudo console failed";
      goto failed;
    }
  
    conpty_object->si_ex.StartupInfo.cb = sizeof(conpty_object->si_ex);
    size_t bytes_required;
    InitializeProcThreadAttributeList(NULL, 1, 0,  & bytes_required);
    conpty_object->si_ex.lpAttributeList =
      (PPROC_THREAD_ATTRIBUTE_LIST)xmalloc(bytes_required);
    if (!InitializeProcThreadAttributeList(conpty_object->si_ex.lpAttributeList,
                                           1,
                                           0,
                                           &bytes_required)) {
      emsg = "InitializeProcThreadAttributeList failed";
      goto failed;
    }
    if (!UpdateProcThreadAttribute(conpty_object->si_ex.lpAttributeList,
                                   0,
                                   PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
                                   conpty_object->pty,
                                   sizeof(conpty_object->pty),
                                   NULL,
                                   NULL)) {
      emsg = "UpdateProcThreadAttribute failed";
      goto failed;
    }
    count++;
    goto finished;
  
  failed:
    ELOG("os_conpty_init:%s : error code: %d",
         emsg, os_translate_sys_error((int)GetLastError()));
    os_conpty_free(conpty_object);
    conpty_object = NULL;
  finished:
    if (in_read != INVALID_HANDLE_VALUE) {
      CloseHandle(in_read);
    }
    if (out_write != INVALID_HANDLE_VALUE) {
      CloseHandle(out_write);
    }
    return conpty_object;
  }
  
  bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *name,
                       wchar_t *cmd_line, wchar_t *cwd, wchar_t *env)
  {
    PROCESS_INFORMATION pi = { 0 };
    if (!CreateProcessW(name,
                        cmd_line,
                        NULL,
                        NULL,
                        false,
                        EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT,
                        env,
                        cwd,
                        &conpty_object->si_ex.StartupInfo,
                        &pi)) {
      return false;
    }
    *process_handle = pi.hProcess;
    return true;
  }
  
  void os_conpty_set_size(conpty_t *conpty_object, uint16_t width, uint16_t height)
  {
    assert(width <= SHRT_MAX);
    assert(height <= SHRT_MAX);
    COORD size = { (int16_t)width, (int16_t)height };
    if (pResizePseudoConsole(conpty_object->pty, size) != S_OK) {
      ELOG("ResizePseudoConsoel failed: error code: %d",
           os_translate_sys_error((int)GetLastError()));
    }
  }
  
  void os_conpty_free(conpty_t *conpty_object)
  {
    if (conpty_object != NULL) {
      if (conpty_object->si_ex.lpAttributeList != NULL) {
        DeleteProcThreadAttributeList(conpty_object->si_ex.lpAttributeList);
        xfree(conpty_object->si_ex.lpAttributeList);
      }
      if (conpty_object->pty != NULL) {
        pClosePseudoConsole(conpty_object->pty);
      }
    }
    xfree(conpty_object);
  }
  