/*******************************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation, Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM Corporation - initial implementation
 *    Karla Callaghan, Intel - Brought multi-platform support in from HCLauncher code which was implemented by IBM
 *    Spundun Bhatt (spundun@gmail.com), with the support and encouragement of the University of Southern California Information Sciences Institute Distributed Scalable Systems Division.
 *    
 * $Id: launcher_md.c,v 1.29 2009/08/26 14:59:51 jwest Exp $ 
 *******************************************************************************/ 

#ifdef MVS
#define _SHR_ENVIRON 1
#include <sys/resource.h>
#endif

#include "tptp/TPTPCommon.h"
#include "tptp/TPTPErrorCode.h"
#include "launcher_md.h"

#ifdef _WIN32
#include <stdio.h>
#else
#include "tptp/TPTPUtils.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#if !defined (_AIX) && !defined (MVS) && !defined (_HPUX) && !defined (__OS400__)
#include <sys/types.h>
#include <dirent.h>
#endif
extern char **environ;
#endif


#ifdef XX_DEBUG
extern FILE *trcFile;
#endif

/* TODO: These need to be mapped to the real values */
#define org_eclipse_hyades_execution_core_IExecutionComponent_DEAD 1
#define org_eclipse_hyades_execution_core_IExecutionComponent_READY 2


BOOL isProcessActive( PID pid )
{
#ifdef _WIN32
	HANDLE handle;
	long status;
	handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
	if(handle) {
		if(GetExitCodeProcess(handle, &status)) {
			CloseHandle(handle); 
			if(status != STILL_ACTIVE) {
				return FALSE;
			}
			else {
				return TRUE;
			}
		}
		CloseHandle(handle); 
	}
	return FALSE;
#elif defined _AIX || defined MVS || defined _HPUX || defined __APPLE__
	errno = 0;
	if(-1 == getpriority(PRIO_PROCESS, pid) && errno != 0) {
		return FALSE;
	}
	else {
		return TRUE;
	}
#elif defined __OS400__
	struct QP0W_PID_Data_T out;
	errno = 0;
	if(0 != Qp0wChkPid(pid, &out)) {
		return FALSE;
	}
	else {
		return TRUE;
	}
#else
	DIR *procDir;
	struct dirent *currentProcess;
	procDir = opendir("/proc");
	if(procDir) {
		for(currentProcess = readdir(procDir); currentProcess != NULL; currentProcess = readdir(procDir)) {
			if(pid == atol(currentProcess->d_name)) {
				closedir(procDir); /* Bug 67736 */
				return TRUE;
			}
		}
		closedir(procDir);
	}
	else {
		/* ra_logServiceMessage(__FILE__, __LINE__,RA_INFORMATION, "Can't read process list errno = %d", errno); */ 
	}
	return FALSE;
#endif

}

/*
 * Generic launch function
 */
PID hc_launchProcess(char *exe, char *args, char *location, char *env, RA_HANDLE consoleChild[])
{
#ifdef OLD_WAY
	int i; /* loop counter */
#endif /* OLD_WAY */

	PID pid; /* process ID of the launched process */

	if((exe == NULL) /*|| (location == NULL)*/)
		return -1;

#ifdef _WIN32
	pid = hc_launchProcess_WIN32(exe, args, location, env, consoleChild);
#elif MVS
	pid = hc_launchProcess_MVS(exe, args, location, env, consoleChild);
#elif __OS400__
	pid = hc_launchProcess_OS400(exe, args, location, env, consoleChild);
#else
	pid = hc_launchProcess_UNIX(exe, args, location, env, consoleChild);
#endif

#ifdef OLD_WAY
	/* CHANGE FROM OLD RAC:
	 * The function which opened the handles should close the handles.
	 * Therefore, this close should be deleted. If decide this needs to stay,
	 * need to let caller know the handles it passed in are now invalid.
	 * NOTE: Remove this ifdef'd code after porting. Leaving for now to document
	 * the change.
	 */
	/* Close all the handles we no longer need in this address space */
	for(i = 0; i < 3; i++) {
		if(consoleChild[i]) {
			CLOSE_RA_HANDLE(consoleChild[i]);
		}
	}
#endif /* OLD_WAY */

	return pid;
}


/*
 * Windows launcher
 */
#ifdef _WIN32
PID hc_launchProcess_WIN32(char *exe, char *cmdline, char *location, char *env, RA_HANDLE consoleChild[]) {
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	DWORD error;
	char* strippedCmdLine=NULL;

	if (exe == NULL)
		return TPTP_INVALID_PID;

	/* Move past any leading blanks */
	strippedCmdLine=cmdline;
	while (*strippedCmdLine == ' ')
	{
		strippedCmdLine++;
	}

	/* Setup the STARTUP_INFO struct */
	ZeroMemory(&si,sizeof(si));
	si.cb=sizeof(si);
	if(consoleChild[0]) {
		si.dwFlags=STARTF_USESTDHANDLES;
		si.hStdInput=consoleChild[0];
	}
	if((consoleChild[1])) {
		si.dwFlags=STARTF_USESTDHANDLES;
		si.hStdOutput=consoleChild[1];
	}
	if(consoleChild[2]) {
		si.dwFlags=STARTF_USESTDHANDLES;
		si.hStdError=consoleChild[2];
	}
	// Calling CreateProcess() with 1st param, so Path is not being searched.
	// This prevents unintended (possibly malicious) apps from getting launched by changes to Path.
	//hc_logServiceMessage(__FILE__, __LINE__, RA_WARNING, "Attempting to launch process : %s  %s in location %s", exe->data, args->data, launchLocation);
	if(CreateProcess(exe,							/* Application to run */
					 strippedCmdLine,						/* The command line args */
					 NULL,							/* Default process security */
					 NULL,							/* Default thread security */
					 TRUE,							/* Inherit handles between children */
					 (consoleChild[0] || consoleChild[1] || consoleChild[2]) ? DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP|CREATE_SEPARATE_WOW_VDM : DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
					 env,							/* Environment */
					 location,						/* Where to run the child */
					 &si,							/* Startup info */
					 &pi)==0) {						/* Process info */

		error=GetLastError();
		//hc_logServiceMessage(__FILE__, __LINE__, RA_SEVERE, "Launching process failed, platform specific error is %d. Path=%s Process command line = %s", error, application->path.data,  cmdline);
		/* Return invalid pid as the process did not launch */
		return TPTP_INVALID_PID;
	}

	//hc_logServiceMessage(__FILE__, __LINE__, RA_WARNING, "Process launched: PID=%lu", pi.dwProcessId);
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
//TODO: Why did orig code free this? Doesn't seem right.
//	ra_free(cmdline);  /* Bug 103601 */

	return pi.dwProcessId;
}
#endif


/*
 * MVS launcher
 */
#ifdef MVS
PID hc_launchProcess_MVS(char *exe, char *cmdline, char *location, char *env, RA_HANDLE consoleChild[]) {
	PID childPID = 0;
	char *parsedArgs[MAX_ARGS];
	char *environment[MAX_ENV+1];
	int fd_map[3];
	int *fdmap;
	int fdcount = 3;
	char *current, *next;
	int i, count;
	char blank;

#ifdef MVS
#pragma convlit(suspend)
#endif
	blank = ' ';
#ifdef MVS
#pragma convlit(resume)
#endif

	if((cmdline == NULL) || (env == NULL)) {
		//return -1;
		return TPTP_INVALID_PID;
	}

	current = cmdline;

	/* 178427 begin */
	/* Move past any leading blanks */
	while (*current == blank) {
		current++;
	}

	/* Parse out the args */
	for(i = 0; (next = (char*)strchr(current, blank)) != NULL; i++) {
		/* If this is a quoted arg we need to remove the quote and skip to the next quote */
		if(current[0]=='\"') {
			current++;
			next=(char*)strchr(current, '\"');
			if(next) {
				*next='\0';
			}
		}
		else {
			*next='\0';
		}

		#ifdef XX_DEBUG                   
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: command arg=<%s>\n", current); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif

		parsedArgs[i]=current;

		/* move past blanks */
		do {
			next++;
		} while (*next == blank);
		current=next;
	}

	/* check if there is another argument */
	if (strlen(current) > 0) {  /* 178427 - handles case of blank at end of cmd line */
		if(current[0]=='\"') { /* If this is a quoted arg we need to remove the quote and skip to the next quote */
			current++;
			next=(char*)strchr(current, '\"');
			if(next) {
				*next='\0';
			}
		}

		#ifdef XX_DEBUG                    
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: command arg=<%s>\n", current); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif

		parsedArgs[i]=current;
		/*	End the list of arguments */
		parsedArgs[i+1]=NULL;
	}
	else {
		/* else end the list of arguments */
		parsedArgs[i]=NULL;
	}

	/* 178427 end */
	/* Load the environment array */
	i=count=0;
	do {
		#ifdef XX_DEBUG                    
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: i=%d  count=%d  env var=<%s>\n", i, count, &env[i]); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif

		environment[count]=&env[i];
		i+=strlen(&env[i])+1;
		count++;
	} while(env[i]!='\0' && count<MAX_ENV);

	/* We have imposed a limit on the number of environment variables */
	if(count==MAX_ENV) {

		#ifdef XX_DEBUG                    
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: Launching process failed, too many environment variables.  count=%d  but Maximum=%d\n", count, MAX_ENV); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif

		exit(-1);
	}
	else {
		/* End the list of environment variables */
		environment[count]=NULL;
	}

   /* Set up file descriptor map for child process */
	if (consoleChild) {
		if ((fd_map[0]=dup(consoleChild[0])) < 0) {  /* child stdin is read end of pipe */
			//hc_logServiceMessage(__FILE__, __LINE__, RA_SEVERE, "Creating stdin for process failed.  Platform specific error is %d", errno);
		}
		if ((fd_map[1]=dup(consoleChild[1])) < 0) {  /* child stdout is write end of pipe */
			//hc_logServiceMessage(__FILE__, __LINE__, RA_SEVERE, "Creating stdout for process failed.  Platform specific error is %d", errno);
		}
		if ((fd_map[2]=dup(consoleChild[2])) < 0) {  /* child stderr is write end of pipe */
			//hc_logServiceMessage(__FILE__, __LINE__, RA_SEVERE, "Creating stderr for process failed.  Platform specific error is %d", errno);
		}
		fdmap = fd_map;
	}
	else {
		fdcount = 0;
		fdmap = NULL;
	}

	/* Change directory if one was specified */
	if (location != NULL) {
		#ifdef XX_DEBUG                    
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: location=<%s>\n", location); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif	

		if(chdir(location)) {

			#ifdef XX_DEBUG
			#pragma convlit(suspend)
			fprintf(trcFile, "hc_launchProcess: chdir to %s failed with error %d %s - returning 0 pid\n", location, errno, strerror(errno)); 
			fflush(trcFile);        
			#pragma convlit(resume)
			#endif

			childPID = 0;
			//return childPID;  //TODO:Why was this returning 0 vs. -1?
			return TPTP_INVALID_PID;
		}
	}

	/* Spawn the new process */
	if((childPID = spawnp(parsedArgs[0], fdcount, fdmap, NULL, parsedArgs, environment))<0) {
		#ifdef XX_DEBUG
		#pragma convlit(suspend)
		fprintf(trcFile, "hc_launchProcess: spawn failed with error %d %s - path=<%s>\n", errno, strerror(errno), parsedArgs[0]); 
		fflush(trcFile);        
		#pragma convlit(resume)
		#endif

		//childPID = -1;  /* 179338 */
		childPID = TPTP_INVALID_PID;
	}

	return childPID;
}
#endif


/*
 * OS/400 launcher
 */
#ifdef __OS400__
 /* Please refer to launcher_os400.c */
#endif


/*
 * UNIX launcher
 */
#if !defined (_WIN32) && !defined (MVS) && !defined (__OS400__)
PID hc_launchProcess_UNIX(char *exe, char *cmdline, char *location, char *env, RA_HANDLE consoleChild[]) {

	PID childPID = TPTP_INVALID_PID;
	char** envp = NULL;

	//printf("hc_launchProcess_UNIX: creating process:%s\n",exe);

//TODO: cmdline could be Null coming in here, if it is, use the exe name for the cmdline.
	if (exe == NULL)
		return TPTP_INVALID_PID;

	childPID = fork();

	if(childPID == 0) {   /* Child process */
		char *parsedArgs[MAX_ARGS];
		char *environment[MAX_ENV+1];
		char *current, *next;
		int i, count;
		BOOL done = FALSE; /* is parsing done? */
		current=cmdline;

		//printf("hc_launchProcess_UNIX: parsing arguments\n");
	     /* Move past any leading blanks */
		while (*current == ' ') {
			current++;
		}

	     /* Move any trailing blanks */
		next = current + strlen(current) - 1;
		while (next >= current && *next == ' ') {
			*next = '\0';
			next--;
		}
		
		/* Parse out the args */
		i = count = 0; /* reset the counters */
		while(!done) {
			BOOL isQuoted = FALSE; /* is the current string quoted? */
			BOOL isDblQuoted = FALSE; /* is the current string double-quoted? */
			char* startIndex = current;
			char* endIndex = current;
			int numChars;
	
			while((*endIndex != ' ' || isQuoted || isDblQuoted)) {
				if(*endIndex == '\'') {
					if(isQuoted) {
						isQuoted = FALSE;
					}
					else {
						isQuoted = TRUE;
					}
				}
				else if(*endIndex == '\"') {
					if(isDblQuoted) {
						isDblQuoted = FALSE;
					}
					else {
						isDblQuoted = TRUE;
					}
				}

				endIndex++;
				if(*endIndex == '\0') {
					done = TRUE;
					break;
				}
			}

			isQuoted = *startIndex == '\'' && *(endIndex - 1) == '\'';
			isDblQuoted = *startIndex == '\"' && *(endIndex - 1) == '\"';
			next = endIndex + 1;

			if (isDblQuoted == TRUE || isQuoted == TRUE) {
				++startIndex;
				--endIndex;
			}

			/* Allocate the memory for parsed arg */
			numChars = endIndex - startIndex; /* including the terminating null */
			parsedArgs[count] = (char*)tptp_malloc(sizeof(char) * (numChars + 1));
			strncpy(parsedArgs[count], startIndex, numChars);
			parsedArgs[count][numChars] = '\0';
			//printf("Parsed arg %s\n", parsedArgs[count]);

			// bug 140439
			removeJavaArgsQuote(&(parsedArgs[count]));



			/* Increment the counter */
			/* We only increment the counter if we have a non-NULL paramter */
			/* There was a bug with Linux compatibility where we add NULL parameters and this was causing a launch failure */
			if (numChars > 0) {
				count++;
			}

			/* Reset the pointer */
			current = next;
		}
		parsedArgs[count] = '\0';

		if (env !=0)
		{
			//printf("hc_launchProcess_UNIX: loading env array\n");
			/* Load the environment array */
			i=count=0;
			do{
				environment[count]=&env[i];
				i+=strlen(&env[i])+1;
				count++;
			} while(env[i]!='\0' && count<MAX_ENV);

			if(count==MAX_ENV) {
				//printf("Launching process failed, too many environment variables.  Maximum=%d\n", MAX_ENV);
				return TPTP_INVALID_PID;
			}
			else {
				environment[count]='\0';
			}
			envp = environment;
		} else
		{
			//printf("hc_launchProcess_UNIX: Use global environ array\n");
			envp = environ; //this is the system provided global environ var
		}

		/* Change directory to the specified location if it exists */
		if(location) {
			//printf("hc_launchProcess_UNIX: change to directory location:%s\n", location);
			if(chdir(location)) {
			    printf("Launching process failed, cannot set location.  Platform specific error is %d. Location=%s\n", errno, location);
			    return TPTP_INVALID_PID;
			}
		}

		//printf("hc_launchProcess_UNIX: Setup console I/O\n");
		/* Setup the console */
		if(dup2(consoleChild[0], STDIN_FILENO) < 0) {
			printf("Creating stdin for process failed.  Platform specific error is %d\n", errno);
		}
		if(dup2(consoleChild[1], STDOUT_FILENO) < 0) {
			printf("Creating stdout for process failed.  Platform specific error is %d\n", errno);
		}
		if(dup2(consoleChild[2], STDERR_FILENO) < 0) {
			printf("Creating stderr for process failed.  Platform specific error is %d\n", errno);
		}

		//printf("hc_launchProcess_UNIX: Exec the process: %s\n", parsedArgs[0]);
		/* Exec the target process */
		/* Note: When taken from the RAC src, this call used parsedArgs[0] rather
		 * than the exe parameter as the 1st arg to the execve. That caused problems
		 * because the caller must ensure that we have a valid executable before
		 * attempting the launch - and it is validating the exe parameter.
		 * WARNING: Since we are in the child process of the fork, if this 
		 * execve() fails to launch the app the parent won't know it. It has
		 * a valid childPiD that resulted from the successful fork() and returns
		 * that to the caller.
		 */
		if(execve(exe, parsedArgs, envp)<0) {
//			printf("Launching process failed (error %d), command line: %s ... %s\n", errno, cmdline, strerror(errno) );
			printf("Launching process failed (error %d), command line: %s\n", errno, cmdline);
			//return (-1);	/* exec failed */
			exit(-1); /* must exit or the forked process will continue executing. */
		}
	}
	else { /* parent process */
		//printf("hc_launchProcess_UNIX: Returning childPID=%d\n", childPID);
		return childPID;
	}
	// Can't get here, but makes the compiler happy.
	return childPID;
}
#endif


/*******************************************************************************
 *                                                                             *
 * Environment                                                                 *
 *                                                                             *
 ******************************************************************************/


/*
 * Get the current system environment
 */
void* hc_getEnvironment() {

#ifdef _WIN32
	return GetEnvironmentStrings(); /* Return a string of environment variables */
#else

	#ifdef XX_DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile, "hc_getEnvironment: environ=%p\n", environ); 
	fflush(trcFile);
	#ifdef MVS        
	#pragma convlit(resume)
	#endif
	#endif

	return (void*)environ;

#endif
}

/*
 * Get the environment variable at the specified offset in the specified environment 
 * and returns the offset of the next environment variable.
 * Input:
 *    env    - environment  
 *    offset - offset of variable in the environment
 *
 * Output:
 *    envvarName  - ptr to environment variable name
 *    envvarValue - ptr to environment variable value
 *
 * Returns - offset of next environment variable in the specified environment 
 *         - -1 if no more environment variables
 */

int hc_getEnvironmentVariable(void *env, int offset, char **envvarName, char **envvarValue) {
	int nextOffset, nameLen, valueLen;
	char *tmp;
	char *envvar;

#ifdef _WIN32
	char *sysEnv = (char *)env;

	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: offset=%d  sysEnv=%p\n", offset, sysEnv); 
	fflush(trcFile);
	#endif

	envvar = sysEnv+offset;

	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: envvar = <%s>\n", envvar); 
	fflush(trcFile);
	#endif

	/* Get the name-value pairs - look for = */
	tmp = strchr(envvar, '=');

	/* If we don't have an = then return the whole string for the name and an empty string for the value */
	if (tmp == NULL) {
		nameLen = strlen(envvar);
		valueLen = 0;
	}

	/* Check if the first character is = (on Windows this is the case for some variables) */
	else if (tmp-envvar == 0) {
		/* check if there is another =                              
		 * If there is another = Then use that one                    
		 * If there isn't another = then use the whole string for the name and make the value an empty string 
		 */
		tmp = strchr(envvar+1, '=');

		if (tmp == NULL) {
			nameLen = strlen(envvar);
			valueLen = 0;
		}
		else {
			nameLen = tmp-envvar;
			valueLen = strlen(tmp)-1;
		}

	}
	else {
		nameLen = tmp-envvar;
		valueLen = strlen(tmp)-1;
	}

	*envvarName = (char *)malloc(nameLen+1);
	*envvarValue = (char *)malloc(valueLen+1);
	memcpy(*envvarName, envvar, nameLen);
	*(*envvarName+nameLen) = '\0';
	if ((tmp == NULL) || (valueLen == 0)) { /* Bug 68899 */
		**envvarValue = '\0';
	}
	else {
		strcpy(*envvarValue, tmp+1);
	}


	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: envvarName=%p <%s> envvarValue=%p <%s>\n", *envvarName, *envvarName, *envvarValue, *envvarValue); 
	fflush(trcFile);
	#endif

	/* Get offset to next environment variable */
	nextOffset = offset + strlen(envvar) + 1;

	if (sysEnv[nextOffset] == '\0') {
		nextOffset = -1;
	}

#else  /* Non-Windows Platforms */
	char *n_envvarName; /* native encoded name */
	char *n_envvarValue; /* native encoded value */
	char **sysEnv = (char **)env;

#ifdef MVS                    
	#pragma convlit(suspend)
#endif

	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: offset=%d  sysEnv=%p\n", offset, sysEnv); 
	fflush(trcFile);
	#endif

	envvar = sysEnv[offset];

	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: envvar = <%s>\n", envvar); 
	fflush(trcFile);
	#endif

	/* Get the name-value pairs - look for = */
	tmp = strchr(envvar, '=');

	/* If we don't have an = then return the whole string for the name and an empty string for the value */
	if (tmp == NULL) {
		nameLen = strlen(envvar);
		valueLen = 0;
	}
	else {
		nameLen = tmp-envvar;
		valueLen = strlen(tmp)-1;
	}

	n_envvarName = (char *)malloc(nameLen+1);
	n_envvarValue = (char *)malloc(valueLen+1);
	memcpy(n_envvarName, envvar, nameLen);
	*(n_envvarName+nameLen) = '\0';
	if ((tmp == NULL) || (valueLen == 0)) { /* Bug 68899 */
		*n_envvarValue = '\0';
	}
	else {
		strcpy(n_envvarValue, tmp+1);
	}

	#ifdef XX_DEBUG
	fprintf(trcFile, "hc_getEnvironmentVariable: envvarName=%p <%s> envvarValue=%p <%s>\n", n_envvarName, n_envvarName, n_envvarValue, n_envvarValue); 
	fflush(trcFile);
	#endif

	/* Convert the string from native to UTF-8 */
	native2unicode(envvarName, n_envvarName, nameLen + 1);
	native2unicode(envvarValue, n_envvarValue, valueLen + 1);

	free(n_envvarName);
	free(n_envvarValue);

	/* Get offset to next environment variable */
	nextOffset = offset + 1;

	/* If we are at the end of the environment variable array then signal it by returning -1 */
	if (sysEnv[nextOffset] == NULL) {
		nextOffset = -1;
	}

#endif

	return nextOffset;

}

/*******************************************************************************
 *                                                                             *
 * Process handling                                                            *
 *                                                                             *
 ******************************************************************************/

/*
 * Get the process state
 * Please refer to IExecutionComponent definition
 */
int hc_getProcessStatus(PID pid) {
#ifdef _WIN32
	HANDLE hProcess;
	DWORD exitCode;

	hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
	if (hProcess) {
		GetExitCodeProcess(hProcess, &exitCode);
		CloseHandle(hProcess); 
	}
	else {
		return org_eclipse_hyades_execution_core_IExecutionComponent_DEAD;
	}

	if(exitCode == STILL_ACTIVE) {
		return org_eclipse_hyades_execution_core_IExecutionComponent_READY;
	}
	else {
		return org_eclipse_hyades_execution_core_IExecutionComponent_DEAD;
	}
#else
	int status = 0;

	pid = waitpid(pid, &status, WNOHANG | WUNTRACED);
	if(pid == 0) {
		return org_eclipse_hyades_execution_core_IExecutionComponent_READY;
	}
	else {
		return org_eclipse_hyades_execution_core_IExecutionComponent_DEAD;
	}
#endif
}

/*
 * Kill the process specified by the process id
 */
int hc_killProcess(PID pid) {

#ifdef _WIN32
	HANDLE hProcess;
	int rc = 0;
	BOOL success;

	hProcess=OpenProcess(PROCESS_TERMINATE, FALSE, pid);
	if (hProcess != NULL) {
		success = TerminateProcess(hProcess, 0);

		/* Documentation does not specify the possible error returns for this
		 * function.  So need to create/expand the list based on testing.
		 * Common cases: bad handle, insufficient permission on that handle.
		 */
		if (!success)
		{
			switch (GetLastError())
			{
			case ERROR_ACCESS_DENIED:
			case ERROR_INVALID_ACCESS:
				rc = TPTP_SYS_ACCESS_DENIED;
				break;
			case ERROR_INVALID_HANDLE:
				rc = TPTP_SYS_INVALID_HANDLE;
				break;
			default:
				rc = TPTP_SYS_UNSPECIFIED_ERR;
				break;
			}
		}

		CloseHandle(hProcess);
	}

	return rc;

#else // non-Windows system
	
	int rc;

	rc = kill(pid, SIGKILL);
	if (rc == -1)
	{
		switch (errno)
		{
		case EINVAL:
			rc = TPTP_SYS_INVALID_SIGNAL;
			break;
		case EPERM:
			rc = TPTP_SYS_ACCESS_DENIED;
			break;
		case ESRCH:
			rc = TPTP_SYS_PROC_NOT_FOUND;
			break;
		default:
			rc = TPTP_SYS_UNSPECIFIED_ERR;
			break;
		}
	}
	else //kill was successful
	{
		rc = 0;
	}

	return rc;

#endif
}


/*******************************************************************************
 *                                                                             *
 * File I/O                                                                    *
 *                                                                             *
 ******************************************************************************/

/*
 * Read data from file descriptor
 */
int hc_readFile(RA_HANDLE fd, char* buffer, int count) {
	int rc;
#ifdef _WIN32
	ReadFile(fd, buffer, count, &rc, NULL);
#else
	rc = read(fd, buffer, count);
#endif
	return rc;
}


/*
 * Write a single character to the file descriptor
 */
int hc_writeFileChar(RA_HANDLE fd, char c) {
	int rc;
#ifdef _WIN32
	WriteFile(fd, &c, 1, &rc, NULL);
#elif defined (__OS400__)
	rc = write(fd, as400_atoe(&c), 1);
#elif defined (MVS)
	char c2[2];
	c2[0] = c;
	c2[1] = '\0';
	__atoe(c2);
	rc = write(fd, c2, 1);
#else
	rc = write(fd, &c, 1);
#endif
	return rc;
}

/**
	
	Remove quotation mark around java VM argument value.  

	The input string should in format -D<name>=<value>.   For example -Dvalue="my value" would be 
	changed to -Dvalue=my value
	
	Return 0 if quotation marks have been removed or -1 otherwise.
*/

int removeJavaArgsQuote(char **str){

	char *current, *end, *argsValue, *argsName;
	int  argsNameLen, argsValueLen;
	
	if( (*str)[0] != '-' || (*str)[1] != 'D'){
		//not valid input parameter
		return -1;
	}

	argsValue = strstr(*str, "=");
	if(argsValue == NULL){
	   //args string does not contain "=", format is wrong
	   return -1;
	}else{
		argsNameLen = strlen(*str) - strlen(argsValue);
		argsName = (char*)tptp_malloc(sizeof(char) * (argsNameLen+1 ));
		strncpy(argsName, *str, argsNameLen);
		argsName[argsNameLen] = '\0';
	}

	//point end to the last char 
	end = argsValue + strlen(argsValue) - 1;
	//move current to pass '='
	current = argsValue+1;
	if(! ((*current == '\'' &&*end == '\'' && current != end ) || (*current == '\"' && *end == '\"' && current!= end)) ){
		//either no quotes were found or quotes don't match;  No action
		return -1;	
	}
	
	//now remove quotes around args value

	//move current to pass first quotation
	current = current +1;
	
	if(end <= current){
		argsValue = "";
		argsValueLen = 0;
	}else{
		argsValueLen = end - current;
		argsValue = (char*)tptp_malloc(sizeof(char) * (argsValueLen+1));
		strncpy(argsValue, current, argsValueLen);
		argsValue[argsValueLen] = '\0';
	}
	*str = (char*)tptp_malloc(sizeof(char) * (argsNameLen + argsValueLen +2));
	sprintf(*str, "%s%s%s", argsName, "=", argsValue);
	return 0;
}
