#include "image.h"
-/* ------------------------------------------------------------------------- */
+/* ========================================================================= */
/* some generic helper functions */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* platform independent wrappers for printf() et al. (newline aware) */
/* ------------------------------------------------------------------------- */
-void fprintf_line(FILE *stream, char *line_string, int line_length)
+static void vfprintf_newline(FILE *stream, char *format, va_list ap)
+{
+ char *newline = STRING_NEWLINE;
+
+ vfprintf(stream, format, ap);
+
+ fprintf(stream, "%s", newline);
+}
+
+static void fprintf_newline(FILE *stream, char *format, ...)
+{
+ if (format)
+ {
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf_newline(stream, format, ap);
+ va_end(ap);
+ }
+}
+
+void fprintf_line(FILE *stream, char *line_chars, int line_length)
{
int i;
for (i = 0; i < line_length; i++)
- fprintf(stream, "%s", line_string);
+ fprintf(stream, "%s", line_chars);
- fprintf(stream, "\n");
+ fprintf_newline(stream, "");
}
-void printf_line(char *line_string, int line_length)
+void printf_line(char *line_chars, int line_length)
{
- fprintf_line(stdout, line_string, line_length);
+ fprintf_line(stdout, line_chars, line_length);
}
-void printf_line_with_prefix(char *prefix, char *line_string, int line_length)
+void printf_line_with_prefix(char *prefix, char *line_chars, int line_length)
{
fprintf(stdout, "%s", prefix);
- fprintf_line(stdout, line_string, line_length);
+ fprintf_line(stdout, line_chars, line_length);
}
+/* ------------------------------------------------------------------------- */
+/* string functions */
+/* ------------------------------------------------------------------------- */
+
/* int2str() returns a number converted to a string;
the used memory is static, but will be overwritten by later calls,
so if you want to save the result, copy it to a private string buffer;
return real_name;
}
-char *getHomeDir()
-{
- static char *dir = NULL;
-
-#if defined(PLATFORM_WIN32)
- if (dir == NULL)
- {
- dir = checked_malloc(MAX_PATH + 1);
-
- if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir)))
- strcpy(dir, ".");
- }
-#elif defined(PLATFORM_UNIX)
- if (dir == NULL)
- {
- if ((dir = getenv("HOME")) == NULL)
- {
- struct passwd *pwd;
-
- if ((pwd = getpwuid(getuid())) != NULL)
- dir = getStringCopy(pwd->pw_dir);
- else
- dir = ".";
- }
- }
-#else
- dir = ".";
-#endif
-
- return dir;
-}
-
/* ------------------------------------------------------------------------- */
/* path manipulation functions */
static char *getLastPathSeparatorPtr(char *filename)
{
- char *last_separator = strrchr(filename, '/');
+ char *last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_UNIX);
-#if !defined(PLATFORM_UNIX)
if (last_separator == NULL) /* also try DOS/Windows variant */
- last_separator = strrchr(filename, '\\');
-#endif
+ last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_DOS);
return last_separator;
}
-static char *getBaseNamePtr(char *filename)
+char *getBaseNamePtr(char *filename)
{
char *last_separator = getLastPathSeparatorPtr(filename);
char *getPath2(char *path1, char *path2)
{
+ char *sep = STRING_PATH_SEPARATOR;
char *complete_path = checked_malloc(strlen(path1) + 1 +
strlen(path2) + 1);
- sprintf(complete_path, "%s/%s", path1, path2);
+ sprintf(complete_path, "%s%s%s", path1, sep, path2);
return complete_path;
}
char *getPath3(char *path1, char *path2, char *path3)
{
+ char *sep = STRING_PATH_SEPARATOR;
char *complete_path = checked_malloc(strlen(path1) + 1 +
strlen(path2) + 1 +
strlen(path3) + 1);
- sprintf(complete_path, "%s/%s/%s", path1, path2, path3);
+ sprintf(complete_path, "%s%s%s%s%s", path1, sep, path2, sep, path3);
return complete_path;
}
*old_value = getStringCopy(new_value);
}
+boolean strEqual(char *s1, char *s2)
+{
+ return (s1 == NULL && s2 == NULL ? TRUE :
+ s1 == NULL && s2 != NULL ? FALSE :
+ s1 != NULL && s2 == NULL ? FALSE :
+ strcmp(s1, s2) == 0);
+}
+
/* ------------------------------------------------------------------------- */
/* command line option handling functions */
in an application package directory -- do not try to use this directory
as the program data directory (Mac OS X handles this correctly anyway) */
- if (strcmp(ro_base_path, ".") == 0)
+ if (strEqual(ro_base_path, "."))
ro_base_path = program.command_basepath;
- if (strcmp(rw_base_path, ".") == 0)
+ if (strEqual(rw_base_path, "."))
rw_base_path = program.command_basepath;
#endif
strcpy(option_str, option); /* copy argument into buffer */
option = option_str;
- if (strcmp(option, "--") == 0) /* stop scanning arguments */
+ if (strEqual(option, "--")) /* stop scanning arguments */
break;
if (strncmp(option, "--", 2) == 0) /* treat '--' like '-' */
option_len = strlen(option);
- if (strcmp(option, "-") == 0)
+ if (strEqual(option, "-"))
Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
else if (strncmp(option, "-help", option_len) == 0)
{
return internal_error;
}
+#if 1
+
+void Error(int mode, char *format, ...)
+{
+ static boolean last_line_was_separator = FALSE;
+ char *process_name = "";
+
+ /* display warnings only when running in verbose mode */
+ if (mode & ERR_WARN && !options.verbose)
+ return;
+
+ if (mode == ERR_RETURN_LINE)
+ {
+ if (!last_line_was_separator)
+ fprintf_line(program.error_file, format, 79);
+
+ last_line_was_separator = TRUE;
+
+ return;
+ }
+
+ last_line_was_separator = FALSE;
+
+ if (mode & ERR_SOUND_SERVER)
+ process_name = " sound server";
+ else if (mode & ERR_NETWORK_SERVER)
+ process_name = " network server";
+ else if (mode & ERR_NETWORK_CLIENT)
+ process_name = " network client **";
+
+ if (format)
+ {
+ va_list ap;
+
+ fprintf(program.error_file, "%s%s: ", program.command_basename,
+ process_name);
+
+ if (mode & ERR_WARN)
+ fprintf(program.error_file, "warning: ");
+
+ va_start(ap, format);
+ vfprintf_newline(program.error_file, format, ap);
+ va_end(ap);
+ }
+
+ if (mode & ERR_HELP)
+ fprintf_newline(program.error_file,
+ "%s: Try option '--help' for more information.",
+ program.command_basename);
+
+ if (mode & ERR_EXIT)
+ fprintf_newline(program.error_file, "%s%s: aborting",
+ program.command_basename, process_name);
+
+ if (mode & ERR_EXIT)
+ {
+ if (mode & ERR_FROM_SERVER)
+ exit(1); /* child process: normal exit */
+ else
+ program.exit_function(1); /* main process: clean up stuff */
+ }
+}
+
+#else
+
void Error(int mode, char *format, ...)
{
static boolean last_line_was_separator = FALSE;
last_line_was_separator = FALSE;
-#if defined(PLATFORM_MSDOS)
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
newline = "\r\n";
if ((error = openErrorFile()) == NULL)
{
printf("Cannot write to error output file!%s", newline);
+
program.exit_function(1);
}
#endif
}
}
+#endif
+
/* ------------------------------------------------------------------------- */
/* checked memory allocation and freeing functions */
return (feof(file) || ferror(file) ? FALSE : TRUE);
}
-void putFileChunk(FILE *file, char *chunk_name, int chunk_size,
- int byte_order)
+int putFileChunk(FILE *file, char *chunk_name, int chunk_size,
+ int byte_order)
{
+ int num_bytes = 0;
+
/* write chunk name */
- fputs(chunk_name, file);
+ if (file != NULL)
+ fputs(chunk_name, file);
+
+ num_bytes += strlen(chunk_name);
if (chunk_size >= 0)
{
/* write chunk size */
- putFile32BitInteger(file, chunk_size, byte_order);
+ if (file != NULL)
+ putFile32BitInteger(file, chunk_size, byte_order);
+
+ num_bytes += 4;
}
+
+ return num_bytes;
}
int getFileVersion(FILE *file)
version_build);
}
-void putFileVersion(FILE *file, int version)
+int putFileVersion(FILE *file, int version)
{
- int version_major = VERSION_MAJOR(version);
- int version_minor = VERSION_MINOR(version);
- int version_patch = VERSION_PATCH(version);
- int version_build = VERSION_BUILD(version);
+ if (file != NULL)
+ {
+ int version_major = VERSION_MAJOR(version);
+ int version_minor = VERSION_MINOR(version);
+ int version_patch = VERSION_PATCH(version);
+ int version_build = VERSION_BUILD(version);
- fputc(version_major, file);
- fputc(version_minor, file);
- fputc(version_patch, file);
- fputc(version_build, file);
+ fputc(version_major, file);
+ fputc(version_minor, file);
+ fputc(version_patch, file);
+ fputc(version_build, file);
+ }
+
+ return 4;
}
void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes)
/* more ASCII keys */
{ KSYM_bracketleft, "XK_bracketleft", "[" },
- { KSYM_backslash, "XK_backslash", "backslash" },
+ { KSYM_backslash, "XK_backslash", "\\" },
{ KSYM_bracketright,"XK_bracketright", "]" },
- { KSYM_asciicircum, "XK_asciicircum", "circumflex" },
+ { KSYM_asciicircum, "XK_asciicircum", "^" },
{ KSYM_underscore, "XK_underscore", "_" },
{ KSYM_grave, "XK_grave", "grave" },
{ KSYM_quoteleft, "XK_quoteleft", "quote left" },
{ KSYM_braceleft, "XK_braceleft", "brace left" },
{ KSYM_bar, "XK_bar", "bar" },
{ KSYM_braceright, "XK_braceright", "brace right" },
- { KSYM_asciitilde, "XK_asciitilde", "ascii tilde" },
+ { KSYM_asciitilde, "XK_asciitilde", "~" },
/* special (non-ASCII) keys */
{ KSYM_Adiaeresis, "XK_Adiaeresis", "Ä" },
sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0));
else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0));
+#if 1
+ else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
+ sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+#else
else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
sprintf(name_buffer, "function F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+#endif
else if (key == KSYM_UNDEFINED)
strcpy(name_buffer, "(undefined)");
else
i = 0;
do
{
- if (strcmp(translate_key[i].name, *name) == 0)
+ if (strEqual(translate_key[i].name, *name))
{
key = translate_key[i].key;
break;
do
{
- if (strcmp(name_ptr, translate_key[i].x11name) == 0)
+ if (strEqual(name_ptr, translate_key[i].x11name))
{
key = translate_key[i].key;
break;
if (strlen(keyname) == 1)
letter = keyname[0];
- else if (strcmp(keyname, "space") == 0)
+ else if (strEqual(keyname, "space"))
letter = ' ';
- else if (strcmp(keyname, "circumflex") == 0)
+ else if (strEqual(keyname, "circumflex"))
letter = '^';
return letter;
for (i = 0; number_text[i][0] != NULL; i++)
for (j = 0; j < 3; j++)
- if (strcmp(s_lower, number_text[i][j]) == 0)
+ if (strEqual(s_lower, number_text[i][j]))
result = i;
if (result == -1)
{
- if (strcmp(s_lower, "false") == 0)
+ if (strEqual(s_lower, "false"))
result = 0;
- else if (strcmp(s_lower, "true") == 0)
+ else if (strEqual(s_lower, "true"))
result = 1;
else
result = atoi(s);
char *s_lower = getStringToLower(s);
boolean result = FALSE;
- if (strcmp(s_lower, "true") == 0 ||
- strcmp(s_lower, "yes") == 0 ||
- strcmp(s_lower, "on") == 0 ||
+ if (strEqual(s_lower, "true") ||
+ strEqual(s_lower, "yes") ||
+ strEqual(s_lower, "on") ||
get_integer_from_string(s) == 1)
result = TRUE;
if (node_first == NULL || *node_first == NULL)
return;
- if (strcmp((*node_first)->key, key) == 0)
+ if (strEqual((*node_first)->key, key))
{
free((*node_first)->key);
if (destructor_function)
if (node_first == NULL)
return NULL;
- if (strcmp(node_first->key, key) == 0)
+ if (strEqual(node_first->key, key))
return node_first;
else
return getNodeFromKey(node_first->next, key);
if (basename_length > suffix_length + 1 &&
basename_lower[basename_length - suffix_length - 1] == '.' &&
- strcmp(&basename_lower[basename_length - suffix_length], suffix) == 0)
+ strEqual(&basename_lower[basename_length - suffix_length], suffix))
return TRUE;
return FALSE;
char *value = getStringToLower(value_raw);
int result = 0; /* probably a save default value */
- if (strcmp(suffix, ".direction") == 0)
+ if (strEqual(suffix, ".direction"))
{
- result = (strcmp(value, "left") == 0 ? MV_LEFT :
- strcmp(value, "right") == 0 ? MV_RIGHT :
- strcmp(value, "up") == 0 ? MV_UP :
- strcmp(value, "down") == 0 ? MV_DOWN : MV_NONE);
+ result = (strEqual(value, "left") ? MV_LEFT :
+ strEqual(value, "right") ? MV_RIGHT :
+ strEqual(value, "up") ? MV_UP :
+ strEqual(value, "down") ? MV_DOWN : MV_NONE);
}
- else if (strcmp(suffix, ".anim_mode") == 0)
+ else if (strEqual(suffix, ".anim_mode"))
{
result = (string_has_parameter(value, "none") ? ANIM_NONE :
string_has_parameter(value, "loop") ? ANIM_LOOP :
string_has_parameter(value, "random") ? ANIM_RANDOM :
string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE :
string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE :
+ string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY :
string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
string_has_parameter(value, "vertical") ? ANIM_VERTICAL :
ANIM_DEFAULT);
if (string_has_parameter(value, "reverse"))
result |= ANIM_REVERSE;
+
+ if (string_has_parameter(value, "opaque_player"))
+ result |= ANIM_OPAQUE_PLAYER;
+
+ if (string_has_parameter(value, "static_panel"))
+ result |= ANIM_STATIC_PANEL;
}
else /* generic parameter of type integer or boolean */
{
- result = (strcmp(value, ARG_UNDEFINED) == 0 ? ARG_UNDEFINED_VALUE :
+ result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
type == TYPE_INTEGER ? get_integer_from_string(value) :
type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
ARG_UNDEFINED_VALUE);
return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
}
+struct ScreenModeInfo *get_screen_mode_from_string(char *screen_mode_string)
+{
+ static struct ScreenModeInfo screen_mode;
+ char *screen_mode_string_x = strchr(screen_mode_string, 'x');
+ char *screen_mode_string_copy;
+ char *screen_mode_string_pos_w;
+ char *screen_mode_string_pos_h;
+
+ if (screen_mode_string_x == NULL) /* invalid screen mode format */
+ return NULL;
+
+ screen_mode_string_copy = getStringCopy(screen_mode_string);
+
+ screen_mode_string_pos_w = screen_mode_string_copy;
+ screen_mode_string_pos_h = strchr(screen_mode_string_copy, 'x');
+ *screen_mode_string_pos_h++ = '\0';
+
+ screen_mode.width = atoi(screen_mode_string_pos_w);
+ screen_mode.height = atoi(screen_mode_string_pos_h);
+
+ return &screen_mode;
+}
+
+void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *screen_mode,
+ int *x, int *y)
+{
+ float aspect_ratio = (float)screen_mode->width / (float)screen_mode->height;
+ float aspect_ratio_new;
+ int i = 1;
+
+ do
+ {
+ *x = i * aspect_ratio + 0.000001;
+ *y = i;
+
+ aspect_ratio_new = (float)*x / (float)*y;
+
+ i++;
+ }
+ while (aspect_ratio_new != aspect_ratio && *y < screen_mode->height);
+}
+
static void FreeCustomArtworkList(struct ArtworkListInfo *,
struct ListNodeInfo ***, int *);
int len_suffix = strlen(suffix_list[j].token);
if (len_suffix < len_config_token &&
- strcmp(&config_list[i].token[len_config_token - len_suffix],
- suffix_list[j].token) == 0)
+ strEqual(&config_list[i].token[len_config_token - len_suffix],
+ suffix_list[j].token))
{
setString(&file_list[list_pos].default_parameter[j],
config_list[i].value);
/* the following tokens are no file definitions, but other config tokens */
for (j = 0; ignore_tokens[j] != NULL; j++)
- if (strcmp(config_list[i].token, ignore_tokens[j]) == 0)
+ if (strEqual(config_list[i].token, ignore_tokens[j]))
is_file_entry = FALSE;
if (is_file_entry)
break;
/* simple sanity check if this is really a file definition */
- if (strcmp(&config_list[i].value[len_config_value - 4], ".pcx") != 0 &&
- strcmp(&config_list[i].value[len_config_value - 4], ".wav") != 0 &&
- strcmp(config_list[i].value, UNDEFINED_FILENAME) != 0)
+ if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") &&
+ !strEqual(&config_list[i].value[len_config_value - 4], ".wav") &&
+ !strEqual(config_list[i].value, UNDEFINED_FILENAME))
{
Error(ERR_RETURN, "Configuration directive '%s' -> '%s':",
config_list[i].token, config_list[i].value);
if (filename == NULL)
return;
+#if 0
+ printf("LoadArtworkConfigFromFilename '%s' ...\n", filename);
+#endif
+
if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
return;
{
char *value = HASH_ITERATION_VALUE(itr);
- if (strcmp(value, known_token_value) != 0)
+ if (!strEqual(value, known_token_value))
setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value);
}
END_HASH_ITERATION(valid_file_hash, itr)
BEGIN_HASH_ITERATION(extra_file_hash, itr)
{
- if (strcmp(HASH_ITERATION_VALUE(itr), known_token_value) == 0)
+ if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value))
dynamic_tokens_found = TRUE;
else
unknown_tokens_found = TRUE;
{
char *value = getHashEntry(extra_file_hash, list->token);
- if (value != NULL && strcmp(value, known_token_value) == 0)
+ if (value != NULL && strEqual(value, known_token_value))
Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
}
{
char *value = getHashEntry(extra_file_hash, list->token);
- if (value != NULL && strcmp(value, known_token_value) != 0)
+ if (value != NULL && !strEqual(value, known_token_value))
Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
}
char *filename_base = UNDEFINED_FILENAME, *filename_local;
int i, j;
-#if 0
- printf("GOT CUSTOM ARTWORK CONFIG FILE '%s'\n", filename);
-#endif
-
DrawInitText("Loading artwork config:", 120, FC_GREEN);
DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW);
filename_local = getCustomArtworkConfigFilename(artwork_info->type);
- if (filename_local != NULL && strcmp(filename_base, filename_local) != 0)
+ if (filename_local != NULL && !strEqual(filename_base, filename_local))
LoadArtworkConfigFromFilename(artwork_info, filename_local);
}
basename = file_list_entry->default_filename;
/* dynamic artwork has no default filename / skip empty default artwork */
- if (basename == NULL || strcmp(basename, UNDEFINED_FILENAME) == 0)
+ if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME))
return;
file_list_entry->fallback_to_default = TRUE;
}
/* check if the old and the new artwork file are the same */
- if (*listnode && strcmp((*listnode)->source_filename, filename) == 0)
+ if (*listnode && strEqual((*listnode)->source_filename, filename))
{
/* The old and new artwork are the same (have the same filename and path).
This usually means that this artwork does not exist in this artwork set
printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
#endif
- if (strcmp(file_list_entry->filename, UNDEFINED_FILENAME) == 0)
+ if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME))
{
deleteArtworkListEntry(artwork_info, listnode);
return;
/* ------------------------------------------------------------------------- */
/* functions only needed for non-Unix (non-command-line) systems */
/* (MS-DOS only; SDL/Windows creates files "stdout.txt" and "stderr.txt") */
+/* (now also added for Windows, to create files in user data directory) */
/* ------------------------------------------------------------------------- */
-#if defined(PLATFORM_MSDOS)
-
-#define ERROR_FILENAME "stderr.txt"
+char *getErrorFilename(char *basename)
+{
+ return getPath2(getUserGameDataDir(), basename);
+}
-void initErrorFile()
+void openErrorFile()
{
- unlink(ERROR_FILENAME);
+ /* always start with reliable default values */
+ program.error_file = stderr;
+
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
+ if ((program.error_file = fopen(program.error_filename, MODE_WRITE)) == NULL)
+ fprintf_newline(stderr, "ERROR: cannot open file '%s' for writing!",
+ program.error_filename);
+#endif
}
-FILE *openErrorFile()
+void closeErrorFile()
{
- return fopen(ERROR_FILENAME, MODE_APPEND);
+ if (program.error_file != stderr) /* do not close stream 'stderr' */
+ fclose(program.error_file);
}
void dumpErrorFile()
{
- FILE *error_file = fopen(ERROR_FILENAME, MODE_READ);
+ FILE *error_file = fopen(program.error_filename, MODE_READ);
if (error_file != NULL)
{
fclose(error_file);
}
}
+
+void NotifyUserAboutErrorFile()
+{
+#if defined(PLATFORM_WIN32)
+ char *title_text = getStringCat2(program.program_title, " Error Message");
+ char *error_text = getStringCat2("The program was aborted due to an error; "
+ "for details, see the following error file:"
+ STRING_NEWLINE, program.error_filename);
+
+ MessageBox(NULL, error_text, title_text, MB_OK);
#endif
+}
/* ------------------------------------------------------------------------- */