/* 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};
DWORD read;
DWORD written;
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
());
ReleaseMutex (pipe_mutex);
return 0;
}
if (!ReadFile (pipe_handle, buf, sizeof (buf), &read, NULL))
{
fprintf (stderr
, "error waiting for cygming wrapper response: %ld",
GetLastError ());
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
);
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;
}
}