/***************************************************************************
** The BSD 3-Clause License. http://www.opensource.org/licenses/BSD-3-Clause
**
** This file is part of 'mingw-builds' project.
** Copyright (c) 2011,2012,2013 by niXman (i dotty nixman doggy gmail dotty com)
** All rights reserved.
**
** Project: mingw-builds ( http://sourceforge.net/projects/mingwbuilds/ )
**
** Redistribution and use in source and binary forms, with or without 
** modification, are permitted provided that the following conditions are met:
** - Redistributions of source code must retain the above copyright 
**     notice, this list of conditions and the following disclaimer.
** - Redistributions in binary form must reproduce the above copyright 
**     notice, this list of conditions and the following disclaimer in 
**     the documentation and/or other materials provided with the distribution.
** - Neither the name of the 'mingw-builds' nor the names of its contributors may 
**     be used to endorse or promote products derived from this software 
**     without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
** A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***************************************************************************/

#include <windows.h>

#include <stdio.h>
#include <strings.h>

#ifdef _DEBUG
#	define dbg_printf(...) fprintf(stderr, __VA_ARGS__)
#else
#	define dbg_printf(...) do {} while(0)
#endif

// When built for the Android NDK, values are
// passed in on the GCC commandline, and when
// built for mingw-builds, these defaults are
// used.
#ifndef GDB_TO_PYTHON_REL_DIR
#	define GDB_TO_PYTHON_REL_DIR "..\\opt\\bin"
#endif

#ifndef GDB_EXECUTABLE_ORIG_FILENAME
#	define GDB_EXECUTABLE_ORIG_FILENAME "gdborig.exe"
#endif

#ifndef PYTHONHOME_REL_DIR
#	define PYTHONHOME_REL_DIR "..\\opt"
#endif

#define DIE_IF_FALSE(expr) \
	do { \
		if ( !(expr) ) { \
			dbg_printf("%s(%d)[%d]: expression \"%s\" fail. terminate.\n" \
				,__FILE__ \
				,__LINE__ \
				,GetLastError() \
				,#expr \
			); \
			exit(1); \
		} \
	} while (0)

int main(int argc, char** argv) {
	enum {
		 envbufsize = 1024*32
		,exebufsize = 1024
		,cmdbufsize = envbufsize
	};

	char *envbuf, *sep, *resbuf, *cmdbuf;
	DWORD len, exitCode;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	DIE_IF_FALSE(
		(envbuf = malloc(envbufsize))
	);
	DIE_IF_FALSE(
		(cmdbuf = malloc(cmdbufsize))
	);
	*cmdbuf = 0;

	DIE_IF_FALSE(
		GetEnvironmentVariable("PATH", envbuf, envbufsize)
	);
    dbg_printf("env: %s\n", envbuf);

	DIE_IF_FALSE(
		GetModuleFileName(0, cmdbuf, exebufsize)
	);
    dbg_printf("curdir: %s\n", cmdbuf);

	DIE_IF_FALSE(
		(sep = strrchr(cmdbuf, '\\'))
	);
	*(sep+1) = 0;
	strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR);
	dbg_printf("sep: %s\n", cmdbuf);

	len = strlen(envbuf)+strlen(cmdbuf)
		+1  /* for envronment separator */
		+1; /* for zero-terminator */
	
	DIE_IF_FALSE(
		(resbuf = malloc(len))
	);

	DIE_IF_FALSE(
		(snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0)
	);
    dbg_printf("PATH: %s\n", resbuf);

	DIE_IF_FALSE(
		SetEnvironmentVariable("PATH", resbuf)
	);

	*(sep+1) = 0;
	strcat(cmdbuf, PYTHONHOME_REL_DIR);
	dbg_printf("PYTHONHOME: %s\n", cmdbuf);
	DIE_IF_FALSE(
		SetEnvironmentVariable("PYTHONHOME", cmdbuf)
	);
	
	*(sep+1) = 0;
	strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" ");
	
	if ( argc > 1 ) {
		for ( ++argv; *argv; ++argv ) {
			len = strlen(cmdbuf);
			snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv);
		}
	}
	dbg_printf("cmd: %s\n", cmdbuf);

	HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/);
	if ( ghJob == NULL ) {
		dbg_printf("Could not create job object\n");
	} else {
		JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
		// Configure all child processes associated with the job to terminate when the last handle to the job is closed
		jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
		if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) {
			dbg_printf("Could not SetInformationJobObject\n");
		}
	}

	memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	si.dwFlags |= STARTF_USESTDHANDLES;
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

	memset(&pi, 0, sizeof(pi));

	DIE_IF_FALSE(
		CreateProcess(
			 0			// exe name
			,cmdbuf	// command line
			,0			// process security attributes
			,0			// primary thread security attributes
			,TRUE		// handles are inherited
			,0			// creation flags
			,0			// use parent's environment
			,0			// use parent's current directory
			,&si		// STARTUPINFO pointer
			,&pi		// receives PROCESS_INFORMATION
		)
	);

	if ( ghJob != NULL && AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) {
		dbg_printf("Could not AssignProcessToObject\n");
	}

	// Do not handle Ctrl-C in the wrapper
	SetConsoleCtrlHandler(NULL, TRUE);

	WaitForSingleObject(pi.hProcess, INFINITE);
	
	DIE_IF_FALSE(
		GetExitCodeProcess(pi.hProcess, &exitCode)
	);

	if ( ghJob != NULL )
		CloseHandle(ghJob);
	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );

	free(envbuf);
	free(resbuf);
	free(cmdbuf);
	
	dbg_printf("exiting with exitCode %d", exitCode);

	return exitCode;
}
