#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 1
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
static unsigned int getCurrentMS()
{
return SDL_GetTicks();
#else
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
static unsigned int mainCounter(int mode)
{
static unsigned int base_ms = 0;
#if defined(PLATFORM_WIN32)
if (login_name == NULL)
{
- unsigned int buffer_size = MAX_USERNAME_LEN + 1;
+ unsigned long buffer_size = MAX_USERNAME_LEN + 1;
login_name = checked_malloc(buffer_size);
if (GetUserName(login_name, &buffer_size) == 0)
if (real_name == NULL)
{
static char buffer[MAX_USERNAME_LEN + 1];
- unsigned int buffer_size = MAX_USERNAME_LEN + 1;
+ unsigned long buffer_size = MAX_USERNAME_LEN + 1;
if (GetUserName(buffer, &buffer_size) != 0)
real_name = get_corrected_real_name(buffer);
else
real_name = ANONYMOUS_NAME;
}
-#elif defined(PLATFORM_UNIX)
+#elif defined(PLATFORM_UNIX) && !defined(PLATFORM_ANDROID)
if (real_name == NULL)
{
struct passwd *pwd;
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);
}
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 */
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)
{
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)
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)
{
{ 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_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 }
}
+/* ------------------------------------------------------------------------- */
+/* 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 */
/* ------------------------------------------------------------------------- */
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)
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()