diff --git a/include/OpenSmalltalkVM.h b/include/OpenSmalltalkVM.h index 34965782cd..e0e5957de0 100644 --- a/include/OpenSmalltalkVM.h +++ b/include/OpenSmalltalkVM.h @@ -83,6 +83,7 @@ typedef enum OSVM_ERROR_UNSUPPORTED_PARAMETER, OSVM_ERROR_FAILED_TO_OPEN_FILE, OSVM_ERROR_FAILED_TO_LOAD_IMAGE, + OSVM_ERROR_FAILED_TO_FIND_IMAGE, } OSVMError; /** @@ -99,6 +100,14 @@ typedef struct OSVMInstance *OSVMInstanceHandle; */ OSVM_VM_CORE_PUBLIC int osvm_getInterfaceVersion(void); +/** + * This function finds a default startup image for a given VM executable path. + * \param startupImagePathResult A pointer to store the startup image path. + * Must be freed with osvm_free(). This can be NULL. + * \return 1 for found, 0 for not found. + */ +OSVM_VM_CORE_PUBLIC int osvm_findStartupImage(const char *vmExecutablePath, char **startupImagePathResult); + /** * Simple all mighty main entry point for running an OpenSmalltalk VM */ diff --git a/platforms/Cross/vm/sqPath.c b/platforms/Cross/vm/sqPath.c index adac1324d4..e97b79f89b 100644 --- a/platforms/Cross/vm/sqPath.c +++ b/platforms/Cross/vm/sqPath.c @@ -32,9 +32,9 @@ #elif defined(__unix__) || defined(__MACH__) || defined(__APPLE__) #include #else -#include #define getcwd(target, targetSize) strcpy(target, ".") #endif +#include #include "sqPath.h" #include "sqTextEncoding.h" diff --git a/platforms/minheadless/common/sqVirtualMachineInterface.c b/platforms/minheadless/common/sqVirtualMachineInterface.c index fb50011fee..836a3a664a 100644 --- a/platforms/minheadless/common/sqVirtualMachineInterface.c +++ b/platforms/minheadless/common/sqVirtualMachineInterface.c @@ -28,6 +28,8 @@ #ifndef _WIN32 #include +#include +#include #endif #include @@ -51,6 +53,10 @@ struct OSVMInstance */ extern int sqVMOptionTraceModuleLoading; +extern int osvm_isFile(const char *path); +extern int osvm_findImagesInFolder(const char *searchPath, char *imagePathBuffer, size_t imagePathBufferSize); + + static struct OSVMInstance osvmInstanceSingleton; char imageName[FILENAME_MAX]; @@ -463,6 +469,118 @@ parseArguments(int argc, char **argv) return OSVM_SUCCESS; } +#ifndef _WIN32 +int +osvm_isFile(const char *path) +{ + struct stat s; + if(stat(path, &s) == 0) + return s.st_mode & S_IFREG; + + return 0; +} + +int +osvm_findImagesInFolder(const char *searchPath, char *imagePathBuffer, size_t imagePathBufferSize) +{ + struct dirent *entry; + int result = 0; + DIR *dir = opendir(searchPath); + if(!dir) + return 0; + + while((entry = readdir(dir)) != NULL) + { + char *name = entry->d_name; + char *extension = strrchr(name, '.'); + if(!extension) + continue; + + if(strcmp(extension, ".image") != 0) + continue; + + if(result == 0) + snprintf(imagePathBuffer, imagePathBufferSize, "%s/%s", searchPath, name); + ++result; + } + closedir(dir); + + return result; +} +#endif + +OSVM_VM_CORE_PUBLIC int +osvm_findStartupImage(const char *vmExecutablePath, char **startupImagePathResult) +{ + char *imagePathBuffer = osvm_malloc(FILENAME_MAX+1); + char *vmPathBuffer = osvm_malloc(FILENAME_MAX+1); + char *searchPathBuffer = osvm_malloc(FILENAME_MAX+1); + findExecutablePath(vmExecutablePath, vmPathBuffer, FILENAME_MAX+1); + + if(startupImagePathResult) + *startupImagePathResult = NULL; + + // Find the mandatory startup.image. + snprintf(imagePathBuffer, FILENAME_MAX+1, "%s/startup.image", vmPathBuffer); + if(osvm_isFile(imagePathBuffer)) + { + if(startupImagePathResult) + *startupImagePathResult = imagePathBuffer; + else + osvm_free(imagePathBuffer); + osvm_free(vmPathBuffer); + osvm_free(searchPathBuffer); + return 1; + } + +#ifdef __APPLE__ + snprintf(imagePathBuffer, FILENAME_MAX+1, "%s/../Resources/startup.image", vmPathBuffer); + if(osvm_isFile(imagePathBuffer)) + { + if(startupImagePathResult) + *startupImagePathResult = imagePathBuffer; + else + osvm_free(imagePathBuffer); + osvm_free(vmPathBuffer); + osvm_free(searchPathBuffer); + return 1; + } +#endif + + // Find automatically an image. + int foundImageCount = 0; + + // Search on the VM executable path. + foundImageCount += osvm_findImagesInFolder(vmPathBuffer, imagePathBuffer, FILENAME_MAX+1); + +#ifdef __APPLE__ + // Search along the bundled resources. + snprintf(searchPathBuffer, FILENAME_MAX+1, "%s/../Resources", vmPathBuffer); + foundImageCount += osvm_findImagesInFolder(searchPathBuffer, imagePathBuffer, FILENAME_MAX+1); +#endif + + // Search in the current working directory. + sqGetCurrentWorkingDir(searchPathBuffer, FILENAME_MAX+1); + foundImageCount += osvm_findImagesInFolder(searchPathBuffer, imagePathBuffer, FILENAME_MAX+1); + + osvm_free(vmPathBuffer); + osvm_free(searchPathBuffer); + if(foundImageCount == 1) + { + if(startupImagePathResult) + *startupImagePathResult = imagePathBuffer; + else + osvm_free(imagePathBuffer); + return 1; + } + else + { + // The image is not found or it is ambiguous. + osvm_free(imagePathBuffer); + return 0; + } +} + OSVM_VM_CORE_PUBLIC void * osvm_malloc(size_t size) { @@ -552,7 +670,18 @@ osvm_loadDefaultImage(OSVMInstanceHandle vmHandle) /* If the image name is empty, try to load the default image. */ if(!shortImageName[0]) - strcpy(shortImageName, DEFAULT_IMAGE_NAME); + { + char *startupImage; + if(osvm_findStartupImage(vmPath, &startupImage)) + { + strcpy(shortImageName, startupImage); + osvm_free(startupImage); + } + else + { + return OSVM_ERROR_FAILED_TO_FIND_IMAGE; + } + } /* Try to load the image as was passed. */ sprintf(tempImageNameAttempt, "%s", shortImageName); diff --git a/platforms/minheadless/mac/sqMain.m b/platforms/minheadless/mac/sqMain.m index a38b3958d1..0daad63246 100644 --- a/platforms/minheadless/mac/sqMain.m +++ b/platforms/minheadless/mac/sqMain.m @@ -133,6 +133,10 @@ - (void) executeVMProcess int main(int argc, const char **argv) { + // If there is a startup image, then we should just use it. + if(osvm_findStartupImage(argv[0], NULL)) + return osvm_main(argc, argv); + // In OS X, the user may want to drop an image file to the VM application. // Dropped image files are treated as events, whose reception is only // obtained through the usage of an AppDelegate, which is tied to a diff --git a/platforms/minheadless/windows/sqWin32Directory.c b/platforms/minheadless/windows/sqWin32Directory.c index c190b1efd6..8817030327 100644 --- a/platforms/minheadless/windows/sqWin32Directory.c +++ b/platforms/minheadless/windows/sqWin32Directory.c @@ -488,3 +488,16 @@ sqInt dir_Delete(char *pathString, sqInt pathLength) { if (hasCaseSensitiveDuplicate(win32Path)) return false; return RemoveDirectoryW(win32Path) == 0 ? false : true; } + +int osvm_isFile(const char *path) +{ + /* TODO: Implement this */ + return 0; +} + +int +osvm_findImagesInFolder(const char *searchPath, char *imagePathBuffer, size_t imagePathBufferSize) +{ + /* TODO: Implmenent this */ + return 0; +} diff --git a/platforms/minheadless/windows/sqWin32Main.c b/platforms/minheadless/windows/sqWin32Main.c index 24d5f64749..3580679c83 100644 --- a/platforms/minheadless/windows/sqWin32Main.c +++ b/platforms/minheadless/windows/sqWin32Main.c @@ -37,6 +37,10 @@ static WCHAR openImageDialogResultBuffer[MAX_PATH + 1]; static int mainEntryPoint(int argc, const char **argv) { + // If there is a startup image, then we should just use it. + if(osvm_findStartupImage(argv[0], NULL)) + return osvm_main(argc, argv); + // Try to find a explicit image on the command line. int hasImageArgument = 0; for(int i = 1; i < argc; ++i)