+void LoadSetup_Default(void)
+{
+ char *filename;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults(&setup);
+
+ // try to load setup values from default setup file
+ filename = getDefaultSetupFilename();
+
+ if (fileExists(filename))
+ LoadSetupFromFilename(filename);
+
+ // try to load setup values from platform setup file
+ filename = getPlatformSetupFilename();
+
+ if (fileExists(filename))
+ LoadSetupFromFilename(filename);
+
+ // try to load setup values from user setup file
+ filename = getSetupFilename();
+
+ LoadSetupFromFilename(filename);
+
+ LoadSetup_SpecialPostProcessing();
+}
+
+void LoadSetup_AutoSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_AutoSetup(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_AutoSetup(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+}
+
+void LoadSetup_ServerSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_ServerSetup(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_ServerSetup(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+
+ if (setup.player_uuid == NULL)
+ {
+ // player UUID does not yet exist in setup file
+ setup.player_uuid = getStringCopy(getUUID());
+ setup.player_version = 2;
+
+ SaveSetup_ServerSetup();
+ }
+}
+
+void LoadSetup_EditorCascade(void)
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_EditorCascade(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_EditorCascade(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+}
+
+void LoadSetup(void)
+{
+ LoadSetup_Default();
+ LoadSetup_AutoSetup();
+ LoadSetup_ServerSetup();
+ LoadSetup_EditorCascade();
+}
+
+static void addGameControllerMappingToHash(SetupFileHash *mappings_hash,
+ char *mapping_line)
+{
+ char mapping_guid[MAX_LINE_LEN];
+ char *mapping_start, *mapping_end;
+
+ // get GUID from game controller mapping line: copy complete line
+ strncpy(mapping_guid, mapping_line, MAX_LINE_LEN - 1);
+ mapping_guid[MAX_LINE_LEN - 1] = '\0';
+
+ // get GUID from game controller mapping line: cut after GUID part
+ mapping_start = strchr(mapping_guid, ',');
+ if (mapping_start != NULL)
+ *mapping_start = '\0';
+
+ // cut newline from game controller mapping line
+ mapping_end = strchr(mapping_line, '\n');
+ if (mapping_end != NULL)
+ *mapping_end = '\0';
+
+ // add mapping entry to game controller mappings hash
+ setHashEntry(mappings_hash, mapping_guid, mapping_line);
+}
+
+static void LoadSetup_ReadGameControllerMappings(SetupFileHash *mappings_hash,
+ char *filename)
+{
+ FILE *file;
+
+ if (!(file = fopen(filename, MODE_READ)))
+ {
+ Warn("cannot read game controller mappings file '%s'", filename);
+
+ return;
+ }
+
+ while (!feof(file))
+ {
+ char line[MAX_LINE_LEN];
+
+ if (!fgets(line, MAX_LINE_LEN, file))
+ break;
+
+ addGameControllerMappingToHash(mappings_hash, line);
+ }
+
+ fclose(file);
+}
+
+void SaveSetup_Default(void)
+{
+ char *filename = getSetupFilename();
+ FILE *file;
+ int i, pnr;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write setup file '%s'", filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, SETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
+ {
+ // just to make things nicer :)
+ if (global_setup_tokens[i].value == &setup.multiple_users ||
+ global_setup_tokens[i].value == &setup.sound ||
+ global_setup_tokens[i].value == &setup.graphics_set ||
+ global_setup_tokens[i].value == &setup.volume_simple ||
+ global_setup_tokens[i].value == &setup.network_mode ||
+ global_setup_tokens[i].value == &setup.touch.control_type ||
+ global_setup_tokens[i].value == &setup.touch.grid_xsize[0] ||
+ global_setup_tokens[i].value == &setup.touch.grid_xsize[1])
+ fprintf(file, "\n");
+
+ fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ int grid_xsize = setup.touch.grid_xsize[i];
+ int grid_ysize = setup.touch.grid_ysize[i];
+ int x, y;
+
+ fprintf(file, "\n");
+
+ for (y = 0; y < grid_ysize; y++)
+ {
+ char token_string[MAX_LINE_LEN];
+ char value_string[MAX_LINE_LEN];
+
+ sprintf(token_string, "touch.virtual_buttons.%d.%02d", i, y);
+
+ for (x = 0; x < grid_xsize; x++)
+ {
+ char c = setup.touch.grid_button[i][x][y];
+
+ value_string[x] = (c == CHAR_GRID_BUTTON_NONE ? '.' : c);
+ }
+
+ value_string[grid_xsize] = '\0';
+
+ fprintf(file, "%s\n", getFormattedSetupEntry(token_string, value_string));
+ }
+ }
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(editor_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(shortcut_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
+
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+ fprintf(file, "\n");
+
+ setup_input = setup.input[pnr];
+ for (i = 0; i < ARRAY_SIZE(player_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
+ }
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(system_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
+
+ // (internal setup values not saved to user setup file)
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
+ if (!strPrefix(debug_setup_tokens[i].text, "debug.xsn_") ||
+ setup.debug.xsn_mode != AUTO)
+ fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+void SaveSetup_AutoSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write auto setup file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, AUTOSETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(auto_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(auto_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup_ServerSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write server setup file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, SERVERSETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(server_setup_tokens); i++)
+ {
+ // just to make things nicer :)
+ if (server_setup_tokens[i].value == &setup.use_api_server)
+ fprintf(file, "\n");
+
+ fprintf(file, "%s\n", getSetupLine(server_setup_tokens, "", i));
+ }
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup_EditorCascade(void)
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write editor cascade state file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, EDITORCASCADE_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(editor_cascade_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup(void)
+{
+ SaveSetup_Default();
+ SaveSetup_AutoSetup();
+ SaveSetup_ServerSetup();
+ SaveSetup_EditorCascade();
+}
+
+static void SaveSetup_WriteGameControllerMappings(SetupFileHash *mappings_hash,
+ char *filename)
+{
+ FILE *file;
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write game controller mappings file '%s'", filename);
+
+ return;
+ }
+
+ BEGIN_HASH_ITERATION(mappings_hash, itr)
+ {
+ fprintf(file, "%s\n", HASH_ITERATION_VALUE(itr));
+ }
+ END_HASH_ITERATION(mappings_hash, itr)
+
+ fclose(file);
+}
+
+void SaveSetup_AddGameControllerMapping(char *mapping)
+{
+ char *filename = getPath2(getSetupDir(), GAMECONTROLLER_BASENAME);
+ SetupFileHash *mappings_hash = newSetupFileHash();
+
+ InitUserDataDirectory();
+
+ // load existing personal game controller mappings
+ LoadSetup_ReadGameControllerMappings(mappings_hash, filename);
+
+ // add new mapping to personal game controller mappings
+ addGameControllerMappingToHash(mappings_hash, mapping);
+
+ // save updated personal game controller mappings
+ SaveSetup_WriteGameControllerMappings(mappings_hash, filename);
+
+ freeSetupFileHash(mappings_hash);
+ free(filename);
+}
+
+void LoadCustomElementDescriptions(void)
+{
+ 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);
+}
+
+static int getElementFromToken(char *token)