Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

/* Replacement termios functions for MinGW32.  These versions of termios
   functions serialize over a pipe to another process, which adjusts
   the terminal.

   Copyright (C) 2008 CodeSourcery, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */


#include <windows.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#include "mingw-termios.h"

static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
static HANDLE pipe_mutex = INVALID_HANDLE_VALUE;

static int
link_to_wrapper (void)
{
  static int tried = 0;

  if (!tried)
    {
      char pipe_name[256];

      tried = 1;

      /* Connect to the named pipe for communication with the wrapper.  */
      sprintf (pipe_name, "\\\\.\\pipe\\gdb_wrapper_%ld",
               GetCurrentProcessId ());

      pipe_handle = CreateFile (pipe_name,
                                GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                0,
                                NULL);
      if (pipe_handle != INVALID_HANDLE_VALUE)
        pipe_mutex = CreateMutex (NULL, TRUE, NULL);
    }
  else if (pipe_mutex != INVALID_HANDLE_VALUE)
    WaitForSingleObject (pipe_mutex, INFINITE);

  return (pipe_handle != INVALID_HANDLE_VALUE);
}

static int
cygming_wrapper_cmd (const char *cmd, const void *args, int arglen, int *ret,
                     char **retdata)
{
  if (link_to_wrapper ())
    {
      static char buf[4096] = {0};
      int len = strlen (cmd) + 1;
      DWORD read;
      DWORD written;

      memcpy (buf, cmd, len);
      memcpy (buf + len, args, arglen);
      //fprintf (stderr, "%.8lx writing to the wrapper\n", GetCurrentThreadId ());
      if (!WriteFile (pipe_handle, buf, len + arglen, &written, NULL))
        {
          fprintf (stderr, "error writting to cygming wrapper: %ld\n", GetLastError ());
          fflush (stderr);
          ReleaseMutex (pipe_mutex);
          return 0;
        }

      if (!ReadFile (pipe_handle, buf, sizeof (buf), &read, NULL))
        {
          fprintf (stderr, "error waiting for cygming wrapper response: %ld",
                   GetLastError ());
          fflush (stderr);
          ReleaseMutex (pipe_mutex);
          return 0;
        }
      //fprintf (stderr, "%.8lx finished read from the wrapper\n", GetCurrentThreadId ());

      /* The returned value should be "OK" <number> ';' <bytes>.  */
      if (memcmp (buf, "OK", 2) != 0)
        {
          fprintf (stderr, "error: unexpected wrapper response: %s\n", buf);
          fflush (stderr);
          ReleaseMutex (pipe_mutex);
          return 0;
        }

      *ret = strtol (buf + 2, retdata, 0);
      (*retdata)++;
      ReleaseMutex (pipe_mutex);
      return 1;
    }
  else
    return 0;
}

int
tcgetattr (int fd, struct termios *buf)
{
  int ret;
  char *retdata;

  if (cygming_wrapper_cmd ("tcgetattr", "", 0, &ret, &retdata))
    {
      if (ret == 0)
        memcpy (buf, retdata, sizeof (*buf));
      else
        errno = EINVAL;
      return ret;
    }
  else
    {
      memset (buf, 0, sizeof (*buf));
      /* If FD is a TTY, readline will use getch for it, so we will
         must echo manually - getch does not echo.  If it is not a
         TTY, we must not echo since we have no way to disable the
         typical echo.  */

      if (isatty (fd))
        buf->c_lflag = ECHO;
      return 0;
    }
}

int
tcsetattr (int fd, int actions, const struct termios *buf)
{
  int ret;
  char *retdata;
  if (cygming_wrapper_cmd ("tcsetattr", buf, sizeof (*buf), &ret, &retdata))
    {
      if (ret != 0)
        errno = EINVAL;
      return ret;
    }
  else
    {
      errno = EINVAL;
      return -1;
    }
}

int
tcdrain (int fd)
{
  int ret;
  char *retdata;
  if (cygming_wrapper_cmd ("tcdrain", "", 0, &ret, &retdata))
    {
      if (ret != 0)
        errno = EINVAL;
      return ret;
    }
  else
    {
      errno = EINVAL;
      return -1;
    }
}

int
tcflow (int fd, int action)
{
  errno = ENOTTY;
  return -1;
}

int
mingw_getwinsize (struct winsize *window_size)
{
  int ret;
  char *retdata;
  if (cygming_wrapper_cmd ("getwinsize", "", 0, &ret, &retdata))
    {
      if (ret == 0)
        memcpy (window_size, retdata, sizeof (*window_size));
      else
        errno = EINVAL;
      return ret;
    }
  else
    {
      errno = EINVAL;
      return -1;
    }
}