X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fmisc.c;h=9d6e0cc9c9e461cd3e55d33f9ffb8e88a8e04e4f;hb=297ee9b33dab3bca9433befc81d7c7ce91450dd0;hp=4c94b7784985f37b466864f8f8bbe2345fe4106b;hpb=80aa0e4b2b060112407417a9d2896395023a21cc;p=rocksndiamonds.git diff --git a/src/libgame/misc.c b/src/libgame/misc.c index 4c94b778..9d6e0cc9 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "platform.h" @@ -42,25 +43,47 @@ /* platform independent wrappers for printf() et al. (newline aware) */ /* ------------------------------------------------------------------------- */ +#if defined(PLATFORM_ANDROID) +static int android_log_prio = ANDROID_LOG_INFO; +#endif + +#if 0 +static void vfPrintLog(FILE *stream, char *format, va_list ap) +{ +} + +static void vfPrintLog(FILE *stream, char *format, va_list ap) +{ +} + +static void fPrintLog(FILE *stream, char *format, va_list ap) +{ +} + +static void fPrintLog(FILE *stream, char *format, va_list ap) +{ +} +#endif + static void vfprintf_newline(FILE *stream, char *format, va_list ap) { +#if defined(PLATFORM_ANDROID) + __android_log_vprint(android_log_prio, program.program_title, format, ap); +#else char *newline = STRING_NEWLINE; vfprintf(stream, format, ap); - fprintf(stream, "%s", newline); +#endif } static void fprintf_newline(FILE *stream, char *format, ...) { - if (format) - { - va_list ap; + va_list ap; - va_start(ap, format); - vfprintf_newline(stream, format, ap); - va_end(ap); - } + va_start(ap, format); + vfprintf_newline(stream, format, ap); + va_end(ap); } void fprintf_line(FILE *stream, char *line_chars, int line_length) @@ -184,7 +207,7 @@ END_OF_FUNCTION(increment_counter); #if 1 -#ifdef TARGET_SDL +#if defined(TARGET_SDL) static unsigned int getCurrentMS() { return SDL_GetTicks(); @@ -222,7 +245,7 @@ static unsigned int mainCounter(int mode) #else -#ifdef TARGET_SDL +#if defined(TARGET_SDL) static unsigned int mainCounter(int mode) { static unsigned int base_ms = 0; @@ -494,7 +517,7 @@ char *getRealName() else real_name = ANONYMOUS_NAME; } -#elif defined(PLATFORM_UNIX) +#elif defined(PLATFORM_UNIX) && !defined(PLATFORM_ANDROID) if (real_name == NULL) { struct passwd *pwd; @@ -564,6 +587,36 @@ char *getBasePath(char *filename) return basepath; } +static char *getProgramMainDataPath() +{ + char *main_data_path = getStringCopy(program.command_basepath); + +#if defined(PLATFORM_MACOSX) + static char *main_data_binary_subdir = NULL; + + if (main_data_binary_subdir == NULL) + { + main_data_binary_subdir = checked_malloc(strlen(program.program_title) + 1 + + strlen("app") + 1 + + strlen(MAC_APP_BINARY_SUBDIR) + 1); + + sprintf(main_data_binary_subdir, "%s.app/%s", + program.program_title, MAC_APP_BINARY_SUBDIR); + } + + // cut relative path to Mac OS X application binary directory from path + if (strSuffix(main_data_path, main_data_binary_subdir)) + main_data_path[strlen(main_data_path) - + strlen(main_data_binary_subdir)] = '\0'; + + // cut trailing path separator from path (but not if path is root directory) + if (strSuffix(main_data_path, "/") && !strEqual(main_data_path, "/")) + main_data_path[strlen(main_data_path) - 1] = '\0'; +#endif + + return main_data_path; +} + /* ------------------------------------------------------------------------- */ /* various string functions */ @@ -602,11 +655,23 @@ char *getStringCat3(char *s1, char *s2, char *s3) char *getPath2(char *path1, char *path2) { +#if defined(PLATFORM_ANDROID) + // workaround for reading from APK assets directory -- skip leading "./" + if (strEqual(path1, ".")) + return getStringCopy(path2); +#endif + return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR); } char *getPath3(char *path1, char *path2, char *path3) { +#if defined(PLATFORM_ANDROID) + // workaround for reading from APK assets directory -- skip leading "./" + if (strEqual(path1, ".")) + return getStringCat2WithSeparator(path2, path3, STRING_PATH_SEPARATOR); +#endif + return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR); } @@ -721,6 +786,18 @@ void GetOptions(char *argv[], void (*print_usage_function)(void)) char *rw_base_path = RW_BASE_PATH; char **options_left = &argv[1]; +#if 1 + /* if the program is configured to start from current directory (default), + determine program package directory from program binary (some versions + of KDE/Konqueror and Mac OS X (especially "Mavericks") apparently do not + set the current working directory to the program package directory) */ + + if (strEqual(ro_base_path, ".")) + ro_base_path = getProgramMainDataPath(); + if (strEqual(rw_base_path, ".")) + rw_base_path = getProgramMainDataPath(); +#else + #if !defined(PLATFORM_MACOSX) /* if the program is configured to start from current directory (default), determine program package directory (KDE/Konqueror does not do this by @@ -732,6 +809,8 @@ void GetOptions(char *argv[], void (*print_usage_function)(void)) ro_base_path = program.command_basepath; if (strEqual(rw_base_path, ".")) rw_base_path = program.command_basepath; +#endif + #endif /* initialize global program options */ @@ -963,9 +1042,16 @@ void Error(int mode, char *format, ...) static boolean last_line_was_separator = FALSE; char *process_name = ""; +#if defined(PLATFORM_ANDROID) + android_log_prio = (mode & ERR_WARN ? ANDROID_LOG_WARN : + mode & ERR_EXIT ? ANDROID_LOG_FATAL : ANDROID_LOG_INFO); +#endif + +#if 1 /* display warnings only when running in verbose mode */ if (mode & ERR_WARN && !options.verbose) return; +#endif if (mode == ERR_INFO_LINE) { @@ -999,6 +1085,13 @@ void Error(int mode, char *format, ...) va_start(ap, format); vfprintf_newline(program.error_file, format, ap); va_end(ap); + + if ((mode & ERR_EXIT) && !(mode & ERR_FROM_SERVER)) + { + va_start(ap, format); + program.exit_message_function(format, ap); + va_end(ap); + } } if (mode & ERR_HELP) @@ -1193,7 +1286,8 @@ boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size, const int chunk_name_length = 4; /* read chunk name */ - fgets(chunk_name, chunk_name_length + 1, file); + if (fgets(chunk_name, chunk_name_length + 1, file) == NULL) + return FALSE; if (chunk_size != NULL) { @@ -1336,8 +1430,10 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_Meta_R, "XK_Meta_R", "right meta" }, { KSYM_Alt_L, "XK_Alt_L", "left alt" }, { KSYM_Alt_R, "XK_Alt_R", "right alt" }, +#if !defined(TARGET_SDL2) { KSYM_Super_L, "XK_Super_L", "left super" }, /* Win-L */ { KSYM_Super_R, "XK_Super_R", "right super" }, /* Win-R */ +#endif { KSYM_Mode_switch, "XK_Mode_switch", "mode switch" }, /* Alt-R */ { KSYM_Multi_key, "XK_Multi_key", "multi key" }, /* Ctrl-R */ @@ -1390,6 +1486,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_braceright, "XK_braceright", "brace right" }, { KSYM_asciitilde, "XK_asciitilde", "~" }, +#if !defined(TARGET_SDL2) /* special (non-ASCII) keys */ { KSYM_degree, "XK_degree", "°" }, { KSYM_Adiaeresis, "XK_Adiaeresis", "Ä" }, @@ -1399,6 +1496,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_odiaeresis, "XK_odiaeresis", "ö" }, { KSYM_udiaeresis, "XK_udiaeresis", "ü" }, { KSYM_ssharp, "XK_ssharp", "sharp s" }, +#endif /* end-of-array identifier */ { 0, NULL, NULL } @@ -1795,6 +1893,144 @@ void dumpList(ListNode *node_first) } +/* ------------------------------------------------------------------------- */ +/* functions for reading directories */ +/* ------------------------------------------------------------------------- */ + +struct Directory *openDirectory(char *dir_name) +{ + struct Directory *dir = checked_calloc(sizeof(struct Directory)); + + dir->dir = opendir(dir_name); + + if (dir->dir != NULL) + { + dir->filename = getStringCopy(dir_name); + + return dir; + } + +#if defined(PLATFORM_ANDROID) + char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME); + + dir->asset_toc_file = SDL_RWFromFile(asset_toc_filename, MODE_READ); + + checked_free(asset_toc_filename); + + if (dir->asset_toc_file != NULL) + { + dir->directory_is_asset = TRUE; + dir->filename = getStringCopy(dir_name); + + return dir; + } +#endif + + checked_free(dir); + + return NULL; +} + +int closeDirectory(struct Directory *dir) +{ + if (dir == NULL) + return -1; + + int result; + +#if defined(PLATFORM_ANDROID) + if (dir->asset_toc_file) + result = SDL_RWclose(dir->asset_toc_file); +#endif + + if (dir->dir) + result = closedir(dir->dir); + + if (dir->dir_entry) + freeDirectoryEntry(dir->dir_entry); + + checked_free(dir->filename); + checked_free(dir); + + return result; +} + +struct DirectoryEntry *readDirectory(struct Directory *dir) +{ + if (dir->dir_entry) + freeDirectoryEntry(dir->dir_entry); + + dir->dir_entry = NULL; + +#if defined(PLATFORM_ANDROID) + if (dir->directory_is_asset) + { + char line[MAX_LINE_LEN]; + char *line_ptr = line; + char *last_line_ptr = line_ptr; + int num_bytes_read = 0; + + while (num_bytes_read < MAX_LINE_LEN && + SDL_RWread(dir->asset_toc_file, line_ptr, 1, 1) == 1 && + *line_ptr != '\n') + { + last_line_ptr = line_ptr; + line_ptr++; + num_bytes_read++; + } + + *line_ptr = '\0'; + + if (strlen(line) == 0) + return NULL; + + dir->dir_entry = checked_calloc(sizeof(struct DirectoryEntry)); + + dir->dir_entry->is_directory = FALSE; + if (line[strlen(line) - 1] = '/') + { + dir->dir_entry->is_directory = TRUE; + + line[strlen(line) - 1] = '\0'; + } + + dir->dir_entry->basename = getStringCopy(line); + dir->dir_entry->filename = getPath2(dir->filename, line); + + return dir->dir_entry; + } +#endif + + struct dirent *dir_entry = readdir(dir->dir); + + if (dir_entry == NULL) + return NULL; + + dir->dir_entry = checked_calloc(sizeof(struct DirectoryEntry)); + + dir->dir_entry->basename = getStringCopy(dir_entry->d_name); + dir->dir_entry->filename = getPath2(dir->filename, dir_entry->d_name); + + struct stat file_status; + + dir->dir_entry->is_directory = + (stat(dir->dir_entry->filename, &file_status) == 0 && + (file_status.st_mode & S_IFMT) != S_IFDIR); + + return dir->dir_entry; +} + +void freeDirectoryEntry(struct DirectoryEntry *dir_entry) +{ + if (dir_entry == NULL) + return; + + checked_free(dir_entry->basename); + checked_free(dir_entry->filename); + checked_free(dir_entry); +} + + /* ------------------------------------------------------------------------- */ /* functions for checking files and filenames */ /* ------------------------------------------------------------------------- */ @@ -1804,7 +2040,18 @@ boolean fileExists(char *filename) if (filename == NULL) return FALSE; +#if defined(PLATFORM_ANDROID) + // workaround: check if file exists by opening and closing it + SDL_RWops *file = SDL_RWFromFile(filename, MODE_READ); + boolean success = (file != NULL); + + if (success) + SDL_RWclose(file); + + return success; +#else return (access(filename, F_OK) == 0); +#endif } boolean fileHasPrefix(char *basename, char *prefix) @@ -3051,8 +3298,12 @@ void openErrorFile() InitUserDataDirectory(); if ((program.error_file = fopen(program.error_filename, MODE_WRITE)) == NULL) - fprintf_newline(stderr, "ERROR: cannot open file '%s' for writing!", - program.error_filename); + { + program.error_file = stderr; + + Error(ERR_WARN, "cannot open file '%s' for writing: %s", + program.error_filename, strerror(errno)); + } } void closeErrorFile()