In the UNIX adapter, start the child process specified on the command line.

* Also propagate the UNIX environment to Win32.  This code doesn't really
   work because variables like PATH need path-translation, but I'd like to
   save a record of it before killing it off.
This commit is contained in:
Ryan Prichard 2012-03-24 16:48:41 -07:00
parent 32627354df
commit 5c185c1617
3 changed files with 101 additions and 16 deletions

12
Misc/ShowArgv.cc Normal file
View File

@ -0,0 +1,12 @@
// This test program is useful for studying commandline<->argv conversion.
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
printf("cmdline = [%s]\n", GetCommandLine());
for (int i = 0; i < argc; ++i)
printf("[%s]\n", argv[i]);
return 0;
}

View File

@ -345,6 +345,10 @@ PCONSOLE_API int pconsole_start_process(pconsole_t *pc,
}
p++;
envStr.assign(env, p);
// Can a Win32 environment be empty? If so, does it end with one NUL or
// two? Add an extra NUL just in case it matters.
envStr.push_back(L'\0');
}
packet.putWString(envStr);
writePacket(pc, packet);

View File

@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/select.h>
@ -31,6 +32,7 @@
#include <pthread.h>
#include <pconsole.h>
#include "../Shared/DebugClient.h"
#include <string>
static int signalWriteFd;
@ -49,19 +51,6 @@ static termios setRawTerminalMode()
exit(1);
}
/*
// This code makes the terminal output non-blocking.
int flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
if (flags == -1) {
perror("fcntl F_GETFL on stdout failed");
exit(1);
}
if (fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl F_SETFL on stdout failed");
exit(1);
}
*/
termios buf;
if (tcgetattr(STDIN_FILENO, &buf) < 0) {
perror("tcgetattr failed");
@ -221,8 +210,84 @@ static void setFdNonBlock(int fd)
fcntl(fd, F_SETFL, status | O_NONBLOCK);
}
int main()
// Convert argc/argv into a Win32 command-line following the escaping convention
// documented on MSDN. (e.g. see CommandLineToArgvW documentation)
static std::string argvToCommandLine(int argc, char *argv[])
{
std::string result;
for (int argIndex = 0; argIndex < argc; ++argIndex) {
if (argIndex > 0)
result.push_back(' ');
const char *arg = argv[argIndex];
bool quote = strchr(arg, ' ') != NULL || strchr(arg, '\"') != NULL;
if (quote)
result.push_back('\"');
int bsCount = 0;
for (const char *p = arg; *p != '\0'; ++p) {
if (*p == '\\') {
bsCount++;
} else if (*p == '\"') {
result.append(bsCount * 2 + 1, '\\');
result.push_back('\"');
bsCount = 0;
} else {
result.append(bsCount, '\\');
bsCount = 0;
result.push_back(*p);
}
}
if (quote) {
result.append(bsCount * 2, '\\');
result.push_back('\"');
} else {
result.append(bsCount, '\\');
}
}
return result;
}
// Convert the std::string to a std::wstring. The input string must not contain
// embedded NUL characters.
static std::wstring wstringFString(const std::string &text)
{
size_t len = mbstowcs(NULL, text.c_str(), 0);
assert(len != (size_t)-1);
wchar_t *tmp = new wchar_t[len + 1];
size_t len2 = mbstowcs(tmp, text.c_str(), len + 1);
assert(len == len2);
std::wstring ret(tmp);
delete [] tmp;
return ret;
}
// Convert the Cygwin/MSYS environment to a Win32 UNICODE environment block.
static std::wstring makeEnvironBlock()
{
std::wstring ret;
for (char **envp = environ; *envp != NULL; ++envp) {
char *env = *envp;
ret += wstringFString(env);
ret.push_back(L'\0');
}
ret.push_back(L'\0');
// Can a Win32 environment be empty? If so, does it end with one NUL or
// two? Add an extra NUL just in case it matters.
ret.push_back(L'\0');
return ret;
}
int main(int argc, char *argv[])
{
{
// Copy the PCONSOLEDBG environment variable from the Cygwin environment
// to the Win32 environment so the agent will inherit it.
const char *dbgvar = getenv("PCONSOLEDBG");
if (dbgvar != NULL) {
SetEnvironmentVariableW(L"PCONSOLEDBG", L"1");
}
}
winsize sz;
ioctl(STDIN_FILENO, TIOCGWINSZ, &sz);
@ -232,8 +297,12 @@ int main()
exit(1);
}
// TODO: start the appropriate child process...
pconsole_start_process(pconsole, L"c:\\cygwin\\bin\\bash.exe", NULL, NULL, NULL);
{
// Start the child process under the console.
std::wstring cmdLine = wstringFString(argvToCommandLine(argc - 1, &argv[1]));
std::wstring envp = makeEnvironBlock();
pconsole_start_process(pconsole, NULL, cmdLine.c_str(), NULL, envp.data());
}
{
struct sigaction resizeSigAct;