2007-03-17 07:39:46 +01:00
/***********************************************************************
*
* Copyright ( C ) 2006 Novell , Inc . All Rights Reserved .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; version 2.1
* of the License .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , Novell , Inc .
*
* To contact Novell about this file by physical or electronic mail ,
* you may find current contact information at www . novell . com .
*
* Author : Greg Richardson < grichardson @ novell . com >
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-01-31 21:24:41 +01:00
// CommandLauncher.cpp : Defines the entry point for the application.
//
# include "stdafx.h"
# include "CommandLauncher.h"
# include "string.h"
# include <stdio.h>
# include <stdlib.h>
# include <conio.h>
# include <process.h>
# include <errno.h>
WCHAR * * G_rgArgs ; // Command line arguments
2007-03-17 07:39:46 +01:00
int G_cArg ; // Count of command line arguments
//FILE * G_pf;
2007-01-31 21:24:41 +01:00
// Forward declarations of functions included in this code module:
int processArguments ( LPTSTR lpCmdLine ) ;
void freeArgs ( ) ;
int countArgs ( LPTSTR lpCmdLine ) ;
int addArg ( int iArg , LPTSTR lpString , int cChar ) ;
void log ( LPTSTR szMessage ) ;
_TCHAR * errorMessage ( int err ) ;
int executeCommand ( int cArg , _TCHAR * rgArg [ ] ) ;
2007-03-17 07:39:46 +01:00
# define ERROR_NO_ERROR 0
# define ERROR_MEMORY_ALLOCATION_FAILED -1
# define ERROR_INVALID_NUMBER_OF_PARAMETERS -2
# define ERROR_EXEC_E2BIG -3
# define ERROR_EXEC_EACCES -4
# define ERROR_EXEC_EINVAL -5
# define ERROR_EXEC_EMFILE -6
# define ERROR_EXEC_ENOENT -7
# define ERROR_EXEC_ENOEXEC -8
# define ERROR_EXEC_ENOMEM -9
# define ERROR_EXEC_UNKNOWN -10
# define ERROR_STRCPY_FAILED -11
# define ERROR_JAVA_EXE_ARG_MISSING -12
# define ERROR_JAVA_CLASSPATH_OPTION_ARG_MISSING -13
# define ERROR_JAVA_CLASSPATH_ARG_MISSING -14
# define ERROR_BAD_COMMAND_LINE -15
2007-01-31 21:24:41 +01:00
int APIENTRY _tWinMain ( HINSTANCE hInstance ,
2007-03-17 07:39:46 +01:00
HINSTANCE hPrevInstance ,
LPTSTR lpCmdLine ,
int nCmdShow )
2007-01-31 21:24:41 +01:00
{
2007-03-17 07:39:46 +01:00
UNREFERENCED_PARAMETER ( hInstance ) ;
UNREFERENCED_PARAMETER ( hPrevInstance ) ;
UNREFERENCED_PARAMETER ( lpCmdLine ) ;
UNREFERENCED_PARAMETER ( nCmdShow ) ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
int rc ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
//_wfopen_s(&G_pf, L"C:\\CommandLauncher.log", L"a+");
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Process the command line
if ( ERROR_NO_ERROR ! = ( rc = processArguments ( lpCmdLine ) ) )
{
return rc ;
}
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
rc = executeCommand ( G_cArg , G_rgArgs ) ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
log ( errorMessage ( rc ) ) ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
//fwprintf(G_pf, L"CommandLauncher: return = %d\n", rc);
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
//fclose(G_pf);
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
return rc ;
2007-01-31 21:24:41 +01:00
}
// <java exe path> -cp <classpath> class k1=v1 k2=k2
int processArguments ( LPTSTR lpCmdLine )
{
2007-03-17 07:39:46 +01:00
int iArg ;
int iChar ;
int iAssignment ;
int iClassStart ;
int iClassEnd ;
int iClassPathStart ;
int iClassPathEnd ;
int rc ;
bool fClasspathOptionFound = false ;
int iKeyStart ;
int iValueEnd ;
//fwprintf( G_pf, L"current command line = %s\n", lpCmdLine);
// Validate the command line
if ( NULL = = lpCmdLine | | ( WCHAR ) 0 = = * lpCmdLine )
{
return ERROR_BAD_COMMAND_LINE ;
}
// Count the arguments on the command line. TThe name of this executable
// is not included in the count.
G_cArg = countArgs ( lpCmdLine ) ;
// Make sure we got enough to exec something. There must be at least the
// path to jave.exe, the classpath option, the classpath and a class.
if ( G_cArg < 4 )
{
return ERROR_INVALID_NUMBER_OF_PARAMETERS ;
}
// Allocate an array of wide string for the arguments, add 1 for a NULL at
// the end of the array
G_rgArgs = ( WCHAR * * ) malloc ( ( G_cArg + 1 ) * sizeof ( WCHAR * ) ) ;
if ( NULL = = G_rgArgs )
{
return ERROR_MEMORY_ALLOCATION_FAILED ;
}
// Null out the array
memset ( G_rgArgs , 0 , ( G_cArg + 1 ) * sizeof ( WCHAR * ) ) ;
// Find the java.exe argument
iChar = 0 ;
for ( iChar = 0 ; 0 ! = lpCmdLine [ iChar + 4 ] ; iChar + + )
{
if ( 0 = = _wcsnicmp ( lpCmdLine + iChar , L " .exe " , 4 ) )
{
break ;
}
}
if ( 0 = = lpCmdLine [ iChar + 4 ] )
{
rc = ERROR_JAVA_EXE_ARG_MISSING ;
goto ErrorOut ;
}
// Add the java.exe argument
if ( ERROR_NO_ERROR ! = ( rc = addArg ( 0 , lpCmdLine , iChar + 4 ) ) )
{
goto ErrorOut ;
}
// Move past the java.exe argument
iChar + = 4 ;
// Move past any spaces
for ( ; L ' ' = = lpCmdLine [ iChar ] ; iChar + + )
{
// Intentionally left blank
}
// Find the classpath argument
for ( ; 0 ! = lpCmdLine [ iChar + 3 ] ; iChar + + )
{
if ( 0 = = _wcsnicmp ( lpCmdLine + iChar , L " -cp " , 3 ) )
{
fClasspathOptionFound = true ;
break ;
}
}
if ( ! fClasspathOptionFound )
{
rc = ERROR_JAVA_CLASSPATH_OPTION_ARG_MISSING ;
goto ErrorOut ;
}
if ( 0 = = lpCmdLine [ iChar + 3 ] )
{
rc = ERROR_JAVA_CLASSPATH_ARG_MISSING ;
goto ErrorOut ;
}
// Add the classpath option argument
if ( ERROR_NO_ERROR ! = ( rc = addArg ( 1 , L " -cp " , iChar + 3 ) ) )
{
goto ErrorOut ;
}
// Move past the classpath option argument
iChar + = 3 ;
// Move past any spaces
for ( ; L ' ' = = lpCmdLine [ iChar ] ; iChar + + )
{
// Intentionally left blank
}
// The classpath is next. It can have spaces in it so we need to work
// backards from the first key/value pair, or the end of the line if
// there are no key/value pairs.
iClassPathStart = iChar ;
// Find the location of the next '='
for ( ; 0 ! = lpCmdLine [ iChar ] & & L ' = ' ! = lpCmdLine [ iChar ] ; iChar + + )
{
// Intentially left blank
}
// If there was a key/value pair - move to the start of the key
if ( L ' = ' = = lpCmdLine [ iChar ] )
{
iAssignment = iChar ;
// Move back to the previous space. This should put us at the
// beginning of the first key/value pair. Assume that all args
// are property key/value pairs and property keys have no spaces.
for ( ; L ' ' ! = lpCmdLine [ iChar ] & & iChar > = 0 ; iChar - - )
{
// Intentially left blank
}
}
else
{
iAssignment = 0 ;
iChar - - ;
}
// Move past any spaces (moving toward the start of the line)
for ( ; L ' ' = = lpCmdLine [ iChar ] ; iChar - - )
{
// Intentionally left blank
}
// This should put us at the end of the class to be executed
iClassEnd = iChar ;
// Move to the previous space (moving toward the start of the line)
for ( ; L ' ' ! = lpCmdLine [ iChar ] ; iChar - - )
{
// Intentionally left blank
}
iClassStart = iChar + 1 ;
// Add the class argument
if ( ERROR_NO_ERROR ! = ( rc = addArg ( 3 , lpCmdLine + iClassStart , iClassEnd - iClassStart + 1 ) ) )
{
goto ErrorOut ;
}
// Move past any spaces (moving toward the start of the line)
for ( ; L ' ' = = lpCmdLine [ iChar ] ; iChar - - )
{
// Intentionally left blank
}
// This should put us at the end of the classpath
iClassPathEnd = iChar ;
// Add the class path argument
if ( ERROR_NO_ERROR ! = ( rc = addArg ( 2 , lpCmdLine + iClassPathStart , iClassPathEnd - iClassPathStart + 1 ) ) )
{
goto ErrorOut ;
}
// Are the any key/value pairs?
if ( 0 ! = iAssignment )
{
iArg = 4 ;
while ( 0 ! = lpCmdLine [ iAssignment ] )
{
iKeyStart = iAssignment ;
// Move back to the previous space. This should put us at the
// beginning of the current next key/value pair. Assume that all args
// are property key/value pairs and property keys have no spaces.
for ( ; L ' ' ! = lpCmdLine [ iKeyStart ] & & iKeyStart > 0 ; iKeyStart - - )
{
// Intentially left blank
}
if ( L ' ' = = lpCmdLine [ iKeyStart ] )
{
iKeyStart + + ;
}
// Find the location of the next '='
iValueEnd = iAssignment + 1 ;
for ( ; 0 ! = lpCmdLine [ iValueEnd ] & & L ' = ' ! = lpCmdLine [ iValueEnd ] ; iValueEnd + + )
{
// Intentially left blank
}
// If there was a property...
if ( L ' = ' = = lpCmdLine [ iValueEnd ] )
{
iAssignment = iValueEnd ;
// Move back to the previous space. This should put us at the
// beginning of the next key/value pair. Assume that all args
// are property key/value pairs and property keys have no spaces.
for ( ; L ' ' ! = lpCmdLine [ iValueEnd ] & & iValueEnd > = 0 ; iValueEnd - - )
{
// Intentially left blank
}
}
else
{
// We have reached the end of the command line - back off from the
// null terminator.
iAssignment = iValueEnd ;
iValueEnd - - ;
}
// Move thorugh any spaces
for ( ; L ' ' = = lpCmdLine [ iValueEnd ] & & iValueEnd > = 0 ; iValueEnd - - )
{
// Intentially left blank
}
// Add the key/value pair
if ( ERROR_NO_ERROR ! = ( rc = addArg ( iArg , lpCmdLine + iKeyStart , iValueEnd - iKeyStart + 1 ) ) )
{
goto ErrorOut ;
}
// Go on to the next arg
iArg + + ;
}
}
return ERROR_NO_ERROR ;
2007-01-31 21:24:41 +01:00
ErrorOut :
2007-03-17 07:39:46 +01:00
freeArgs ( ) ;
log ( errorMessage ( rc ) ) ;
return rc ;
2007-01-31 21:24:41 +01:00
}
void freeArgs ( )
{
2007-03-17 07:39:46 +01:00
int iArg ;
if ( NULL ! = G_rgArgs )
{
for ( iArg = 0 ; iArg < G_cArg ; iArg + + )
{
if ( NULL ! = G_rgArgs [ iArg ] )
{
free ( G_rgArgs [ iArg ] ) ;
G_rgArgs [ iArg ] = NULL ;
}
}
free ( G_rgArgs ) ;
G_rgArgs = NULL ;
}
2007-01-31 21:24:41 +01:00
}
int countArgs ( LPTSTR lpCmdLine )
{
2007-03-17 07:39:46 +01:00
int cArgument ;
// Check if the exe to execute is the only argument. Assume that all additional
// arguments have an '=' in them.
for ( cArgument = 4 ; * lpCmdLine ! = ( WCHAR ) 0 ; lpCmdLine + + )
{
if ( * lpCmdLine = = L ' = ' )
{
cArgument + + ;
}
}
return cArgument ;
2007-01-31 21:24:41 +01:00
}
int addArg ( int iArg , LPTSTR lpString , int cChar )
{
2007-03-17 07:39:46 +01:00
int cb = ( cChar + 3 ) * sizeof ( WCHAR ) ; // count of bytes
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Allocate space for the new arg
G_rgArgs [ iArg ] = ( WCHAR * ) malloc ( cb ) ;
if ( NULL = = G_rgArgs [ iArg ] )
{
return ERROR_MEMORY_ALLOCATION_FAILED ;
}
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Null out the argument
memset ( G_rgArgs [ iArg ] , 0 , cb ) ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Add a starting quote
// G_rgArgs[iArg][0] = L'\"';
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Copy the arg
if ( 0 ! = wcsncpy_s ( G_rgArgs [ iArg ] , cChar + 1 , lpString , cChar ) )
{
return ERROR_STRCPY_FAILED ;
}
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
// Add a terminating quote
// G_rgArgs[iArg][cb-1] = L'\"';
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
return ERROR_NO_ERROR ;
2007-01-31 21:24:41 +01:00
}
void log ( LPTSTR szMessage )
{
2007-03-17 07:39:46 +01:00
/*
LPTSTR szT = L " " ;
if ( NULL = = szMessage )
szMessage = szT ;
fwprintf ( G_pf , L " JavaLauncher: %s \n " , szMessage ) ;
*/
2007-01-31 21:24:41 +01:00
}
_TCHAR * errorMessage ( int err )
{
2007-03-17 07:39:46 +01:00
switch ( err )
{
case ERROR_NO_ERROR :
return L " No error \n " ;
case ERROR_MEMORY_ALLOCATION_FAILED :
return L " Memory allocation failed \n " ;
case ERROR_INVALID_NUMBER_OF_PARAMETERS :
return L " Invalid number of parameters \n " ;
case ERROR_EXEC_E2BIG :
return L " _exec: The space required for the arguments and environment settings exceeds 32 KB. \n " ;
case ERROR_EXEC_EACCES :
return L " _exec: The specified file has a locking or sharing violation. \n " ;
case ERROR_EXEC_EINVAL :
return L " _exec: Invalid parameter. \n " ;
case ERROR_EXEC_EMFILE :
return L " _exec: Too many files open (the specified file must be opened to determine whether it is executable). \n " ;
case ERROR_EXEC_ENOENT :
return L " _exec: The file or path not found. \n " ;
case ERROR_EXEC_ENOEXEC :
return L " _exec: The specified file is not executable or has an invalid executable-file format. \n " ;
case ERROR_EXEC_ENOMEM :
return L " _exec: Not enough memory is available to execute the new process; the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly. \n " ;
case ERROR_EXEC_UNKNOWN :
return L " Unknown _exec error. \n " ;
case ERROR_STRCPY_FAILED :
return L " String copy failed. \n " ;
case ERROR_JAVA_CLASSPATH_OPTION_ARG_MISSING :
return L " Classpath option \" -cp \" missing \n " ;
case ERROR_JAVA_CLASSPATH_ARG_MISSING :
return L " Classpath argument missing \n " ;
case ERROR_BAD_COMMAND_LINE :
return L " Bad command line \n " ;
default :
return L " Unknown error. \n " ;
}
2007-01-31 21:24:41 +01:00
}
int executeCommand ( int cArg , _TCHAR * rgArg [ ] )
{
2007-03-17 07:39:46 +01:00
int i ; // Looping variable
int rc = ERROR_NO_ERROR ; // Return code
//fwprintf( G_pf, L"Arg count = %d\n", cArg);
//for (i = 0; i < cArg; i++)
//{
// fwprintf(G_pf, L"rgArg[%d] (%s)\n", i, rgArg[i]);
//}
// exec the command
// if (-1 == _wexecv( rgArg[0], rgArg))
if ( - 1 = = _wspawnv ( _P_WAIT , rgArg [ 0 ] , rgArg ) )
{
switch ( errno )
{
case E2BIG : // The space required for the arguments and environment settings exceeds 32 KB.
rc = ERROR_EXEC_E2BIG ;
break ;
case EACCES : // The specified file has a locking or sharing violation.
rc = ERROR_EXEC_EACCES ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
case EINVAL : // Invalid parameter.
rc = ERROR_EXEC_EINVAL ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
case EMFILE : // Too many files open (the specified file must be opened to determine whether it is executable).
rc = ERROR_EXEC_EMFILE ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
case ENOENT : // The file or path not found.
rc = ERROR_EXEC_ENOENT ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
case ENOEXEC : // The specified file is not executable or has an invalid executable-file format.
rc = ERROR_EXEC_ENOEXEC ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
case ENOMEM : // Not enough memory is available to execute the new process; the available memory has been
// corrupted; or an invalid block exists, indicating that the calling process was not allocated
// properly.
rc = ERROR_EXEC_ENOMEM ;
break ;
2007-01-31 21:24:41 +01:00
2007-03-17 07:39:46 +01:00
default :
rc = ERROR_EXEC_UNKNOWN ;
break ;
}
}
//fwprintf(G_pf, L"ExecuteCommand returning %d\n", rc);
return rc ;
2007-01-31 21:24:41 +01:00
}