#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "platform.h"
/* 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)
/* ------------------------------------------------------------------------- */
#if defined(PLATFORM_MSDOS)
-volatile unsigned long counter = 0;
+volatile unsigned int counter = 0;
void 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()
+{
+ 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 long base_ms = 0;
- unsigned long current_ms;
- unsigned long counter_ms;
+ 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();
#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);
#endif /* PLATFORM_UNIX */
#endif /* !TARGET_SDL */
+#endif
+
void InitCounter() /* set counter back to zero */
{
#if !defined(PLATFORM_MSDOS)
#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);
#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);
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)
}
}
-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)
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)
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)
{
/* 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)
{
-#if defined(TARGET_SDL)
- seed = (long)SDL_GetTicks();
-#else
+ /* default random seed */
+ seed = (int)time(NULL); // seconds since the epoch
+
+#if !defined(PLATFORM_WIN32)
+ /* add some more randomness */
struct timeval current_time;
gettimeofday(¤t_time, NULL);
- seed = (long)current_time.tv_usec;
+
+ seed += (int)current_time.tv_usec; // microseconds since the epoch
+#endif
+
+#if defined(TARGET_SDL)
+ /* add some more randomness */
+ seed += (int)SDL_GetTicks(); // milliseconds since SDL init
+#endif
+
+#if 1
+ /* add some more randomness */
+ seed += GetSimpleRandom(1000000);
#endif
}
/* 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);
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 */
else
real_name = ANONYMOUS_NAME;
}
-#elif defined(PLATFORM_UNIX)
+#elif defined(PLATFORM_UNIX) && !defined(PLATFORM_ANDROID)
if (real_name == NULL)
{
struct passwd *pwd;
return real_name;
}
+time_t getFileTimestampEpochSeconds(char *filename)
+{
+ struct stat file_status;
+
+ if (stat(filename, &file_status) != 0) /* cannot stat file */
+ return 0;
+
+ return file_status.st_mtime;
+}
+
/* ------------------------------------------------------------------------- */
/* path manipulation functions */
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 */
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);
}
strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0);
}
+boolean strPrefixLower(char *s, char *prefix)
+{
+ char *s_lower = getStringToLower(s);
+ boolean match = strPrefix(s_lower, prefix);
+
+ free(s_lower);
+
+ return match;
+}
+
+boolean strSuffixLower(char *s, char *suffix)
+{
+ char *s_lower = getStringToLower(s);
+ boolean match = strSuffix(s_lower, suffix);
+
+ free(s_lower);
+
+ return match;
+}
+
/* ------------------------------------------------------------------------- */
/* command line option handling functions */
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
ro_base_path = program.command_basepath;
if (strEqual(rw_base_path, "."))
rw_base_path = program.command_basepath;
+#endif
+
#endif
/* initialize global program options */
options.display_name = NULL;
options.server_host = NULL;
options.server_port = 0;
+
options.ro_base_directory = ro_base_path;
options.rw_base_directory = rw_base_path;
options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY);
options.sounds_directory = getPath2(ro_base_path, SOUNDS_DIRECTORY);
options.music_directory = getPath2(ro_base_path, MUSIC_DIRECTORY);
options.docs_directory = getPath2(ro_base_path, DOCS_DIRECTORY);
+
options.execute_command = NULL;
+ options.special_flags = NULL;
+
options.serveronly = FALSE;
options.network = FALSE;
options.verbose = FALSE;
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)
if (strEqual(option, "--")) /* stop scanning arguments */
break;
- if (strncmp(option, "--", 2) == 0) /* treat '--' like '-' */
+ if (strPrefix(option, "--")) /* treat '--' like '-' */
option++;
option_arg = strchr(option, '=');
{
options.debug = TRUE;
}
+ else if (strncmp(option, "-debug-x11-sync", option_len) == 0)
+ {
+ options.debug_x11_sync = TRUE;
+ }
+ else if (strPrefix(option, "-D"))
+ {
+#if 1
+ options.special_flags = getStringCopy(&option[2]);
+#else
+ char *flags_string = &option[2];
+ unsigned int flags_value;
+
+ if (*flags_string == '\0')
+ Error(ERR_EXIT_HELP, "empty flag ignored");
+
+ flags_value = get_special_flags_function(flags_string);
+
+ if (flags_value == 0)
+ Error(ERR_EXIT_HELP, "unknown flag '%s'", flags_string);
+
+ options.special_flags |= flags_value;
+#endif
+ }
else if (strncmp(option, "-execute", option_len) == 0)
{
if (option_arg == NULL)
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)
{
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)
/* checked memory allocation and freeing functions */
/* ------------------------------------------------------------------------- */
-void *checked_malloc(unsigned long size)
+void *checked_malloc(unsigned int size)
{
void *ptr;
return ptr;
}
-void *checked_calloc(unsigned long size)
+void *checked_calloc(unsigned int size)
{
void *ptr;
return ptr;
}
-void *checked_realloc(void *ptr, unsigned long size)
+void *checked_realloc(void *ptr, unsigned int size)
{
ptr = realloc(ptr, size);
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 */
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)
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)
(fgetc(file) << 8));
}
+#endif
+
int putFile16BitInteger(FILE *file, int value, int byte_order)
{
if (file != NULL)
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)
(fgetc(file) << 24));
}
+#endif
+
int putFile32BitInteger(FILE *file, int value, int byte_order)
{
if (file != NULL)
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)
{
return (feof(file) || ferror(file) ? FALSE : TRUE);
}
+#endif
+
int putFileChunk(FILE *file, char *chunk_name, int chunk_size,
int byte_order)
{
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);
version_build);
}
+#endif
+
int putFileVersion(FILE *file, int version)
{
if (file != NULL)
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;
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;
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);
{ 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 */
{ 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 */
+
+ { KSYM_Menu, "XK_Menu", "menu" }, /* menu key */
+ { KSYM_Back, "XK_Back", "back" }, /* back key */
/* ASCII 0x20 to 0x40 keys (except numbers) */
{ KSYM_space, "XK_space", "space" },
{ 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", "Ä" },
{ KSYM_odiaeresis, "XK_odiaeresis", "ö" },
{ KSYM_udiaeresis, "XK_udiaeresis", "ü" },
{ KSYM_ssharp, "XK_ssharp", "sharp s" },
+#endif
/* end-of-array identifier */
{ 0, NULL, NULL }
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;
Key key = KSYM_UNDEFINED;
char *name_ptr = *x11name;
- if (strncmp(name_ptr, "XK_", 3) == 0 && strlen(name_ptr) == 4)
+ if (strPrefix(name_ptr, "XK_") && strlen(name_ptr) == 4)
{
char c = name_ptr[3];
else if (c >= '0' && c <= '9')
key = KSYM_0 + (Key)(c - '0');
}
- else if (strncmp(name_ptr, "XK_KP_", 6) == 0 && strlen(name_ptr) == 7)
+ else if (strPrefix(name_ptr, "XK_KP_") && strlen(name_ptr) == 7)
{
char c = name_ptr[6];
if (c >= '0' && c <= '9')
key = KSYM_KP_0 + (Key)(c - '0');
}
- else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
+ else if (strPrefix(name_ptr, "XK_F") && strlen(name_ptr) <= 6)
{
char c1 = name_ptr[4];
char c2 = name_ptr[5];
if (d >= 1 && d <= KSYM_NUM_FKEYS)
key = KSYM_F1 + (Key)(d - 1);
}
- else if (strncmp(name_ptr, "XK_", 3) == 0)
+ else if (strPrefix(name_ptr, "XK_"))
{
i = 0;
}
while (translate_key[++i].x11name);
}
- else if (strncmp(name_ptr, "0x", 2) == 0)
+ else if (strPrefix(name_ptr, "0x"))
{
- unsigned long value = 0;
+ unsigned int value = 0;
name_ptr += 2;
return result;
}
+int get_switch3_from_string(char *s)
+{
+ char *s_lower = getStringToLower(s);
+ int result = FALSE;
+
+ if (strEqual(s_lower, "true") ||
+ strEqual(s_lower, "yes") ||
+ strEqual(s_lower, "on") ||
+ get_integer_from_string(s) == 1)
+ result = TRUE;
+ else if (strEqual(s_lower, "auto"))
+ result = AUTO;
+
+ free(s_lower);
+
+ return result;
+}
+
/* ------------------------------------------------------------------------- */
/* functions for generic lists */
}
+/* ------------------------------------------------------------------------- */
+/* 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;
+
+#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;
+
+#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)
{
char *basename = getBaseNamePtr(filename);
+#if defined(TARGET_SDL)
+ return (!fileHasSuffix(basename, "txt") &&
+ !fileHasSuffix(basename, "conf"));
+#else
return fileHasSuffix(basename, "pcx");
+#endif
}
boolean FileIsSound(char *filename)
{
char *basename = getBaseNamePtr(filename);
+#if defined(TARGET_SDL)
+ return (!fileHasSuffix(basename, "txt") &&
+ !fileHasSuffix(basename, "conf"));
+#else
return fileHasSuffix(basename, "wav");
+#endif
}
boolean FileIsMusic(char *filename)
{
char *basename = getBaseNamePtr(filename);
+#if defined(TARGET_SDL)
+ return (!fileHasSuffix(basename, "txt") &&
+ !fileHasSuffix(basename, "conf"));
+#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") ||
fileHasSuffix(basename, "mp3") ||
fileHasSuffix(basename, "ogg"))
return TRUE;
+#endif
#endif
return FALSE;
+#endif
}
boolean FileIsArtworkType(char *basename, 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 :
}
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++)
config_list[i].value);
is_file_entry = FALSE;
+
break;
}
}
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") &&
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;
if (filename == NULL)
return;
-#if 1
+#if 0
printf("LoadArtworkConfigFromFilename '%s' ...\n", filename);
#endif
/* first look for special artwork configured in level series config */
filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type);
+#if 0
printf("::: filename_base == '%s' [%s, %s]\n", filename_base,
leveldir_current->graphics_set,
leveldir_current->graphics_path);
+#endif
if (fileExists(filename_base))
LoadArtworkConfigFromFilename(artwork_info, filename_base);
if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME))
{
deleteArtworkListEntry(artwork_info, listnode);
+
return;
}
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]);
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
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()
#if DEBUG
-#define DEBUG_NUM_TIMESTAMPS 5
-#define DEBUG_TIME_IN_MICROSECONDS 0
+#define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
+#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()
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();
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)),
printf("\n");
}
}
+
+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");
+}
+
+#endif /* DEBUG */