#include "installOS.h" | |
#include "installShm.h" | |
#include "installConfig.h" | |
#include "log.h" | |
#include "extract.h" | |
#ifdef _WIN32 | |
#include <direct.h> | |
#else | |
#include <unistd.h> | |
#include <strings.h> | |
#endif | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <errno.h> | |
#include <ctype.h> | |
#include <signal.h> | |
#include <stddef.h> | |
#ifndef boolean | |
#define boolean int | |
#endif | |
#define MAX_PATH_LENGTH 2000 | |
#define MAX_SHARED_LENGTH (16 * 1024) | |
#ifdef _WIN32 | |
#define LOG_FILE _T_INSTALL("C:\\rcpinstall.log") | |
#else | |
#define LOG_FILE _T_INSTALL("/tmp/rcpinstall.log") | |
#endif | |
/* Global Variables */ | |
_TCHAR* officialName = NULL; | |
/* Global Data */ | |
static _TCHAR* program = NULL; /* full pathname of the program */ | |
static _TCHAR* temporaryDir = NULL; /* temporary directory where files extracted */ | |
static _TCHAR* javaVM = NULL; /* full pathname of the Java VM to run */ | |
static _TCHAR* jarFile = NULL; /* full pathname of the startup jar file to run */ | |
static _TCHAR* sharedID = NULL; /* ID for the shared memory */ | |
static _TCHAR* sharedSplashID = NULL; /* ID for the shared memory */ | |
/* Define the maximum time (in seconds) for the splash window to remain visible. */ | |
static _TCHAR* splashTimeout = _T_INSTALL("600"); /* 10 minutes */ | |
/* Define error messages. (non-NLS) */ | |
static _TCHAR* exitMsg = _T_INSTALL("JVM terminated. Exit code=%d\n%s"); | |
static _TCHAR* pathMsg = _T_INSTALL("%s\n'%s' in your current PATH"); | |
static _TCHAR* showMsg = _T_INSTALL("Could not load splash bitmap:\n%s"); | |
static _TCHAR* shareMsg = _T_INSTALL("No shared data available."); | |
static _TCHAR* noVMMsg = | |
_T_INSTALL("A Java Runtime Environment (JRE) or Java Development Kit (JDK)\n\ | |
must be available in order to run %s. No Java virtual machine\n\ | |
was found after searching the following locations:\n\ | |
%s"); | |
static _TCHAR* configName = _T_INSTALL("install.ini"); | |
static _TCHAR* splashName = _T_INSTALL("splash.bmp"); | |
#define DEFAULT_STARTUP _T_INSTALL("install.jar") | |
/* Define constants for the options recognized by the launcher. */ | |
#define CONSOLE _T_INSTALL("-console") | |
#define CONSOLELOG _T_INSTALL("-consoleLog") | |
#define DEBUG _T_INSTALL("-debug") | |
#define LOG _T_INSTALL("-log") | |
#define OS _T_INSTALL("-os") | |
#define OSARCH _T_INSTALL("-arch") | |
#define NOSPLASH _T_INSTALL("-nosplash") | |
#define LAUNCHER _T_INSTALL("-launcher") | |
#define SHOWSPLASH _T_INSTALL("-showsplash") | |
#define ENDSPLASH _T_INSTALL("-endsplash") | |
#define EXITDATA _T_INSTALL("-exitdata") | |
#define STARTUP _T_INSTALL("-startup") | |
#define VM _T_INSTALL("-vm") | |
#define WS _T_INSTALL("-ws") | |
#define NAME _T_INSTALL("-name") | |
#define VMARGS _T_INSTALL("-vmargs") /* special option processing required */ | |
/* Define the variables to receive the option values. */ | |
static int needConsole = 0; /* True: user wants a console */ | |
static int debug = 0; /* True: output debugging info */ | |
static int log = 0; /* True: enable logging */ | |
static int noSplash = 0; /* True: do not show splash win */ | |
static _TCHAR* osArg = _T_INSTALL(DEFAULT_OS); | |
static _TCHAR* osArchArg = _T_INSTALL(DEFAULT_OS_ARCH); | |
static _TCHAR* showSplashArg = NULL; /* showsplash data (main launcher window) */ | |
static _TCHAR* exitDataArg = NULL; | |
static _TCHAR * startupArg = DEFAULT_STARTUP; /* path of the startup.jar the user wants to run relative to the program path */ | |
static _TCHAR* vmName = NULL; /* Java VM that the user wants to run */ | |
static _TCHAR* wsArg = _T_INSTALL(DEFAULT_WS); /* the SWT supported GUI to be used */ | |
static _TCHAR* name = NULL; /* program name */ | |
static _TCHAR** userVMarg = NULL; /* user specific args for the Java VM */ | |
static _TCHAR* endSplashArg = NULL; | |
/* Define a table for processing command line options. */ | |
typedef struct | |
{ | |
_TCHAR* name; /* the option recognized by the launcher */ | |
_TCHAR** value; /* the variable where the option value is saved */ | |
int* flag; /* the variable that is set if the option is defined */ | |
int remove; /* the number of argments to remove from the list */ | |
} Option; | |
static Option options[] = { | |
{ CONSOLE, NULL, &needConsole, 0 }, | |
{ CONSOLELOG, NULL, &needConsole, 0 }, | |
{ DEBUG, NULL, &debug, 0 }, | |
{ LOG, NULL, &log, 0 }, | |
{ NOSPLASH, NULL, &noSplash, 1 }, | |
{ OS, &osArg, NULL, 2 }, | |
{ OSARCH, &osArchArg, NULL, 2 }, | |
// { SHOWSPLASH, &showSplashArg, NULL, 2 }, | |
{ ENDSPLASH, &endSplashArg, NULL, 2 }, | |
// { EXITDATA, &exitDataArg, NULL, 2 }, | |
// { STARTUP, &startupArg, NULL, 2 }, | |
{ VM, &vmName, NULL, 2 }, | |
{ NAME, &name, NULL, 2 }, | |
{ WS, &wsArg, NULL, 2 } }; | |
static int optionsSize = (sizeof(options) / sizeof(options[0])); | |
static int configArgc = 0; | |
static _TCHAR** configArgv = NULL; | |
/* Define the required VM arguments (all platforms). */ | |
static _TCHAR* jar = _T_INSTALL("-jar"); | |
static _TCHAR** reqVMarg[] = { &jar, &jarFile, NULL }; | |
/* Local methods */ | |
static int createUserArgs(int configArgc, _TCHAR **configArgv, int *argc, _TCHAR ***argv); | |
static void parseArgs( int* argc, _TCHAR* argv[] ); | |
static _TCHAR** parseArgList( _TCHAR *data ); | |
static void freeArgList( _TCHAR** data ); | |
static _TCHAR** getVMCommand( int argc, _TCHAR* argv[] ); | |
_TCHAR* findCommand( _TCHAR* command ); | |
static _TCHAR* formatVmCommandMsg( _TCHAR* args[] ); | |
_TCHAR* getProgramDir(); | |
static _TCHAR* getDefaultOfficialName(); | |
static int isMainInstall( int argc, _TCHAR **argv ); | |
#ifdef _WIN32 | |
#ifdef UNICODE | |
extern int main(int, char**); | |
int mainW(int, wchar_t**); | |
int wmain( int argc, wchar_t** argv ) { | |
OSVERSIONINFOW info; | |
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); | |
/* | |
* If the OS supports UNICODE functions, run the UNICODE version | |
* of the main function. Otherwise, convert the arguments to | |
* MBCS and run the ANSI version of the main function. | |
*/ | |
if (!GetVersionExW (&info)) { | |
int i, result; | |
char **newArgv = malloc(argc * sizeof(char *)); | |
for (i=0; i<argc; i++) { | |
wchar_t *oldArg = argv[i]; | |
int byteCount = WideCharToMultiByte (CP_ACP, 0, oldArg, -1, NULL, 0, NULL, NULL); | |
char *newArg = malloc(byteCount+1); | |
newArg[byteCount] = 0; | |
WideCharToMultiByte (CP_ACP, 0, oldArg, -1, newArg, byteCount, NULL, NULL); | |
newArgv[i] = newArg; | |
} | |
result = main(argc, newArgv); | |
for (i=0; i<argc; i++) { | |
free(newArgv[i]); | |
} | |
free(newArgv); | |
return result; | |
} | |
return mainW(argc, argv); | |
} | |
#define main mainW | |
#endif /* UNICODE */ | |
#endif /* _WIN32 */ | |
int main( int argc, _TCHAR* argv[] ) | |
{ | |
_TCHAR* splashBitmap = NULL; | |
_TCHAR* data; | |
_TCHAR* shippedVM = NULL; | |
_TCHAR* vmSearchPath = NULL; | |
_TCHAR** vmCommand = NULL; | |
_TCHAR** vmCommandList = NULL; | |
_TCHAR** vmCommandArgs = NULL; | |
_TCHAR* vmCommandMsg = NULL; | |
_TCHAR* errorMsg; | |
int exitCode; | |
_TCHAR* configFile = NULL; | |
struct _stat stats; | |
boolean isMain; | |
/* Determine the full pathname of this program. */ | |
#ifdef _WIN32 | |
program = malloc( MAX_PATH_LENGTH + 1 ); | |
GetModuleFileName( NULL, program, MAX_PATH_LENGTH ); | |
#else | |
program = findCommand( argv[0] ); | |
if (program == NULL) | |
{ | |
program = malloc( strlen( argv[0] ) + 1 ); | |
strcpy( program, argv[0] ); | |
} | |
#endif | |
/* Parse command line arguments (looking for the VM to use). */ | |
/* Override configuration file arguments */ | |
parseArgs( &argc, argv ); | |
/* Special case - user arguments specified in the config file | |
* are appended to the user arguments passed from the command line. | |
*/ | |
if (configArgc > 1) | |
{ | |
createUserArgs(configArgc, configArgv, &argc, &argv); | |
} | |
if ( isMain = isMainInstall(argc, argv) ) | |
{ | |
int error; | |
if ( log ) createLog(LOG_FILE); | |
logFormatS(_T_INSTALL("\tINSTALL_FILE = %s"),program); | |
temporaryDir = getTempPath(); | |
logFormatS(_T_INSTALL("\tTEMPORARY_DIR = %s"),temporaryDir); | |
writeLog(_T_INSTALL("[i] Creating TEMPORARY_DIR")); | |
if ( _tmkdir(temporaryDir) != 0 ) | |
{ | |
writeLog(_T_INSTALL("[x] Failed to create TEMPORARY_DIR")); | |
exit( 1 ); | |
} | |
//****************extract config and splash files first**************************** | |
error = extractFile(program,temporaryDir,configName); | |
if ( error != 0 ) { | |
cleanup(); | |
exit( error ); | |
} | |
error = extractFile(program,temporaryDir,splashName); | |
if ( error != 0 ) { | |
cleanup(); | |
exit( error ); | |
} | |
//****************old implementation****************************** | |
/* error = extract(program,temporaryDir); | |
if ( error != 0 ) { | |
cleanup(); | |
exit( error ); | |
} | |
*/ | |
configFile = malloc((_tcslen(temporaryDir)+_tcslen(configName))*sizeof(_TCHAR)); | |
_tcscpy(configFile,temporaryDir); | |
_tcscat(configFile,configName); | |
if (_tstat( configFile, &stats ) == 0) | |
{ | |
logFormatS(_T_INSTALL("\tCONFIG_FILE = %s"),configFile); | |
writeLog(_T_INSTALL("[i] Reading CONFIG_FILE")); | |
/* Parse configuration file arguments */ | |
if ( readConfigFile(configFile, argv[0], &configArgc, &configArgv) == 0 ) | |
{ | |
writeLog(_T_INSTALL("[i] Parsing CONFIG_FILE options")); | |
parseArgs (&configArgc, configArgv); | |
} | |
} | |
if ( configFile != NULL ) | |
free(configFile); | |
} | |
/* Initialize official program name */ | |
officialName = name != NULL ? _tcsdup( name ) : getDefaultOfficialName(); | |
/* Initialize the window system. */ | |
initWindowSystem( &argc, argv, (showSplashArg != NULL) ); | |
/* If the exit data option was given, set exit data */ | |
if (exitDataArg != NULL) | |
{ | |
/* If an extra argument was given, use it as the exit data, otherwise clear exit data */ | |
data = argc > 1 ? argv[1] : NULL; | |
if (data != NULL && _tcslen( data ) > MAX_SHARED_LENGTH - 1) | |
{ | |
exitCode = EINVAL; | |
} | |
else { | |
exitCode = setSharedData( exitDataArg, data ); | |
} | |
if (exitCode != 0 && debug) displayMessage( shareMsg ); | |
exit( exitCode ); | |
} | |
if ( endSplashArg != NULL ) | |
{ | |
exitCode = setSharedData( endSplashArg, ENDSPLASH ); | |
if (exitCode != 0 && debug) displayMessage( shareMsg ); | |
exit( exitCode ); | |
} | |
/* If the showsplash option was given */ | |
if ( isMain && !noSplash ) | |
{ | |
/* look for splash */ | |
splashBitmap = malloc((_tcslen(temporaryDir)+_tcslen(splashName))*sizeof(_TCHAR)); | |
_tcscpy(splashBitmap,temporaryDir); | |
_tcscat(splashBitmap,splashName); | |
if (_tstat( splashBitmap, &stats ) == 0) | |
{ | |
logFormatS(_T_INSTALL("\tSPLASH_FILE = %s"),splashBitmap); | |
writeLog(_T_INSTALL("[i] Showing SPLASH_FILE")); | |
exitCode = showSplash( NULL, splashBitmap ); | |
if (exitCode && debug) | |
{ | |
errorMsg = malloc( (_tcslen(showMsg) + _tcslen(splashBitmap) + 10) * sizeof(_TCHAR) ); | |
_stprintf( errorMsg, showMsg, splashBitmap ); | |
displayMessage( errorMsg ); | |
free( errorMsg ); | |
} else { | |
if (createSharedData( &sharedSplashID, MAX_SHARED_LENGTH )) { | |
if (debug) { | |
displayMessage( shareMsg ); | |
} | |
exit(1); | |
} | |
} | |
} | |
} else if ( showSplashArg != NULL && argc > 1) | |
{ | |
splashBitmap = _tcsdup(argv[1]); | |
exitCode = showSplash( showSplashArg, splashBitmap ); | |
if (exitCode && debug) | |
{ | |
errorMsg = malloc( (_tcslen(showMsg) + _tcslen(splashBitmap) + 10) * sizeof(_TCHAR) ); | |
_stprintf( errorMsg, showMsg, splashBitmap ); | |
displayMessage( errorMsg ); | |
free( errorMsg ); | |
} | |
exit( exitCode ); | |
} | |
/* If the user did not specify a VM to be used */ | |
if (vmName == NULL) | |
{ | |
/* Determine which type of VM should be used. */ | |
vmName = ((debug || needConsole) ? consoleVM : defaultVM); | |
/* Try to find the VM shipped with installer. */ | |
shippedVM = malloc( (_tcslen( temporaryDir ) + _tcslen( shippedVMDir ) + _tcslen( vmName ) + 10) * sizeof(_TCHAR) ); | |
_stprintf( shippedVM, _T_INSTALL("%s%s%s"), temporaryDir, shippedVMDir, vmName ); | |
javaVM = findCommand( shippedVM ); | |
/* Format a message to indicate the default VM search path. */ | |
vmSearchPath = malloc( (_tcslen( pathMsg ) + _tcslen( shippedVM ) + _tcslen( vmName ) + 10) * sizeof(_TCHAR) ); | |
_stprintf( vmSearchPath, pathMsg, shippedVM, vmName ); | |
free( shippedVM ); | |
shippedVM = NULL; | |
} | |
/* If a Java VM has not been found yet */ | |
if (javaVM == NULL) | |
{ | |
/* Either verify the VM specified by the user or | |
attempt to find the VM in the user's PATH. */ | |
javaVM = findCommand( vmName ); | |
/* If the VM was not found, display a message and exit. */ | |
if (javaVM == NULL) | |
{ | |
if (vmSearchPath != NULL) vmName = vmSearchPath; /* used default VM searching */ | |
errorMsg = malloc( (_tcslen(noVMMsg) + _tcslen(officialName) + _tcslen(vmName) + 10) * sizeof(_TCHAR) ); | |
_stprintf( errorMsg, noVMMsg, officialName, vmName ); | |
cleanup(); | |
displayMessage( errorMsg ); | |
free( errorMsg ); | |
exit(1); | |
} | |
} | |
logFormatS(_T_INSTALL("\tJAVA_VM = %s"),javaVM); | |
if (createSharedData( &sharedID, MAX_SHARED_LENGTH )) { | |
if (debug) { | |
displayMessage( shareMsg ); | |
} | |
} | |
//****************************** | |
if ( isMain ) | |
{ | |
int error = extract(program,temporaryDir); | |
if ( error != 0 ) { | |
cleanup(); | |
exit( error ); | |
} | |
} | |
//******************************* | |
/* Construct the absolute name of the startup jar */ | |
jarFile = malloc( (_tcslen( temporaryDir ) + _tcslen( startupArg ) + 1) * sizeof( _TCHAR ) ); | |
jarFile = _tcscpy( jarFile, temporaryDir ); | |
jarFile = _tcscat( jarFile, startupArg ); | |
logFormatS(_T_INSTALL("\tSTARTUP_JAR = %s"),jarFile); | |
/* If the file does not exist, treat the argument as an absolute path */ | |
if (_tstat( jarFile, &stats ) != 0) | |
{ | |
/* TODO: no STARTUP_JAR */ | |
writeLog(_T_INSTALL("[x] Failed to find STARTUP_JAR")); | |
} | |
/* Get the command to start the Java VM. */ | |
vmCommandArgs = getVMCommand( argc, argv ); | |
/* While the Java VM should be restarted */ | |
vmCommand = vmCommandArgs; | |
while (vmCommand != NULL) | |
{ | |
vmCommandMsg = formatVmCommandMsg( vmCommand ); | |
if ( debug ) logFormatS(_T_INSTALL("\tVM_COMMAND = %s"),vmCommandMsg); | |
writeLog(_T_INSTALL("[i] Starting JAVA_VM")); | |
exitCode = startJavaVM( vmCommand ); | |
logFormatI(_T_INSTALL("[i] Process JAVA_VM completes with exitcode #%i"),exitCode); | |
switch( exitCode ) { | |
case 0: | |
vmCommand = NULL; | |
break; | |
default: | |
vmCommand = NULL; | |
errorMsg = NULL; | |
if (getSharedData( sharedID, &errorMsg ) == 0) { | |
if (_tcslen( errorMsg ) == 0) { | |
free( errorMsg ); | |
errorMsg = NULL; | |
} | |
} else { | |
if (debug) displayMessage( shareMsg ); | |
} | |
if (errorMsg == NULL) { | |
errorMsg = malloc( (_tcslen(exitMsg) + _tcslen(vmCommandMsg) + 10) * sizeof(_TCHAR) ); | |
_stprintf( errorMsg, exitMsg, exitCode, vmCommandMsg ); | |
} | |
displayMessage( errorMsg ); | |
free( errorMsg ); | |
break; | |
} | |
free( vmCommandMsg ); | |
} | |
/* Cleanup time. */ | |
cleanup(); | |
writeLog(_T_INSTALL("[i] Deleting TEMPORARY_DIR")); | |
_trmdir(temporaryDir); | |
free( jarFile ); | |
free( splashBitmap ); | |
free( temporaryDir ); | |
free( program ); | |
if ( vmSearchPath != NULL ) free( vmSearchPath ); | |
if ( vmCommandList != NULL ) freeArgList( vmCommandList ); | |
if ( configArgv != NULL ) freeConfig( configArgv ); | |
if (configArgc > 1) free( argv ); | |
free( officialName ); | |
if ( sharedID != NULL ) { | |
if (destroySharedData( sharedID ) != 0) { | |
if (debug) displayMessage( shareMsg ); | |
} | |
free( sharedID ); | |
} | |
if ( sharedSplashID != NULL ) { | |
if (destroySharedData( sharedSplashID ) != 0) { | |
if (debug) displayMessage( shareMsg ); | |
} | |
free( sharedSplashID ); | |
} | |
return 0; | |
} | |
int isEndSplash() | |
{ | |
_TCHAR* end; | |
if (getSharedData( sharedSplashID, &end ) == 0) { | |
if (_tcscmp( end, ENDSPLASH ) == 0) { | |
free( end ); | |
setSharedData( sharedSplashID, _T_INSTALL("") ); | |
writeLog(_T_INSTALL("[i] Hide SPLASH_FILE")); | |
return 1; | |
} | |
free( end ); | |
} | |
return 0; | |
} | |
/* Return 1 if the current process is the process that starts the java VM | |
* Return 0 if it is an process used to display a splash screen or to write | |
* data to a shared memory segment. | |
* The main process is the only one that reads the .ini file. | |
*/ | |
static int isMainInstall( int argc, _TCHAR **argv ) | |
{ | |
/* It is the main program if the argument 3 is neither SHOWSPLASH|ENDSPLASH nor EXITDATA */ | |
// if (argc < 4) return 1; | |
// return (_tcsicmp( argv[3], SHOWSPLASH ) != 0 && _tcsicmp( argv[3], ENDSPLASH ) != 0 && _tcsicmp( argv[3], EXITDATA ) != 0); | |
return (exitDataArg == NULL) && (endSplashArg == NULL); | |
} | |
/* | |
* Parse arguments of the command. | |
*/ | |
static void parseArgs( int* pArgc, _TCHAR* argv[] ) | |
{ | |
Option* option; | |
int remArgs; | |
int index; | |
int i; | |
/* Ensure the list of user argument is NULL terminated. */ | |
argv[ *pArgc ] = NULL; | |
/* For each user defined argument (excluding the program) */ | |
for (index = 1; index < *pArgc; index++){ | |
remArgs = 0; | |
/* Find the corresponding argument is a option supported by the launcher */ | |
option = NULL; | |
for (i = 0; option == NULL && i < optionsSize; i++) | |
{ | |
if (_tcsicmp( argv[ index ], options[ i ].name ) == 0) | |
option = &options[ i ]; | |
} | |
/* If the option is recognized by the launcher */ | |
if (option != NULL) | |
{ | |
/* If the option requires a value and there is one, extract the value. */ | |
if (option->value != NULL && (index+1) < *pArgc) | |
*option->value = argv[ index+1 ]; | |
/* If the option requires a flag to be set, set it. */ | |
if (option->flag != NULL) | |
*option->flag = 1; | |
remArgs = option->remove; | |
} | |
/* All of the remaining arguments are user VM args. */ | |
else if (_tcsicmp( argv[ index ], VMARGS ) == 0) | |
{ | |
userVMarg = &argv[ index+1 ]; | |
argv[ index ] = NULL; | |
*pArgc = index; | |
} | |
/* Remove any matched arguments from the list. */ | |
if (remArgs > 0) | |
{ | |
for (i = (index + remArgs); i <= *pArgc; i++) | |
{ | |
argv[ i - remArgs ] = argv[ i ]; | |
} | |
index--; | |
*pArgc -= remArgs; | |
} | |
} | |
} | |
/* | |
* Create a new array containing user arguments from the config file first and | |
* from the command line second. | |
* Allocate an array large enough to host all the strings passed in from | |
* the argument configArgv and argv. That array is passed back to the | |
* argv argument. That array must be freed with the regular free(). | |
* Note that both arg lists are expected to contain the argument 0 from the C | |
* main method. That argument contains the path/executable name. It is | |
* only copied once in the resulting list. | |
* | |
* Returns 0 if success. | |
*/ | |
static int createUserArgs(int configArgc, _TCHAR **configArgv, int *argc, _TCHAR ***argv) | |
{ | |
_TCHAR** newArray = (_TCHAR **)malloc((configArgc + *argc) * sizeof(_TCHAR *)); | |
memcpy(newArray, configArgv, configArgc * sizeof(_TCHAR *)); | |
/* Skip the argument zero (program path and name) */ | |
memcpy(newArray + configArgc, *argv + 1, (*argc - 1) * sizeof(_TCHAR *)); | |
/* Null terminate the new list of arguments and return it. */ | |
*argv = newArray; | |
*argc += configArgc - 1; | |
(*argv)[*argc] = NULL; | |
return 0; | |
} | |
/* | |
* Free the memory allocated by parseArgList(). | |
*/ | |
static void freeArgList( _TCHAR** data ) { | |
if (data == NULL) return; | |
free( data [0] ); | |
free( data ); | |
} | |
/* | |
* Parse the data into a list of arguments separarted by \n. | |
* | |
* The list of strings returned by this function must be freed with | |
* freeArgList(). | |
*/ | |
static _TCHAR** parseArgList( _TCHAR* data ) { | |
int totalArgs = 0, dst = 0, length; | |
_TCHAR *ch1, *ch2, **execArg; | |
length = _tcslen( data ); | |
ch1 = ch2 = data; | |
while ((ch2 = _tcschr( ch1, _T_INSTALL('\n') )) != NULL) { | |
totalArgs++; | |
ch1 = ch2 + 1; | |
} | |
if (ch1 != data + length) totalArgs++; | |
execArg = malloc( (totalArgs + 1) * sizeof( _TCHAR* ) ); | |
ch1 = ch2 = data; | |
while ((ch2 = _tcschr( ch1, _T_INSTALL('\n') )) != NULL) { | |
execArg[ dst++ ] = ch1; | |
ch2[ 0 ] = _T_INSTALL('\0'); | |
ch1 = ch2 + 1; | |
} | |
if (ch1 != data + length) execArg[ dst++ ] = ch1; | |
execArg[ dst++ ] = NULL; | |
return execArg; | |
} | |
/* | |
* Find the absolute pathname to where a command resides. | |
* | |
* The string returned by the function must be freed. | |
*/ | |
#define EXTRA 20 | |
_TCHAR* findCommand( _TCHAR* command ) | |
{ | |
_TCHAR* cmdPath; | |
int length; | |
_TCHAR* ch; | |
_TCHAR* dir; | |
_TCHAR* path; | |
struct _stat stats; | |
/* If the command was an abolute pathname, use it as is. */ | |
if (command[0] == dirSeparator || | |
(_tcslen( command ) > 2 && command[1] == _T_INSTALL(':'))) | |
{ | |
length = _tcslen( command ); | |
cmdPath = malloc( (length + EXTRA) * sizeof(_TCHAR) ); /* add extra space for a possible ".exe" extension */ | |
_tcscpy( cmdPath, command ); | |
} | |
else | |
{ | |
/* If the command string contains a path separator */ | |
if (_tcschr( command, dirSeparator ) != NULL) | |
{ | |
/* It must be relative to the current directory. */ | |
length = MAX_PATH_LENGTH + EXTRA + _tcslen( command ); | |
cmdPath = malloc( length * sizeof (_TCHAR)); | |
_tgetcwd( cmdPath, length ); | |
if (cmdPath[ _tcslen( cmdPath ) - 1 ] != dirSeparator) | |
{ | |
length = _tcslen( cmdPath ); | |
cmdPath[ length ] = dirSeparator; | |
cmdPath[ length+1 ] = _T_INSTALL('\0'); | |
} | |
_tcscat( cmdPath, command ); | |
} | |
/* else the command must be in the PATH somewhere */ | |
else | |
{ | |
/* Get the directory PATH where executables reside. */ | |
path = _tgetenv( _T_INSTALL("PATH") ); | |
if (!path) | |
{ | |
return NULL; | |
} | |
else | |
{ | |
length = _tcslen( path ) + _tcslen( command ) + MAX_PATH_LENGTH; | |
cmdPath = malloc( length * sizeof(_TCHAR)); | |
/* Foreach directory in the PATH */ | |
dir = path; | |
while (dir != NULL && *dir != _T_INSTALL('\0')) | |
{ | |
ch = _tcschr( dir, pathSeparator ); | |
if (ch == NULL) | |
{ | |
_tcscpy( cmdPath, dir ); | |
} | |
else | |
{ | |
length = ch - dir; | |
_tcsncpy( cmdPath, dir, length ); | |
cmdPath[ length ] = _T_INSTALL('\0'); | |
ch++; | |
} | |
dir = ch; /* advance for the next iteration */ | |
#ifdef _WIN32 | |
/* Remove quotes */ | |
if (_tcschr( cmdPath, _T_INSTALL('"') ) != NULL) | |
{ | |
int i = 0, j = 0, c; | |
length = _tcslen( cmdPath ); | |
while (i < length) { | |
c = cmdPath[ i++ ]; | |
if (c == _T_INSTALL('"')) continue; | |
cmdPath[ j++ ] = c; | |
} | |
cmdPath[ j ] = _T_INSTALL('\0'); | |
} | |
#endif | |
/* Determine if the executable resides in this directory. */ | |
if (cmdPath[0] == _T_INSTALL('.') && | |
(_tcslen(cmdPath) == 1 || (_tcslen(cmdPath) == 2 && cmdPath[1] == dirSeparator))) | |
{ | |
_tgetcwd( cmdPath, MAX_PATH_LENGTH ); | |
} | |
if (cmdPath[ _tcslen( cmdPath ) - 1 ] != dirSeparator) | |
{ | |
length = _tcslen( cmdPath ); | |
cmdPath[ length ] = dirSeparator; | |
cmdPath[ length+1 ] = _T_INSTALL('\0'); | |
} | |
_tcscat( cmdPath, command ); | |
/* If the file is not a directory and can be executed */ | |
if (_tstat( cmdPath, &stats ) == 0 && (stats.st_mode & S_IFREG) != 0) | |
{ | |
/* Stop searching */ | |
dir = NULL; | |
} | |
} | |
} | |
} | |
} | |
#ifdef _WIN32 | |
/* If the command does not exist */ | |
if (_tstat( cmdPath, &stats ) != 0 || (stats.st_mode & S_IFREG) == 0) | |
{ | |
/* If the command does not end with .exe, append it an try again. */ | |
length = _tcslen( cmdPath ); | |
if (length > 4 && _tcsicmp( &cmdPath[ length - 4 ], _T_INSTALL(".exe") ) != 0) | |
_tcscat( cmdPath, _T_INSTALL(".exe") ); | |
} | |
#endif | |
/* Verify the resulting command actually exists. */ | |
if (_tstat( cmdPath, &stats ) != 0 || (stats.st_mode & S_IFREG) == 0) | |
{ | |
free( cmdPath ); | |
cmdPath = NULL; | |
} | |
/* Return the absolute command pathname. */ | |
return cmdPath; | |
} | |
/* | |
* Get the command and arguments to start the Java VM. | |
* | |
* Memory allocated by this function is assumed to be | |
* deallocated when the program terminates. | |
* | |
* Some of the arguments returned by this function were | |
* passed directly from the main( argv ) array so they | |
* should not be deallocated. | |
*/ | |
static _TCHAR** getVMCommand( int argc, _TCHAR* argv[] ) | |
{ | |
_TCHAR** defVMarg; | |
int nDefVMarg = 0; | |
int nReqVMarg = 0; | |
int nUserVMarg = 0; | |
int totalArgs; | |
_TCHAR** execArg; | |
int src; | |
int dst; | |
/* Calculate the number of user VM arguments. */ | |
if (userVMarg != NULL) | |
{ | |
while (userVMarg[ nUserVMarg ] != NULL) | |
nUserVMarg++; | |
} | |
/* Calculate the number of default VM arguments. */ | |
defVMarg = getArgVM( javaVM ); | |
while (defVMarg[ nDefVMarg ] != NULL) | |
nDefVMarg++; | |
/* Calculate the number of required VM arguments. */ | |
while (reqVMarg[ nReqVMarg ] != NULL) | |
nReqVMarg++; | |
/* Allocate the arg list for the exec call. | |
* (VM + userVMargs + defaultVMargs + requiredVMargs + OS <os> + WS <ws> + ARCH <arch> + LAUNCHER <launcher> + NAME <officialName> + | |
* + [SHOWSPLASH <cmd> | ENDSPLASH <cmd>] + EXITDATA <cmd> + argv[] + VM + <vm> + VMARGS + userVMargs + defaultVMargs + requiredVMargs | |
* + NULL) | |
*/ | |
totalArgs = 1 + nUserVMarg + nDefVMarg + nReqVMarg + 2 + 2 + 2 + 2 + 2 + 2 + 2 + argc + 2 + 1 + nUserVMarg + nDefVMarg + nReqVMarg + 1; | |
execArg = malloc( totalArgs * sizeof( _TCHAR* ) ); | |
dst = 0; | |
execArg[ dst++ ] = javaVM; | |
/* If the user specified "-vmargs", add them instead of the default VM args. */ | |
if (userVMarg != NULL) | |
{ | |
for (src = 0; src < nUserVMarg; src++) | |
execArg[ dst++ ] = userVMarg[ src ]; | |
} | |
else | |
{ | |
for (src = 0; src < nDefVMarg; src++) | |
execArg[ dst++ ] = defVMarg[ src ]; | |
} | |
/* For each required VM arg */ | |
for (src = 0; src < nReqVMarg; src++) | |
execArg[ dst++ ] = *(reqVMarg[ src ]); | |
/* Append the required options. */ | |
execArg[ dst++ ] = OS; | |
execArg[ dst++ ] = osArg; | |
execArg[ dst++ ] = WS; | |
execArg[ dst++ ] = wsArg; | |
execArg[ dst++ ] = OSARCH; | |
execArg[ dst++ ] = osArchArg; | |
/* Append the launcher command */ | |
execArg[ dst++ ] = LAUNCHER; | |
execArg[ dst++ ] = program; | |
/* Append the name command */ | |
execArg[ dst++ ] = NAME; | |
execArg[ dst++ ] = officialName; | |
/* Append the show splash window command, if defined. */ | |
if (!noSplash) | |
{ | |
if ( sharedSplashID == NULL ) | |
{ | |
execArg[ dst++ ] = SHOWSPLASH; | |
execArg[ dst++ ] = splashTimeout; | |
} else { | |
execArg[ dst++ ] = ENDSPLASH; | |
execArg[ dst++ ] = sharedSplashID; | |
} | |
} | |
/* Append the exit data command. */ | |
if (sharedID) { | |
execArg[ dst++ ] = EXITDATA; | |
execArg[ dst++ ] = sharedID; | |
} | |
/* Append the remaining user defined arguments. */ | |
for (src = 1; src < argc; src++) | |
{ | |
execArg[ dst++ ] = argv[ src ]; | |
} | |
/* Append VM and VMARGS to be able to relaunch using exit data. */ | |
execArg[ dst++ ] = VM; | |
execArg[ dst++ ] = javaVM; | |
execArg[ dst++ ] = VMARGS; | |
/* If the user specified "-vmargs", add them instead of the default VM args. */ | |
if (userVMarg != NULL) | |
{ | |
for (src = 0; src < nUserVMarg; src++) | |
execArg[ dst++ ] = userVMarg[ src ]; | |
} | |
else | |
{ | |
for (src = 0; src < nDefVMarg; src++) | |
execArg[ dst++ ] = defVMarg[ src ]; | |
} | |
/* For each required VM arg */ | |
for (src = 0; src < nReqVMarg; src++) | |
execArg[ dst++ ] = *(reqVMarg[ src ]); | |
execArg[ dst++ ] = NULL; | |
return execArg; | |
} | |
/* Format the JVM start command for error messages | |
* | |
* This method formats a string with the JVM start command (and all arguments) | |
* that can be used in displaying error messages. The string returned from this | |
* method is probably not NLS compliant and must be deallocated by the caller. | |
*/ | |
static _TCHAR* formatVmCommandMsg( _TCHAR* args[] ) | |
{ | |
int index; | |
int length; | |
_TCHAR* ch; | |
_TCHAR* message; | |
/* Determine the length of the message buffer. */ | |
length = 0; | |
for (index = 0; args[index] != NULL; index++) | |
{ | |
length += _tcslen(args[index]) + 1; | |
} | |
message = malloc( (length + 5) * sizeof(_TCHAR) ); | |
/* Format the message such that options (args starting with '-') begin | |
on a new line. Otherwise, the Motif MessageBox does not automatically wrap | |
the messages and the message window can extend beyond both sides of the display. */ | |
ch = message; | |
for (index = 0; args[index] != NULL; index++) | |
{ | |
if (args[index][0] == _T_INSTALL('-') && *(ch-1) == _T_INSTALL(' ')) | |
*(ch-1) = _T_INSTALL('\n'); | |
_tcscpy( ch, args[index] ); | |
ch += _tcslen( args[index] ); | |
*ch++ = _T_INSTALL(' '); | |
} | |
*ch = _T_INSTALL('\0'); | |
return message; | |
} | |
/* | |
* Determine the default official application name | |
* | |
*/ | |
static _TCHAR* getDefaultOfficialName() | |
{ | |
_TCHAR *ch = NULL; | |
/* Skip the directory part */ | |
ch = _tcsrchr( program, dirSeparator ); | |
if (ch == NULL) ch = program; | |
else ch++; | |
ch = _tcsdup( ch ); | |
#ifdef _WIN32 | |
{ | |
/* Search for the extension .exe and cut it */ | |
_TCHAR *extension = _tcsrchr(ch, _T_INSTALL('.')); | |
if (extension != NULL) | |
{ | |
*extension = _T_INSTALL('\0'); | |
} | |
} | |
#endif | |
/* Upper case the first character */ | |
#ifndef LINUX | |
{ | |
*ch = _totupper(*ch); | |
} | |
#else | |
{ | |
if (*ch >= 'a' && *ch <= 'z') | |
{ | |
*ch -= 32; | |
} | |
} | |
#endif | |
return ch; | |
} | |
_TCHAR* getProgramDir( ) | |
{ | |
_TCHAR* ch; | |
_TCHAR* programDir; | |
programDir = malloc( (_tcslen( program ) + 1) * sizeof(_TCHAR) ); | |
_tcscpy( programDir, program ); | |
ch = _tcsrchr( programDir, dirSeparator ); | |
if (ch != NULL) | |
{ | |
*(ch+1) = _T_INSTALL('\0'); | |
return programDir; | |
} | |
free( programDir ); | |
return NULL; | |
} |