/*
    rsxwin32.c

    connect a spawned process (detached) with a pipe

*/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <process.h>
#include <errno.h>

/* pipe read, pipe write */
#define P_READ	0
#define P_WRITE 1

static PROCESS_INFORMATION procinfo;
static HANDLE output_handles[2];

static HANDLE InheritHandle(HANDLE hin, BOOL bInherit)
{
    HANDLE hproc;
    HANDLE hout = INVALID_HANDLE_VALUE;

    hproc = GetCurrentProcess();
    DuplicateHandle(hproc, hin, hproc, &hout, 0, bInherit,
	    DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS);

    return hout;
}

static int connect_process(LPSTR lpszCmdLine)
{
    static SECURITY_ATTRIBUTES defsec =
	{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
    STARTUPINFO si;

    if (CreatePipe(&output_handles[P_READ], &output_handles[P_WRITE],
	    &defsec, 8192) == FALSE)
        return -EPIPE;

    /* don't allow read access */
    output_handles[P_READ] = InheritHandle(output_handles[P_READ], FALSE);

    memset(&si, 0, sizeof (STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdOutput = output_handles[P_WRITE];
    si.hStdError = output_handles[P_WRITE];
    si.hStdInput = INVALID_HANDLE_VALUE;

    if (CreateProcess(NULL, lpszCmdLine, NULL, NULL,
	    TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
	    NULL, NULL, &si, &procinfo) == FALSE)
        return -ENOENT;

    /* close handles, only other process use them */
    CloseHandle(output_handles[P_WRITE]);

    return 0;
}

static DWORD WINAPI output_thread(LPVOID lpThreadParameter)
{
    char buf[512];
    DWORD r;

    while (ReadFile(output_handles[P_READ], buf, 512, &r, NULL) == TRUE) {
        if (r > 0) {
            OemToChar (buf, buf);
            write(1, buf, r);
        }
    }
    CloseHandle(output_handles[P_READ]);
    return 0;
}

static int run_cmd(LPSTR lpszCmdLine)
{
    DWORD tid1;
    int ret;

    ret = connect_process(lpszCmdLine);

    if (ret >= 0) {
        CreateThread(NULL, 0, output_thread, 0, 0, &tid1);
	ResumeThread(procinfo.hThread);
    }
    return ret;
}

int spawnvpe (int flag, const char *prg,
                char * const * argv, char * const * env)
{
    char buf[1024];
    int i, len, n;
    int ret;

    len = strlen (prg);
    memcpy (buf, prg, len);

    for (i = 1; argv[i]; ++i)
    {
        buf [len++] = ' ';
        n = strlen (argv[i]);
        memcpy (buf + len, argv[i], n);
        len += n;
    }
    buf [len] = 0;

    ret = run_cmd (buf);

    if (ret < 0) {
        errno = -ret;
        return -1;
    }
    else {
        WaitForSingleObject (procinfo.hProcess, INFINITE);
        return 0;
    }
}
