/**********************************************************************
Copyright (c) 2005, 2007 IBM Corporation and others.
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
$Id: launcher_os400.c,v 1.2 2007/04/05 23:58:24 jkubasta Exp $
 
Contributors:
    IBM Corporation - initial implementation
**********************************************************************/

#ifdef __OS400__ /* 236501 */

#include "launcher_common.h"
#include "RAComm.h"

char* processAS400Arg2(char** parsedArgs, int numArgs);
char* processAS400Arg3(char** environment, int numEnv);
char* processAS400Arg4(char** parsedArgs, int* pNumArgs, int* intrepret, char** p_opt, char** p_chk);


/*
 * Launch a process
 */
PID hc_launchProcess_OS400(char *exe, char *cmdline, char *location, char *env, RA_HANDLE consoleChild[]) {
	PID childPID = 0;
	struct inheritance inherit;
	char *as400Args[9];
	int numAS400Args; /* Total number of AS/400 argumens, including JVM properties */
	int numAS400Env;  /* Total number of environment variables */

	char *parsedArgs[MAX_ARGS];
	char *environment[MAX_ENV+1];
	int fd_map[3];
	int *fdmap;
	int fdcount = 3;
	char *current, *next;
	int i, count;

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

	current=cmdline;

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

	/* Parse out the args */
	for(i=0; (next=(char*)strchr(current, ' '))!=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';
		}

		parsedArgs[i]=current;

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

	/* check if there is another argument */
	if (strlen(current) > 0) {  /* 178427 - handles case of blank at end of cmd line */

		/* 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';
			}
		}

		parsedArgs[i]=current;
		parsedArgs[i+1]='\0';
	}
	/* Else end the list of arguments */
	else {
		parsedArgs[i]='\0';
	}

	numAS400Args = i+1; /* Total number of JVM arguments, including trailing NULL (-D or -X) */

	/* 178427 end */
	/* 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) {
		exit(-1);
	}
	else {
		environment[count]='\0';
	}

	numAS400Env = count; /* Total number of environment variables */

	/* 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;
	}

#if 0 /* Bug 68899 */
	/* Change directory to the one specified in the config file */
	if(chdir(location)) {
		childPID = 0;
		return childPID;
	}
#endif

	if(strstr(parsedArgs[0], "Q5BVAJVM") != 0) { /* 239022 */
		int intrepret = FALSE;
		char* opt = NULL;
		char* chk = NULL;

		/*                         */
		/* Processing iSeries args */
		/*                         */
		as400Args[4] = processAS400Arg4(parsedArgs, &numAS400Args, &intrepret, &opt, &chk); /* Step 4 goes first to remove all -D and -X parameters */
		as400Args[0] = parsedArgs[0];
		as400Args[1] = parsedArgs[1]; /* class name */
		as400Args[2] = processAS400Arg2(parsedArgs, numAS400Args);
		as400Args[3] = processAS400Arg3(environment, numAS400Env);
		as400Args[5] = opt; /* Optimization */
		as400Args[6] = chk; /* Path check level */
		if(intrepret)
			as400Args[7] = "*YES"; /* Interpret */
		else
			as400Args[7] = "*NO"; /* Interpret */
		as400Args[8] = "\0";

		environment[numAS400Env++] = "QIBM_USE_DESCRIPTOR_STDIO=Y";
		environment[numAS400Env++] = '\0';
		inherit.flags = SPAWN_SETTHREAD_NP; /* 232010 */

		/* Launch the java process */
		childPID = spawnp(as400Args[0], fdcount, fdmap, &inherit, as400Args, environment);

		free(as400Args[2]); /* program param */
		free(as400Args[3]); /* classpath */
		free(as400Args[4]); /* jvm prop */
	}
	else {
		environment[numAS400Env++] = "QIBM_USE_DESCRIPTOR_STDIO=Y";
		environment[numAS400Env++] = '\0';
		inherit.flags = SPAWN_SETTHREAD_NP;

		/* Launch the process */
		childPID = spawnp(parsedArgs[0], fdcount, fdmap, &inherit, parsedArgs, environment);
	}

	if(childPID < 0) {
		childPID = -1;
	}

	return childPID;
}


/*                        */
/* Processing arg 2       */
/* Command line arguments */
/*                        */
char* processAS400Arg2(char** parsedArgs, int numArgs) {
	char* as400arg2;
	int propLen = 0; /* Length of the string storing the command line args in AS/400 format */
	int i;
	char len[3];
	int numParam = 0; /* 238048 Number of ACTUAL (non-null) command line arg passed to program */

	if(numArgs > 2) {
		/* Calculate the length of the array required */
		for(i = 2; (i < numArgs) && (parsedArgs[i] != NULL); i++) { /* 238048 */
			propLen += 3; /* the 3 digits "xxx" showing the length of the arg name */
			propLen += strlen(parsedArgs[i]); /* the length of the arg */
			numParam++; /* 238048 we got one more arg */
		}
		propLen += 3; /* The 3 digit "nnn" show the number of JVM args */

		as400arg2 = (char*)malloc(sizeof(char) * propLen);
		BZERO(as400arg2, propLen);
		sprintf(as400arg2, "%03d", numParam); /* 238048 Total number of args */
		for(i = 2; (i < numArgs) && (parsedArgs[i] != NULL); i++) { /* 238048 */
			sprintf(len, "%03d", strlen(parsedArgs[i]));
			strcat(as400arg2, len);
			strcat(as400arg2, parsedArgs[i]);
		}
		strcat(as400arg2, "\0"); /* add a null to the end */
	}
	else { /* if(numAD400Args <= 2) */
		as400arg2 = "0";
	}

	return as400arg2;
}


/*                  */
/* Processing arg 3 */
/* CLASSPATH        */
/*                  */
char* processAS400Arg3(char** environment, int numEnv) {
	char* as400arg3;
	int cplength = 0; /* classpath length */
	int i, j;

	as400arg3 = (char*)malloc(sizeof(char) * AS400_CLASSPATH_LENGTH);
	BZERO(as400arg3, AS400_CLASSPATH_LENGTH);

	for(i = 0; i < numEnv; i++) {
		if(!strncmp(environment[i], "CLASSPATH=", 10)) {
			for(j = 10; j < strlen(environment[i]); j++) {
				as400arg3[cplength++] = environment[i][j];
			}
			as400arg3[cplength++] = ':';
		}
	}
	as400arg3[cplength-1] = '\0';

	return as400arg3;
}


/*                  */
/* Processing arg 4 */
/* JVM properties   */
/*                  */
char* processAS400Arg4(char** parsedArgs, int* pNumArgs, int* intrepret, char** p_opt, char** p_chk) {
	char* as400arg4;
	char* jvmPropBuf_X; /* 239249 */
	char* jvmPropBuf_D;
	int propLen = 0; /* Length of the string storing the JVM props in AS/400 format */
	int numProp = 0; /* Number of JVM properties processed */
	int i, j;
	BOOL endOfJvmArgs = FALSE;

	*p_opt = (char*)malloc(sizeof(char) * 3);
	*p_chk = (char*)malloc(sizeof(char) * 3);
	strcpy(*p_opt, "10"); /* default optimize level */
	strcpy(*p_chk, "10"); /* default path check level */

	propLen = 3; /* The 3 digit "nnn" show the number of JVM args */
	propLen += 26; /* 217412 workaround, stdin prop "019os400.stdin.allowed0011" */
	propLen += 21; /* Bug 68899 "012java.version0031.4" */

	/* Calculate the length of the array required */
	for(i = 0; (i < (*pNumArgs)) && (parsedArgs[i] != NULL); i++) { /* 238048 */
		propLen += 3; /* the 3 digits "xxx" showing the length of the property name */
		propLen += strlen(parsedArgs[i]); /* the length of the property */
		propLen += 3; /* the 3 digits "yyy" showing the length of the property value */
	}

	as400arg4 = (char*)malloc(sizeof(char) * propLen); /* Allocate  */
	BZERO(as400arg4, propLen);

	jvmPropBuf_X = (char*)malloc(sizeof(char) * (propLen - 3)); /* Not counting "nnn" */
	BZERO(jvmPropBuf_X, (propLen - 3));

	jvmPropBuf_D = (char*)malloc(sizeof(char) * (propLen - 3)); /* Not counting "nnn" */
	BZERO(jvmPropBuf_D, (propLen - 3));

	/* Rearrange the JVM arguments in AS/400 format */
	for(i = 1; (i < (*pNumArgs)) && (parsedArgs[i] != NULL); i++) { /* do not parse the 1st one since it is the program name */
		if(((!strncmp(parsedArgs[i], "-D", 2)) ||
			(!strncmp(parsedArgs[i], "-X", 2)) ||
			(!strncmp(parsedArgs[i], "-opt", 4)) ||
			(!strncmp(parsedArgs[i], "-chkpath", 8)) ||
			(!strncmp(parsedArgs[i], "-interpret", 10))) && (!endOfJvmArgs)) {
			if(!strncmp(parsedArgs[i], "-D", 2)) {
				const char delimiters[] = "=";
				char *value1, *value2;
				char *tmpbuf = (char*)malloc(sizeof(char) * (strlen(parsedArgs[i]) + 6)); /* adding "xxx" and "yyy" */
				BZERO(tmpbuf, (strlen(parsedArgs[i]) + 6));

				value1 = strtok(parsedArgs[i], delimiters);
				value1 += 2; /* skipping the "-D" */
				value2 = strtok(NULL, delimiters);
				if(value2 == NULL) {
					sprintf(tmpbuf, "%03d-D%s=000", strlen(value1)+3, value1); /* 237157 */ /* 239249 */
				}
				else {
					sprintf(tmpbuf, "%03d%s%03d%s", strlen(value1), value1, strlen(value2), value2);
				}
				//hc_logServiceMessage(__FILE__, __LINE__, RA_DEBUG, "iSeries JVM property \"%s\" encountered, convert it to \"%s\"", parsedArgs[i], tmpbuf);
				strcat(jvmPropBuf_D, tmpbuf);
				numProp++;
				free(tmpbuf);
			}
			else if(!strncmp(parsedArgs[i], "-X", 2)) {
				char *tmpbuf = (char*)malloc(sizeof(char) * (strlen(parsedArgs[i]) + 6)); /* adding "xxx" and "yyy" */
				BZERO(tmpbuf, (strlen(parsedArgs[i]) + 6));

				sprintf(tmpbuf, "%03d%s000", strlen(parsedArgs[i]), parsedArgs[i]); /* Do not skip -X */
				//hc_logServiceMessage(__FILE__, __LINE__, RA_DEBUG, "iSeries JVM property \"%s\" encountered, convert it to \"%s\"", parsedArgs[i], tmpbuf);
				strcat(jvmPropBuf_X, tmpbuf);
				numProp++;
				free(tmpbuf);
			}
			else if(!strncmp(parsedArgs[i], "-opt", 4)) {
				free(*p_opt);
				*p_opt = (char*)malloc(sizeof(char) * 3);
				BZERO(*p_opt, 3);
				strncpy(*p_opt, parsedArgs[i]+4, 2); /* skipping "-opt" */
			}
			else if(!strncmp(parsedArgs[i], "-chkpath", 8)) {
				free(*p_chk);
				*p_chk = (char*)malloc(sizeof(char) * 3);
				BZERO(*p_chk, 3);
				strncpy(*p_chk, parsedArgs[i]+8, 2); /* skipping "-chkpath" */
			}
			else if(!strncmp(parsedArgs[i], "-interpret", 10)) {
				*intrepret = TRUE;
			}

			/* free(parsedArgs[i]); */  /* JVM arg processes, remove it from the list */
			for(j = i; j < (*pNumArgs);  j++) {
					parsedArgs[j] = parsedArgs[j+1]; /* Move the string upward by 1 */
			}
			(*pNumArgs)--; /* Remove 1 from the total number of arguments */
			i--; /* Move the counter back since we've removed the args */
		}
		else if((!strncmp(parsedArgs[i], "-", 1)) && (!endOfJvmArgs)) { /* for "-verbose", "-noverify", etc. support */
				char *tmpbuf = (char*)malloc(sizeof(char) * (strlen(parsedArgs[i]) + 6)); /* adding "xxx" and "yyy" */
				BZERO(tmpbuf, (strlen(parsedArgs[i]) + 6));

				sprintf(tmpbuf, "%03d%s000", strlen(parsedArgs[i]), parsedArgs[i]);
				strcat(jvmPropBuf_X, tmpbuf);
				numProp++;
				free(tmpbuf);

				for(j = i; j < (*pNumArgs);  j++) {
						parsedArgs[j] = parsedArgs[j+1]; /* Move the string upward by 1 */
				}
				(*pNumArgs)--; /* Remove 1 from the total number of arguments */
				i--; /* Move the counter back since we've removed the args */
		}
		else {
			endOfJvmArgs = TRUE;
		}
	}

	/* Workaround for defect 217412 "stdin problem on iSeries" */
	numProp++; /* 239022 */
	strcat(jvmPropBuf_D, "019os400.stdin.allowed0011"); /* 26 chars */
	/* Workaround ends */

	/* Bug 68899 */
	numProp++;
	strcat(jvmPropBuf_D, "012java.version0031.4"); /* 21 chars */
	/* Bug 68899 */

	if(numProp == 0) {
		as400arg4 = "0"; /* If no JVM arg then set to zero */
	}
	else {
		sprintf(as400arg4, "%03d", numProp); /* Print the number of JVM args */
		strcat(as400arg4, jvmPropBuf_X); /* Append the actual AS/400 formatted JVM args */
		strcat(as400arg4, jvmPropBuf_D); /* Append the actual AS/400 formatted JVM args */
	}
	free(jvmPropBuf_X);
	free(jvmPropBuf_D);

	return as400arg4;
}

#if 0 /* Code to clean up file descriptors */
/* 239720 */
void hc_initProcessStdioList() {
	int i;
	for(i = 0; i < MAX_FD; i++) {
		processStdioList[i].pid = -1;
		processStdioList[i].in = -1;
		processStdioList[i].out = -1;
		processStdioList[i].err = -1;
	}
}

void hc_addToProcessStdioList(PID pid, int in, int out, int err) {
	int i = 0;
	BOOL done = FALSE;

	while((i < MAX_FD) && (!done)) {
		if(processStdioList[i].pid == -1) { /* found an empty spot */
			processStdioList[i].pid = pid;
			processStdioList[i].in = in;
			processStdioList[i].out = out;
			processStdioList[i].err = err;
			done = TRUE;
		}
		i++;
	}
	if(!done) {
	}

	return;
}

void hc_removeFromProcessStdioList(PID pid) {
	int i = 0;
	BOOL done = FALSE;

	while((i < MAX_FD) && (!done)) {
		if(processStdioList[i].pid == pid) { /* found the pid */
			close(processStdioList[i].in);
			close(processStdioList[i].out);
			close(processStdioList[i].err);
			processStdioList[i].pid = -1;
			processStdioList[i].in = -1;
			processStdioList[i].out = -1;
			processStdioList[i].err = -1;
			done = TRUE;
		}
		i++;
	}
	if(!done) {
	}
	else {
	}

	return;
}
/* 239720 */
#endif

#endif
