+ si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED);
+ }
+
+ si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
+ si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+
+ si->options.verbose = FALSE;
+}
+
+static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
+{
+ int i, pnr;
+
+ if (!setup_file_hash)
+ return;
+
+ /* global setup */
+ si = setup;
+ for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
+ setSetupInfo(global_setup_tokens, i,
+ getHashEntry(setup_file_hash, global_setup_tokens[i].text));
+ setup = si;
+
+ /* editor setup */
+ sei = setup.editor;
+ for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+ setSetupInfo(editor_setup_tokens, i,
+ getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
+ setup.editor = sei;
+
+ /* shortcut setup */
+ ssi = setup.shortcut;
+ for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
+ setSetupInfo(shortcut_setup_tokens, i,
+ getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
+ setup.shortcut = ssi;
+
+ /* player setup */
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+
+ sii = setup.input[pnr];
+ for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
+ {
+ char full_token[100];
+
+ sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
+ setSetupInfo(player_setup_tokens, i,
+ getHashEntry(setup_file_hash, full_token));
+ }
+ setup.input[pnr] = sii;
+ }
+
+ /* system setup */
+ syi = setup.system;
+ for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
+ setSetupInfo(system_setup_tokens, i,
+ getHashEntry(setup_file_hash, system_setup_tokens[i].text));
+ setup.system = syi;
+
+ /* options setup */
+ soi = setup.options;
+ for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
+ setSetupInfo(options_setup_tokens, i,
+ getHashEntry(setup_file_hash, options_setup_tokens[i].text));
+ setup.options = soi;
+}
+
+void LoadSetup()
+{
+ char *filename = getSetupFilename();
+ SetupFileHash *setup_file_hash = NULL;
+
+ /* always start with reliable default values */
+ setSetupInfoToDefaults(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ char *player_name_new;
+
+ checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+ decodeSetupFileHash(setup_file_hash);
+
+ setup.direct_draw = !setup.double_buffering;
+
+ freeSetupFileHash(setup_file_hash);
+
+ /* needed to work around problems with fixed length strings */
+ player_name_new = get_corrected_login_name(setup.player_name);
+ free(setup.player_name);
+ setup.player_name = player_name_new;
+ }
+ else
+ Error(ERR_WARN, "using default setup values");
+}
+
+void SaveSetup()
+{
+ char *filename = getSetupFilename();
+ FILE *file;
+ int i, pnr;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Error(ERR_WARN, "cannot write setup file '%s'", filename);
+ return;
+ }
+
+ fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+ getCookie("SETUP")));
+ fprintf(file, "\n");
+
+ /* global setup */
+ si = setup;
+ for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
+ {
+ /* just to make things nicer :) */
+ if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
+ i == SETUP_TOKEN_GRAPHICS_SET)
+ fprintf(file, "\n");
+
+ fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
+ }
+
+ /* editor setup */
+ sei = setup.editor;
+ fprintf(file, "\n");
+ for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
+
+ /* shortcut setup */
+ ssi = setup.shortcut;
+ fprintf(file, "\n");
+ for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
+
+ /* player setup */
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+ fprintf(file, "\n");
+
+ sii = setup.input[pnr];
+ for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
+ }
+
+ /* system setup */
+ syi = setup.system;
+ fprintf(file, "\n");
+ for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
+
+ /* options setup */
+ soi = setup.options;
+ fprintf(file, "\n");
+ for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
+ fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+void LoadCustomElementDescriptions()
+{
+ char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+ SetupFileHash *setup_file_hash;
+ int i;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ {
+ if (element_info[i].custom_description != NULL)
+ {
+ free(element_info[i].custom_description);
+ element_info[i].custom_description = NULL;
+ }
+ }
+
+ if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+ return;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ {
+ char *token = getStringCat2(element_info[i].token_name, ".name");
+ char *value = getHashEntry(setup_file_hash, token);
+
+ if (value != NULL)
+ element_info[i].custom_description = getStringCopy(value);
+
+ free(token);
+ }
+
+ freeSetupFileHash(setup_file_hash);
+}
+
+void LoadSpecialMenuDesignSettings()
+{
+ char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+ SetupFileHash *setup_file_hash;
+ int i, j;
+
+ /* always start with reliable default values from default config */
+ for (i = 0; image_config_vars[i].token != NULL; i++)
+ for (j = 0; image_config[j].token != NULL; j++)
+ if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
+ *image_config_vars[i].value =
+ get_auto_parameter_value(image_config_vars[i].token,
+ image_config[j].value);
+
+ if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+ return;
+
+ /* special case: initialize with default values that may be overwritten */
+ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+ {
+ char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
+ char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
+ char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
+
+ if (value_x != NULL)
+ menu.draw_xoffset[i] = get_integer_from_string(value_x);
+ if (value_y != NULL)
+ menu.draw_yoffset[i] = get_integer_from_string(value_y);
+ if (list_size != NULL)
+ menu.list_size[i] = get_integer_from_string(list_size);
+ }
+
+ /* read (and overwrite with) values that may be specified in config file */
+ for (i = 0; image_config_vars[i].token != NULL; i++)
+ {
+ char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
+
+ if (value != NULL)
+ *image_config_vars[i].value =
+ get_auto_parameter_value(image_config_vars[i].token, value);
+ }
+
+ freeSetupFileHash(setup_file_hash);
+}
+
+void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
+{
+ char *filename = getEditorSetupFilename();
+ SetupFileList *setup_file_list, *list;
+ SetupFileHash *element_hash;
+ int num_unknown_tokens = 0;
+ int i;
+
+ if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+ return;
+
+ element_hash = newSetupFileHash();
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
+
+ /* determined size may be larger than needed (due to unknown elements) */
+ *num_elements = 0;
+ for (list = setup_file_list; list != NULL; list = list->next)
+ (*num_elements)++;
+
+ /* add space for up to 3 more elements for padding that may be needed */
+ *num_elements += 3;
+
+ *elements = checked_malloc(*num_elements * sizeof(int));
+
+ *num_elements = 0;
+ for (list = setup_file_list; list != NULL; list = list->next)
+ {
+ char *value = getHashEntry(element_hash, list->token);
+
+ if (value)
+ {
+ (*elements)[(*num_elements)++] = atoi(value);
+ }
+ else
+ {
+ if (num_unknown_tokens == 0)
+ {
+ Error(ERR_RETURN_LINE, "-");
+ Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
+ Error(ERR_RETURN, "- config file: '%s'", filename);
+
+ num_unknown_tokens++;
+ }
+
+ Error(ERR_RETURN, "- token: '%s'", list->token);
+ }
+ }
+
+ if (num_unknown_tokens > 0)
+ Error(ERR_RETURN_LINE, "-");
+
+ while (*num_elements % 4) /* pad with empty elements, if needed */
+ (*elements)[(*num_elements)++] = EL_EMPTY;
+
+ freeSetupFileList(setup_file_list);
+ freeSetupFileHash(element_hash);
+
+#if 0
+ /* TEST-ONLY */
+ for (i = 0; i < *num_elements; i++)
+ printf("editor: element '%s' [%d]\n",
+ element_info[(*elements)[i]].token_name, (*elements)[i]);
+#endif
+}
+
+static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
+ boolean is_sound)
+{
+ SetupFileHash *setup_file_hash = NULL;
+ struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
+ char *filename_music, *filename_prefix, *filename_info;
+ struct
+ {
+ char *token;
+ char **value_ptr;
+ }
+ token_to_value_ptr[] =
+ {
+ { "title_header", &tmp_music_file_info.title_header },
+ { "artist_header", &tmp_music_file_info.artist_header },
+ { "album_header", &tmp_music_file_info.album_header },
+ { "year_header", &tmp_music_file_info.year_header },
+
+ { "title", &tmp_music_file_info.title },
+ { "artist", &tmp_music_file_info.artist },
+ { "album", &tmp_music_file_info.album },
+ { "year", &tmp_music_file_info.year },
+
+ { NULL, NULL },
+ };
+ int i;
+
+ filename_music = (is_sound ? getCustomSoundFilename(basename) :
+ getCustomMusicFilename(basename));
+
+ if (filename_music == NULL)
+ return NULL;
+
+ /* ---------- try to replace file extension ---------- */
+
+ filename_prefix = getStringCopy(filename_music);
+ if (strrchr(filename_prefix, '.') != NULL)
+ *strrchr(filename_prefix, '.') = '\0';
+ filename_info = getStringCat2(filename_prefix, ".txt");
+
+#if 0
+ printf("trying to load file '%s'...\n", filename_info);
+#endif
+
+ if (fileExists(filename_info))
+ setup_file_hash = loadSetupFileHash(filename_info);
+
+ free(filename_prefix);
+ free(filename_info);
+
+ if (setup_file_hash == NULL)
+ {
+ /* ---------- try to add file extension ---------- */
+
+ filename_prefix = getStringCopy(filename_music);
+ filename_info = getStringCat2(filename_prefix, ".txt");
+
+#if 0
+ printf("trying to load file '%s'...\n", filename_info);
+#endif
+
+ if (fileExists(filename_info))
+ setup_file_hash = loadSetupFileHash(filename_info);
+
+ free(filename_prefix);
+ free(filename_info);
+ }
+
+ if (setup_file_hash == NULL)
+ return NULL;
+
+ /* ---------- music file info found ---------- */
+
+ memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
+
+ for (i = 0; token_to_value_ptr[i].token != NULL; i++)
+ {
+ char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
+
+ *token_to_value_ptr[i].value_ptr =
+ getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
+ }
+
+ tmp_music_file_info.basename = getStringCopy(basename);
+ tmp_music_file_info.music = music;
+ tmp_music_file_info.is_sound = is_sound;
+
+ new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
+ *new_music_file_info = tmp_music_file_info;
+
+ return new_music_file_info;
+}
+
+static struct MusicFileInfo *get_music_file_info(char *basename, int music)
+{
+ return get_music_file_info_ext(basename, music, FALSE);
+}
+
+static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
+{
+ return get_music_file_info_ext(basename, sound, TRUE);
+}
+
+static boolean music_info_listed_ext(struct MusicFileInfo *list,
+ char *basename, boolean is_sound)
+{
+ for (; list != NULL; list = list->next)
+ if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
+{
+ return music_info_listed_ext(list, basename, FALSE);
+}
+
+static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
+{
+ return music_info_listed_ext(list, basename, TRUE);
+}
+
+void LoadMusicInfo()
+{
+ char *music_directory = getCustomMusicDirectory();
+ int num_music = getMusicListSize();
+ int num_music_noconf = 0;
+ int num_sounds = getSoundListSize();
+ DIR *dir;
+ struct dirent *dir_entry;
+ struct FileInfo *music, *sound;
+ struct MusicFileInfo *next, **new;
+ int i;
+
+ while (music_file_info != NULL)
+ {
+ next = music_file_info->next;
+
+ checked_free(music_file_info->basename);
+
+ checked_free(music_file_info->title_header);
+ checked_free(music_file_info->artist_header);
+ checked_free(music_file_info->album_header);
+ checked_free(music_file_info->year_header);
+
+ checked_free(music_file_info->title);
+ checked_free(music_file_info->artist);
+ checked_free(music_file_info->album);
+ checked_free(music_file_info->year);
+
+ free(music_file_info);
+
+ music_file_info = next;