diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 2d78655e37..13d1c0ff54 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -85,8 +85,8 @@ + - diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 1b5b6966ab..d32f0f5439 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -300,7 +300,7 @@ Source\Platform - + Source\Platform @@ -825,4 +825,4 @@ Source\Interface - \ No newline at end of file + diff --git a/src/platform/linux.c b/src/platform/linux.c index bce343888c..f5d062e5dd 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -18,756 +18,40 @@ * along with this program. If not, see . *****************************************************************************/ -#ifdef __linux +#if defined(__linux__) -#include -#include -#include -#include -#include -#include "../addresses.h" -#include "../cmdline.h" -#include "../openrct2.h" -#include "../localisation/language.h" -#include "../localisation/currency.h" -#include "../config.h" #include "platform.h" -#include "../util/util.h" -#include -#include -#include +#include -// The name of the mutex used to prevent multiple instances of the game from running -#define SINGLE_INSTANCE_MUTEX_NAME "RollerCoaster Tycoon 2_GSKMUTEX" +// See http://syprog.blogspot.ru/2011/12/listing-loaded-shared-objects-in-linux.html +struct lmap { + void* base_address; + char* path; + void* unused; + struct lmap *next, *prev; +}; -utf8 _userDataDirectoryPath[MAX_PATH] = { 0 }; +struct dummy { + void* pointers[3]; + struct dummy* ptr; +}; -/** - * The function that is called directly from the host application (rct2.exe)'s WinMain. This will be removed when OpenRCT2 can - * be built as a stand alone application. - */ -int main(int argc, const char **argv) -{ - //RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance; - //RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine; +bool platform_check_steam_overlay_attached() { + void* processHandle = dlopen(NULL, RTLD_NOW); - STUB(); - int run_game = cmdline_run(argv, argc); - if (run_game == 1) - { - openrct2_launch(); + struct dummy* p = (struct dummy*) processHandle; + p = p->ptr; + + struct lmap* pl = (struct lmap*) p->ptr; + + while (pl != NULL) { + if (strstr(pl->path, "gameoverlayrenderer.so") != NULL) { + return true; + } + pl = pl->next; } - exit(gExitCode); - return gExitCode; -} - -void platform_get_date(rct2_date *out_date) -{ - assert(out_date != NULL); - time_t rawtime; - struct tm * timeinfo; - time(&rawtime); - timeinfo = gmtime(&rawtime); - out_date->day = timeinfo->tm_mday; - out_date->month = timeinfo->tm_mon; - out_date->year = timeinfo->tm_year; - out_date->day_of_week = timeinfo->tm_wday; -} - -void platform_get_time(rct2_time *out_time) -{ - assert(out_time != NULL); - time_t rawtime; - struct tm * timeinfo; - time(&rawtime); - timeinfo = gmtime(&rawtime); - out_time->second = timeinfo->tm_sec; - out_time->minute = timeinfo->tm_min; - out_time->hour = timeinfo->tm_hour; -} - -char platform_get_path_separator() -{ - return '/'; -} - -bool platform_file_exists(const utf8 *path) -{ - wchar_t *wPath = utf8_to_widechar(path); - int len = min(MAX_PATH, utf8_length(path)); - char buffer[MAX_PATH]; - wcstombs(buffer, wPath, len); - buffer[len] = '\0'; - free(wPath); - bool exists = access(buffer, F_OK) != -1; - log_warning("file '%s' exists = %i", buffer, exists); - return exists; -} - -bool platform_directory_exists(const utf8 *path) -{ - wchar_t *wPath = utf8_to_widechar(path); - int len = min(MAX_PATH, utf8_length(path)); - char buffer[MAX_PATH]; - wcstombs(buffer, wPath, len); - buffer[len] = '\0'; - free(wPath); - struct stat dirinfo; - int result = stat(buffer, &dirinfo); - log_verbose("checking dir %s, result = %d, is_dir = %d", buffer, result, S_ISDIR(dirinfo.st_mode)); - if ((result != 0) || !S_ISDIR(dirinfo.st_mode)) - { - return false; - } - return true; -} - -bool platform_original_game_data_exists(const utf8 *path) -{ - wchar_t *wPath = utf8_to_widechar(path); - int len = min(MAX_PATH, utf8_length(path)); - char buffer[MAX_PATH]; - wcstombs(buffer, wPath, len); - buffer[len] = '\0'; - free(wPath); - char checkPath[MAX_PATH]; - sprintf(checkPath, "%s%c%s%c%s", buffer, platform_get_path_separator(), "Data", platform_get_path_separator(), "g1.dat"); - return platform_file_exists(checkPath); -} - -mode_t getumask() -{ - mode_t mask = umask(0); - umask(mask); - return 0777 & ~mask; // Keep in mind 0777 is octal -} - -bool platform_ensure_directory_exists(const utf8 *path) -{ - mode_t mask = getumask(); - - wchar_t *wPath = utf8_to_widechar(path); - int len = min(MAX_PATH, utf8_length(path)); - char buffer[MAX_PATH]; - wcstombs(buffer, wPath, len); - buffer[len - 1] = '\0'; - free(wPath); - log_verbose("%s", buffer); - const int result = mkdir(buffer, mask); - if (result == 0 || (result == -1 && errno == EEXIST)) - return true; return false; } -bool platform_directory_delete(const utf8 *path) -{ - STUB(); - return true; -} - -bool platform_lock_single_instance() -{ - STUB(); - return true; -} - -typedef struct { - char active; - char pattern[MAX_PATH]; - struct dirent **fileListTemp; - char **paths; - int cnt; - int handle; - void* data; -} enumerate_file_info; -static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; - -char *g_file_pattern; - -static int winfilter(const struct dirent *d) -{ - int entry_length = strnlen(d->d_name, MAX_PATH); - char *name_upper = malloc(entry_length + 1); - if (name_upper == NULL) - { - log_error("out of memory"); - return 0; - } - for (int i = 0; i < entry_length; i++) - { - name_upper[i] = (char)toupper(d->d_name[i]); - } - name_upper[entry_length] = '\0'; - bool match = fnmatch(g_file_pattern, name_upper, FNM_PATHNAME) == 0; - //log_warning("trying matching filename %s, result = %d", name_upper, match); - free(name_upper); - return match; -} - -int platform_enumerate_files_begin(const utf8 *pattern) -{ - enumerate_file_info *enumFileInfo; - wchar_t *wpattern = utf8_to_widechar(pattern); - int length = min(utf8_length(pattern), MAX_PATH); - char *npattern = malloc(length+1); - int converted; - converted = wcstombs(npattern, wpattern, length); - npattern[length] = '\0'; - if (converted == MAX_PATH) { - log_warning("truncated string %s", npattern); - } - log_warning("begin file search, pattern: %s", npattern); - - char *file_name = strrchr(npattern, platform_get_path_separator()); - char *dir_name; - if (file_name != NULL) - { - dir_name = strndup(npattern, file_name - npattern); - file_name = &file_name[1]; - } else { - file_name = npattern; - dir_name = strdup("."); - } - - - int pattern_length = strlen(file_name); - g_file_pattern = strndup(file_name, pattern_length); - for (int j = 0; j < pattern_length; j++) - { - g_file_pattern[j] = (char)toupper(g_file_pattern[j]); - } - log_warning("looking for file matching %s", g_file_pattern); - int cnt; - for (int i = 0; i < countof(_enumerateFileInfoList); i++) { - enumFileInfo = &_enumerateFileInfoList[i]; - if (!enumFileInfo->active) { - safe_strncpy(enumFileInfo->pattern, npattern, sizeof(enumFileInfo->pattern)); - cnt = scandir(dir_name, &enumFileInfo->fileListTemp, winfilter, alphasort); - if (cnt < 0) - { - break; - } - log_warning("found %d files matching in dir '%s'", cnt, dir_name); - enumFileInfo->cnt = cnt; - enumFileInfo->paths = malloc(cnt * sizeof(char *)); - char **paths = enumFileInfo->paths; - // 256 is size of dirent.d_name - const int buf_len = min(MAX_PATH, 256); - const int dir_name_len = strnlen(dir_name, MAX_PATH); - char separator[] = {platform_get_path_separator(), 0}; - for (int idx = 0; idx < cnt; idx++) - { - struct dirent *d = enumFileInfo->fileListTemp[idx]; - const int entry_len = strnlen(d->d_name, MAX_PATH); - // 1 for separator, 1 for trailing null - paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); - paths[idx][0] = '\0'; - log_verbose("dir_name: %s", dir_name); - strncat(paths[idx], dir_name, MAX_PATH); - strncat(paths[idx], separator, MAX_PATH); - strncat(paths[idx], d->d_name, MAX_PATH); - log_verbose("paths[%d] = %s", idx, paths[idx]); - } - enumFileInfo->handle = 0; - enumFileInfo->active = 1; - free(dir_name); - free(g_file_pattern); - g_file_pattern = NULL; - free(wpattern); - free(npattern); - return i; - } - } - - free(dir_name); - free(g_file_pattern); - g_file_pattern = NULL; - free(wpattern); - free(npattern); - return -1; -} - -bool platform_enumerate_files_next(int handle, file_info *outFileInfo) -{ - - if (handle < 0) - { - return false; - } - enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; - bool result; - - if (enumFileInfo->handle < enumFileInfo->cnt) { - result = true; - } else { - result = false; - } - - if (result) { - int entryIdx = enumFileInfo->handle++; - struct stat fileInfo; - log_verbose("trying handle %d", entryIdx); - char *fileName = enumFileInfo->paths[entryIdx]; - int statRes; - statRes = stat(fileName, &fileInfo); - if (statRes == -1) { - log_error("failed to stat file '%s'! errno = %i", fileName, errno); - return false; - } - outFileInfo->path = basename(fileName); - outFileInfo->size = fileInfo.st_size; - outFileInfo->last_modified = fileInfo.st_mtime; - return true; - } else { - return false; - } -} - -void platform_enumerate_files_end(int handle) -{ - if (handle < 0) - { - return; - } - enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; - int cnt = enumFileInfo->cnt; - for (int i = 0; i < cnt; i++) { - free(enumFileInfo->fileListTemp[i]); - free(enumFileInfo->paths[i]); - } - free(enumFileInfo->fileListTemp); - free(enumFileInfo->paths); - // FIXME: this here could have a bug - enumFileInfo->fileListTemp = NULL; - enumFileInfo->handle = 0; - enumFileInfo->active = 0; -} - -static int dirfilter(const struct dirent *d) -{ - if (d->d_name[0] == '.') { - return 0; - } -#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) - if (d->d_type == DT_DIR) - { - return 1; - } else { - return 0; - } -#else -#error implement dirfilter! -#endif // defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) -} - -int platform_enumerate_directories_begin(const utf8 *directory) -{ - enumerate_file_info *enumFileInfo; - wchar_t *wpattern = utf8_to_widechar(directory); - int length = min(utf8_length(directory), MAX_PATH); - char *npattern = malloc(length+1); - int converted; - converted = wcstombs(npattern, wpattern, length); - npattern[length] = '\0'; - if (converted == MAX_PATH) { - log_warning("truncated string %s", npattern); - } - log_warning("begin directory listing, path: %s", npattern); - - // TODO: add some checking for stringness and directoryness - - int cnt; - for (int i = 0; i < countof(_enumerateFileInfoList); i++) { - enumFileInfo = &_enumerateFileInfoList[i]; - if (!enumFileInfo->active) { - safe_strncpy(enumFileInfo->pattern, npattern, length); - cnt = scandir(npattern, &enumFileInfo->fileListTemp, dirfilter, alphasort); - if (cnt < 0) - { - break; - } - log_warning("found %d files in dir '%s'", cnt, npattern); - enumFileInfo->cnt = cnt; - enumFileInfo->paths = malloc(cnt * sizeof(char *)); - char **paths = enumFileInfo->paths; - // 256 is size of dirent.d_name - const int buf_len = min(MAX_PATH, 256); - const int dir_name_len = strnlen(npattern, MAX_PATH); - char separator[] = {platform_get_path_separator(), 0}; - for (int idx = 0; idx < cnt; idx++) - { - struct dirent *d = enumFileInfo->fileListTemp[idx]; - const int entry_len = strnlen(d->d_name, MAX_PATH); - // 1 for separator, 1 for trailing null - paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); - paths[idx][0] = '\0'; - log_verbose("dir_name: %s", npattern); - strncat(paths[idx], npattern, MAX_PATH); - strncat(paths[idx], separator, MAX_PATH); - strncat(paths[idx], d->d_name, MAX_PATH); - log_verbose("paths[%d] = %s", idx, paths[idx]); - } - enumFileInfo->handle = 0; - enumFileInfo->active = 1; - free(wpattern); - free(npattern); - return i; - } - } - - free(wpattern); - free(npattern); - return -1; -} - -bool platform_enumerate_directories_next(int handle, utf8 *path) -{ - if (handle < 0) - { - return false; - } - - bool result; - enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; - - log_verbose("handle = %d", handle); - if (enumFileInfo->handle < enumFileInfo->cnt) { - result = true; - } else { - result = false; - } - - if (result) { - int entryIdx = enumFileInfo->handle++; - struct stat fileInfo; - char *fileName = enumFileInfo->paths[entryIdx]; - int statRes; - statRes = stat(fileName, &fileInfo); - if (statRes == -1) { - log_error("failed to stat file '%s'! errno = %i", fileName, errno); - return false; - } - // so very, very wrong - safe_strncpy(path, basename(fileName), MAX_PATH); - strncat(path, "/", MAX_PATH); - path[MAX_PATH - 1] = '\0'; - return true; - } else { - return false; - } -} - -void platform_enumerate_directories_end(int handle) -{ - if (handle < 0) - { - return; - } - enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; - int cnt = enumFileInfo->cnt; - for (int i = 0; i < cnt; i++) { - free(enumFileInfo->fileListTemp[i]); - free(enumFileInfo->paths[i]); - } - free(enumFileInfo->fileListTemp); - free(enumFileInfo->paths); - // FIXME: this here could have a bug - enumFileInfo->fileListTemp = NULL; - enumFileInfo->handle = 0; - enumFileInfo->active = 0; -} - -int platform_get_drives(){ - /* - return GetLogicalDrives(); - */ - STUB(); - return 0; -} - -bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite) -{ - STUB(); - return 0; -} - -bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) -{ - STUB(); - return 0; -} - -bool platform_file_delete(const utf8 *path) -{ - STUB(); - return 0; -} - -wchar_t *regular_to_wchar(const char* src) -{ - int len = strnlen(src, MAX_PATH); - wchar_t *w_buffer = malloc((len + 1) * sizeof(wchar_t)); - mbtowc (NULL, NULL, 0); /* reset mbtowc */ - - int max = len; - int i = 0; - while (max > 0) - { - int length; - length = mbtowc(&w_buffer[i], &src[i], max); - if (length < 1) - { - w_buffer[i + 1] = '\0'; - break; - } - i += length; - max -= length; - } - return w_buffer; -} - -/** - * Default directory fallback is: - * - (command line argument) - * - $XDG_CONFIG_HOME/.config/OpenRCT2 - * - /home/[uid]/.config/OpenRCT2 - */ -void platform_resolve_user_data_path() -{ - const char separator[2] = { platform_get_path_separator(), 0 }; - - if (gCustomUserDataPath[0] != 0) { - realpath(gCustomUserDataPath, _userDataDirectoryPath); - - // Ensure path ends with separator - int len = strlen(_userDataDirectoryPath); - if (_userDataDirectoryPath[len - 1] != separator[0]) { - strcat(_userDataDirectoryPath, separator); - } - return; - } - - char buffer[MAX_PATH]; - buffer[0] = '\0'; - log_verbose("buffer = '%s'", buffer); - const char *homedir = getenv("XDG_CONFIG_HOME"); - log_verbose("homedir = '%s'", homedir); - if (homedir == NULL) - { - homedir = getpwuid(getuid())->pw_dir; - log_verbose("homedir was null, used getuid, now is = '%s'", homedir); - if (homedir == NULL) - { - log_fatal("Couldn't find user data directory"); - exit(-1); - return; - } - - strncat(buffer, homedir, MAX_PATH); - strncat(buffer, separator, MAX_PATH); - strncat(buffer, ".config", MAX_PATH); - } - else - { - strncat(buffer, homedir, MAX_PATH); - } - strncat(buffer, separator, MAX_PATH); - strncat(buffer, "OpenRCT2", MAX_PATH); - strncat(buffer, separator, MAX_PATH); - log_verbose("OpenRCT2 user data directory = '%s'", buffer); - int len = strnlen(buffer, MAX_PATH); - wchar_t *w_buffer = regular_to_wchar(buffer); - w_buffer[len] = '\0'; - utf8 *path = widechar_to_utf8(w_buffer); - free(w_buffer); - safe_strncpy(_userDataDirectoryPath, path, MAX_PATH); - free(path); -} - -void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) -{ - const char separator[2] = { platform_get_path_separator(), 0 }; - char buffer[MAX_PATH]; - safe_strncpy(buffer, _userDataDirectoryPath, sizeof(buffer)); - if (subDirectory != NULL && subDirectory[0] != 0) { - log_verbose("adding subDirectory '%s'", subDirectory); - strcat(buffer, subDirectory); - strcat(buffer, separator); - } - int len = strnlen(buffer, MAX_PATH); - wchar_t *w_buffer = regular_to_wchar(buffer); - w_buffer[len] = '\0'; - utf8 *path = widechar_to_utf8(w_buffer); - free(w_buffer); - safe_strncpy(outPath, path, MAX_PATH); - free(path); - log_verbose("outPath + subDirectory = '%s'", buffer); -} - -void platform_show_messagebox(char *message) -{ - STUB(); - log_warning(message); -} - -/** - * - * rct2: 0x004080EA - */ -int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) -{ - STUB(); - return 0; -} - -utf8 *platform_open_directory_browser(utf8 *title) -{ - STUB(); - return NULL; -} - -uint16 platform_get_locale_language(){ - /* - CHAR langCode[4]; - - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_SABBREVLANGNAME, - (LPSTR)&langCode, - sizeof(langCode)) == 0){ - return LANGUAGE_UNDEFINED; - } - - if (strcmp(langCode, "ENG") == 0){ - return LANGUAGE_ENGLISH_UK; - } - else if (strcmp(langCode, "ENU") == 0){ - return LANGUAGE_ENGLISH_US; - } - else if (strcmp(langCode, "DEU") == 0){ - return LANGUAGE_GERMAN; - } - else if (strcmp(langCode, "NLD") == 0){ - return LANGUAGE_DUTCH; - } - else if (strcmp(langCode, "FRA") == 0){ - return LANGUAGE_FRENCH; - } - else if (strcmp(langCode, "HUN") == 0){ - return LANGUAGE_HUNGARIAN; - } - else if (strcmp(langCode, "PLK") == 0){ - return LANGUAGE_POLISH; - } - else if (strcmp(langCode, "ESP") == 0){ - return LANGUAGE_SPANISH; - } - else if (strcmp(langCode, "SVE") == 0){ - return LANGUAGE_SWEDISH; - } - else if (strcmp(langCode, "ITA") == 0){ - return LANGUAGE_ITALIAN; - } - else if (strcmp(langCode, "POR") == 0){ - return LANGUAGE_PORTUGUESE_BR; - } - */ - STUB(); - return LANGUAGE_ENGLISH_UK; -} - -time_t platform_file_get_modified_time(const utf8* path){ - struct stat buf; - if (stat(path, &buf) == 0) { - return buf.st_mtime; - } - return 100; -} - -uint8 platform_get_locale_currency(){ - /* - CHAR currCode[4]; - - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_SINTLSYMBOL, - (LPSTR)&currCode, - sizeof(currCode)) == 0){ - return CURRENCY_POUNDS; - } - if (strcmp(currCode, "GBP") == 0){ - return CURRENCY_POUNDS; - } - else if (strcmp(currCode, "USD") == 0){ - return CURRENCY_DOLLARS; - } - else if (strcmp(currCode, "EUR") == 0){ - return CURRENCY_EUROS; - } - else if (strcmp(currCode, "SEK") == 0){ - return CURRENCY_KRONA; - } - else if (strcmp(currCode, "DEM") == 0){ - return CURRENCY_DEUTSCHMARK; - } - else if (strcmp(currCode, "ITL") == 0){ - return CURRENCY_LIRA; - } - else if (strcmp(currCode, "JPY") == 0){ - return CURRENCY_YEN; - } - else if (strcmp(currCode, "ESP") == 0){ - return CURRENCY_PESETA; - } - else if (strcmp(currCode, "FRF") == 0){ - return CURRENCY_FRANC; - } - else if (strcmp(currCode, "NLG") == 0){ - return CURRENCY_GUILDERS; - } - */ - STUB(); - return CURRENCY_POUNDS; -} - -uint8 platform_get_locale_measurement_format(){ - /* - UINT measurement_system; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, - (LPSTR)&measurement_system, - sizeof(measurement_system)) == 0){ - return MEASUREMENT_FORMAT_IMPERIAL; - } - switch (measurement_system){ - case 0: - return MEASUREMENT_FORMAT_METRIC; - case 1: - default: - return MEASUREMENT_FORMAT_IMPERIAL; - }*/ - STUB(); - return MEASUREMENT_FORMAT_METRIC; -} - -uint8 platform_get_locale_temperature_format(){ - /* - // There does not seem to be a function to obtain this, just check the countries - UINT country; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, - (LPSTR)&country, - sizeof(country)) == 0){ - return TEMPERATURE_FORMAT_C; - } - switch (country){ - case CTRY_UNITED_STATES: - case CTRY_BELIZE: - return TEMPERATURE_FORMAT_F; - default: - return TEMPERATURE_FORMAT_C; - } - */ - STUB(); - return TEMPERATURE_FORMAT_C; -} -#endif // __linux +#endif diff --git a/src/platform/osx.c b/src/platform/osx.c index 4f08d128f1..c1928d0f02 100644 --- a/src/platform/osx.c +++ b/src/platform/osx.c @@ -18,19 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(__MACH__) -/** - * OSX entry point to OpenRCT2. - */ -// int main(char *argv[], int argc) -// { -// return 0; -// } +#include "platform.h" -char platform_get_path_separator() -{ - return '/'; +bool platform_check_steam_overlay_attached() { + STUB(); + return false; } -#endif \ No newline at end of file +#endif diff --git a/src/platform/posix.c b/src/platform/posix.c new file mode 100644 index 0000000000..917f27ff4f --- /dev/null +++ b/src/platform/posix.c @@ -0,0 +1,774 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + +#include +#include +#include +#include +#include +#include "../addresses.h" +#include "../cmdline.h" +#include "../openrct2.h" +#include "../localisation/language.h" +#include "../localisation/currency.h" +#include "../config.h" +#include "platform.h" +#include "../util/util.h" +#include +#include +#include + +// The name of the mutex used to prevent multiple instances of the game from running +#define SINGLE_INSTANCE_MUTEX_NAME "RollerCoaster Tycoon 2_GSKMUTEX" + +utf8 _userDataDirectoryPath[MAX_PATH] = { 0 }; + +/** + * The function that is called directly from the host application (rct2.exe)'s WinMain. This will be removed when OpenRCT2 can + * be built as a stand alone application. + */ +int main(int argc, const char **argv) +{ + //RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance; + //RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine; + + STUB(); + int run_game = cmdline_run(argv, argc); + if (run_game == 1) + { + openrct2_launch(); + } + + exit(gExitCode); + return gExitCode; +} + +void platform_get_date(rct2_date *out_date) +{ + assert(out_date != NULL); + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = gmtime(&rawtime); + out_date->day = timeinfo->tm_mday; + out_date->month = timeinfo->tm_mon; + out_date->year = timeinfo->tm_year; + out_date->day_of_week = timeinfo->tm_wday; +} + +void platform_get_time(rct2_time *out_time) +{ + assert(out_time != NULL); + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = gmtime(&rawtime); + out_time->second = timeinfo->tm_sec; + out_time->minute = timeinfo->tm_min; + out_time->hour = timeinfo->tm_hour; +} + +char platform_get_path_separator() +{ + return '/'; +} + +bool platform_file_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + bool exists = access(buffer, F_OK) != -1; + log_warning("file '%s' exists = %i", buffer, exists); + return exists; +} + +bool platform_directory_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + struct stat dirinfo; + int result = stat(buffer, &dirinfo); + log_verbose("checking dir %s, result = %d, is_dir = %d", buffer, result, S_ISDIR(dirinfo.st_mode)); + if ((result != 0) || !S_ISDIR(dirinfo.st_mode)) + { + return false; + } + return true; +} + +bool platform_original_game_data_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + char checkPath[MAX_PATH]; + sprintf(checkPath, "%s%c%s%c%s", buffer, platform_get_path_separator(), "Data", platform_get_path_separator(), "g1.dat"); + return platform_file_exists(checkPath); +} + +mode_t getumask() +{ + mode_t mask = umask(0); + umask(mask); + return 0777 & ~mask; // Keep in mind 0777 is octal +} + +bool platform_ensure_directory_exists(const utf8 *path) +{ + mode_t mask = getumask(); + + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len - 1] = '\0'; + free(wPath); + log_verbose("%s", buffer); + const int result = mkdir(buffer, mask); + if (result == 0 || (result == -1 && errno == EEXIST)) + return true; + return false; +} + +bool platform_directory_delete(const utf8 *path) +{ + STUB(); + return true; +} + +bool platform_lock_single_instance() +{ + STUB(); + return true; +} + +typedef struct { + char active; + char pattern[MAX_PATH]; + struct dirent **fileListTemp; + char **paths; + int cnt; + int handle; + void* data; +} enumerate_file_info; +static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; + +char *g_file_pattern; + +static int winfilter(const struct dirent *d) +{ + int entry_length = strnlen(d->d_name, MAX_PATH); + char *name_upper = malloc(entry_length + 1); + if (name_upper == NULL) + { + log_error("out of memory"); + return 0; + } + for (int i = 0; i < entry_length; i++) + { + name_upper[i] = (char)toupper(d->d_name[i]); + } + name_upper[entry_length] = '\0'; + bool match = fnmatch(g_file_pattern, name_upper, FNM_PATHNAME) == 0; + //log_warning("trying matching filename %s, result = %d", name_upper, match); + free(name_upper); + return match; +} + +int platform_enumerate_files_begin(const utf8 *pattern) +{ + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(pattern); + int length = min(utf8_length(pattern), MAX_PATH); + char *npattern = malloc(length+1); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin file search, pattern: %s", npattern); + + char *file_name = strrchr(npattern, platform_get_path_separator()); + char *dir_name; + if (file_name != NULL) + { + dir_name = strndup(npattern, file_name - npattern); + file_name = &file_name[1]; + } else { + file_name = npattern; + dir_name = strdup("."); + } + + + int pattern_length = strlen(file_name); + g_file_pattern = strndup(file_name, pattern_length); + for (int j = 0; j < pattern_length; j++) + { + g_file_pattern[j] = (char)toupper(g_file_pattern[j]); + } + log_warning("looking for file matching %s", g_file_pattern); + int cnt; + for (int i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + safe_strncpy(enumFileInfo->pattern, npattern, sizeof(enumFileInfo->pattern)); + cnt = scandir(dir_name, &enumFileInfo->fileListTemp, winfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files matching in dir '%s'", cnt, dir_name); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(dir_name, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", dir_name); + strncat(paths[idx], dir_name, MAX_PATH); + strncat(paths[idx], separator, MAX_PATH); + strncat(paths[idx], d->d_name, MAX_PATH); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return i; + } + } + + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_files_next(int handle, file_info *outFileInfo) +{ + + if (handle < 0) + { + return false; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + bool result; + + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + log_verbose("trying handle %d", entryIdx); + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return false; + } + outFileInfo->path = basename(fileName); + outFileInfo->size = fileInfo.st_size; + outFileInfo->last_modified = fileInfo.st_mtime; + return true; + } else { + return false; + } +} + +void platform_enumerate_files_end(int handle) +{ + if (handle < 0) + { + return; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (int i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +static int dirfilter(const struct dirent *d) +{ + if (d->d_name[0] == '.') { + return 0; + } +#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) + if (d->d_type == DT_DIR) + { + return 1; + } else { + return 0; + } +#else +#error implement dirfilter! +#endif // defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) +} + +int platform_enumerate_directories_begin(const utf8 *directory) +{ + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(directory); + int length = min(utf8_length(directory), MAX_PATH); + char *npattern = malloc(length+1); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin directory listing, path: %s", npattern); + + // TODO: add some checking for stringness and directoryness + + int cnt; + for (int i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + safe_strncpy(enumFileInfo->pattern, npattern, length); + cnt = scandir(npattern, &enumFileInfo->fileListTemp, dirfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files in dir '%s'", cnt, npattern); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(npattern, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", npattern); + strncat(paths[idx], npattern, MAX_PATH); + strncat(paths[idx], separator, MAX_PATH); + strncat(paths[idx], d->d_name, MAX_PATH); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(wpattern); + free(npattern); + return i; + } + } + + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_directories_next(int handle, utf8 *path) +{ + if (handle < 0) + { + return false; + } + + bool result; + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + + log_verbose("handle = %d", handle); + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return false; + } + // so very, very wrong + safe_strncpy(path, basename(fileName), MAX_PATH); + strncat(path, "/", MAX_PATH); + path[MAX_PATH - 1] = '\0'; + return true; + } else { + return false; + } +} + +void platform_enumerate_directories_end(int handle) +{ + if (handle < 0) + { + return; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (int i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +int platform_get_drives(){ + /* + return GetLogicalDrives(); + */ + STUB(); + return 0; +} + +bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite) +{ + STUB(); + return 0; +} + +bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) +{ + STUB(); + return 0; +} + +bool platform_file_delete(const utf8 *path) +{ + STUB(); + return 0; +} + +wchar_t *regular_to_wchar(const char* src) +{ + int len = strnlen(src, MAX_PATH); + wchar_t *w_buffer = malloc((len + 1) * sizeof(wchar_t)); + mbtowc (NULL, NULL, 0); /* reset mbtowc */ + + int max = len; + int i = 0; + while (max > 0) + { + int length; + length = mbtowc(&w_buffer[i], &src[i], max); + if (length < 1) + { + w_buffer[i + 1] = '\0'; + break; + } + i += length; + max -= length; + } + return w_buffer; +} + +/** + * Default directory fallback is: + * - (command line argument) + * - $XDG_CONFIG_HOME/.config/OpenRCT2 + * - /home/[uid]/.config/OpenRCT2 + */ +void platform_resolve_user_data_path() +{ + const char separator[2] = { platform_get_path_separator(), 0 }; + + if (gCustomUserDataPath[0] != 0) { + realpath(gCustomUserDataPath, _userDataDirectoryPath); + + // Ensure path ends with separator + int len = strlen(_userDataDirectoryPath); + if (_userDataDirectoryPath[len - 1] != separator[0]) { + strcat(_userDataDirectoryPath, separator); + } + return; + } + + char buffer[MAX_PATH]; + buffer[0] = '\0'; + log_verbose("buffer = '%s'", buffer); + const char *homedir = getenv("XDG_CONFIG_HOME"); + log_verbose("homedir = '%s'", homedir); + if (homedir == NULL) + { + homedir = getpwuid(getuid())->pw_dir; + log_verbose("homedir was null, used getuid, now is = '%s'", homedir); + if (homedir == NULL) + { + log_fatal("Couldn't find user data directory"); + exit(-1); + return; + } + + strncat(buffer, homedir, MAX_PATH); + strncat(buffer, separator, MAX_PATH); + strncat(buffer, ".config", MAX_PATH); + } + else + { + strncat(buffer, homedir, MAX_PATH); + } + strncat(buffer, separator, MAX_PATH); + strncat(buffer, "OpenRCT2", MAX_PATH); + strncat(buffer, separator, MAX_PATH); + log_verbose("OpenRCT2 user data directory = '%s'", buffer); + int len = strnlen(buffer, MAX_PATH); + wchar_t *w_buffer = regular_to_wchar(buffer); + w_buffer[len] = '\0'; + utf8 *path = widechar_to_utf8(w_buffer); + free(w_buffer); + safe_strncpy(_userDataDirectoryPath, path, MAX_PATH); + free(path); +} + +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) +{ + const char separator[2] = { platform_get_path_separator(), 0 }; + char buffer[MAX_PATH]; + safe_strncpy(buffer, _userDataDirectoryPath, sizeof(buffer)); + if (subDirectory != NULL && subDirectory[0] != 0) { + log_verbose("adding subDirectory '%s'", subDirectory); + strcat(buffer, subDirectory); + strcat(buffer, separator); + } + int len = strnlen(buffer, MAX_PATH); + wchar_t *w_buffer = regular_to_wchar(buffer); + w_buffer[len] = '\0'; + utf8 *path = widechar_to_utf8(w_buffer); + free(w_buffer); + safe_strncpy(outPath, path, MAX_PATH); + free(path); + log_verbose("outPath + subDirectory = '%s'", buffer); +} + +void platform_show_messagebox(char *message) +{ + STUB(); + log_warning(message); +} + +/** + * + * rct2: 0x004080EA + */ +int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +{ + STUB(); + return 0; +} + +utf8 *platform_open_directory_browser(utf8 *title) +{ + STUB(); + return NULL; +} + +uint16 platform_get_locale_language(){ + /* + CHAR langCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SABBREVLANGNAME, + (LPSTR)&langCode, + sizeof(langCode)) == 0){ + return LANGUAGE_UNDEFINED; + } + + if (strcmp(langCode, "ENG") == 0){ + return LANGUAGE_ENGLISH_UK; + } + else if (strcmp(langCode, "ENU") == 0){ + return LANGUAGE_ENGLISH_US; + } + else if (strcmp(langCode, "DEU") == 0){ + return LANGUAGE_GERMAN; + } + else if (strcmp(langCode, "NLD") == 0){ + return LANGUAGE_DUTCH; + } + else if (strcmp(langCode, "FRA") == 0){ + return LANGUAGE_FRENCH; + } + else if (strcmp(langCode, "HUN") == 0){ + return LANGUAGE_HUNGARIAN; + } + else if (strcmp(langCode, "PLK") == 0){ + return LANGUAGE_POLISH; + } + else if (strcmp(langCode, "ESP") == 0){ + return LANGUAGE_SPANISH; + } + else if (strcmp(langCode, "SVE") == 0){ + return LANGUAGE_SWEDISH; + } + else if (strcmp(langCode, "ITA") == 0){ + return LANGUAGE_ITALIAN; + } + else if (strcmp(langCode, "POR") == 0){ + return LANGUAGE_PORTUGUESE_BR; + } + */ + STUB(); + return LANGUAGE_ENGLISH_UK; +} + +time_t platform_file_get_modified_time(const utf8* path){ + struct stat buf; + if (stat(path, &buf) == 0) { + return buf.st_mtime; + } + return 100; +} + +uint8 platform_get_locale_currency(){ + /* + CHAR currCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SINTLSYMBOL, + (LPSTR)&currCode, + sizeof(currCode)) == 0){ + return CURRENCY_POUNDS; + } + if (strcmp(currCode, "GBP") == 0){ + return CURRENCY_POUNDS; + } + else if (strcmp(currCode, "USD") == 0){ + return CURRENCY_DOLLARS; + } + else if (strcmp(currCode, "EUR") == 0){ + return CURRENCY_EUROS; + } + else if (strcmp(currCode, "SEK") == 0){ + return CURRENCY_KRONA; + } + else if (strcmp(currCode, "DEM") == 0){ + return CURRENCY_DEUTSCHMARK; + } + else if (strcmp(currCode, "ITL") == 0){ + return CURRENCY_LIRA; + } + else if (strcmp(currCode, "JPY") == 0){ + return CURRENCY_YEN; + } + else if (strcmp(currCode, "ESP") == 0){ + return CURRENCY_PESETA; + } + else if (strcmp(currCode, "FRF") == 0){ + return CURRENCY_FRANC; + } + else if (strcmp(currCode, "NLG") == 0){ + return CURRENCY_GUILDERS; + } + */ + STUB(); + return CURRENCY_POUNDS; +} + +uint8 platform_get_locale_measurement_format(){ + /* + UINT measurement_system; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&measurement_system, + sizeof(measurement_system)) == 0){ + return MEASUREMENT_FORMAT_IMPERIAL; + } + switch (measurement_system){ + case 0: + return MEASUREMENT_FORMAT_METRIC; + case 1: + default: + return MEASUREMENT_FORMAT_IMPERIAL; + }*/ + STUB(); + return MEASUREMENT_FORMAT_METRIC; +} + +uint8 platform_get_locale_temperature_format(){ + /* + // There does not seem to be a function to obtain this, just check the countries + UINT country; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&country, + sizeof(country)) == 0){ + return TEMPERATURE_FORMAT_C; + } + switch (country){ + case CTRY_UNITED_STATES: + case CTRY_BELIZE: + return TEMPERATURE_FORMAT_F; + default: + return TEMPERATURE_FORMAT_C; + } + */ + STUB(); + return TEMPERATURE_FORMAT_C; +} + +#endif diff --git a/src/platform/unix.c b/src/platform/unix.c deleted file mode 100644 index 956828364e..0000000000 --- a/src/platform/unix.c +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program 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 General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef _WIN32 -#ifndef __APPLE__ - -#include "../cmdline.h" -#include "../openrct2.h" -#include - -/** - * Unix, linux and fallback entry point to OpenRCT2. - */ -// int main(char *argv[], int argc) -// { -// if (cmdline_run(argv, argc)) -// openrct2_launch(); -// -// return gExitCode; -// } - -/* -char platform_get_path_separator() -{ - return '/'; -} -*/ - -// See http://syprog.blogspot.ru/2011/12/listing-loaded-shared-objects-in-linux.html -struct lmap { - void* base_address; - char* path; - void* unused; - struct lmap *next, *prev; -}; - -struct dummy { - void* pointers[3]; - struct dummy* ptr; -}; - -bool platform_check_steam_overlay_attached() { - void* processHandle = dlopen(NULL, RTLD_NOW); - - struct dummy* p = (struct dummy*) processHandle; - p = p->ptr; - - struct lmap* pl = (struct lmap*) p->ptr; - - while (pl != NULL) { - if (strstr(pl->path, "gameoverlayrenderer.so") != NULL) { - return true; - } - pl = pl->next; - } - - return false; -} - -#endif -#endif diff --git a/src/rct2.h b/src/rct2.h index 660536a691..4910528dbc 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -92,7 +92,7 @@ typedef utf16* utf16string; #ifdef __linux__ #define OPENRCT2_PLATFORM "Linux" #endif -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(__MACH__) #define OPENRCT2_PLATFORM "OS X" #endif #ifndef OPENRCT2_PLATFORM