bool GetJREPathFromEnvVars(char* path, size_t pathSize, const char* arch) { bool found = false; static const size_t possLoc_sizeMax = 32; char* possLoc[possLoc_sizeMax]; size_t possLoc_i = 0; possLoc[possLoc_i++] = util_allocStrCpy("JAVA_HOME"); possLoc[possLoc_i++] = util_allocStrCpy("JDK_HOME"); possLoc[possLoc_i++] = util_allocStrCpy("JRE_HOME"); size_t l; for (l=0; l < possLoc_i; ++l) { const char* envPath = getenv(possLoc[l]); if (envPath != NULL) { found = GetJREPathFromBase(path, pathSize, envPath, arch); if (found) { simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in env var \"%s\"!", possLoc[l]); goto locSearchEnd; } } } locSearchEnd: // cleanup for (l=0; l < possLoc_i; ++l) { free(possLoc[l]); possLoc[l] = NULL; } return found; }
void simpleLog_init(const char* _logFileName, bool _useTimeStamps, int _logLevel, bool append) { if (_logFileName != NULL) { // NOTE: this causes a memory leack, as it is never freed. // but it is used till the end of the applications runtime anyway // -> no problem logFileName = util_allocStrCpy(_logFileName); // delete the logFile, and try writing to it FILE* file = NULL; if (logFileName != NULL) { if (append) { file = FOPEN(logFileName, "a"); } else { file = FOPEN(logFileName, "w"); } } if (file != NULL) { // make the file empty FPRINTF(file, "%s", ""); fclose(file); file = NULL; } else { // report the error to stderr FPRINTF(stderr, "Failed writing to the log file \"%s\".\n%s", logFileName, "We will continue logging to stdout."); } // make sure the dir of the log file exists char* logFileDir = util_allocStrCpy(logFileName); if (!util_getParentDir(logFileDir)) { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Failed to evaluate the parent dir of the config file: %s", logFileName); } else if (!util_makeDir(logFileDir, true)) { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Failed to create the parent dir of the config file: %s", logFileDir); } free(logFileDir); } else { simpleLog_logL(-1, "No log file name supplied -> logging to stdout and stderr", useTimeStamps ? "yes" : "no", logLevel); logFileName = NULL; } useTimeStamps = _useTimeStamps; logLevel = _logLevel; simpleLog_logL(-1, "[logging started (time-stamps: %s / logLevel: %i)]", useTimeStamps ? "yes" : "no", logLevel); }
bool java_initSkirmishAIClass( const char* const shortName, const char* const version, const char* const className, int skirmishAIId) { bool success = false; // see if an AI for className is instantiated already size_t sai; size_t firstFree = skirmishAiImpl_size; for (sai = 0; sai < skirmishAiImpl_size; ++sai) { if (skirmishAiImpl_className[sai] == NULL) { firstFree = sai; } else if (strcmp(skirmishAiImpl_className[sai], className) == 0) { break; } } // sai is now either the instantiated one, or a free one // instantiate AI (if needed) if (skirmishAiImpl_className[sai] == NULL) { sai = firstFree; java_establishJavaEnv(); JNIEnv* env = java_getJNIEnv(); jobject instance = NULL; jobject classLoader = NULL; success = java_loadSkirmishAI(env, shortName, version, className, &(instance), &(classLoader)); java_establishSpringEnv(); if (success) { skirmishAiImpl_instance[sai] = instance; skirmishAiImpl_classLoader[sai] = classLoader; skirmishAiImpl_className[sai] = util_allocStrCpy(className); if (firstFree == skirmishAiImpl_size) { skirmishAiImpl_size++; } } else { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Class loading failed for class: %s", className); } } else { success = true; } if (success) { skirmishAIId_skirmishAiImpl[skirmishAIId] = sai; } return success; }
static unsigned int util_listFilesRec(const char* dir, const char* suffix, char** fileNames, bool recursive, const unsigned int maxFileNames, unsigned int numFiles, const char* relPath) { struct dirent** files; util_initFileSelector(suffix); unsigned int currentNumFiles = util_listFilesU(dir, &files); unsigned int f; for (f = 0; f < currentNumFiles && numFiles < maxFileNames; ++f) { char fileRelPath[strlen(relPath) + strlen(files[f]->d_name) + 1]; STRCPY(fileRelPath, relPath); STRCAT(fileRelPath, files[f]->d_name); fileNames[numFiles++] = util_allocStrCpy(fileRelPath); } /* for (; f < currentNumFiles; ++f) { free(files[f]); } */ if (recursive) { struct stat dirStat; util_initFileSelector(""); currentNumFiles = util_listFilesU(dir, &files); for (f = 0; f < currentNumFiles && numFiles < maxFileNames; ++f) { if (strcmp(files[f]->d_name, ".") == 0 || strcmp(files[f]->d_name, "..") == 0) { continue; } char subDir[strlen(dir) + strlen("/") + strlen(relPath) + strlen(files[f]->d_name) + 1]; STRCPY(subDir, dir); STRCAT(subDir, "/"); STRCAT(subDir, relPath); STRCAT(subDir, files[f]->d_name); char subRelPath[strlen(relPath) + strlen(files[f]->d_name) + strlen("/") + 1]; STRCPY(subRelPath, relPath); STRCAT(subRelPath, files[f]->d_name); STRCAT(subRelPath, "/"); int retStat = stat(subDir, &dirStat); if (retStat == 0 && S_ISDIR(dirStat.st_mode)) { numFiles = util_listFilesRec(subDir, suffix, fileNames, recursive, maxFileNames, numFiles, subRelPath); } } } return numFiles; }
/////////////////////////////////////////////////////// // methods from here on are for AI internal use only // /////////////////////////////////////////////////////// const char* aiexport_getDataDir(bool absoluteAndWriteable) { static char* dd_ws_rel = NULL; static char* dd_ws_abs_w = NULL; if (absoluteAndWriteable) { if (dd_ws_abs_w == NULL) { // this is the writeable one, absolute dd_ws_abs_w = util_allocStrCpy(firstCallback->Clb_DataDirs_getWriteableDir(firstTeamId)); } return dd_ws_abs_w; } else { if (dd_ws_rel == NULL) { dd_ws_rel = util_allocStrCpy(firstCallback->Clb_DataDirs_getConfigDir(firstTeamId)); // remove the X, so we end up with a slash at the end if (dd_ws_rel != NULL) { dd_ws_rel[strlen(dd_ws_rel) -1] = '\0'; } } return dd_ws_rel; } return NULL; }
static size_t ExecFileSystemGlob(char** pathHits, size_t pathHits_sizeMax, const char* globPattern) { size_t pathHits_size = 0; // assemble the command static const size_t cmd_sizeMax = 512; char cmd[cmd_sizeMax]; SNPRINTF(cmd, cmd_sizeMax, "find %s/ -maxdepth 0 2> /dev/null", globPattern); // execute FILE* cmd_fp = popen(cmd, "r"); if (cmd_fp == NULL) { return pathHits_size; } // parse results static const size_t line_sizeMax = 512; char line[line_sizeMax]; while (fgets(line, line_sizeMax, cmd_fp) && (pathHits_size < pathHits_sizeMax)) { size_t line_size = strlen(line); if (*(line+line_size-1) == '\n') { // remove trailing '\n' *(line+line_size-1) = '\0'; line_size--; } simpleLog_logL(SIMPLELOG_LEVEL_FINEST, "glob-hit \"%s\"!", line); if (line_size > 0 && *line == '/') { *(line+line_size-1) = '\0'; // remove trailing '/' pathHits[pathHits_size++] = util_allocStrCpy(line); } } pclose(cmd_fp); return pathHits_size; }
static bool GetJREPathInCommonLocations(char* path, size_t pathSize, const char* arch) { bool found = false; static const size_t possLoc_sizeMax = 32; char* possLoc[possLoc_sizeMax]; size_t possLoc_i = 0; possLoc[possLoc_i++] = util_allocStrCpy("/usr/local/jdk*"); possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-sun"); possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-*"); possLoc[possLoc_i++] = util_allocStrCpy("~/jdk*"); possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jdk*"); possLoc[possLoc_i++] = util_allocStrCpy("~/jre*"); possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jre*"); static const size_t globHits_sizeMax = 32; char* globHits[globHits_sizeMax]; size_t l, g; for (l=0; l < possLoc_i; ++l) { const size_t globHits_size = ExecFileSystemGlob(globHits, globHits_sizeMax, possLoc[l]); for (g=0; g < globHits_size; ++g) { found = GetJREPathFromBase(path, pathSize, globHits[g], arch); if (found) { simpleLog_logL(SIMPLELOG_LEVEL_FINER, "JRE found common location env var \"%s\"!", possLoc[l]); goto locSearchEnd; } } } locSearchEnd: // cleanup for (l=0; l < possLoc_i; ++l) { free(possLoc[l]); possLoc[l] = NULL; } return found; }
static unsigned int util_listFilesRec(const char* dir, const char* suffix, char** fileNames, bool recursive, const unsigned int maxFileNames, unsigned int numFileNames, const char* relPath) { if (numFileNames >= maxFileNames) { return numFileNames; } struct _finddata_t fileInfo; int handle; // look for files which end in: suffix char suffixFilesSpec[strlen(dir) + strlen("\\*") + strlen(suffix) + 1]; STRCPY(suffixFilesSpec, dir); STRCAT(suffixFilesSpec, "\\*"); STRCAT(suffixFilesSpec, suffix); handle = _findfirst(suffixFilesSpec, &fileInfo); if (handle != -1L) { if (util_isFile(&fileInfo)) { fileNames[numFileNames++] = util_allocStrCpy(fileInfo.name); } while (_findnext(handle, &fileInfo) == 0 && numFileNames < maxFileNames) { if (util_isFile(&fileInfo)) { char fileRelPath[strlen(relPath) + strlen(fileInfo.name) + 1]; STRCPY(fileRelPath, relPath); STRCAT(fileRelPath, fileInfo.name); fileNames[numFileNames++] = util_allocStrCpy(fileRelPath); } } _findclose(handle); } // search in sub-directories if (recursive) { char subDirsSpec[strlen(dir) + strlen("\\*.*") + 1]; STRCPY(subDirsSpec, dir); STRCAT(subDirsSpec, "\\*.*"); handle = _findfirst(subDirsSpec, &fileInfo); if (handle != -1L) { // check if not current or parent directories if (util_isNormalDir(&fileInfo)) { char subDir[strlen(dir) + strlen("\\") + strlen(fileInfo.name) + 1]; STRCPY(subDir, dir); STRCAT(subDir, "\\"); STRCAT(subDir, fileInfo.name); char subRelPath[strlen(relPath) + strlen(fileInfo.name) + strlen("\\") + 1]; STRCPY(subRelPath, relPath); STRCAT(subRelPath, fileInfo.name); STRCAT(subRelPath, "\\"); numFileNames = util_listFilesRec(subDir, suffix, fileNames, recursive, maxFileNames, numFileNames, subRelPath); } while (_findnext(handle, &fileInfo) == 0 && numFileNames < maxFileNames) { if (util_isNormalDir(&fileInfo)) { char subDir[strlen(dir) + strlen("\\") + strlen(fileInfo.name) + 1]; STRCPY(subDir, dir); STRCAT(subDir, "\\"); STRCAT(subDir, fileInfo.name); char subRelPath[strlen(relPath) + strlen(fileInfo.name) + strlen("\\") + 1]; STRCPY(subRelPath, relPath); STRCAT(subRelPath, fileInfo.name); STRCAT(subRelPath, "\\"); numFileNames = util_listFilesRec(subDir, suffix, fileNames, recursive, maxFileNames, numFileNames, subRelPath); } } _findclose(handle); } } return numFileNames; }
EXPORT(int) initStatic(int _interfaceId, const struct SAIInterfaceCallback* _callback) { bool success = false; // initialize C part of the interface interfaceId = _interfaceId; callback = _callback; const char* const myShortName = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_SHORT_NAME); const char* const myVersion = callback->AIInterface_Info_getValueByKey(interfaceId, AI_INTERFACE_PROPERTY_VERSION); static const int maxProps = 64; const char* propKeys[maxProps]; char* propValues[maxProps]; int numProps = 0; // ### read the interface config file (optional) ### static const unsigned int propFilePath_sizeMax = 1024; char propFilePath[propFilePath_sizeMax]; // eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}" bool propFileFetched = callback->DataDirs_locatePath(interfaceId, propFilePath, propFilePath_sizeMax, INTERFACE_PROPERTIES_FILE, false, false, false, false); if (!propFileFetched) { // if the version specific file does not exist, // try to get the common one propFileFetched = callback->DataDirs_locatePath(interfaceId, propFilePath, propFilePath_sizeMax, INTERFACE_PROPERTIES_FILE, false, false, false, true); } if (propFileFetched) { numProps = util_parsePropertiesFile(propFilePath, propKeys, (const char**)propValues, maxProps); static const unsigned int ddw_sizeMax = 1024; char ddw[ddw_sizeMax]; // eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}" bool ddwFetched = callback->DataDirs_locatePath(interfaceId, ddw, ddw_sizeMax, "", true, true, true, false); if (!ddwFetched) { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Failed locating writeable data-dir \"%s\"", ddw); } int p; for (p=0; p < numProps; ++p) { char* propValue_tmp = util_allocStrReplaceStr(propValues[p], "${home-dir}", ddw); // char* propValue_tmp = util_allocStrReplaceStr(propValues[p], // "${home-dir}/", ""); free(propValues[p]); propValues[p] = propValue_tmp; } } // ### try to fetch the log-level from the properties ### int logLevel = SIMPLELOG_LEVEL_NORMAL; const char* logLevel_str = util_map_getValueByKey(numProps, propKeys, (const char**)propValues, "log.level"); if (logLevel_str != NULL) { int logLevel_tmp = atoi(logLevel_str); if (logLevel_tmp >= SIMPLELOG_LEVEL_ERROR && logLevel_tmp <= SIMPLELOG_LEVEL_FINEST) { logLevel = logLevel_tmp; } } // ### try to fetch whether to use time-stamps from the properties ### bool useTimeStamps = true; const char* useTimeStamps_str = util_map_getValueByKey(numProps, propKeys, (const char**)propValues, "log.useTimeStamps"); if (useTimeStamps_str != NULL) { useTimeStamps = util_strToBool(useTimeStamps_str); } // ### init the log file ### char* logFile = util_allocStrCpy( util_map_getValueByKey(numProps, propKeys, (const char**)propValues, "log.file")); if (logFile == NULL) { logFile = util_allocStrCatFSPath(2, "log", MY_LOG_FILE); } static const unsigned int logFilePath_sizeMax = 1024; char logFilePath[logFilePath_sizeMax]; // eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}" bool logFileFetched = callback->DataDirs_locatePath(interfaceId, logFilePath, logFilePath_sizeMax, logFile, true, true, false, false); if (logFileFetched) { simpleLog_init(logFilePath, useTimeStamps, logLevel, false); } else { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Failed initializing log-file \"%s\"", logFileFetched); } // log settings loaded from interface config file if (propFileFetched) { simpleLog_logL(SIMPLELOG_LEVEL_FINE, "settings loaded from: %s", propFilePath); int p; for (p=0; p < numProps; ++p) { simpleLog_logL(SIMPLELOG_LEVEL_FINE, "\t%i: %s = %s", p, propKeys[p], propValues[p]); } } else { simpleLog_logL(SIMPLELOG_LEVEL_FINE, "settings NOT loaded from: %s", propFilePath); } simpleLog_log("This is the log-file of the %s v%s AI Interface", myShortName, myVersion); simpleLog_log("Using read/write data-directory: %s", callback->DataDirs_getWriteableDir(interfaceId)); simpleLog_log("Using log file: %s", propFilePath); FREE(logFile); // initialize Java part of the interface success = java_initStatic(interfaceId, callback); // load the JVM success = success && java_preloadJNIEnv(); if (success) { simpleLog_logL(SIMPLELOG_LEVEL_FINE, "Initialization successfull."); } else { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Initialization failed."); } return success ? 0 : -1; }
/** * Creates a Skirmish AI local Java class path. * * It will consist of the following: * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/[*].jar * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/ * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/[*].jar */ static size_t java_createAIClassPath(const char* shortName, const char* version, char** classPathParts, const size_t classPathParts_sizeMax) { size_t classPathParts_size = 0; // the .jar files in the following list will be added to the classpath const size_t jarFiles_sizeMax = classPathParts_sizeMax; char** jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*)); size_t jarFiles_size = 0; const char* const skirmDD = callback->SkirmishAIs_Info_getValueByKey(interfaceId, shortName, version, SKIRMISH_AI_PROPERTY_DATA_DIR); if (skirmDD == NULL) { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Retrieving the data-dir of Skirmish AI %s-%s failed.", shortName, version); } // {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar jarFiles[jarFiles_size++] = util_allocStrCatFSPath(2, skirmDD, "SkirmishAI.jar"); // the directories in the following list will be searched for .jar files // which then will be added to the classpath, plus they will be added // to the classpath directly, so you can keep .class files in there const size_t jarDirs_sizeMax = classPathParts_sizeMax; char** jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*)); size_t jarDirs_size = 0; // add to classpath ... // {spring-data-dir}/Skirmish/MyJavaAI/0.1/SkirmishAI/ // this can be usefull for AI devs while testing, // if they do not want to put everything into a jar all the time jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "SkirmishAI"); // add to classpath: // {spring-data-dir}/Skirmish/MyJavaAI/0.1/${x}/ jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jconfig"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "config"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jresources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "resources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jscript"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "script"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jlib"); // "lib" is for native libs only // add the dir common for all versions of the Skirmish AI, // if it is specified and exists const char* const skirmDDCommon = callback->SkirmishAIs_Info_getValueByKey(interfaceId, shortName, version, SKIRMISH_AI_PROPERTY_DATA_DIR_COMMON); if (skirmDDCommon != NULL) { // add to classpath: // {spring-data-dir}/Skirmish/MyJavaAI/common/${x}/ jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jconfig"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "config"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jresources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "resources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jscript"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "script"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jlib"); // "lib" is for native libs only } // add the directly specified .jar files size_t jf; for (jf = 0; (jf < jarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++jf) { classPathParts[classPathParts_size++] = util_allocStrCpy(jarFiles[jf]); FREE(jarFiles[jf]); } // add the dirs and the contained .jar files size_t jd, sjf; for (jd = 0; (jd < jarDirs_size) && (classPathParts_size < classPathParts_sizeMax); ++jd) { if (jarDirs[jd] != NULL && util_fileExists(jarDirs[jd])) { // add the jar dir (for .class files) // For this to work properly with URLClassPathHandler, // we have to ensure there is a '/' at the end, // for the class-path-part to be recognized as a directory. classPathParts[classPathParts_size++] = util_allocStrCat(2, jarDirs[jd], "/"); // add the jars in the dir const size_t subJarFiles_sizeMax = classPathParts_sizeMax - classPathParts_size; char** subJarFiles = (char**) calloc(subJarFiles_sizeMax, sizeof(char*)); const size_t subJarFiles_size = util_listFiles(jarDirs[jd], ".jar", subJarFiles, true, subJarFiles_sizeMax); for (sjf = 0; (sjf < subJarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++sjf) { // .../[*].jar classPathParts[classPathParts_size++] = util_allocStrCatFSPath(2, jarDirs[jd], subJarFiles[sjf]); FREE(subJarFiles[sjf]); } FREE(subJarFiles); } FREE(jarDirs[jd]); } FREE(jarDirs); FREE(jarFiles); return classPathParts_size; }
/** * Creates the AI Interface global Java class path. * * It will consist of the following: * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/AIInterface.jar * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/ * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/[*].jar * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/ * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/[*].jar * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/ * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/[*].jar * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/ * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/[*].jar * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/ * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/[*].jar */ static size_t java_createClassPath(char* classPathStr, const size_t classPathStr_sizeMax) { // the dirs and .jar files in the following array // will be concatenated with intermediate path separators // to form the classPathStr static const size_t classPath_sizeMax = 128; char** classPath = (char**) calloc(classPath_sizeMax, sizeof(char*)); size_t classPath_size = 0; // the Java AI Interfaces java library file path (.../AIInterface.jar) // We need to search for this jar, instead of looking only where // the AIInterface.so/InterfaceInfo.lua is, because on some systems // (eg. Debian), the .so is in /usr/lib, and the .jar's are in /usr/shared. char* mainJarPath = callback->DataDirs_allocatePath(interfaceId, JAVA_AI_INTERFACE_LIBRARY_FILE_NAME, false, false, false, false); classPath[classPath_size++] = util_allocStrCpy(mainJarPath); bool ok = util_getParentDir(mainJarPath); if (!ok) { simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Retrieving the parent dir of the path to AIInterface.jar (%s) failed.", mainJarPath); } char* jarsDataDir = mainJarPath; mainJarPath = NULL; // the directories in the following list will be searched for .jar files // which will then be added to the classPathStr, plus the dirs will be added // to the classPathStr directly, so you can keep .class files in there static const size_t jarDirs_sizeMax = 128; char** jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*)); size_t jarDirs_size = 0; // add to classpath: // {spring-data-dir}/Interfaces/Java/0.1/${x}/ jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jconfig"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "config"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jresources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "resources"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jscript"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "script"); jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jlib"); // "lib" is for native libs only // add the jar dirs (for .class files) and all contained .jars recursively size_t jd, jf; for (jd=0; (jd < jarDirs_size) && (classPath_size < classPath_sizeMax); ++jd) { if (util_fileExists(jarDirs[jd])) { // add the dir directly // For this to work properly with URLClassPathHandler, // we have to ensure there is a '/' at the end, // for the class-path-part to be recognized as a directory. classPath[classPath_size++] = util_allocStrCat(2, jarDirs[jd], "/"); // add the contained jars recursively static const size_t jarFiles_sizeMax = 128; char** jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*)); const size_t jarFiles_size = util_listFiles(jarDirs[jd], ".jar", jarFiles, true, jarFiles_sizeMax); for (jf=0; (jf < jarFiles_size) && (classPath_size < classPath_sizeMax); ++jf) { classPath[classPath_size++] = util_allocStrCatFSPath(2, jarDirs[jd], jarFiles[jf]); FREE(jarFiles[jf]); } FREE(jarFiles); } FREE(jarDirs[jd]); } FREE(jarDirs); // concat the classpath entries classPathStr[0] = '\0'; if (classPath[0] != NULL) { STRCATS(classPathStr, classPathStr_sizeMax, classPath[0]); FREE(classPath[0]); } size_t cp; for (cp=1; cp < classPath_size; ++cp) { if (classPath[cp] != NULL) { STRCATS(classPathStr, classPathStr_sizeMax, ENTRY_DELIM); STRCATS(classPathStr, classPathStr_sizeMax, classPath[cp]); FREE(classPath[cp]); } } FREE(classPath); return classPath_size; }