/* 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 . */
#include
#include
#include
#include
#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" ';' . */
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;
}
}