X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fmisc.c;h=ae4b5d78e797c470863e88e09313172700eeca0d;hp=27cf37c6d2e48a655162471db25681b059084c59;hb=a7c06161253796a30a0237a7f5a044f459c8cf35;hpb=4a8368abd71c718621838773eed914b5bbd4e1d8 diff --git a/src/libgame/misc.c b/src/libgame/misc.c index 27cf37c6..ae4b5d78 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,80 @@ /* 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_nonewline(FILE *stream, char *format, va_list ap) +{ +#if defined(PLATFORM_ANDROID) + // (prefix text of logging output is currently skipped on Android) + //__android_log_vprint(android_log_prio, program.program_title, format, ap); +#else + va_list ap2; + va_copy(ap2, ap); + + vfprintf(stream, format, ap); + vfprintf(stderr, format, ap2); + + va_end(ap2); +#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); + va_list ap2; + va_copy(ap2, ap); + vfprintf(stream, format, ap); fprintf(stream, "%s", newline); + + vfprintf(stderr, format, ap2); + fprintf(stderr, "%s", newline); + + va_end(ap2); +#endif +} + +static void fprintf_nonewline(FILE *stream, char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf_nonewline(stream, format, ap); + va_end(ap); } 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) @@ -68,7 +124,7 @@ void fprintf_line(FILE *stream, char *line_chars, int line_length) int i; for (i = 0; i < line_length; i++) - fprintf(stream, "%s", line_chars); + fprintf_nonewline(stream, "%s", line_chars); fprintf_newline(stream, ""); } @@ -168,7 +224,7 @@ boolean getTokenValueFromString(char *string, char **token, char **value) /* ------------------------------------------------------------------------- */ #if defined(PLATFORM_MSDOS) -volatile unsigned long counter = 0; +volatile unsigned int counter = 0; void increment_counter() { @@ -182,12 +238,52 @@ END_OF_FUNCTION(increment_counter); /* maximal allowed length of a command line option */ #define MAX_OPTION_LEN 256 -#ifdef TARGET_SDL -static unsigned long mainCounter(int mode) +#if 1 + +#if defined(TARGET_SDL) +static unsigned int getCurrentMS() +{ + return SDL_GetTicks(); +} + +#else /* !TARGET_SDL */ + +#if defined(PLATFORM_UNIX) +static unsigned int getCurrentMS() { - static unsigned long base_ms = 0; - unsigned long current_ms; - unsigned long counter_ms; + struct timeval current_time; + + gettimeofday(¤t_time, NULL); + + return current_time.tv_sec * 1000 + current_time.tv_usec / 1000; +} +#endif /* PLATFORM_UNIX */ +#endif /* !TARGET_SDL */ + +static unsigned int mainCounter(int mode) +{ + static unsigned int base_ms = 0; + unsigned int current_ms; + + /* get current system milliseconds */ + current_ms = getCurrentMS(); + + /* reset base timestamp in case of counter reset or wrap-around */ + if (mode == INIT_COUNTER || current_ms < base_ms) + base_ms = current_ms; + + /* return milliseconds since last counter reset */ + return current_ms - base_ms; +} + +#else + +#if defined(TARGET_SDL) +static unsigned int mainCounter(int mode) +{ + static unsigned int base_ms = 0; + unsigned int current_ms; + unsigned int counter_ms; current_ms = SDL_GetTicks(); @@ -203,11 +299,11 @@ static unsigned long mainCounter(int mode) #else /* !TARGET_SDL */ #if defined(PLATFORM_UNIX) -static unsigned long mainCounter(int mode) +static unsigned int mainCounter(int mode) { static struct timeval base_time = { 0, 0 }; struct timeval current_time; - unsigned long counter_ms; + unsigned int counter_ms; gettimeofday(¤t_time, NULL); @@ -223,6 +319,8 @@ static unsigned long mainCounter(int mode) #endif /* PLATFORM_UNIX */ #endif /* !TARGET_SDL */ +#endif + void InitCounter() /* set counter back to zero */ { #if !defined(PLATFORM_MSDOS) @@ -234,7 +332,7 @@ void InitCounter() /* set counter back to zero */ #endif } -unsigned long Counter() /* get milliseconds since last call of InitCounter() */ +unsigned int Counter() /* get milliseconds since last call of InitCounter() */ { #if !defined(PLATFORM_MSDOS) return mainCounter(READ_COUNTER); @@ -243,7 +341,7 @@ unsigned long Counter() /* get milliseconds since last call of InitCounter() */ #endif } -static void sleep_milliseconds(unsigned long milliseconds_delay) +static void sleep_milliseconds(unsigned int milliseconds_delay) { boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE); @@ -254,7 +352,7 @@ static void sleep_milliseconds(unsigned long milliseconds_delay) therefore it's better to do a short interval of busy waiting to get our sleeping time more accurate */ - unsigned long base_counter = Counter(), actual_counter = Counter(); + unsigned int base_counter = Counter(), actual_counter = Counter(); while (actual_counter < base_counter + milliseconds_delay && actual_counter >= base_counter) @@ -278,15 +376,15 @@ static void sleep_milliseconds(unsigned long milliseconds_delay) } } -void Delay(unsigned long delay) /* Sleep specified number of milliseconds */ +void Delay(unsigned int delay) /* Sleep specified number of milliseconds */ { sleep_milliseconds(delay); } -boolean FrameReached(unsigned long *frame_counter_var, - unsigned long frame_delay) +boolean FrameReached(unsigned int *frame_counter_var, + unsigned int frame_delay) { - unsigned long actual_frame_counter = FrameCounter; + unsigned int actual_frame_counter = FrameCounter; if (actual_frame_counter >= *frame_counter_var && actual_frame_counter < *frame_counter_var + frame_delay) @@ -297,10 +395,10 @@ boolean FrameReached(unsigned long *frame_counter_var, return TRUE; } -boolean DelayReached(unsigned long *counter_var, - unsigned long delay) +boolean DelayReached(unsigned int *counter_var, + unsigned int delay) { - unsigned long actual_counter = Counter(); + unsigned int actual_counter = Counter(); if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) @@ -311,9 +409,9 @@ boolean DelayReached(unsigned long *counter_var, return TRUE; } -void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) +void WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay) { - unsigned long actual_counter; + unsigned int actual_counter; while (1) { @@ -334,12 +432,12 @@ void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) /* random generator functions */ /* ------------------------------------------------------------------------- */ -unsigned int init_random_number(int nr, long seed) +unsigned int init_random_number(int nr, int seed) { if (seed == NEW_RANDOMIZE) { /* default random seed */ - seed = (long)time(NULL); // seconds since the epoch + seed = (int)time(NULL); // seconds since the epoch #if !defined(PLATFORM_WIN32) /* add some more randomness */ @@ -347,12 +445,12 @@ unsigned int init_random_number(int nr, long seed) gettimeofday(¤t_time, NULL); - seed += (long)current_time.tv_usec; // microseconds since the epoch + seed += (int)current_time.tv_usec; // microseconds since the epoch #endif #if defined(TARGET_SDL) /* add some more randomness */ - seed += (long)SDL_GetTicks(); // milliseconds since SDL init + seed += (int)SDL_GetTicks(); // milliseconds since SDL init #endif #if 1 @@ -376,7 +474,7 @@ unsigned int get_random_number(int nr, int max) /* system info functions */ /* ------------------------------------------------------------------------- */ -#if !defined(PLATFORM_MSDOS) +#if !defined(PLATFORM_MSDOS) && !defined(PLATFORM_ANDROID) static char *get_corrected_real_name(char *real_name) { char *real_name_new = checked_malloc(MAX_USERNAME_LEN + 1); @@ -384,7 +482,7 @@ static char *get_corrected_real_name(char *real_name) char *to_ptr = real_name_new; /* copy the name string, but not more than MAX_USERNAME_LEN characters */ - while (*from_ptr && (long)(to_ptr - real_name_new) < MAX_USERNAME_LEN - 1) + while (*from_ptr && (int)(to_ptr - real_name_new) < MAX_USERNAME_LEN - 1) { /* the name field read from "passwd" file may also contain additional user information, separated by commas, which will be removed here */ @@ -452,7 +550,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; @@ -522,6 +620,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 */ @@ -560,11 +688,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); } @@ -679,6 +819,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 @@ -690,6 +842,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 */ @@ -714,9 +868,13 @@ void GetOptions(char *argv[], void (*print_usage_function)(void)) options.debug = FALSE; options.debug_x11_sync = FALSE; +#if 1 + options.verbose = TRUE; +#else #if !defined(PLATFORM_UNIX) if (*options_left == NULL) /* no options given -- enable verbose mode */ options.verbose = TRUE; +#endif #endif while (*options_left) @@ -848,7 +1006,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void)) options.special_flags = getStringCopy(&option[2]); #else char *flags_string = &option[2]; - unsigned long flags_value; + unsigned int flags_value; if (*flags_string == '\0') Error(ERR_EXIT_HELP, "empty flag ignored"); @@ -921,9 +1079,19 @@ 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_DEBUG ? ANDROID_LOG_DEBUG : + mode & ERR_INFO ? ANDROID_LOG_INFO : + mode & ERR_WARN ? ANDROID_LOG_WARN : + mode & ERR_EXIT ? ANDROID_LOG_FATAL : + ANDROID_LOG_UNKNOWN); +#endif + +#if 1 /* display warnings only when running in verbose mode */ if (mode & ERR_WARN && !options.verbose) return; +#endif if (mode == ERR_INFO_LINE) { @@ -948,15 +1116,22 @@ void Error(int mode, char *format, ...) { va_list ap; - fprintf(program.error_file, "%s%s: ", program.command_basename, - process_name); + fprintf_nonewline(program.error_file, "%s%s: ", program.command_basename, + process_name); if (mode & ERR_WARN) - fprintf(program.error_file, "warning: "); + fprintf_nonewline(program.error_file, "warning: "); 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) @@ -982,7 +1157,7 @@ void Error(int mode, char *format, ...) /* checked memory allocation and freeing functions */ /* ------------------------------------------------------------------------- */ -void *checked_malloc(unsigned long size) +void *checked_malloc(unsigned int size) { void *ptr; @@ -994,7 +1169,7 @@ void *checked_malloc(unsigned long size) return ptr; } -void *checked_calloc(unsigned long size) +void *checked_calloc(unsigned int size) { void *ptr; @@ -1006,7 +1181,7 @@ void *checked_calloc(unsigned long size) return ptr; } -void *checked_realloc(void *ptr, unsigned long size) +void *checked_realloc(void *ptr, unsigned int size) { ptr = realloc(ptr, size); @@ -1022,7 +1197,7 @@ void checked_free(void *ptr) free(ptr); } -void clear_mem(void *ptr, unsigned long size) +void clear_mem(void *ptr, unsigned int size) { #if defined(PLATFORM_WIN32) /* for unknown reason, memset() sometimes crashes when compiled with MinGW */ @@ -1066,11 +1241,22 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) of the (not yet written) chunk, write the correct chunk size and finally write the chunk itself */ +#if 1 + +int getFile8BitInteger(File *file) +{ + return getByteFromFile(file); +} + +#else + int getFile8BitInteger(FILE *file) { return fgetc(file); } +#endif + int putFile8BitInteger(FILE *file, int value) { if (file != NULL) @@ -1079,6 +1265,20 @@ int putFile8BitInteger(FILE *file, int value) return 1; } +#if 1 + +int getFile16BitInteger(File *file, int byte_order) +{ + if (byte_order == BYTE_ORDER_BIG_ENDIAN) + return ((getByteFromFile(file) << 8) | + (getByteFromFile(file) << 0)); + else /* BYTE_ORDER_LITTLE_ENDIAN */ + return ((getByteFromFile(file) << 0) | + (getByteFromFile(file) << 8)); +} + +#else + int getFile16BitInteger(FILE *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) @@ -1089,6 +1289,8 @@ int getFile16BitInteger(FILE *file, int byte_order) (fgetc(file) << 8)); } +#endif + int putFile16BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) @@ -1108,6 +1310,24 @@ int putFile16BitInteger(FILE *file, int value, int byte_order) return 2; } +#if 1 + +int getFile32BitInteger(File *file, int byte_order) +{ + if (byte_order == BYTE_ORDER_BIG_ENDIAN) + return ((getByteFromFile(file) << 24) | + (getByteFromFile(file) << 16) | + (getByteFromFile(file) << 8) | + (getByteFromFile(file) << 0)); + else /* BYTE_ORDER_LITTLE_ENDIAN */ + return ((getByteFromFile(file) << 0) | + (getByteFromFile(file) << 8) | + (getByteFromFile(file) << 16) | + (getByteFromFile(file) << 24)); +} + +#else + int getFile32BitInteger(FILE *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) @@ -1122,6 +1342,8 @@ int getFile32BitInteger(FILE *file, int byte_order) (fgetc(file) << 24)); } +#endif + int putFile32BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) @@ -1145,13 +1367,36 @@ int putFile32BitInteger(FILE *file, int value, int byte_order) return 4; } +#if 1 + +boolean getFileChunk(File *file, char *chunk_name, int *chunk_size, + int byte_order) +{ + const int chunk_name_length = 4; + + /* read chunk name */ + if (getStringFromFile(file, chunk_name, chunk_name_length + 1) == NULL) + return FALSE; + + if (chunk_size != NULL) + { + /* read chunk size */ + *chunk_size = getFile32BitInteger(file, byte_order); + } + + return (checkEndOfFile(file) ? FALSE : TRUE); +} + +#else + boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size, int byte_order) { 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) { @@ -1162,6 +1407,8 @@ boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size, return (feof(file) || ferror(file) ? FALSE : TRUE); } +#endif + int putFileChunk(FILE *file, char *chunk_name, int chunk_size, int byte_order) { @@ -1185,6 +1432,21 @@ int putFileChunk(FILE *file, char *chunk_name, int chunk_size, return num_bytes; } +#if 1 + +int getFileVersion(File *file) +{ + int version_major = getByteFromFile(file); + int version_minor = getByteFromFile(file); + int version_patch = getByteFromFile(file); + int version_build = getByteFromFile(file); + + return VERSION_IDENT(version_major, version_minor, version_patch, + version_build); +} + +#else + int getFileVersion(FILE *file) { int version_major = fgetc(file); @@ -1196,6 +1458,8 @@ int getFileVersion(FILE *file) version_build); } +#endif + int putFileVersion(FILE *file, int version) { if (file != NULL) @@ -1214,7 +1478,19 @@ int putFileVersion(FILE *file, int version) return 4; } -void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes) +#if 1 + +void ReadBytesFromFile(File *file, byte *buffer, unsigned int bytes) +{ + int i; + + for (i = 0; i < bytes && !checkEndOfFile(file); i++) + buffer[i] = getByteFromFile(file); +} + +#else + +void ReadBytesFromFile(FILE *file, byte *buffer, unsigned int bytes) { int i; @@ -1222,7 +1498,9 @@ void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes) buffer[i] = fgetc(file); } -void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes) +#endif + +void WriteBytesToFile(FILE *file, byte *buffer, unsigned int bytes) { int i; @@ -1230,13 +1508,25 @@ void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes) fputc(buffer[i], file); } -void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes) +#if 1 + +void ReadUnusedBytesFromFile(File *file, unsigned int bytes) +{ + while (bytes-- && !checkEndOfFile(file)) + getByteFromFile(file); +} + +#else + +void ReadUnusedBytesFromFile(FILE *file, unsigned int bytes) { while (bytes-- && !feof(file)) fgetc(file); } -void WriteUnusedBytesToFile(FILE *file, unsigned long bytes) +#endif + +void WriteUnusedBytesToFile(FILE *file, unsigned int bytes) { while (bytes--) fputc(0, file); @@ -1294,8 +1584,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 */ @@ -1308,7 +1600,11 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_End, "XK_End", "end" }, { KSYM_Page_Up, "XK_Page_Up", "page up" }, { KSYM_Page_Down, "XK_Page_Down", "page down" }, - { KSYM_Menu, "XK_Menu", "menu" }, /* Win-Menu */ + +#if defined(TARGET_SDL2) + { KSYM_Menu, "XK_Menu", "menu" }, /* menu key */ + { KSYM_Back, "XK_Back", "back" }, /* back key */ +#endif /* ASCII 0x20 to 0x40 keys (except numbers) */ { KSYM_space, "XK_space", "space" }, @@ -1348,7 +1644,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_braceright, "XK_braceright", "brace right" }, { KSYM_asciitilde, "XK_asciitilde", "~" }, - /* special (non-ASCII) keys */ + /* special (non-ASCII) keys (ISO-Latin-1) */ { KSYM_degree, "XK_degree", "°" }, { KSYM_Adiaeresis, "XK_Adiaeresis", "Ä" }, { KSYM_Odiaeresis, "XK_Odiaeresis", "Ö" }, @@ -1358,6 +1654,35 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { KSYM_udiaeresis, "XK_udiaeresis", "ü" }, { KSYM_ssharp, "XK_ssharp", "sharp s" }, +#if defined(TARGET_SDL2) + /* special (non-ASCII) keys (UTF-8, for reverse mapping only) */ + { KSYM_degree, "XK_degree", "\xc2\xb0" }, + { KSYM_Adiaeresis, "XK_Adiaeresis", "\xc3\x84" }, + { KSYM_Odiaeresis, "XK_Odiaeresis", "\xc3\x96" }, + { KSYM_Udiaeresis, "XK_Udiaeresis", "\xc3\x9c" }, + { KSYM_adiaeresis, "XK_adiaeresis", "\xc3\xa4" }, + { KSYM_odiaeresis, "XK_odiaeresis", "\xc3\xb6" }, + { KSYM_udiaeresis, "XK_udiaeresis", "\xc3\xbc" }, + { KSYM_ssharp, "XK_ssharp", "\xc3\x9f" }, + + /* other keys (for reverse mapping only) */ + { KSYM_space, "XK_space", " " }, +#endif + +#if defined(TARGET_SDL2) + /* keypad keys are not in numerical order in SDL2 */ + { KSYM_KP_0, "XK_KP_0", "keypad 0" }, + { KSYM_KP_1, "XK_KP_1", "keypad 1" }, + { KSYM_KP_2, "XK_KP_2", "keypad 2" }, + { KSYM_KP_3, "XK_KP_3", "keypad 3" }, + { KSYM_KP_4, "XK_KP_4", "keypad 4" }, + { KSYM_KP_5, "XK_KP_5", "keypad 5" }, + { KSYM_KP_6, "XK_KP_6", "keypad 6" }, + { KSYM_KP_7, "XK_KP_7", "keypad 7" }, + { KSYM_KP_8, "XK_KP_8", "keypad 8" }, + { KSYM_KP_9, "XK_KP_9", "keypad 9" }, +#endif + /* end-of-array identifier */ { 0, NULL, NULL } }; @@ -1375,8 +1700,10 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) sprintf(name_buffer, "%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0)); +#if !defined(TARGET_SDL2) else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0)); +#endif else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) @@ -1412,8 +1739,10 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) sprintf(name_buffer, "XK_%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "XK_%c", '0' + (char)(key - KSYM_0)); +#if !defined(TARGET_SDL2) else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - KSYM_KP_0)); +#endif else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "XK_F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) @@ -1433,7 +1762,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) while (translate_key[++i].x11name); if (!translate_key[i].x11name) - sprintf(name_buffer, "0x%04lx", (unsigned long)key); + sprintf(name_buffer, "0x%04x", (unsigned int)key); } *x11name = name_buffer; @@ -1441,17 +1770,34 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) else if (mode == TRANSLATE_KEYNAME_TO_KEYSYM) { Key key = KSYM_UNDEFINED; + char *name_ptr = *name; - i = 0; - do + if (strlen(*name) == 1) { - if (strEqual(translate_key[i].name, *name)) + char c = name_ptr[0]; + + if (c >= 'A' && c <= 'Z') + key = KSYM_A + (Key)(c - 'A'); + else if (c >= 'a' && c <= 'z') + key = KSYM_a + (Key)(c - 'a'); + else if (c >= '0' && c <= '9') + key = KSYM_0 + (Key)(c - '0'); + } + + if (key == KSYM_UNDEFINED) + { + i = 0; + + do { - key = translate_key[i].key; - break; + if (strEqual(translate_key[i].name, *name)) + { + key = translate_key[i].key; + break; + } } + while (translate_key[++i].x11name); } - while (translate_key[++i].x11name); if (key == KSYM_UNDEFINED) Error(ERR_WARN, "getKeyFromKeyName(): not completely implemented"); @@ -1474,6 +1820,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) else if (c >= '0' && c <= '9') key = KSYM_0 + (Key)(c - '0'); } +#if !defined(TARGET_SDL2) else if (strPrefix(name_ptr, "XK_KP_") && strlen(name_ptr) == 7) { char c = name_ptr[6]; @@ -1481,6 +1828,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) if (c >= '0' && c <= '9') key = KSYM_KP_0 + (Key)(c - '0'); } +#endif else if (strPrefix(name_ptr, "XK_F") && strlen(name_ptr) <= 6) { char c1 = name_ptr[4]; @@ -1510,7 +1858,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode) } else if (strPrefix(name_ptr, "0x")) { - unsigned long value = 0; + unsigned int value = 0; name_ptr += 2; @@ -1753,16 +2101,355 @@ void dumpList(ListNode *node_first) } +/* ------------------------------------------------------------------------- */ +/* functions for file handling */ +/* ------------------------------------------------------------------------- */ + +File *openFile(char *filename, char *mode) +{ + File *file = checked_calloc(sizeof(File)); + + file->file = fopen(filename, mode); + + if (file->file != NULL) + { + file->filename = getStringCopy(filename); + + return file; + } + +#if defined(PLATFORM_ANDROID) + file->asset_file = SDL_RWFromFile(filename, mode); + + if (file->asset_file != NULL) + { + file->file_is_asset = TRUE; + file->filename = getStringCopy(filename); + + return file; + } +#endif + + checked_free(file); + + return NULL; +} + +int closeFile(File *file) +{ + if (file == NULL) + return -1; + + int result = 0; + +#if defined(PLATFORM_ANDROID) + if (file->asset_file) + result = SDL_RWclose(file->asset_file); +#endif + + if (file->file) + result = fclose(file->file); + + checked_free(file->filename); + checked_free(file); + + return result; +} + +int checkEndOfFile(File *file) +{ +#if defined(PLATFORM_ANDROID) + if (file->file_is_asset) + return file->end_of_file; +#endif + + return feof(file->file); +} + +size_t readFile(File *file, void *buffer, size_t item_size, size_t num_items) +{ +#if defined(PLATFORM_ANDROID) + if (file->file_is_asset) + { + if (file->end_of_file) + return 0; + + size_t num_items_read = + SDL_RWread(file->asset_file, buffer, item_size, num_items); + + if (num_items_read < num_items) + file->end_of_file = TRUE; + + return num_items_read; + } +#endif + + return fread(buffer, item_size, num_items, file->file); +} + +int seekFile(File *file, long offset, int whence) +{ +#if defined(PLATFORM_ANDROID) + if (file->file_is_asset) + { + int sdl_whence = (whence == SEEK_SET ? RW_SEEK_SET : + whence == SEEK_CUR ? RW_SEEK_CUR : + whence == SEEK_END ? RW_SEEK_END : 0); + + return (SDL_RWseek(file->asset_file, offset, sdl_whence) == -1 ? -1 : 0); + } +#endif + + return fseek(file->file, offset, whence); +} + +int getByteFromFile(File *file) +{ +#if defined(PLATFORM_ANDROID) + if (file->file_is_asset) + { + if (file->end_of_file) + return EOF; + + byte c; + size_t num_bytes_read = SDL_RWread(file->asset_file, &c, 1, 1); + + if (num_bytes_read < 1) + file->end_of_file = TRUE; + + return (file->end_of_file ? EOF : (int)c); + } +#endif + + return fgetc(file->file); +} + +char *getStringFromFile(File *file, char *line, int size) +{ +#if defined(PLATFORM_ANDROID) + if (file->file_is_asset) + { + if (file->end_of_file) + return NULL; + + char *line_ptr = line; + int num_bytes_read = 0; + + while (num_bytes_read < size - 1 && + SDL_RWread(file->asset_file, line_ptr, 1, 1) == 1 && + *line_ptr++ != '\n') + num_bytes_read++; + + *line_ptr = '\0'; + + if (strlen(line) == 0) + { + file->end_of_file = TRUE; + + return NULL; + } + + return line; + } +#endif + + return fgets(line, size, file->file); +} + + +/* ------------------------------------------------------------------------- */ +/* functions for directory handling */ +/* ------------------------------------------------------------------------- */ + +Directory *openDirectory(char *dir_name) +{ + Directory *dir = checked_calloc(sizeof(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(Directory *dir) +{ + if (dir == NULL) + return -1; + + int result = 0; + +#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; +} + +DirectoryEntry *readDirectory(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; + int num_bytes_read = 0; + + while (num_bytes_read < MAX_LINE_LEN - 1 && + SDL_RWread(dir->asset_toc_file, line_ptr, 1, 1) == 1 && + *line_ptr != '\n') + { + line_ptr++; + num_bytes_read++; + } + + *line_ptr = '\0'; + + if (strlen(line) == 0) + return NULL; + + dir->dir_entry = checked_calloc(sizeof(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(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); + +#if 0 + Error(ERR_INFO, "::: '%s' is directory: %d", + dir->dir_entry->basename, + dir->dir_entry->is_directory); +#endif + + return dir->dir_entry; +} + +void freeDirectoryEntry(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 */ /* ------------------------------------------------------------------------- */ +boolean directoryExists(char *dir_name) +{ + if (dir_name == NULL) + return FALSE; + + boolean success = (access(dir_name, F_OK) == 0); + +#if defined(PLATFORM_ANDROID) + if (!success) + { + // this might be an asset directory; check by trying to open toc file + char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME); + SDL_RWops *file = SDL_RWFromFile(asset_toc_filename, MODE_READ); + + checked_free(asset_toc_filename); + + success = (file != NULL); + + if (success) + SDL_RWclose(file); + } +#endif + + return success; +} + boolean fileExists(char *filename) { if (filename == NULL) return FALSE; - return (access(filename, F_OK) == 0); + boolean success = (access(filename, F_OK) == 0); + +#if defined(PLATFORM_ANDROID) + if (!success) + { + // this might be an asset file; check by trying to open it + SDL_RWops *file = SDL_RWFromFile(filename, MODE_READ); + + success = (file != NULL); + + if (success) + SDL_RWclose(file); + } +#endif + + return success; } boolean fileHasPrefix(char *basename, char *prefix) @@ -1809,29 +2496,51 @@ boolean fileHasSuffix(char *basename, char *suffix) return FALSE; } +#if defined(TARGET_SDL) +static boolean FileCouldBeArtwork(char *basename) +{ + return (!strEqual(basename, ".") && + !strEqual(basename, "..") && + !fileHasSuffix(basename, "txt") && + !fileHasSuffix(basename, "conf")); +} +#endif + boolean FileIsGraphic(char *filename) { char *basename = getBaseNamePtr(filename); +#if defined(TARGET_SDL) + return FileCouldBeArtwork(basename); +#else return fileHasSuffix(basename, "pcx"); +#endif } boolean FileIsSound(char *filename) { char *basename = getBaseNamePtr(filename); +#if defined(TARGET_SDL) + return FileCouldBeArtwork(basename); +#else return fileHasSuffix(basename, "wav"); +#endif } boolean FileIsMusic(char *filename) { char *basename = getBaseNamePtr(filename); +#if defined(TARGET_SDL) + return FileCouldBeArtwork(basename); +#else if (FileIsSound(basename)) return TRUE; +#if 0 #if defined(TARGET_SDL) - if (fileHasPrefix(basename, "mod") || + if ((fileHasPrefix(basename, "mod") && !fileHasSuffix(basename, "txt")) || fileHasSuffix(basename, "mod") || fileHasSuffix(basename, "s3m") || fileHasSuffix(basename, "it") || @@ -1841,9 +2550,11 @@ boolean FileIsMusic(char *filename) fileHasSuffix(basename, "mp3") || fileHasSuffix(basename, "ogg")) return TRUE; +#endif #endif return FALSE; +#endif } boolean FileIsArtworkType(char *basename, int type) @@ -1969,6 +2680,20 @@ int get_parameter_value(char *value_raw, char *suffix, int type) if (string_has_parameter(value, "static_panel")) result |= ANIM_STATIC_PANEL; } + else if (strEqual(suffix, ".class")) + { + result = get_hash_from_key(value); + } + else if (strEqual(suffix, ".style")) + { + result = STYLE_DEFAULT; + + if (string_has_parameter(value, "accurate_borders")) + result |= STYLE_ACCURATE_BORDERS; + + if (string_has_parameter(value, "inner_corners")) + result |= STYLE_INNER_CORNERS; + } else if (strEqual(suffix, ".fade_mode")) { result = (string_has_parameter(value, "none") ? FADE_MODE_NONE : @@ -2087,10 +2812,13 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, } list_pos = 0; + for (i = 0; config_list[i].token != NULL; i++) { int len_config_token = strlen(config_list[i].token); +#if 0 int len_config_value = strlen(config_list[i].value); +#endif boolean is_file_entry = TRUE; for (j = 0; suffix_list[j].token != NULL; j++) @@ -2105,6 +2833,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, config_list[i].value); is_file_entry = FALSE; + break; } } @@ -2122,6 +2851,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, if (list_pos >= num_file_list_entries) break; +#if 0 /* simple sanity check if this is really a file definition */ if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") && !strEqual(&config_list[i].value[len_config_value - 4], ".wav") && @@ -2131,6 +2861,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, config_list[i].token, config_list[i].value); Error(ERR_EXIT, "This seems to be no valid definition -- please fix"); } +#endif file_list[list_pos].token = config_list[i].token; file_list[list_pos].default_filename = config_list[i].value; @@ -2921,6 +3652,7 @@ static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info, if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME)) { deleteArtworkListEntry(artwork_info, listnode); + return; } @@ -2936,6 +3668,8 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info) artwork_info->num_dynamic_file_list_entries; int i; + print_timestamp_init("ReloadCustomArtworkList"); + for (i = 0; i < num_file_list_entries; i++) LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i], &file_list[i]); @@ -2944,6 +3678,8 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info) LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i], &dynamic_file_list[i]); + print_timestamp_done("ReloadCustomArtworkList"); + #if 0 dumpList(artwork_info->content_list); #endif @@ -2995,8 +3731,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() @@ -3037,8 +3777,11 @@ void NotifyUserAboutErrorFile() #if DEBUG -#define DEBUG_NUM_TIMESTAMPS 5 -#define DEBUG_TIME_IN_MICROSECONDS 0 +#define DEBUG_PRINT_INIT_TIMESTAMPS FALSE +#define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 10 + +#define DEBUG_NUM_TIMESTAMPS 10 +#define DEBUG_TIME_IN_MICROSECONDS 0 #if DEBUG_TIME_IN_MICROSECONDS static double Counter_Microseconds() @@ -3092,7 +3835,7 @@ void debug_print_timestamp(int counter_nr, char *message) counter[counter_nr][0] = Counter_Microseconds(); #else - static long counter[DEBUG_NUM_TIMESTAMPS][2]; + static int counter[DEBUG_NUM_TIMESTAMPS][2]; char *unit = "s"; counter[counter_nr][0] = Counter(); @@ -3102,7 +3845,11 @@ void debug_print_timestamp(int counter_nr, char *message) counter[counter_nr][1] = counter[counter_nr][0]; if (message) +#if 1 + Error(ERR_DEBUG, "%s%s%s %.3f %s", +#else printf("%s%s%s %.3f %s\n", +#endif debug_print_timestamp_get_padding(counter_nr * indent_size), message, debug_print_timestamp_get_padding(padding_size - strlen(message)), @@ -3126,4 +3873,69 @@ void debug_print_parent_only(char *format, ...) printf("\n"); } } + +#endif /* DEBUG */ + +void print_timestamp_ext(char *message, char *mode) +{ +#if DEBUG_PRINT_INIT_TIMESTAMPS + static char *debug_message = NULL; + static char *last_message = NULL; + static int counter_nr = 0; + int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH; + + checked_free(debug_message); + debug_message = getStringCat3(mode, " ", message); + + if (strEqual(mode, "INIT")) + { + debug_print_timestamp(counter_nr, NULL); + + if (counter_nr + 1 < max_depth) + debug_print_timestamp(counter_nr, debug_message); + + counter_nr++; + + debug_print_timestamp(counter_nr, NULL); + } + else if (strEqual(mode, "DONE")) + { + counter_nr--; + + if (counter_nr + 1 < max_depth || + (counter_nr == 0 && max_depth == 1)) + { + last_message = message; + + if (counter_nr == 0 && max_depth == 1) + { + checked_free(debug_message); + debug_message = getStringCat3("TIME", " ", message); + } + + debug_print_timestamp(counter_nr, debug_message); + } + } + else if (!strEqual(mode, "TIME") || + !strEqual(message, last_message)) + { + if (counter_nr < max_depth) + debug_print_timestamp(counter_nr, debug_message); + } #endif +} + +void print_timestamp_init(char *message) +{ + print_timestamp_ext(message, "INIT"); +} + +void print_timestamp_time(char *message) +{ + print_timestamp_ext(message, "TIME"); +} + +void print_timestamp_done(char *message) +{ + print_timestamp_ext(message, "DONE"); +}