/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#include "system.h"
#include <osl/thread.h>

#include <osl/diagnose.h>
//#include <osl/socket.h>

#ifndef _OSL_FILE_PATH_HELPER_H_
#include "file_path_helper.h"
#endif

#include "procimpl.h"
//#include "sockimpl.h"
//#include "secimpl.h"

#include <ctype.h>

//#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
//#endif

// for exception logging
#include <stdio.h>
#include <setjmp.h>


#define MAX_ARGS 255
#define PIPENAMEMASK  "\\PIPE\\OSL_PIPE_%u"
#define SEMNAMEMASK   "\\SEM32\\OSL_SEM_%u"

typedef enum {
	MSG_DATA,
	MSG_END,
	MSG_ACK,
	MSG_REL,
	MSG_UNKNOWN
} MessageType;

typedef struct {
	MessageType		  m_Type;
	oslDescriptorFlag m_Flags;
	oslDescriptorType m_Data;
	HANDLE			  m_Value;
} Message;

typedef struct {
	HPIPE	m_hPipe;
} Pipe;

typedef struct _oslSocketCallbackArg {
	HANDLE	m_socket;
	Pipe*	m_pipe;
} oslSocketCallbackArg;

/* process termination queue */
static sal_Bool            bInitSessionTerm = sal_False;
static const sal_Char * const SessionTermQueueName = "\\QUEUES\\SESSIONS.QUE";
static HQUEUE             SessionTermQueue;

/******************************************************************************
 *
 *                  Function Declarations
 *
 *****************************************************************************/

oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
                                                sal_Char *pszArguments[],
                                                oslProcessOption Options,
                                                oslSecurity Security,
                                                sal_Char *pszDirectory,
                                                sal_Char *pszEnvironments[],
                                                oslProcess *pProcess,
												oslFileHandle *pInputWrite,
												oslFileHandle *pOutputRead,
												oslFileHandle *pErrorRead );

/* implemented in file.c */
extern oslFileError FileURLToPath( char *, size_t, rtl_uString* );

static sal_Bool InitSessionTerm( void )
{
	DosCreateQueue( &SessionTermQueue, QUE_FIFO, (PCSZ) SessionTermQueueName );

	return sal_True;
}

/******************************************************************************
 *
 *                  Functions for starting a process
 *
 *****************************************************************************/

/**********************************************
 osl_executeProcess_WithRedirectedIO
 *********************************************/
 
oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
											rtl_uString *ustrImageName,
											rtl_uString *ustrArguments[],
                                            sal_uInt32   nArguments,
											oslProcessOption Options,
											oslSecurity Security,
											rtl_uString *ustrWorkDir,
											rtl_uString *ustrEnvironment[],
                                            sal_uInt32   nEnvironmentVars,
											oslProcess *pProcess,
											oslFileHandle	*pInputWrite,
											oslFileHandle	*pOutputRead,
											oslFileHandle	*pErrorRead
											)
{

    oslProcessError Error;
    sal_Char* pszWorkDir=0;
    sal_Char** pArguments=0;
    sal_Char** pEnvironment=0;
    unsigned int index;
    
    char szImagePath[PATH_MAX] = "";
    char szWorkDir[PATH_MAX] = "";

#if 0
	if (Options & osl_Process_SEARCHPATH)
	{
		const rtl::OUString PATH1;
		OUString PATH (RTL_CONSTASCII_USTRINGPARAM("PATH"));

		rtl_uString * pSearchPath = 0;
		osl_getEnvironment (PATH.pData, &pSearchPath);
		if (pSearchPath)
		{
			rtl_uString * pSearchResult = 0;
			osl_searchPath (ustrImageName, pSearchPath, &pSearchResult);
			if (pSearchResult)
			{
				rtl_uString_assign (ustrImageName, pSearchResult);
				rtl_uString_release (pSearchResult);
			}
			rtl_uString_release (pSearchPath);
		}
	}
#endif

    if ( ustrImageName && ustrImageName->length )
    {
        FileURLToPath( szImagePath, PATH_MAX, ustrImageName );
    }

    if ( ustrWorkDir != 0 && ustrWorkDir->length )
    {
        FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir );
        pszWorkDir = szWorkDir;
    }

    if ( pArguments == 0 && nArguments > 0 )
    {
        pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) );
    }


    for ( index = 0 ; index < nArguments ; ++index )
    {
        rtl_String* strArg =0;


        rtl_uString2String( &strArg,
                            rtl_uString_getStr(ustrArguments[index]),
                            rtl_uString_getLength(ustrArguments[index]),
                            osl_getThreadTextEncoding(),
                            OUSTRING_TO_OSTRING_CVTFLAGS );

        pArguments[index]=strdup(rtl_string_getStr(strArg));
        rtl_string_release(strArg);
		pArguments[index+1]=0;
    }

    for ( index = 0 ; index < nEnvironmentVars ; ++index )
    {
        rtl_String* strEnv=0;

        if ( pEnvironment == 0 )
        {
            pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) );
        }

        rtl_uString2String( &strEnv,
                            rtl_uString_getStr(ustrEnvironment[index]),
                            rtl_uString_getLength(ustrEnvironment[index]),
                            osl_getThreadTextEncoding(),
                            OUSTRING_TO_OSTRING_CVTFLAGS );

        pEnvironment[index]=strdup(rtl_string_getStr(strEnv));
        rtl_string_release(strEnv);
        pEnvironment[index+1]=0;
    }

	int		rc, pid;
	int		saveOutput = -1, saveInput = -1, saveError = -1;
	int		stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
	FILE	*i, *o, *e;

	if (pInputWrite)
		pipe( stdInput);
	if (pOutputRead)
		pipe( stdOutput);
	if (pErrorRead)
		pipe( stdError);

	fcntl( stdInput[0], F_SETFD, FD_CLOEXEC);
	fcntl( stdInput[1], F_SETFD, FD_CLOEXEC);
	fcntl( stdOutput[0], F_SETFD, FD_CLOEXEC);
	fcntl( stdOutput[1], F_SETFD, FD_CLOEXEC);
	fcntl( stdError[0], F_SETFD, FD_CLOEXEC);
	fcntl( stdError[1], F_SETFD, FD_CLOEXEC);

	saveInput = dup( STDIN_FILENO);
	fcntl( saveInput, F_SETFD, FD_CLOEXEC);
	dup2( stdInput[0], STDIN_FILENO );
	close( stdInput[0] );

	saveOutput = dup( STDOUT_FILENO);
	fcntl( saveOutput, F_SETFD, FD_CLOEXEC);
	dup2( stdOutput[1], STDOUT_FILENO );
	close( stdOutput[1] );

	saveError = dup( STDERR_FILENO);
	fcntl( saveError, F_SETFD, FD_CLOEXEC);
	dup2( stdError[1], STDERR_FILENO );
	close( stdError[1] );

    Error = osl_psz_executeProcess(szImagePath,
                                   pArguments,
                                   Options,
                                   Security,
                                   pszWorkDir,
                                   pEnvironment,
                                   pProcess,
								   pInputWrite,
								   pOutputRead,
								   pErrorRead
								   );

	if ( pInputWrite )
		*(pInputWrite) = osl_createFileHandleFromFD( stdInput[1] );
		
	if ( pOutputRead )
		*(pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] );
		
	if ( pErrorRead )
		*(pErrorRead) = osl_createFileHandleFromFD( stdError[0] );

	// restore handles
	dup2( saveInput, STDIN_FILENO);
	close( saveInput);
	dup2( saveOutput, STDOUT_FILENO);
	close( saveOutput);
	dup2( saveError, STDERR_FILENO);
	close( saveError);

    if ( pArguments != 0 )
    {
        for ( index = 0 ; index < nArguments ; ++index )
        {
            if ( pArguments[index] != 0 )
            {
                free(pArguments[index]);
            }
        }
        free(pArguments);
    }

    if ( pEnvironment != 0 )
    {
        for ( index = 0 ; index < nEnvironmentVars ; ++index )
        {
            if ( pEnvironment[index] != 0 )
            {
                free(pEnvironment[index]);
            }
        }
        free(pEnvironment);
    }

    return Error;
}

/**********************************************
 osl_executeProcess
 *********************************************/
 
oslProcessError SAL_CALL osl_executeProcess(
											rtl_uString *ustrImageName,
											rtl_uString *ustrArguments[],
                                            sal_uInt32   nArguments,
											oslProcessOption Options,
											oslSecurity Security,
											rtl_uString *ustrWorkDir,
											rtl_uString *ustrEnvironment[],
                                            sal_uInt32   nEnvironmentVars,
											oslProcess *pProcess
											)
{
	return osl_executeProcess_WithRedirectedIO(
		ustrImageName,
		ustrArguments,
		nArguments,
		Options,
		Security,
		ustrWorkDir,
		ustrEnvironment,
		nEnvironmentVars,
		pProcess,
		NULL,
		NULL,
		NULL
		);
}

/**********************************************
 osl_psz_executeProcess
 *********************************************/
 
oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
                                                sal_Char *pszArguments[],
                                                oslProcessOption Options,
                                                oslSecurity Security,
                                                sal_Char *pszDirectory,
                                                sal_Char *pszEnvironments[],
                                                oslProcess *pProcess,
												oslFileHandle	*pInputWrite,
												oslFileHandle	*pOutputRead,
												oslFileHandle	*pErrorRead
												)
{
	ULONG ulSessID	= 0;		  /* Session ID returned		  */
	PID pidProcess;
	APIRET rc;
	sal_Char* pStr;
	sal_Char*		 args;
	sal_Char*		 envs;
	int i;
	int n = 1;
	oslProcessImpl* pProcImpl;
    ULONG nAppType, nOwnAppType;
    ULONG nCurrentDisk, nDriveMap, nBufSize;
   	int	 first = 0;
    sal_Char path[ _MAX_PATH ];
    sal_Char currentDir[ _MAX_PATH ];
    sal_Char ownfilename[ _MAX_PATH ];
	RESULTCODES resultCode;
	char** p;

	/* get imagename from arg list, if not specified */
	if (pszImageName == NULL)
		pszImageName = pszArguments[first++];

	OSL_ASSERT(pszImageName != NULL);

	/* check application type */
	rc = DosQueryAppType( (PCSZ) pszImageName, &nAppType );
	if( rc != NO_ERROR )
	{
		if( (rc == ERROR_FILE_NOT_FOUND) || (rc == ERROR_PATH_NOT_FOUND) )
			return osl_Process_E_NotFound;
		else
			return osl_Process_E_Unknown;
    }

    /* backup current disk information */
    if(DosQueryCurrentDisk(&nCurrentDisk, &nDriveMap))
    {
        nCurrentDisk = 0;
    }

    /* backup current directory information */
    nBufSize = _MAX_PATH;
    if(DosQueryCurrentDir(0, (BYTE*)currentDir, &nBufSize))
    {
        *currentDir = '\0';
    }

    /* change to working directory */
    if(pszDirectory && pszDirectory[1] == ':')
    {
        BYTE nDrive = toupper(pszDirectory[0]) - 'A' + 1;

        if(NO_ERROR == DosSetDefaultDisk(nDrive))
        {
            DosSetCurrentDir((PSZ) pszDirectory);
        }
    }

	/* query current executable filename and application type */
	{
		CHAR    szName[CCHMAXPATH];
		PPIB    ppib;
		PTIB    ptib;
		APIRET	rc;
		rc = DosGetInfoBlocks(&ptib, &ppib);
		rc = DosQueryModuleName(ppib->pib_hmte, sizeof(szName), szName);
		DosQueryAppType( (PCSZ)szName, &nOwnAppType );
	}

	/* combination of flags WAIT and DETACHED not supported */
	if( (Options & osl_Process_DETACHED) && (Options & osl_Process_WAIT) )
		Options &= !osl_Process_DETACHED;

	/* start in same session if possible and detached flag not set */
	if( ((nAppType & 0x00000007) == (nOwnAppType & 0x00000007))
/*	    && ((Options & osl_Process_DETACHED) == 0) */ )
	{
		CHAR szbuf[CCHMAXPATH];

		/* calculate needed space for arguments */
		n = strlen( pszImageName ) + 1;
		if( pszArguments )
		   	for (i = first; pszArguments[i] != NULL; i++)
			   	n += strlen(pszArguments[i]) + 1;

		/* allocate space for arguments */
		args = (sal_Char*)malloc(n + 1);
		pStr = args;

		/* add program name as first string to arguments */
		memcpy(pStr, pszImageName, strlen( pszImageName ) );
		pStr += strlen( pszImageName );
		*pStr++ = '\0';

		/* add given strings to arguments */
		if( pszArguments )
			for (i = first; pszArguments[i] != NULL; i++)
			{
				memcpy(pStr, pszArguments[i], strlen( pszArguments[i] ) );
				pStr += strlen( pszArguments[i] );
				if (pszArguments[i+1] != NULL)
					*pStr++ = ' ';
			}

		/* set end marker for arguments */
		*pStr++ = '\0';
		*pStr = '\0';

		OSL_TRACE( "osl_executeProcess with DosExecPgm (args: %s)\n", args );

		/* calculate needed space for environment: since enviroment var search
		   is a linear scan of the current enviroment, we place new variables
		   before existing ones; so the child will find new definitions before
		   olders; this doesn't require us to replace existing vars */
		// existing enviroment size
		n = 0;
		p = environ;
		while( *p) 
		{
			int l = strlen( *p);
			n += l + 1;
			p++;
		}
		// new env size (if exists)
		if( pszEnvironments )
		{
			for (i = 0; pszEnvironments[i] != NULL; i++)
			   	n += strlen(pszEnvironments[i]) + 1;
		}
		/* allocate space for environment */
		envs = (sal_Char*)malloc(n + 1);
		pStr = envs;

		// add new vars
		if( pszEnvironments )
		{
			/* add given strings to environment */
			for (i = 0; pszEnvironments[i] != NULL; i++)
			{
				memcpy(pStr, pszEnvironments[i], strlen( pszEnvironments[i] ) );
				pStr += strlen( pszEnvironments[i] );
				*pStr++ = '\0';
			}
		}
		// add existing vars
		p = environ;
		while( *p) 
		{
			memcpy(pStr, *p, strlen( *p ) );
			pStr += strlen( *p );
			*pStr++ = '\0';
			p++;
		}
		/* set end marker for environment */
		*pStr = '\0';


		if(Options & osl_Process_DETACHED)
		{
			rc = DosExecPgm( szbuf, sizeof( szbuf ), EXEC_BACKGROUND,
							 (PSZ) args, (PSZ) envs, &resultCode, (PSZ) pszImageName );
		}
		else
		{
			rc = DosExecPgm( szbuf, sizeof( szbuf ), EXEC_ASYNCRESULT,
							 (PSZ) args, (PSZ) envs, &resultCode, (PSZ) pszImageName );
		}

		pidProcess = resultCode.codeTerminate;

		/* cleanup */
		free(envs);
   		free(args);

		/* error handling */
		if( rc != NO_ERROR )
			return osl_Process_E_Unknown;
	}

	else
	{
		STARTDATA SData = { 0 };
		UCHAR achObjBuf[ 256 ] = { 0 };

		/* combine arguments separated by spaces */
		if( pszArguments )
		{
			for (i = first; pszArguments[i] != NULL; i++)
				n += strlen(pszArguments[i]) + 1;
			// YD DosStartSession requires low-mem buffers!
			args = (sal_Char*)_tmalloc(n);
			*args = '\0';
			for (i = first; pszArguments[i] != NULL; i++)
			{
				strcat(args, pszArguments[i]);
				strcat(args, " ");
			}
		}
		else
			args = NULL;

		/* combine environment separated by NULL */
		if( pszEnvironments )
		{
			for (i = 0; pszEnvironments[i] != NULL; i++)
				n += strlen(pszEnvironments[i]) + 1;
			// YD DosStartSession requires low-mem buffers!
			envs = (sal_Char*)_tmalloc(n + 1);
			pStr = (sal_Char*)envs;
			for (i = 0; pszEnvironments[i] != NULL; i++)
			{
				memcpy(pStr, pszEnvironments[i], strlen( pszEnvironments[i] ) );
				pStr += strlen( pszEnvironments[i] );
				*pStr = '\0';
				pStr++;
			}
			*pStr = '\0';
		}
		else
			envs = NULL;

		/* initialize data structure */
		memset( &SData, 0, sizeof( STARTDATA ) );
		SData.Length  = sizeof(STARTDATA);

		OSL_TRACE( "osl_executeProcess with DosStartSession (args: %s)\n", args );

		/* OS/2 Application ? */
		if(nAppType & 0x00000007)
		{
		
			/* inherit options from parent */
			SData.InheritOpt = SSF_INHERTOPT_PARENT;

			switch (Options & (osl_Process_NORMAL | osl_Process_MINIMIZED |
						    osl_Process_MAXIMIZED | osl_Process_FULLSCREEN))
			{
				case osl_Process_MINIMIZED:
					SData.SessionType = SSF_TYPE_DEFAULT;
					SData.PgmControl |= SSF_CONTROL_MINIMIZE;
					break;

				case osl_Process_MAXIMIZED:
					SData.SessionType = SSF_TYPE_DEFAULT;
					SData.PgmControl |= SSF_CONTROL_MAXIMIZE;
					break;

				case osl_Process_FULLSCREEN:
					SData.SessionType = SSF_TYPE_FULLSCREEN;
					break;

				default:
					SData.SessionType = SSF_TYPE_DEFAULT;
			} /* switch */
		}


		if( Options & osl_Process_DETACHED )
		{
			/* start an independent session */
			SData.Related = SSF_RELATED_INDEPENDENT;
			SData.TermQ = NULL;
		}
		else
		{
			/* start a child session and set Termination Queue */
			SData.Related = SSF_RELATED_CHILD;

			if(! bInitSessionTerm)
				bInitSessionTerm = InitSessionTerm();

			SData.TermQ = (BYTE*) SessionTermQueueName;
		}

		SData.FgBg	= SSF_FGBG_FORE;	  /* start session in foreground  */
		SData.TraceOpt = SSF_TRACEOPT_NONE;	  /* No trace				 */

		SData.PgmTitle = NULL;
		SData.PgmInputs = (BYTE*)args;
		SData.PgmName = (PSZ) pszImageName;
		SData.Environment = (BYTE*)envs;

		if( Options & osl_Process_HIDDEN )
			SData.PgmControl |= SSF_CONTROL_INVISIBLE;
		else
			SData.PgmControl |= SSF_CONTROL_VISIBLE;

		SData.ObjectBuffer  = (PSZ) achObjBuf;
		SData.ObjectBuffLen = (ULONG) sizeof(achObjBuf);


		/* Start the session */
		rc = DosStartSession( &SData, &ulSessID, &pidProcess );

		/* ignore error "session started in background" */
		if( rc == ERROR_SMG_START_IN_BACKGROUND )
			rc = NO_ERROR;

	
		if(envs)
			_tfree(envs);
		if(args)
			_tfree(args);

		if( rc != NO_ERROR )
			return osl_Process_E_Unknown;

	} /* else */


    /* restore current disk */
    if(nCurrentDisk)
    {
        DosSetDefaultDisk(nCurrentDisk);
    }

    /* restore current drive information */
    if(*currentDir)
    {
        DosSetCurrentDir((PCSZ)currentDir);
    }

	/* allocate intern process structure and store child process ID */
	pProcImpl = (oslProcessImpl*)malloc(sizeof(oslProcessImpl));
	pProcImpl->pProcess = pidProcess;
	pProcImpl->nSessionID = ulSessID;

   	pProcImpl->bResultCodeValid = FALSE;

	if( Options & osl_Process_WAIT )
		osl_joinProcess(pProcImpl);

	*pProcess = (oslProcess)pProcImpl;

	if( rc == NO_ERROR )
		return osl_Process_E_None;
	else

		return osl_Process_E_Unknown;
}

/*----------------------------------------------------------------------------*/

oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
{
	if (Process == NULL)
		return osl_Process_E_Unknown;

	/* Stop the session */
	DosStopSession( STOP_SESSION_SPECIFIED, ((oslProcessImpl*)Process)->nSessionID );

	return osl_Process_E_None;
}

/*----------------------------------------------------------------------------*/

oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident)
{
	HANDLE		  hProcess;
	oslProcessImpl* pProcImpl;

	/* check, if given PID is a valid process */
	if (FALSE)
	{
		pProcImpl = (oslProcessImpl*)malloc(sizeof(oslProcessImpl));
/*		
		pProcImpl->pProcess = pidProcess;
		pProcImpl->nSessionID = ulSessID;
*/		
	}
	else
		pProcImpl = NULL;

	return (pProcImpl);
}

/*----------------------------------------------------------------------------*/

void SAL_CALL osl_freeProcessHandle(oslProcess Process)
{
	/* free intern process structure */
	if (Process != NULL)
		free((oslProcessImpl*)Process);
}

/*----------------------------------------------------------------------------*/

oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
{
	oslProcessImpl* pProcImpl = (oslProcessImpl*) Process;
	APIRET rc;

	if (Process == NULL)
		return osl_Process_E_Unknown;

	/* process of same session ? */
	if( pProcImpl->nSessionID == 0 )
	{
		RESULTCODES resultCode;
		PID pidEnded;
			
		rc = DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &resultCode,
		        &pidEnded, pProcImpl->pProcess );

		if( rc == NO_ERROR )
		{
			pProcImpl->nResultCode = resultCode.codeResult;
			pProcImpl->bResultCodeValid = TRUE;

			return osl_Process_E_None;
		}
	}
	else
	{
		ULONG pcbData, ulElement = 0;
		REQUESTDATA rdData;
		BYTE bPriority;
		struct {
			USHORT SessionID;
			USHORT ReturnValue;
		} *pvBuffer;

		/* search/wait for the correct entry in termination queue */
		while( ( rc = DosPeekQueue( SessionTermQueue, &rdData, &pcbData,
			            (PPVOID) &pvBuffer, &ulElement, DCWW_WAIT,
			            &bPriority, NULLHANDLE )) == NO_ERROR )
		{

			if( pvBuffer->SessionID == pProcImpl->nSessionID )
			{
				pProcImpl->nResultCode = pvBuffer->ReturnValue;
				pProcImpl->bResultCodeValid = TRUE;

				/* remove item from queue */
				rc = DosReadQueue( SessionTermQueue, &rdData, &pcbData,
				       (PPVOID)&pvBuffer, ulElement, DCWW_WAIT,
					   &bPriority, NULLHANDLE );

				if( rc == NO_ERROR )
					return osl_Process_E_None;
				else
					return osl_Process_E_Unknown;
			}
		} /* while */
	}
	return osl_Process_E_Unknown;
}

/***************************************************************************/

//YD FIXME incomplete!
oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout)
{
	return osl_joinProcess( Process);
}

/*----------------------------------------------------------------------------*/

oslProcessError SAL_CALL osl_getCommandArgs( sal_Char* pszBuffer, sal_uInt32 Max)
{

	static int  CmdLen = -1;
	static sal_Char CmdLine[_MAX_CMD];

	OSL_ASSERT(pszBuffer);
	OSL_ASSERT(Max > 1);

	/* Query commandline during first call of function only */
	if (CmdLen < 0)
	{
		sal_Bool bEscaped = sal_False;
		sal_Bool bSeparated = sal_True;
		sal_Char* pszBufferOrg = pszBuffer;
		sal_Char* pszCmdLine;

		/* get pointer to commandline */
		{
			PTIB pptib = NULL;
			PPIB pppib = NULL;

			DosGetInfoBlocks(&pptib, &pppib);
			pszCmdLine = pppib->pib_pchcmd;
		}

		/* skip first string */
		while( *pszCmdLine )
			pszCmdLine++;

		/* concatenate commandline arguments for the given string */
		Max -= 2;
		while ( !((*pszCmdLine == '\0') && (*(pszCmdLine + 1) == '\0')) && (Max > 0))
        {
            /*
             *  C-Runtime expects char to be unsigned and so to be
             *  preceeded with 00 instead of FF when converting to int
             */
            int n = *((unsigned char *) pszCmdLine);
			if (! (isspace(n) || (*pszCmdLine == '\0')) )
			{
				if (*pszCmdLine == '"')
				{
					if (*(pszCmdLine + 1) != '"')
						bEscaped = ! bEscaped;
					else
					{
						pszCmdLine++;
						*pszBuffer++ = *pszCmdLine;
						Max--;
					}
				}
				else
				{
					*pszBuffer++ = *pszCmdLine;
					Max--;
				}
				bSeparated = sal_False;
			}
			else
			{
				if (bEscaped)
					*pszBuffer++ = *pszCmdLine;
				else
					if (! bSeparated)
					{
						*pszBuffer++ = '\0';
						bSeparated = sal_True;
					}
				Max--;
			}

			pszCmdLine++;
		}

		*pszBuffer++ = '\0';
		*pszBuffer++ = '\0';

		/* restore pointer and save commandline for next query */
		CmdLen = pszBuffer - pszBufferOrg;
		pszBuffer = pszBufferOrg;
		memcpy( CmdLine, pszBuffer, CmdLen );
	}
	else
	   memcpy( pszBuffer, CmdLine, CmdLen );

	OSL_TRACE( "osl_getCommandArgs (args: %s)\n", pszBuffer );

	return osl_Process_E_None;
}

/*----------------------------------------------------------------------------*/

oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields,
								   oslProcessInfo* pInfo)
{
	if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
		return osl_Process_E_Unknown;

	pInfo->Fields = 0;		

	if (Fields & osl_Process_IDENTIFIER)
	{
		if( Process == NULL )
		{
			PTIB pptib = NULL;
			PPIB pppib = NULL;

			DosGetInfoBlocks( &pptib, &pppib );
			pInfo->Ident = pppib->pib_ulpid;
		}
		else
			pInfo->Ident = ((oslProcessImpl*)Process)->pProcess;
			
		pInfo->Fields |= osl_Process_IDENTIFIER;		
	}

	if (Fields & osl_Process_EXITCODE)
	{
		oslProcessImpl* pProcImpl = (oslProcessImpl*) Process;
		
		if( pProcImpl->bResultCodeValid )
		{
			pInfo->Code = pProcImpl->nResultCode;
			pInfo->Fields |= osl_Process_EXITCODE;
		}
		else
		{
			APIRET rc;

			if( pProcImpl->nSessionID == 0 )
			{
				RESULTCODES resultCode;
				PID pidEnded;
					
				rc = DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &resultCode,
				        &pidEnded, pProcImpl->pProcess );

				if( rc == NO_ERROR )
				{
					pProcImpl->nResultCode = resultCode.codeResult;
					pProcImpl->bResultCodeValid = TRUE;

					pInfo->Code = pProcImpl->nResultCode;
					pInfo->Fields |= osl_Process_EXITCODE;

					return osl_Process_E_None;
				}
			}
			else
			{
				ULONG pcbData, ulElement = 0;
				REQUESTDATA rdData;
				BYTE bPriority;
				struct {
					USHORT SessionID;
					USHORT ReturnValue;
				} *pvBuffer;

				/* search/wait for the correct entry in termination queue */
				while( ( rc = DosPeekQueue( SessionTermQueue, &rdData, &pcbData,
					            (PPVOID) &pvBuffer, &ulElement, DCWW_WAIT,
					            &bPriority, NULLHANDLE )) == NO_ERROR )
				{

					if( pvBuffer->SessionID == pProcImpl->nSessionID )
					{
						pProcImpl->nResultCode = pvBuffer->ReturnValue;
						pProcImpl->bResultCodeValid = TRUE;

						pInfo->Code = pProcImpl->nResultCode;
						pInfo->Fields |= osl_Process_EXITCODE;

						/* remove item from queue */
						rc = DosReadQueue( SessionTermQueue, &rdData, &pcbData,
					   	    (PPVOID)&pvBuffer, ulElement, DCWW_WAIT,
							   &bPriority, NULLHANDLE );

						break;
					}
				}
			} 
		} 
	}

	if (Fields & osl_Process_HEAPUSAGE)
	{
	}
	if (Fields & osl_Process_CPUTIMES)
	{
	}

	return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
}
