/***********************************************************
* Artsoft Retro-Game Library *
*----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment *
+* (c) 1994-2006 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#include "setup.h"
#include "random.h"
#include "text.h"
+#include "image.h"
-/* ------------------------------------------------------------------------- */
+/* ========================================================================= */
/* some generic helper functions */
+/* ========================================================================= */
+
/* ------------------------------------------------------------------------- */
+/* platform independent wrappers for printf() et al. (newline aware) */
+/* ------------------------------------------------------------------------- */
+
+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_string, int line_length)
+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);
+ for (i = 0; i < line_length; i++)
+ fprintf(stream, "%s", line_chars);
+
+ fprintf_newline(stream, "");
+}
- fprintf(stream, "\n");
+void printf_line(char *line_chars, int line_length)
+{
+ fprintf_line(stdout, line_chars, line_length);
}
-void printf_line(char *line_string, int line_length)
+void printf_line_with_prefix(char *prefix, char *line_chars, int line_length)
{
- fprintf_line(stdout, line_string, line_length);
+ fprintf(stdout, "%s", prefix);
+ 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;
}
+/* something similar to "int2str()" above, but allocates its own memory
+ and has a different interface; we cannot use "itoa()", because this
+ seems to be already defined when cross-compiling to the win32 target */
+
+char *i_to_a(unsigned int i)
+{
+ static char *a = NULL;
+
+ checked_free(a);
+
+ if (i > 2147483647) /* yes, this is a kludge */
+ i = 2147483647;
+
+ a = checked_malloc(10 + 1);
+
+ sprintf(a, "%d", i);
+
+ return a;
+}
+
+
+/* calculate base-2 logarithm of argument (rounded down to integer;
+ this function returns the number of the highest bit set in argument) */
+
+int log_2(unsigned int x)
+{
+ int e = 0;
+
+ while ((1 << e) < x)
+ {
+ x -= (1 << e); /* for rounding down (rounding up: remove this line) */
+ e++;
+ }
+
+ return e;
+}
+
+
/* ------------------------------------------------------------------------- */
/* counter functions */
/* ------------------------------------------------------------------------- */
{
boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
-#if 0
-#if defined(PLATFORM_MSDOS)
- /* don't use select() to perform waiting operations under DOS
- environment; always use a busy loop for waiting instead */
- do_busy_waiting = TRUE;
-#endif
-#endif
-
if (do_busy_waiting)
{
/* we want to wait only a few ms -- if we assume that we have a
{
unsigned long actual_frame_counter = FrameCounter;
- if (actual_frame_counter < *frame_counter_var + frame_delay &&
- actual_frame_counter >= *frame_counter_var)
+ if (actual_frame_counter >= *frame_counter_var &&
+ actual_frame_counter < *frame_counter_var + frame_delay)
return FALSE;
*frame_counter_var = actual_frame_counter;
{
unsigned long actual_counter = Counter();
- if (actual_counter < *counter_var + delay &&
- actual_counter >= *counter_var)
+ if (actual_counter >= *counter_var &&
+ actual_counter < *counter_var + delay)
return FALSE;
*counter_var = actual_counter;
{
unsigned long actual_counter;
- while(1)
+ while (1)
{
actual_counter = Counter();
- if (actual_counter < *counter_var + delay &&
- actual_counter >= *counter_var)
+ if (actual_counter >= *counter_var &&
+ actual_counter < *counter_var + delay)
sleep_milliseconds((*counter_var + delay - actual_counter) / 2);
else
break;
/* random generator functions */
/* ------------------------------------------------------------------------- */
-unsigned int SimpleRND(unsigned int max)
+unsigned int init_random_number(int nr, long seed)
{
+ if (seed == NEW_RANDOMIZE)
+ {
#if defined(TARGET_SDL)
- static unsigned long root = 654321;
- unsigned long current_ms;
-
- current_ms = SDL_GetTicks();
- root = root * 4253261 + current_ms;
- return (root % max);
+ seed = (long)SDL_GetTicks();
#else
- static unsigned long root = 654321;
- struct timeval current_time;
+ struct timeval current_time;
- gettimeofday(¤t_time, NULL);
- root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
- return (root % max);
+ gettimeofday(¤t_time, NULL);
+ seed = (long)current_time.tv_usec;
#endif
-}
+ }
-#ifdef DEBUG
-static unsigned int last_RND_value = 0;
+ srandom_linux_libc(nr, (unsigned int) seed);
-unsigned int last_RND()
-{
- return last_RND_value;
+ return (unsigned int) seed;
}
-#endif
-unsigned int RND(unsigned int max)
+unsigned int get_random_number(int nr, int max)
{
-#ifdef DEBUG
- return (last_RND_value = random_linux_libc() % max);
-#else
- return (random_linux_libc() % max);
-#endif
+ return (max > 0 ? random_linux_libc(nr) % max : 0);
}
-unsigned int InitRND(long seed)
+
+/* ------------------------------------------------------------------------- */
+/* system info functions */
+/* ------------------------------------------------------------------------- */
+
+#if !defined(PLATFORM_MSDOS)
+static char *get_corrected_real_name(char *real_name)
{
-#if defined(TARGET_SDL)
- unsigned long current_ms;
+ char *real_name_new = checked_malloc(MAX_USERNAME_LEN + 1);
+ char *from_ptr = real_name;
+ char *to_ptr = real_name_new;
- if (seed == NEW_RANDOMIZE)
+ /* 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)
{
- current_ms = SDL_GetTicks();
- srandom_linux_libc((unsigned int) current_ms);
- return (unsigned int) current_ms;
- }
- else
- {
- srandom_linux_libc((unsigned int) seed);
- return (unsigned int) seed;
- }
-#else
- struct timeval current_time;
+ /* the name field read from "passwd" file may also contain additional
+ user information, separated by commas, which will be removed here */
+ if (*from_ptr == ',')
+ break;
- if (seed == NEW_RANDOMIZE)
- {
- gettimeofday(¤t_time, NULL);
- srandom_linux_libc((unsigned int) current_time.tv_usec);
- return (unsigned int) current_time.tv_usec;
- }
- else
- {
- srandom_linux_libc((unsigned int) seed);
- return (unsigned int) seed;
+ /* the user's real name may contain 'ß' characters (german sharp s),
+ which have no equivalent in upper case letters (used by our fonts) */
+ if (*from_ptr == 'ß')
+ {
+ from_ptr++;
+ *to_ptr++ = 's';
+ *to_ptr++ = 's';
+ }
+ else
+ *to_ptr++ = *from_ptr++;
}
-#endif
-}
+ *to_ptr = '\0';
-/* ------------------------------------------------------------------------- */
-/* system info functions */
-/* ------------------------------------------------------------------------- */
+ return real_name_new;
+}
+#endif
char *getLoginName()
{
-#if defined(PLATFORM_WIN32)
- return ANONYMOUS_NAME;
-#else
static char *login_name = NULL;
+#if defined(PLATFORM_WIN32)
+ if (login_name == NULL)
+ {
+ unsigned long buffer_size = MAX_USERNAME_LEN + 1;
+ login_name = checked_malloc(buffer_size);
+
+ if (GetUserName(login_name, &buffer_size) == 0)
+ strcpy(login_name, ANONYMOUS_NAME);
+ }
+#else
if (login_name == NULL)
{
struct passwd *pwd;
else
login_name = getStringCopy(pwd->pw_name);
}
+#endif
return login_name;
-#endif
}
char *getRealName()
{
-#if defined(PLATFORM_UNIX)
- struct passwd *pwd;
+ static char *real_name = NULL;
- if ((pwd = getpwuid(getuid())) == NULL || strlen(pwd->pw_gecos) == 0)
- return ANONYMOUS_NAME;
- else
+#if defined(PLATFORM_WIN32)
+ if (real_name == NULL)
{
- static char real_name[1024];
- char *from_ptr = pwd->pw_gecos, *to_ptr = real_name;
+ static char buffer[MAX_USERNAME_LEN + 1];
+ unsigned long buffer_size = MAX_USERNAME_LEN + 1;
- if (strchr(pwd->pw_gecos, 'ß') == NULL)
- return pwd->pw_gecos;
-
- /* the user's real name contains a 'ß' character (german sharp s),
- which has no equivalent in upper case letters (which our fonts use) */
- while (*from_ptr != '\0' && (long)(to_ptr - real_name) < 1024 - 2)
- {
- if (*from_ptr != 'ß')
- *to_ptr++ = *from_ptr++;
- else
- {
- from_ptr++;
- *to_ptr++ = 's';
- *to_ptr++ = 's';
- }
- }
- *to_ptr = '\0';
+ if (GetUserName(buffer, &buffer_size) != 0)
+ real_name = get_corrected_real_name(buffer);
+ else
+ real_name = ANONYMOUS_NAME;
+ }
+#elif defined(PLATFORM_UNIX)
+ if (real_name == NULL)
+ {
+ struct passwd *pwd;
- return real_name;
+ if ((pwd = getpwuid(getuid())) != NULL && strlen(pwd->pw_gecos) != 0)
+ real_name = get_corrected_real_name(pwd->pw_gecos);
+ else
+ real_name = ANONYMOUS_NAME;
}
-#else /* !PLATFORM_UNIX */
- return ANONYMOUS_NAME;
+#else
+ real_name = ANONYMOUS_NAME;
#endif
+
+ return real_name;
}
-char *getHomeDir()
+
+/* ------------------------------------------------------------------------- */
+/* path manipulation functions */
+/* ------------------------------------------------------------------------- */
+
+static char *getLastPathSeparatorPtr(char *filename)
{
-#if defined(PLATFORM_UNIX)
- static char *home_dir = NULL;
+ char *last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_UNIX);
- if (home_dir == NULL)
- {
- if ((home_dir = getenv("HOME")) == NULL)
- {
- struct passwd *pwd;
+ if (last_separator == NULL) /* also try DOS/Windows variant */
+ last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_DOS);
- if ((pwd = getpwuid(getuid())) == NULL)
- home_dir = ".";
- else
- home_dir = getStringCopy(pwd->pw_dir);
- }
- }
+ return last_separator;
+}
- return home_dir;
-#else
- return ".";
-#endif
+char *getBaseNamePtr(char *filename)
+{
+ char *last_separator = getLastPathSeparatorPtr(filename);
+
+ if (last_separator != NULL)
+ return last_separator + 1; /* separator found: strip base path */
+ else
+ return filename; /* no separator found: filename has no path */
+}
+
+char *getBaseName(char *filename)
+{
+ return getStringCopy(getBaseNamePtr(filename));
+}
+
+char *getBasePath(char *filename)
+{
+ char *basepath = getStringCopy(filename);
+ char *last_separator = getLastPathSeparatorPtr(basepath);
+
+ if (last_separator != NULL)
+ *last_separator = '\0'; /* separator found: strip basename */
+ else
+ basepath = "."; /* no separator found: use current path */
+
+ return basepath;
}
/* various string functions */
/* ------------------------------------------------------------------------- */
-char *getPath2(char *path1, char *path2)
+char *getStringCat2WithSeparator(char *s1, char *s2, char *sep)
{
- char *complete_path = checked_malloc(strlen(path1) + 1 +
- strlen(path2) + 1);
+ char *complete_string = checked_malloc(strlen(s1) + strlen(sep) +
+ strlen(s2) + 1);
+
+ sprintf(complete_string, "%s%s%s", s1, sep, s2);
- sprintf(complete_path, "%s/%s", path1, path2);
- return complete_path;
+ return complete_string;
}
-char *getPath3(char *path1, char *path2, char *path3)
+char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep)
{
- char *complete_path = checked_malloc(strlen(path1) + 1 +
- strlen(path2) + 1 +
- strlen(path3) + 1);
+ char *complete_string = checked_malloc(strlen(s1) + strlen(sep) +
+ strlen(s2) + strlen(sep) +
+ strlen(s3) + 1);
+
+ sprintf(complete_string, "%s%s%s%s%s", s1, sep, s2, sep, s3);
+
+ return complete_string;
+}
- sprintf(complete_path, "%s/%s/%s", path1, path2, path3);
- return complete_path;
+char *getStringCat2(char *s1, char *s2)
+{
+ return getStringCat2WithSeparator(s1, s2, "");
}
-static char *getStringCat2(char *s1, char *s2)
+char *getStringCat3(char *s1, char *s2, char *s3)
{
- char *complete_string = checked_malloc(strlen(s1) + strlen(s2) + 1);
+ return getStringCat3WithSeparator(s1, s2, s3, "");
+}
- sprintf(complete_string, "%s%s", s1, s2);
- return complete_string;
+char *getPath2(char *path1, char *path2)
+{
+ return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR);
+}
+
+char *getPath3(char *path1, char *path2, char *path3)
+{
+ return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR);
}
char *getStringCopy(char *s)
return NULL;
s_copy = checked_malloc(strlen(s) + 1);
-
strcpy(s_copy, s);
+
return s_copy;
}
return s_copy;
}
+void setString(char **old_value, char *new_value)
+{
+ checked_free(*old_value);
+
+ *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 */
/* ------------------------------------------------------------------------- */
-static void printUsage()
-{
- printf("\n"
- "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n"
- "\n"
- "Options:\n"
- " -d, --display HOSTNAME[:SCREEN] specify X server display\n"
- " -b, --basepath DIRECTORY alternative base DIRECTORY\n"
- " -l, --level DIRECTORY alternative level DIRECTORY\n"
- " -g, --graphics DIRECTORY alternative graphics DIRECTORY\n"
- " -s, --sounds DIRECTORY alternative sounds DIRECTORY\n"
- " -m, --music DIRECTORY alternative music DIRECTORY\n"
- " -n, --network network multiplayer game\n"
- " --serveronly only start network server\n"
- " -v, --verbose verbose mode\n"
- " --debug display debugging information\n"
- " -e, --execute COMMAND execute batch COMMAND:\n"
- "\n"
- "Valid commands for '--execute' option:\n"
- " \"print graphicsinfo.conf\" print default graphics config\n"
- " \"print soundsinfo.conf\" print default sounds config\n"
- " \"print musicinfo.conf\" print default music config\n"
- " \"dump level FILE\" dump level data from FILE\n"
- " \"dump tape FILE\" dump tape data from FILE\n"
- " \"autoplay LEVELDIR\" play level tapes for LEVELDIR\n"
- "\n",
- program.command_basename);
-}
-
-void GetOptions(char *argv[])
+void GetOptions(char *argv[], void (*print_usage_function)(void))
{
+ char *ro_base_path = RO_BASE_PATH;
+ char *rw_base_path = RW_BASE_PATH;
char **options_left = &argv[1];
+#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
+ itself and fails otherwise); on Mac OS X, the program binary is stored
+ 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 (strEqual(ro_base_path, "."))
+ ro_base_path = program.command_basepath;
+ if (strEqual(rw_base_path, "."))
+ rw_base_path = program.command_basepath;
+#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 = RO_BASE_PATH "/" LEVELS_DIRECTORY;
- options.graphics_directory = RO_BASE_PATH "/" GRAPHICS_DIRECTORY;
- options.sounds_directory = RO_BASE_PATH "/" SOUNDS_DIRECTORY;
- options.music_directory = RO_BASE_PATH "/" MUSIC_DIRECTORY;
+ options.ro_base_directory = ro_base_path;
+ options.rw_base_directory = rw_base_path;
+ options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY);
+ options.graphics_directory = getPath2(ro_base_path, GRAPHICS_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.serveronly = FALSE;
options.network = FALSE;
options.verbose = FALSE;
options.debug = FALSE;
+#if !defined(PLATFORM_UNIX)
+ if (*options_left == NULL) /* no options given -- enable verbose mode */
+ options.verbose = TRUE;
+#endif
+
while (*options_left)
{
char option_str[MAX_OPTION_LEN];
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)
{
- printUsage();
+ print_usage_function();
exit(0);
}
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
/* this should be extended to separate options for ro and rw data */
- options.ro_base_directory = option_arg;
- options.rw_base_directory = option_arg;
+ options.ro_base_directory = ro_base_path = option_arg;
+ options.rw_base_directory = rw_base_path = option_arg;
if (option_arg == next_option)
options_left++;
- /* adjust path for level directory accordingly */
- options.level_directory =
- getPath2(options.ro_base_directory, LEVELS_DIRECTORY);
+ /* adjust paths for sub-directories in base directory accordingly */
+ options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY);
+ options.graphics_directory = getPath2(ro_base_path, GRAPHICS_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);
}
else if (strncmp(option, "-levels", option_len) == 0)
{
options.execute_command = option_arg;
if (option_arg == next_option)
options_left++;
+
+ /* when doing batch processing, always enable verbose mode (warnings) */
+ options.verbose = TRUE;
}
else if (*option == '-')
{
{
static boolean last_line_was_separator = FALSE;
char *process_name = "";
- FILE *error = stderr;
- char *newline = "\n";
/* display warnings only when running in verbose mode */
if (mode & ERR_WARN && !options.verbose)
return;
- if (mode == ERR_RETURN_LINE)
+ if (mode == ERR_INFO_LINE)
{
if (!last_line_was_separator)
- fprintf_line(error, format, 79);
+ fprintf_line(program.error_file, format, 79);
last_line_was_separator = TRUE;
last_line_was_separator = FALSE;
-#if defined(PLATFORM_MSDOS)
- newline = "\r\n";
-
- if ((error = openErrorFile()) == NULL)
- {
- printf("Cannot write to error output file!%s", newline);
- program.exit_function(1);
- }
-#endif
-
if (mode & ERR_SOUND_SERVER)
process_name = " sound server";
else if (mode & ERR_NETWORK_SERVER)
{
va_list ap;
- fprintf(error, "%s%s: ", program.command_basename, process_name);
+ fprintf(program.error_file, "%s%s: ", program.command_basename,
+ process_name);
if (mode & ERR_WARN)
- fprintf(error, "warning: ");
+ fprintf(program.error_file, "warning: ");
va_start(ap, format);
- vfprintf(error, format, ap);
+ vfprintf_newline(program.error_file, format, ap);
va_end(ap);
-
- fprintf(error, "%s", newline);
}
if (mode & ERR_HELP)
- fprintf(error, "%s: Try option '--help' for more information.%s",
- program.command_basename, newline);
+ fprintf_newline(program.error_file,
+ "%s: Try option '--help' for more information.",
+ program.command_basename);
if (mode & ERR_EXIT)
- fprintf(error, "%s%s: aborting%s",
- program.command_basename, process_name, newline);
-
- if (error != stderr)
- fclose(error);
+ fprintf_newline(program.error_file, "%s%s: aborting",
+ program.command_basename, process_name);
if (mode & ERR_EXIT)
{
/* ------------------------------------------------------------------------- */
-/* memory allocation functions */
+/* checked memory allocation and freeing functions */
/* ------------------------------------------------------------------------- */
void *checked_malloc(unsigned long size)
return ptr;
}
+void checked_free(void *ptr)
+{
+ if (ptr != NULL) /* this check should be done by free() anyway */
+ free(ptr);
+}
+
/* ------------------------------------------------------------------------- */
/* various helper functions */
*y2 = help_y;
}
-short getFile16BitInteger(FILE *file, int byte_order)
+/* the "put" variants of the following file access functions check for the file
+ pointer being != NULL and return the number of bytes they have or would have
+ written; this allows for chunk writing functions to first determine the size
+ of the (not yet written) chunk, write the correct chunk size and finally
+ write the chunk itself */
+
+int getFile8BitInteger(FILE *file)
{
- if (byte_order == BYTE_ORDER_BIG_ENDIAN)
- return ((fgetc(file) << 8) |
- (fgetc(file) << 0));
- else /* BYTE_ORDER_LITTLE_ENDIAN */
- return ((fgetc(file) << 0) |
- (fgetc(file) << 8));
+ return fgetc(file);
+}
+
+int putFile8BitInteger(FILE *file, int value)
+{
+ if (file != NULL)
+ fputc(value, file);
+
+ return 1;
}
-void putFile16BitInteger(FILE *file, short value, int byte_order)
+int getFile16BitInteger(FILE *file, int byte_order)
{
if (byte_order == BYTE_ORDER_BIG_ENDIAN)
- {
- fputc((value >> 8) & 0xff, file);
- fputc((value >> 0) & 0xff, file);
- }
+ return ((fgetc(file) << 8) |
+ (fgetc(file) << 0));
else /* BYTE_ORDER_LITTLE_ENDIAN */
+ return ((fgetc(file) << 0) |
+ (fgetc(file) << 8));
+}
+
+int putFile16BitInteger(FILE *file, int value, int byte_order)
+{
+ if (file != NULL)
{
- fputc((value >> 0) & 0xff, file);
- fputc((value >> 8) & 0xff, file);
+ if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+ {
+ fputc((value >> 8) & 0xff, file);
+ fputc((value >> 0) & 0xff, file);
+ }
+ else /* BYTE_ORDER_LITTLE_ENDIAN */
+ {
+ fputc((value >> 0) & 0xff, file);
+ fputc((value >> 8) & 0xff, file);
+ }
}
+
+ return 2;
}
int getFile32BitInteger(FILE *file, int byte_order)
(fgetc(file) << 24));
}
-void putFile32BitInteger(FILE *file, int value, int byte_order)
+int putFile32BitInteger(FILE *file, int value, int byte_order)
{
- if (byte_order == BYTE_ORDER_BIG_ENDIAN)
- {
- fputc((value >> 24) & 0xff, file);
- fputc((value >> 16) & 0xff, file);
- fputc((value >> 8) & 0xff, file);
- fputc((value >> 0) & 0xff, file);
- }
- else /* BYTE_ORDER_LITTLE_ENDIAN */
+ if (file != NULL)
{
- fputc((value >> 0) & 0xff, file);
- fputc((value >> 8) & 0xff, file);
- fputc((value >> 16) & 0xff, file);
- fputc((value >> 24) & 0xff, file);
+ if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+ {
+ fputc((value >> 24) & 0xff, file);
+ fputc((value >> 16) & 0xff, file);
+ fputc((value >> 8) & 0xff, file);
+ fputc((value >> 0) & 0xff, file);
+ }
+ else /* BYTE_ORDER_LITTLE_ENDIAN */
+ {
+ fputc((value >> 0) & 0xff, file);
+ fputc((value >> 8) & 0xff, file);
+ fputc((value >> 16) & 0xff, file);
+ fputc((value >> 24) & 0xff, file);
+ }
}
+
+ return 4;
}
boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
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)
{
- int version_major, version_minor, version_patch;
+ int version_major = fgetc(file);
+ int version_minor = fgetc(file);
+ int version_patch = fgetc(file);
+ int version_build = fgetc(file);
+
+ return VERSION_IDENT(version_major, version_minor, version_patch,
+ version_build);
+}
+
+int putFileVersion(FILE *file, int 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);
+ }
+
+ return 4;
+}
- version_major = fgetc(file);
- version_minor = fgetc(file);
- version_patch = fgetc(file);
- fgetc(file); /* not used */
+void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes)
+{
+ int i;
- return VERSION_IDENT(version_major, version_minor, version_patch);
+ for(i = 0; i < bytes && !feof(file); i++)
+ buffer[i] = fgetc(file);
}
-void putFileVersion(FILE *file, int version)
+void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes)
{
- int version_major = VERSION_MAJOR(version);
- int version_minor = VERSION_MINOR(version);
- int version_patch = VERSION_PATCH(version);
+ int i;
- fputc(version_major, file);
- fputc(version_minor, file);
- fputc(version_patch, file);
- fputc(0, file); /* not used */
+ for(i = 0; i < bytes; i++)
+ fputc(buffer[i], file);
}
void ReadUnusedBytesFromFile(FILE *file, 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_degree, "XK_degree", "°" },
{ KSYM_Adiaeresis, "XK_Adiaeresis", "Ä" },
{ KSYM_Odiaeresis, "XK_Odiaeresis", "Ö" },
{ KSYM_Udiaeresis, "XK_Udiaeresis", "Ü" },
else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0));
else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
- sprintf(name_buffer, "function F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+ sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1));
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;
char c = name_ptr[6];
if (c >= '0' && c <= '9')
- key = KSYM_0 + (Key)(c - '0');
+ key = KSYM_KP_0 + (Key)(c - '0');
}
else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
{
do
{
- if (strcmp(name_ptr, translate_key[i].x11name) == 0)
+ if (strEqual(name_ptr, translate_key[i].x11name))
{
key = translate_key[i].key;
break;
char getCharFromKey(Key key)
{
char *keyname = getKeyNameFromKey(key);
- char letter = 0;
+ char c = 0;
if (strlen(keyname) == 1)
- letter = keyname[0];
- else if (strcmp(keyname, "space") == 0)
- letter = ' ';
- else if (strcmp(keyname, "circumflex") == 0)
- letter = '^';
+ c = keyname[0];
+ else if (strEqual(keyname, "space"))
+ c = ' ';
+
+ return c;
+}
+
+char getValidConfigValueChar(char c)
+{
+ if (c == '#' || /* used to mark comments */
+ c == '\\') /* used to mark continued lines */
+ c = 0;
- return letter;
+ return c;
}
{
static char *number_text[][3] =
{
- { "0", "zero", "null", },
- { "1", "one", "first" },
- { "2", "two", "second" },
- { "3", "three", "third" },
- { "4", "four", "fourth" },
- { "5", "five", "fifth" },
- { "6", "six", "sixth" },
- { "7", "seven", "seventh" },
- { "8", "eight", "eighth" },
- { "9", "nine", "ninth" },
- { "10", "ten", "tenth" },
- { "11", "eleven", "eleventh" },
- { "12", "twelve", "twelfth" },
+ { "0", "zero", "null", },
+ { "1", "one", "first" },
+ { "2", "two", "second" },
+ { "3", "three", "third" },
+ { "4", "four", "fourth" },
+ { "5", "five", "fifth" },
+ { "6", "six", "sixth" },
+ { "7", "seven", "seventh" },
+ { "8", "eight", "eighth" },
+ { "9", "nine", "ninth" },
+ { "10", "ten", "tenth" },
+ { "11", "eleven", "eleventh" },
+ { "12", "twelve", "twelfth" },
+
+ { NULL, NULL, NULL },
};
int i, j;
char *s_lower = getStringToLower(s);
int result = -1;
- for (i=0; i<13; i++)
- for (j=0; j<3; j++)
- if (strcmp(s_lower, number_text[i][j]) == 0)
+ for (i = 0; number_text[i][0] != NULL; i++)
+ for (j = 0; j < 3; j++)
+ if (strEqual(s_lower, number_text[i][j]))
result = i;
if (result == -1)
- result = atoi(s);
+ {
+ if (strEqual(s_lower, "false"))
+ result = 0;
+ else if (strEqual(s_lower, "true"))
+ result = 1;
+ else
+ result = atoi(s);
+ }
free(s_lower);
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;
{
ListNode *node_new = newListNode();
-#if 0
- printf("LIST: adding node with key '%s'\n", key);
-#endif
-
node_new->key = getStringCopy(key);
node_new->content = content;
node_new->next = *node_first;
if (node_first == NULL || *node_first == NULL)
return;
-#if 0
- printf("[CHECKING LIST KEY '%s' == '%s']\n",
- (*node_first)->key, key);
-#endif
-
- if (strcmp((*node_first)->key, key) == 0)
+ if (strEqual((*node_first)->key, key))
{
-#if 0
- printf("[DELETING LIST ENTRY]\n");
-#endif
-
- free((*node_first)->key);
+ checked_free((*node_first)->key);
if (destructor_function)
destructor_function((*node_first)->content);
*node_first = (*node_first)->next;
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);
/* ------------------------------------------------------------------------- */
-/* functions for checking filenames */
+/* functions for checking files and filenames */
/* ------------------------------------------------------------------------- */
-boolean FileIsGraphic(char *filename)
+boolean fileExists(char *filename)
{
- if (strlen(filename) > 4 &&
- strcmp(&filename[strlen(filename) - 4], ".pcx") == 0)
- return TRUE;
+ if (filename == NULL)
+ return FALSE;
- return FALSE;
+ return (access(filename, F_OK) == 0);
}
-boolean FileIsSound(char *basename)
+boolean fileHasPrefix(char *basename, char *prefix)
{
- if (strlen(basename) > 4 &&
- strcmp(&basename[strlen(basename) - 4], ".wav") == 0)
- return TRUE;
+ static char *basename_lower = NULL;
+ int basename_length, prefix_length;
- return FALSE;
+ checked_free(basename_lower);
+
+ if (basename == NULL || prefix == NULL)
+ return FALSE;
+
+ basename_lower = getStringToLower(basename);
+ basename_length = strlen(basename_lower);
+ prefix_length = strlen(prefix);
+
+ if (basename_length > prefix_length + 1 &&
+ basename_lower[prefix_length] == '.' &&
+ strncmp(basename_lower, prefix, prefix_length) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+boolean fileHasSuffix(char *basename, char *suffix)
+{
+ static char *basename_lower = NULL;
+ int basename_length, suffix_length;
+
+ checked_free(basename_lower);
+
+ if (basename == NULL || suffix == NULL)
+ return FALSE;
+
+ basename_lower = getStringToLower(basename);
+ basename_length = strlen(basename_lower);
+ suffix_length = strlen(suffix);
+
+ if (basename_length > suffix_length + 1 &&
+ basename_lower[basename_length - suffix_length - 1] == '.' &&
+ strEqual(&basename_lower[basename_length - suffix_length], suffix))
+ return TRUE;
+
+ return FALSE;
}
-boolean FileIsMusic(char *basename)
+boolean FileIsGraphic(char *filename)
{
- /* "music" can be a WAV (loop) file or (if compiled with SDL) a MOD file */
+ char *basename = getBaseNamePtr(filename);
+
+ return fileHasSuffix(basename, "pcx");
+}
+
+boolean FileIsSound(char *filename)
+{
+ char *basename = getBaseNamePtr(filename);
+
+ return fileHasSuffix(basename, "wav");
+}
+
+boolean FileIsMusic(char *filename)
+{
+ char *basename = getBaseNamePtr(filename);
if (FileIsSound(basename))
return TRUE;
#if defined(TARGET_SDL)
- if (strlen(basename) > 4 &&
- (strcmp(&basename[strlen(basename) - 4], ".mod") == 0 ||
- strcmp(&basename[strlen(basename) - 4], ".MOD") == 0 ||
- strncmp(basename, "mod.", 4) == 0 ||
- strncmp(basename, "MOD.", 4) == 0))
+ if (fileHasPrefix(basename, "mod") ||
+ fileHasSuffix(basename, "mod") ||
+ fileHasSuffix(basename, "s3m") ||
+ fileHasSuffix(basename, "it") ||
+ fileHasSuffix(basename, "xm") ||
+ fileHasSuffix(basename, "midi") ||
+ fileHasSuffix(basename, "mid") ||
+ fileHasSuffix(basename, "mp3") ||
+ fileHasSuffix(basename, "ogg"))
return TRUE;
#endif
/* functions for loading artwork configuration information */
/* ------------------------------------------------------------------------- */
-static void FreeCustomArtworkList(struct ArtworkListInfo *,
- struct ListNodeInfo ***, int *);
+char *get_mapped_token(char *token)
+{
+ /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */
+ static char *map_token_prefix[][2] =
+ {
+ { "char_procent", "char_percent" },
+ { NULL, }
+ };
+ int i;
+
+ for (i = 0; map_token_prefix[i][0] != NULL; i++)
+ {
+ int len_token_prefix = strlen(map_token_prefix[i][0]);
+
+ if (strncmp(token, map_token_prefix[i][0], len_token_prefix) == 0)
+ return getStringCat2(map_token_prefix[i][1], &token[len_token_prefix]);
+ }
+
+ return NULL;
+}
+
+/* This function checks if a string <s> of the format "string1, string2, ..."
+ exactly contains a string <s_contained>. */
+
+static boolean string_has_parameter(char *s, char *s_contained)
+{
+ char *substring;
+
+ if (s == NULL || s_contained == NULL)
+ return FALSE;
+
+ if (strlen(s_contained) > strlen(s))
+ return FALSE;
+
+ if (strncmp(s, s_contained, strlen(s_contained)) == 0)
+ {
+ char next_char = s[strlen(s_contained)];
+
+ /* check if next character is delimiter or whitespace */
+ return (next_char == ',' || next_char == '\0' ||
+ next_char == ' ' || next_char == '\t' ? TRUE : FALSE);
+ }
+
+ /* check if string contains another parameter string after a comma */
+ substring = strchr(s, ',');
+ if (substring == NULL) /* string does not contain a comma */
+ return FALSE;
+
+ /* advance string pointer to next character after the comma */
+ substring++;
+
+ /* skip potential whitespaces after the comma */
+ while (*substring == ' ' || *substring == '\t')
+ substring++;
-static int get_parameter_value(int type, char *value)
+ return string_has_parameter(substring, s_contained);
+}
+
+int get_parameter_value(char *value_raw, char *suffix, int type)
{
- return (strcmp(value, ARG_UNDEFINED) == 0 ? ARG_UNDEFINED_VALUE :
- type == TYPE_INTEGER ? get_integer_from_string(value) :
- type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
- -1);
+ char *value = getStringToLower(value_raw);
+ int result = 0; /* probably a save default value */
+
+ if (strEqual(suffix, ".direction"))
+ {
+ 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 (strEqual(suffix, ".align"))
+ {
+ result = (strEqual(value, "left") ? ALIGN_LEFT :
+ strEqual(value, "right") ? ALIGN_RIGHT :
+ strEqual(value, "center") ? ALIGN_CENTER : ALIGN_DEFAULT);
+ }
+ 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, "linear") ? ANIM_LINEAR :
+ string_has_parameter(value, "pingpong") ? ANIM_PINGPONG :
+ string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 :
+ 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 :
+ string_has_parameter(value, "centered") ? ANIM_CENTERED :
+ string_has_parameter(value, "fade") ? ANIM_FADE :
+ string_has_parameter(value, "crossfade") ? ANIM_CROSSFADE :
+ 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 = (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);
+ }
+
+ free(value);
+
+ return result;
}
+int get_auto_parameter_value(char *token, char *value_raw)
+{
+ char *suffix;
+
+ if (token == NULL || value_raw == NULL)
+ return ARG_UNDEFINED_VALUE;
+
+ suffix = strrchr(token, '.');
+ if (suffix == NULL)
+ suffix = token;
+
+ 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 *);
+
struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
- struct ConfigInfo *suffix_list,
+ struct ConfigTypeInfo *suffix_list,
+ char **ignore_tokens,
int num_file_list_entries)
{
struct FileInfo *file_list;
int num_file_list_entries_found = 0;
int num_suffix_list_entries = 0;
- int list_pos = 0;
+ int list_pos;
int i, j;
file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo));
- for (i=0; suffix_list[i].token != NULL; i++)
+ for (i = 0; suffix_list[i].token != NULL; i++)
num_suffix_list_entries++;
/* always start with reliable default values */
- for (i=0; i<num_file_list_entries; i++)
+ for (i = 0; i < num_file_list_entries; i++)
{
file_list[i].token = NULL;
+
file_list[i].default_filename = NULL;
file_list[i].filename = NULL;
if (num_suffix_list_entries > 0)
{
- int parameter_array_size = num_suffix_list_entries * sizeof(int);
+ int parameter_array_size = num_suffix_list_entries * sizeof(char *);
file_list[i].default_parameter = checked_calloc(parameter_array_size);
file_list[i].parameter = checked_calloc(parameter_array_size);
- for (j=0; j<num_suffix_list_entries; j++)
+ for (j = 0; j < num_suffix_list_entries; j++)
{
- int default_parameter =
- get_parameter_value(suffix_list[j].type, suffix_list[j].value);
-
- file_list[i].default_parameter[j] = default_parameter;
- file_list[i].parameter[j] = default_parameter;
+ setString(&file_list[i].default_parameter[j], suffix_list[j].value);
+ setString(&file_list[i].parameter[j], suffix_list[j].value);
}
+
+ file_list[i].redefined = FALSE;
+ file_list[i].fallback_to_default = FALSE;
}
}
- for (i=0; config_list[i].token != NULL; i++)
+ list_pos = 0;
+ for (i = 0; config_list[i].token != NULL; i++)
{
int len_config_token = strlen(config_list[i].token);
int len_config_value = strlen(config_list[i].value);
boolean is_file_entry = TRUE;
- for (j=0; suffix_list[j].token != NULL; j++)
+ for (j = 0; suffix_list[j].token != NULL; j++)
{
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))
{
- file_list[list_pos].default_parameter[j] =
- get_parameter_value(suffix_list[j].type, config_list[i].value);
+ setString(&file_list[list_pos].default_parameter[j],
+ config_list[i].value);
is_file_entry = FALSE;
break;
}
}
+ /* the following tokens are no file definitions, but other config tokens */
+ for (j = 0; ignore_tokens[j] != NULL; j++)
+ if (strEqual(config_list[i].token, ignore_tokens[j]))
+ is_file_entry = FALSE;
+
if (is_file_entry)
{
if (i > 0)
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':",
+ Error(ERR_INFO, "Configuration directive '%s' -> '%s':",
config_list[i].token, config_list[i].value);
Error(ERR_EXIT, "This seems to be no valid definition -- please fix");
}
file_list[list_pos].token = config_list[i].token;
file_list[list_pos].default_filename = config_list[i].value;
+
+#if 0
+ printf("::: '%s' => '%s'\n", config_list[i].token, config_list[i].value);
+#endif
}
}
num_file_list_entries_found = list_pos + 1;
if (num_file_list_entries_found != num_file_list_entries)
{
- Error(ERR_RETURN_LINE, "-");
- Error(ERR_RETURN, "inconsistant config list information:");
- Error(ERR_RETURN, "- should be: %d (according to 'src/conf_gfx.h')",
+ Error(ERR_INFO_LINE, "-");
+ Error(ERR_INFO, "inconsistant config list information:");
+ Error(ERR_INFO, "- should be: %d (according to 'src/conf_xxx.h')",
num_file_list_entries);
- Error(ERR_RETURN, "- found to be: %d (according to 'src/conf_gfx.c')",
+ Error(ERR_INFO, "- found to be: %d (according to 'src/conf_xxx.c')",
num_file_list_entries_found);
Error(ERR_EXIT, "please fix");
}
+#if 0
+ printf("::: ---------- DONE ----------\n");
+#endif
+
return file_list;
}
int len_token = strlen(token);
int len_suffix = strlen(suffix);
-#if 0
- if (IS_PARENT_PROCESS(audio.mixer_pid))
- printf(":::::::::: check '%s' for '%s' ::::::::::\n", token, suffix);
-#endif
-
if (start_pos < 0) /* compare suffix from end of string */
start_pos += len_token;
return FALSE;
}
-#define KNOWN_TOKEN_VALUE "[KNOWN_TOKEN]"
+#define KNOWN_TOKEN_VALUE "[KNOWN_TOKEN_VALUE]"
-static void read_token_parameters(struct SetupFileList *setup_file_list,
- struct ConfigInfo *suffix_list,
+static void read_token_parameters(SetupFileHash *setup_file_hash,
+ struct ConfigTypeInfo *suffix_list,
struct FileInfo *file_list_entry)
{
/* check for config token that is the base token without any suffixes */
- char *filename = getTokenValue(setup_file_list, file_list_entry->token);
+ char *filename = getHashEntry(setup_file_hash, file_list_entry->token);
char *known_token_value = KNOWN_TOKEN_VALUE;
int i;
if (filename != NULL)
{
+ setString(&file_list_entry->filename, filename);
+
/* when file definition found, set all parameters to default values */
- for (i=0; suffix_list[i].token != NULL; i++)
- file_list_entry->parameter[i] =
- get_parameter_value(suffix_list[i].type, suffix_list[i].value);
+ for (i = 0; suffix_list[i].token != NULL; i++)
+ setString(&file_list_entry->parameter[i], suffix_list[i].value);
- file_list_entry->filename = getStringCopy(filename);
+ file_list_entry->redefined = TRUE;
/* mark config file token as well known from default config */
- setTokenValue(setup_file_list, file_list_entry->token, known_token_value);
+ setHashEntry(setup_file_hash, file_list_entry->token, known_token_value);
}
- else
- file_list_entry->filename =
- getStringCopy(file_list_entry->default_filename);
/* check for config tokens that can be build by base token and suffixes */
- for (i=0; suffix_list[i].token != NULL; i++)
+ for (i = 0; suffix_list[i].token != NULL; i++)
{
char *token = getStringCat2(file_list_entry->token, suffix_list[i].token);
- char *value = getTokenValue(setup_file_list, token);
+ char *value = getHashEntry(setup_file_hash, token);
if (value != NULL)
{
- file_list_entry->parameter[i] =
- get_parameter_value(suffix_list[i].type, value);
+ setString(&file_list_entry->parameter[i], value);
/* mark config file token as well known from default config */
- setTokenValue(setup_file_list, token, known_token_value);
+ setHashEntry(setup_file_hash, token, known_token_value);
}
free(token);
static void add_dynamic_file_list_entry(struct FileInfo **list,
int *num_list_entries,
- struct SetupFileList *extra_file_list,
- struct ConfigInfo *suffix_list,
+ SetupFileHash *extra_file_hash,
+ struct ConfigTypeInfo *suffix_list,
int num_suffix_list_entries,
char *token)
{
struct FileInfo *new_list_entry;
- int parameter_array_size = num_suffix_list_entries * sizeof(int);
-
-#if 0
- if (IS_PARENT_PROCESS(audio.mixer_pid))
- printf("===> found dynamic definition '%s'\n", token);
-#endif
+ int parameter_array_size = num_suffix_list_entries * sizeof(char *);
(*num_list_entries)++;
*list = checked_realloc(*list, *num_list_entries * sizeof(struct FileInfo));
new_list_entry = &(*list)[*num_list_entries - 1];
new_list_entry->token = getStringCopy(token);
+ new_list_entry->default_filename = NULL;
+ new_list_entry->filename = NULL;
new_list_entry->parameter = checked_calloc(parameter_array_size);
- read_token_parameters(extra_file_list, suffix_list, new_list_entry);
+ new_list_entry->redefined = FALSE;
+ new_list_entry->fallback_to_default = FALSE;
+
+ read_token_parameters(extra_file_hash, suffix_list, new_list_entry);
}
-void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
+static void add_property_mapping(struct PropertyMapping **list,
+ int *num_list_entries,
+ int base_index, int ext1_index,
+ int ext2_index, int ext3_index,
+ int artwork_index)
+{
+ struct PropertyMapping *new_list_entry;
+
+ (*num_list_entries)++;
+ *list = checked_realloc(*list,
+ *num_list_entries * sizeof(struct PropertyMapping));
+ new_list_entry = &(*list)[*num_list_entries - 1];
+
+ new_list_entry->base_index = base_index;
+ new_list_entry->ext1_index = ext1_index;
+ new_list_entry->ext2_index = ext2_index;
+ new_list_entry->ext3_index = ext3_index;
+
+ new_list_entry->artwork_index = artwork_index;
+}
+
+static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
+ char *filename)
{
struct FileInfo *file_list = artwork_info->file_list;
- struct ConfigInfo *suffix_list = artwork_info->suffix_list;
+ struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list;
char **base_prefixes = artwork_info->base_prefixes;
char **ext1_suffixes = artwork_info->ext1_suffixes;
char **ext2_suffixes = artwork_info->ext2_suffixes;
+ char **ext3_suffixes = artwork_info->ext3_suffixes;
+ char **ignore_tokens = artwork_info->ignore_tokens;
int num_file_list_entries = artwork_info->num_file_list_entries;
int num_suffix_list_entries = artwork_info->num_suffix_list_entries;
int num_base_prefixes = artwork_info->num_base_prefixes;
int num_ext1_suffixes = artwork_info->num_ext1_suffixes;
int num_ext2_suffixes = artwork_info->num_ext2_suffixes;
- char *filename = getCustomArtworkConfigFilename(artwork_info->type);
- struct SetupFileList *setup_file_list;
- struct SetupFileList *extra_file_list = NULL;
- struct SetupFileList *list;
+ int num_ext3_suffixes = artwork_info->num_ext3_suffixes;
+ int num_ignore_tokens = artwork_info->num_ignore_tokens;
+ SetupFileHash *setup_file_hash, *valid_file_hash;
+ SetupFileHash *extra_file_hash, *empty_file_hash;
char *known_token_value = KNOWN_TOKEN_VALUE;
- int i, j, k;
+ int i, j, k, l;
+
+ if (filename == NULL)
+ return;
#if 0
- printf("GOT CUSTOM ARTWORK CONFIG FILE '%s'\n", filename);
+ printf("LoadArtworkConfigFromFilename '%s' ...\n", filename);
#endif
- /* always start with reliable default values */
- for (i=0; i<num_file_list_entries; i++)
+ if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+ return;
+
+ /* separate valid (defined) from empty (undefined) config token values */
+ valid_file_hash = newSetupFileHash();
+ empty_file_hash = newSetupFileHash();
+ BEGIN_HASH_ITERATION(setup_file_hash, itr)
{
- if (file_list[i].filename != NULL)
- free(file_list[i].filename);
- file_list[i].filename = NULL;
+ char *value = HASH_ITERATION_VALUE(itr);
- for (j=0; j<num_suffix_list_entries; j++)
- file_list[i].parameter[j] = file_list[i].default_parameter[j];
+ setHashEntry(*value ? valid_file_hash : empty_file_hash,
+ HASH_ITERATION_TOKEN(itr), value);
}
+ END_HASH_ITERATION(setup_file_hash, itr)
- /* free previous dynamic artwork file array */
- if (artwork_info->dynamic_file_list != NULL)
+ /* at this point, we do not need the setup file hash anymore -- free it */
+ freeSetupFileHash(setup_file_hash);
+
+ /* map deprecated to current tokens (using prefix match and replace) */
+ BEGIN_HASH_ITERATION(valid_file_hash, itr)
{
- for (i=0; i<artwork_info->num_dynamic_file_list_entries; i++)
+ char *token = HASH_ITERATION_TOKEN(itr);
+ char *mapped_token = get_mapped_token(token);
+
+ if (mapped_token != NULL)
{
- free(artwork_info->dynamic_file_list[i].token);
- free(artwork_info->dynamic_file_list[i].filename);
- free(artwork_info->dynamic_file_list[i].parameter);
- }
+ char *value = HASH_ITERATION_VALUE(itr);
- free(artwork_info->dynamic_file_list);
+ /* add mapped token */
+ setHashEntry(valid_file_hash, mapped_token, value);
- artwork_info->dynamic_file_list = NULL;
- artwork_info->num_dynamic_file_list_entries = 0;
+ /* ignore old token (by setting it to "known" keyword) */
+ setHashEntry(valid_file_hash, token, known_token_value);
- FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
- &artwork_info->num_dynamic_file_list_entries);
+ free(mapped_token);
+ }
}
-
- if (filename == NULL)
- return;
-
- if ((setup_file_list = loadSetupFileList(filename)) == NULL)
- return;
+ END_HASH_ITERATION(valid_file_hash, itr)
/* read parameters for all known config file tokens */
- for (i=0; i<num_file_list_entries; i++)
- read_token_parameters(setup_file_list, suffix_list, &file_list[i]);
+ for (i = 0; i < num_file_list_entries; i++)
+ read_token_parameters(valid_file_hash, suffix_list, &file_list[i]);
- /* set some additional tokens to "known" */
- setTokenValue(setup_file_list, "name", known_token_value);
- setTokenValue(setup_file_list, "sort_priority", known_token_value);
+ /* set all tokens that can be ignored here to "known" keyword */
+ for (i = 0; i < num_ignore_tokens; i++)
+ setHashEntry(valid_file_hash, ignore_tokens[i], known_token_value);
- /* copy all unknown config file tokens to extra config list */
- for (list = setup_file_list; list != NULL; list = list->next)
+ /* copy all unknown config file tokens to extra config hash */
+ extra_file_hash = newSetupFileHash();
+ BEGIN_HASH_ITERATION(valid_file_hash, itr)
{
- if (strcmp(list->value, known_token_value) != 0)
- {
- if (extra_file_list == NULL)
- extra_file_list = newSetupFileList(list->token, list->value);
- else
- setTokenValue(extra_file_list, list->token, list->value);
- }
+ char *value = HASH_ITERATION_VALUE(itr);
+
+ if (!strEqual(value, known_token_value))
+ setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value);
}
+ END_HASH_ITERATION(valid_file_hash, itr)
- /* at this point, we do not need the config file list anymore -- free it */
- freeSetupFileList(setup_file_list);
+ /* at this point, we do not need the valid file hash anymore -- free it */
+ freeSetupFileHash(valid_file_hash);
/* now try to determine valid, dynamically defined config tokens */
- for (list = extra_file_list; list != NULL; list = list->next)
+ BEGIN_HASH_ITERATION(extra_file_hash, itr)
{
- struct FileInfo **dynamic_file_list = &artwork_info->dynamic_file_list;
+ struct FileInfo **dynamic_file_list =
+ &artwork_info->dynamic_file_list;
int *num_dynamic_file_list_entries =
&artwork_info->num_dynamic_file_list_entries;
- char *token = list->token;
+ struct PropertyMapping **property_mapping =
+ &artwork_info->property_mapping;
+ int *num_property_mapping_entries =
+ &artwork_info->num_property_mapping_entries;
+ int current_summarized_file_list_entry =
+ artwork_info->num_file_list_entries +
+ artwork_info->num_dynamic_file_list_entries;
+ char *token = HASH_ITERATION_TOKEN(itr);
int len_token = strlen(token);
int start_pos;
boolean base_prefix_found = FALSE;
boolean parameter_suffix_found = FALSE;
+#if 0
+ printf("::: examining '%s' -> '%s'\n", token, HASH_ITERATION_VALUE(itr));
+#endif
+
/* skip all parameter definitions (handled by read_token_parameters()) */
- for (i=0; i < num_suffix_list_entries && !parameter_suffix_found; i++)
+ for (i = 0; i < num_suffix_list_entries && !parameter_suffix_found; i++)
{
int len_suffix = strlen(suffix_list[i].token);
parameter_suffix_found = TRUE;
}
-#if 0
- if (IS_PARENT_PROCESS(audio.mixer_pid))
- {
- if (parameter_suffix_found)
- printf("---> skipping token '%s' (parameter token)\n", token);
- else
- printf("---> examining token '%s': search prefix ...\n", token);
- }
-#endif
-
if (parameter_suffix_found)
continue;
- /* ---------- step 1: search for matching base prefix ---------- */
+ /* ---------- step 0: search for matching base prefix ---------- */
start_pos = 0;
- for (i=0; i<num_base_prefixes && !base_prefix_found; i++)
+ for (i = 0; i < num_base_prefixes && !base_prefix_found; i++)
{
char *base_prefix = base_prefixes[i];
int len_base_prefix = strlen(base_prefix);
boolean ext1_suffix_found = FALSE;
+ boolean ext2_suffix_found = FALSE;
+ boolean ext3_suffix_found = FALSE;
+ boolean exact_match = FALSE;
+ int base_index = -1;
+ int ext1_index = -1;
+ int ext2_index = -1;
+ int ext3_index = -1;
base_prefix_found = token_suffix_match(token, base_prefix, start_pos);
if (!base_prefix_found)
continue;
+ base_index = i;
+
if (start_pos + len_base_prefix == len_token) /* exact match */
{
+ exact_match = TRUE;
+
add_dynamic_file_list_entry(dynamic_file_list,
num_dynamic_file_list_entries,
- extra_file_list,
+ extra_file_hash,
suffix_list,
num_suffix_list_entries,
token);
+ add_property_mapping(property_mapping,
+ num_property_mapping_entries,
+ base_index, -1, -1, -1,
+ current_summarized_file_list_entry);
continue;
}
#if 0
- if (IS_PARENT_PROCESS(audio.mixer_pid))
+ if (IS_PARENT_PROCESS())
printf("---> examining token '%s': search 1st suffix ...\n", token);
#endif
- /* ---------- step 2: search for matching first suffix ---------- */
+ /* ---------- step 1: search for matching first suffix ---------- */
start_pos += len_base_prefix;
- for (j=0; j<num_ext1_suffixes && !ext1_suffix_found; j++)
+ for (j = 0; j < num_ext1_suffixes && !ext1_suffix_found; j++)
{
char *ext1_suffix = ext1_suffixes[j];
int len_ext1_suffix = strlen(ext1_suffix);
- boolean ext2_suffix_found = FALSE;
ext1_suffix_found = token_suffix_match(token, ext1_suffix, start_pos);
if (!ext1_suffix_found)
continue;
+ ext1_index = j;
+
if (start_pos + len_ext1_suffix == len_token) /* exact match */
{
+ exact_match = TRUE;
+
add_dynamic_file_list_entry(dynamic_file_list,
num_dynamic_file_list_entries,
- extra_file_list,
+ extra_file_hash,
suffix_list,
num_suffix_list_entries,
token);
+ add_property_mapping(property_mapping,
+ num_property_mapping_entries,
+ base_index, ext1_index, -1, -1,
+ current_summarized_file_list_entry);
continue;
}
+ start_pos += len_ext1_suffix;
+ }
+
+ if (exact_match)
+ break;
+
#if 0
- if (IS_PARENT_PROCESS(audio.mixer_pid))
- printf("---> examining token '%s': search 2nd suffix ...\n", token);
+ if (IS_PARENT_PROCESS())
+ printf("---> examining token '%s': search 2nd suffix ...\n", token);
#endif
- /* ---------- step 3: search for matching second suffix ---------- */
+ /* ---------- step 2: search for matching second suffix ---------- */
- start_pos += len_ext1_suffix;
- for (k=0; k<num_ext2_suffixes && !ext2_suffix_found; k++)
+ for (k = 0; k < num_ext2_suffixes && !ext2_suffix_found; k++)
+ {
+ char *ext2_suffix = ext2_suffixes[k];
+ int len_ext2_suffix = strlen(ext2_suffix);
+
+ ext2_suffix_found = token_suffix_match(token, ext2_suffix, start_pos);
+
+ if (!ext2_suffix_found)
+ continue;
+
+ ext2_index = k;
+
+ if (start_pos + len_ext2_suffix == len_token) /* exact match */
{
- char *ext2_suffix = ext2_suffixes[k];
- int len_ext2_suffix = strlen(ext2_suffix);
-
- ext2_suffix_found = token_suffix_match(token, ext2_suffix,start_pos);
-
- if (!ext2_suffix_found)
- continue;
-
- if (start_pos + len_ext2_suffix == len_token) /* exact match */
- {
- add_dynamic_file_list_entry(dynamic_file_list,
- num_dynamic_file_list_entries,
- extra_file_list,
- suffix_list,
- num_suffix_list_entries,
- token);
- continue;
- }
+ exact_match = TRUE;
+
+ add_dynamic_file_list_entry(dynamic_file_list,
+ num_dynamic_file_list_entries,
+ extra_file_hash,
+ suffix_list,
+ num_suffix_list_entries,
+ token);
+ add_property_mapping(property_mapping,
+ num_property_mapping_entries,
+ base_index, ext1_index, ext2_index, -1,
+ current_summarized_file_list_entry);
+ continue;
+ }
+
+ start_pos += len_ext2_suffix;
+ }
+
+ if (exact_match)
+ break;
+
+#if 0
+ if (IS_PARENT_PROCESS())
+ printf("---> examining token '%s': search 3rd suffix ...\n",token);
+#endif
+
+ /* ---------- step 3: search for matching third suffix ---------- */
+
+ for (l = 0; l < num_ext3_suffixes && !ext3_suffix_found; l++)
+ {
+ char *ext3_suffix = ext3_suffixes[l];
+ int len_ext3_suffix = strlen(ext3_suffix);
+
+ ext3_suffix_found = token_suffix_match(token, ext3_suffix, start_pos);
+
+ if (!ext3_suffix_found)
+ continue;
+
+ ext3_index = l;
+
+ if (start_pos + len_ext3_suffix == len_token) /* exact match */
+ {
+ exact_match = TRUE;
+
+ add_dynamic_file_list_entry(dynamic_file_list,
+ num_dynamic_file_list_entries,
+ extra_file_hash,
+ suffix_list,
+ num_suffix_list_entries,
+ token);
+ add_property_mapping(property_mapping,
+ num_property_mapping_entries,
+ base_index, ext1_index, ext2_index, ext3_index,
+ current_summarized_file_list_entry);
+ continue;
}
}
}
}
+ END_HASH_ITERATION(extra_file_hash, itr)
if (artwork_info->num_dynamic_file_list_entries > 0)
{
artwork_info->sizeof_artwork_list_entry);
}
- if (extra_file_list != NULL &&
- options.verbose && IS_PARENT_PROCESS(audio.mixer_pid))
+ if (options.verbose && IS_PARENT_PROCESS())
{
+ SetupFileList *setup_file_list, *list;
boolean dynamic_tokens_found = FALSE;
boolean unknown_tokens_found = FALSE;
+ boolean undefined_values_found = (hashtable_count(empty_file_hash) != 0);
+
+ if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+ Error(ERR_EXIT, "loadSetupFileHash works, but loadSetupFileList fails");
- for (list = extra_file_list; list != NULL; list = list->next)
+ BEGIN_HASH_ITERATION(extra_file_hash, itr)
{
- if (strcmp(list->value, known_token_value) == 0)
+ if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value))
dynamic_tokens_found = TRUE;
else
unknown_tokens_found = TRUE;
}
+ END_HASH_ITERATION(extra_file_hash, itr)
-#if DEBUG
- if (dynamic_tokens_found)
+ if (options.debug && dynamic_tokens_found)
{
- Error(ERR_RETURN_LINE, "-");
- Error(ERR_RETURN, "dynamic token(s) found:");
+ Error(ERR_INFO_LINE, "-");
+ Error(ERR_INFO, "dynamic token(s) found in config file:");
+ Error(ERR_INFO, "- config file: '%s'", filename);
- for (list = extra_file_list; list != NULL; list = list->next)
- if (strcmp(list->value, known_token_value) == 0)
- Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
+ for (list = setup_file_list; list != NULL; list = list->next)
+ {
+ char *value = getHashEntry(extra_file_hash, list->token);
- Error(ERR_RETURN_LINE, "-");
+ if (value != NULL && strEqual(value, known_token_value))
+ Error(ERR_INFO, "- dynamic token: '%s'", list->token);
+ }
+
+ Error(ERR_INFO_LINE, "-");
}
-#endif
if (unknown_tokens_found)
{
- Error(ERR_RETURN_LINE, "-");
- Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
- Error(ERR_RETURN, "- config file: '%s'", filename);
+ Error(ERR_INFO_LINE, "-");
+ Error(ERR_INFO, "warning: unknown token(s) found in config file:");
+ Error(ERR_INFO, "- config file: '%s'", filename);
- for (list = extra_file_list; list != NULL; list = list->next)
- if (strcmp(list->value, known_token_value) != 0)
- Error(ERR_RETURN, "- unknown token: '%s'", list->token);
+ for (list = setup_file_list; list != NULL; list = list->next)
+ {
+ char *value = getHashEntry(extra_file_hash, list->token);
+
+ if (value != NULL && !strEqual(value, known_token_value))
+ Error(ERR_INFO, "- dynamic token: '%s'", list->token);
+ }
+
+ Error(ERR_INFO_LINE, "-");
+ }
+
+ if (undefined_values_found)
+ {
+ Error(ERR_INFO_LINE, "-");
+ Error(ERR_INFO, "warning: undefined values found in config file:");
+ Error(ERR_INFO, "- config file: '%s'", filename);
+
+ for (list = setup_file_list; list != NULL; list = list->next)
+ {
+ char *value = getHashEntry(empty_file_hash, list->token);
+
+ if (value != NULL)
+ Error(ERR_INFO, "- undefined value for token: '%s'", list->token);
+ }
- Error(ERR_RETURN_LINE, "-");
+ Error(ERR_INFO_LINE, "-");
}
+
+ freeSetupFileList(setup_file_list);
}
- freeSetupFileList(extra_file_list);
+ freeSetupFileHash(extra_file_hash);
+ freeSetupFileHash(empty_file_hash);
#if 0
- for (i=0; i<num_file_list_entries; i++)
+ for (i = 0; i < num_file_list_entries; i++)
{
printf("'%s' ", file_list[i].token);
if (file_list[i].filename)
#endif
}
+void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
+{
+ struct FileInfo *file_list = artwork_info->file_list;
+ int num_file_list_entries = artwork_info->num_file_list_entries;
+ int num_suffix_list_entries = artwork_info->num_suffix_list_entries;
+ char *filename_base = UNDEFINED_FILENAME, *filename_local;
+ int i, j;
+
+ DrawInitText("Loading artwork config", 120, FC_GREEN);
+ DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW);
+
+ /* always start with reliable default values */
+ for (i = 0; i < num_file_list_entries; i++)
+ {
+ setString(&file_list[i].filename, file_list[i].default_filename);
+
+ for (j = 0; j < num_suffix_list_entries; j++)
+ setString(&file_list[i].parameter[j], file_list[i].default_parameter[j]);
+
+ file_list[i].redefined = FALSE;
+ file_list[i].fallback_to_default = FALSE;
+ }
+
+ /* free previous dynamic artwork file array */
+ if (artwork_info->dynamic_file_list != NULL)
+ {
+ for (i = 0; i < artwork_info->num_dynamic_file_list_entries; i++)
+ {
+ free(artwork_info->dynamic_file_list[i].token);
+ free(artwork_info->dynamic_file_list[i].filename);
+ free(artwork_info->dynamic_file_list[i].parameter);
+ }
+
+ free(artwork_info->dynamic_file_list);
+ artwork_info->dynamic_file_list = NULL;
+
+ FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
+ &artwork_info->num_dynamic_file_list_entries);
+ }
+
+ /* free previous property mapping */
+ if (artwork_info->property_mapping != NULL)
+ {
+ free(artwork_info->property_mapping);
+
+ artwork_info->property_mapping = NULL;
+ artwork_info->num_property_mapping_entries = 0;
+ }
+
+ if (!SETUP_OVERRIDE_ARTWORK(setup, artwork_info->type))
+ {
+ /* first look for special artwork configured in level series config */
+ filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type);
+
+ if (fileExists(filename_base))
+ LoadArtworkConfigFromFilename(artwork_info, filename_base);
+ }
+
+ filename_local = getCustomArtworkConfigFilename(artwork_info->type);
+
+ if (filename_local != NULL && !strEqual(filename_base, filename_local))
+ LoadArtworkConfigFromFilename(artwork_info, filename_local);
+}
+
static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info,
struct ListNodeInfo **listnode)
{
{
char *filename = (*listnode)->source_filename;
-#if 0
- printf("[decrementing reference counter of artwork '%s']\n", filename);
-#endif
-
if (--(*listnode)->num_references <= 0)
- {
-#if 0
- printf("[deleting artwork '%s']\n", filename);
-#endif
-
deleteNodeFromList(&artwork_info->content_list, filename,
artwork_info->free_artwork);
- }
*listnode = NULL;
}
static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
struct ListNodeInfo **listnode,
- char *basename)
+ struct FileInfo *file_list_entry)
{
char *init_text[] =
- { "",
- "Loading graphics:",
- "Loading sounds:",
- "Loading music:"
+ {
+ "Loading graphics",
+ "Loading sounds",
+ "Loading music"
};
ListNode *node;
+ char *basename = file_list_entry->filename;
char *filename = getCustomArtworkFilename(basename, artwork_info->type);
if (filename == NULL)
{
- int error_mode = ERR_WARN;
+ Error(ERR_WARN, "cannot find artwork file '%s'", basename);
- /* we can get away without sounds and music, but not without graphics */
- if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS)
- error_mode = ERR_EXIT;
+ basename = file_list_entry->default_filename;
- Error(error_mode, "cannot find artwork file '%s'", basename);
- return;
+ /* dynamic artwork has no default filename / skip empty default artwork */
+ if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME))
+ return;
+
+ file_list_entry->fallback_to_default = TRUE;
+
+ Error(ERR_WARN, "trying default artwork file '%s'", basename);
+
+ filename = getCustomArtworkFilename(basename, artwork_info->type);
+
+ if (filename == NULL)
+ {
+ int error_mode = ERR_WARN;
+
+ /* we can get away without sounds and music, but not without graphics */
+ if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS)
+ error_mode = ERR_EXIT;
+
+ Error(error_mode, "cannot find default artwork file '%s'", basename);
+
+ return;
+ }
}
/* 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
static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
struct ListNodeInfo **listnode,
- char *basename)
+ struct FileInfo *file_list_entry)
{
#if 0
printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
#endif
- if (strcmp(basename, UNDEFINED_FILENAME) == 0)
+ if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME))
{
deleteArtworkListEntry(artwork_info, listnode);
return;
}
- replaceArtworkListEntry(artwork_info, listnode, basename);
-}
-
-static void LoadArtworkToList(struct ArtworkListInfo *artwork_info,
- struct ListNodeInfo **listnode,
- char *basename, int list_pos)
-{
-#if 0
- if (artwork_info->artwork_list == NULL ||
- list_pos >= artwork_info->num_file_list_entries)
- return;
-#endif
-
-#if 0
- printf("loading artwork '%s' ... [%d]\n",
- basename, getNumNodes(artwork_info->content_list));
-#endif
-
-#if 1
- LoadCustomArtwork(artwork_info, listnode, basename);
-#else
- LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[list_pos],
- basename);
-#endif
-
-#if 0
- printf("loading artwork '%s' done [%d]\n",
- basename, getNumNodes(artwork_info->content_list));
-#endif
+ replaceArtworkListEntry(artwork_info, listnode, file_list_entry);
}
void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
artwork_info->num_dynamic_file_list_entries;
int i;
-#if 0
- printf("DEBUG: reloading %d static artwork files ...\n",
- num_file_list_entries);
- printf("DEBUG: reloading %d dynamic artwork files ...\n",
- num_dynamic_file_list_entries);
-#endif
+ for (i = 0; i < num_file_list_entries; i++)
+ LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i],
+ &file_list[i]);
- for(i=0; i<num_file_list_entries; i++)
- LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
- file_list[i].filename, i);
-
- for(i=0; i<num_dynamic_file_list_entries; i++)
- LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
- dynamic_file_list[i].filename, i);
+ for (i = 0; i < num_dynamic_file_list_entries; i++)
+ LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i],
+ &dynamic_file_list[i]);
#if 0
dumpList(artwork_info->content_list);
if (*list == NULL)
return;
- for(i=0; i<*num_list_entries; i++)
+ for (i = 0; i < *num_list_entries; i++)
deleteArtworkListEntry(artwork_info, &(*list)[i]);
free(*list);
if (artwork_info == NULL)
return;
-#if 0
- printf("%s: FREEING ARTWORK ...\n",
- IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
-#endif
-
FreeCustomArtworkList(artwork_info, &artwork_info->artwork_list,
&artwork_info->num_file_list_entries);
FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
&artwork_info->num_dynamic_file_list_entries);
-
-#if 0
- printf("%s: FREEING ARTWORK -- DONE\n",
- IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
-#endif
}
/* ------------------------------------------------------------------------- */
/* 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);
+ 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);
}
-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
+}
/* ------------------------------------------------------------------------- */
/* the following is only for debugging purpose and normally not used */
/* ------------------------------------------------------------------------- */
+#if DEBUG
+
#define DEBUG_NUM_TIMESTAMPS 3
void debug_print_timestamp(int counter_nr, char *message)
counter[counter_nr][0] = Counter();
if (message)
- printf("%s %.2f seconds\n", message,
+ printf("%s %.3f seconds\n", message,
(float)(counter[counter_nr][0] - counter[counter_nr][1]) / 1000);
- counter[counter_nr][1] = Counter();
+ counter[counter_nr][1] = counter[counter_nr][0];
}
+
+void debug_print_parent_only(char *format, ...)
+{
+ if (!IS_PARENT_PROCESS())
+ return;
+
+ if (format)
+ {
+ va_list ap;
+
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+
+ printf("\n");
+ }
+}
+#endif