+ else if (strEqual(suffix, ".align"))
+ {
+ result = (strEqual(value, "left") ? ALIGN_LEFT :
+ strEqual(value, "right") ? ALIGN_RIGHT :
+ strEqual(value, "center") ? ALIGN_CENTER :
+ strEqual(value, "middle") ? ALIGN_CENTER : ALIGN_DEFAULT);
+ }
+ else if (strEqual(suffix, ".valign"))
+ {
+ result = (strEqual(value, "top") ? VALIGN_TOP :
+ strEqual(value, "bottom") ? VALIGN_BOTTOM :
+ strEqual(value, "middle") ? VALIGN_MIDDLE :
+ strEqual(value, "center") ? VALIGN_MIDDLE : VALIGN_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 :
+ 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 if (strEqual(suffix, ".fade_mode"))
+ {
+ result = (string_has_parameter(value, "none") ? FADE_MODE_NONE :
+ string_has_parameter(value, "fade") ? FADE_MODE_FADE :
+ string_has_parameter(value, "crossfade") ? FADE_MODE_CROSSFADE :
+ string_has_parameter(value, "melt") ? FADE_MODE_MELT :
+ FADE_MODE_DEFAULT);
+ }
+#if 1
+ else if (strPrefix(suffix, ".font")) /* (may also be ".font_xyz") */
+#else
+ else if (strEqualN(suffix, ".font", 5)) /* (may also be ".font_xyz") */
+#endif
+ {
+ result = gfx.get_font_from_token_function(value);
+ }
+ 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;
+}
+
+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 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;
+ int i, j;
+
+ file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo));
+
+ 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++)
+ {
+ 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(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++)
+ {
+ 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;
+ file_list[i].default_is_cloned = FALSE;
+ }
+ }
+
+ 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++)
+ {
+ int len_suffix = strlen(suffix_list[j].token);
+
+ if (len_suffix < len_config_token &&
+ 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);
+
+ 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)
+ list_pos++;
+
+ if (list_pos >= num_file_list_entries)
+ break;
+
+ /* simple sanity check if this is really a file definition */
+ if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") &&
+ !strEqual(&config_list[i].value[len_config_value - 4], ".wav") &&
+ !strEqual(config_list[i].value, UNDEFINED_FILENAME))
+ {
+ 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
+ }
+
+ if (strSuffix(config_list[i].token, ".clone_from"))
+ file_list[list_pos].default_is_cloned = TRUE;
+ }
+
+ num_file_list_entries_found = list_pos + 1;
+ if (num_file_list_entries_found != num_file_list_entries)
+ {
+ 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_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;
+}
+
+static boolean token_suffix_match(char *token, char *suffix, int start_pos)
+{
+ int len_token = strlen(token);
+ int len_suffix = strlen(suffix);
+
+ if (start_pos < 0) /* compare suffix from end of string */
+ start_pos += len_token;
+
+ if (start_pos < 0 || start_pos + len_suffix > len_token)
+ return FALSE;
+
+ if (strncmp(&token[start_pos], suffix, len_suffix) != 0)
+ return FALSE;
+
+ if (token[start_pos + len_suffix] == '\0')
+ return TRUE;
+
+ if (token[start_pos + len_suffix] == '.')
+ return TRUE;
+
+ return FALSE;
+}
+
+#define KNOWN_TOKEN_VALUE "[KNOWN_TOKEN_VALUE]"
+
+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 = 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++)
+ setString(&file_list_entry->parameter[i], suffix_list[i].value);
+
+ file_list_entry->redefined = TRUE;
+
+ /* mark config file token as well known from default config */
+ setHashEntry(setup_file_hash, file_list_entry->token, known_token_value);
+ }
+
+ /* check for config tokens that can be build by base token and suffixes */
+ for (i = 0; suffix_list[i].token != NULL; i++)
+ {
+ char *token = getStringCat2(file_list_entry->token, suffix_list[i].token);
+ char *value = getHashEntry(setup_file_hash, token);
+
+ if (value != NULL)
+ {
+ setString(&file_list_entry->parameter[i], value);
+
+ /* mark config file token as well known from default config */
+ setHashEntry(setup_file_hash, token, known_token_value);
+ }
+
+ free(token);
+ }
+}
+
+static void add_dynamic_file_list_entry(struct FileInfo **list,
+ int *num_list_entries,
+ 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(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);
+
+ new_list_entry->redefined = FALSE;
+ new_list_entry->fallback_to_default = FALSE;
+ new_list_entry->default_is_cloned = FALSE;
+
+ read_token_parameters(extra_file_hash, suffix_list, new_list_entry);
+}
+
+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 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;
+ 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, l;
+
+ if (filename == NULL)