X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=8662b204bb5f336ca426408be1b2fe841efa58a7;hp=562152961c32009cb61133db36eeb424b1c0e160;hb=05818ea4267c3e2a196071d17d8735d6f6fe65c9;hpb=2e95647b2bd7e2fb71e052441638742e89b6aaf1 diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 56215296..8662b204 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -133,15 +133,25 @@ static char *getUserLevelDir(char *level_subdir) static char *getScoreDir(char *level_subdir) { static char *score_dir = NULL; - char *data_dir = getCommonDataDir(); + static char *score_level_dir = NULL; char *score_subdir = SCORES_DIRECTORY; - checked_free(score_dir); + if (score_dir == NULL) + { + if (program.global_scores) + score_dir = getPath2(getCommonDataDir(), score_subdir); + else + score_dir = getPath2(getUserGameDataDir(), score_subdir); + } if (level_subdir != NULL) - score_dir = getPath3(data_dir, score_subdir, level_subdir); - else - score_dir = getPath2(data_dir, score_subdir); + { + checked_free(score_level_dir); + + score_level_dir = getPath2(score_dir, level_subdir); + + return score_level_dir; + } return score_dir; } @@ -192,6 +202,28 @@ char *getCurrentLevelDir() return getLevelDirFromTreeInfo(leveldir_current); } +char *getNewUserLevelSubdir() +{ + static char *new_level_subdir = NULL; + char *subdir_prefix = getLoginName(); + char subdir_suffix[10]; + int max_suffix_number = 1000; + int i = 0; + + while (++i < max_suffix_number) + { + sprintf(subdir_suffix, "_%d", i); + + checked_free(new_level_subdir); + new_level_subdir = getStringCat2(subdir_prefix, subdir_suffix); + + if (!directoryExists(getUserLevelDir(new_level_subdir))) + break; + } + + return new_level_subdir; +} + static char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; @@ -393,6 +425,29 @@ inline static char *getLevelArtworkDir(int type) return LEVELDIR_ARTWORK_PATH(leveldir_current, type); } +char *getProgramConfigFilename(char *command_filename_ptr) +{ + char *command_filename_1 = getStringCopy(command_filename_ptr); + + // strip trailing executable suffix from command filename + if (strSuffix(command_filename_1, ".exe")) + command_filename_1[strlen(command_filename_1) - 4] = '\0'; + + char *command_basepath = getBasePath(command_filename_ptr); + char *command_basename = getBaseNameNoSuffix(command_filename_ptr); + char *command_filename_2 = getPath2(command_basepath, command_basename); + + char *config_filename_1 = getStringCat2(command_filename_1, ".conf"); + char *config_filename_2 = getStringCat2(command_filename_2, ".conf"); + + // 1st try: look for config file that exactly matches the binary filename + if (fileExists(config_filename_1)) + return config_filename_1; + + // 2nd try: return config filename that matches binary filename without suffix + return config_filename_2; +} + char *getTapeFilename(int nr) { static char *filename = NULL; @@ -456,6 +511,11 @@ char *getSetupFilename() return filename; } +char *getDefaultSetupFilename() +{ + return program.config_filename; +} + char *getEditorSetupFilename() { static char *filename = NULL; @@ -659,18 +719,20 @@ char *getCustomImageFilename(char *basename) if (fileExists(filename)) return filename; -#if defined(CREATE_SPECIAL_EDITION) - free(filename); + if (!strEqual(GFX_FALLBACK_FILENAME, UNDEFINED_FILENAME)) + { + free(filename); - if (options.debug) - Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", + basename); - /* 6th try: look for fallback artwork in old default artwork directory */ - /* (needed to prevent errors when trying to access unused artwork files) */ - filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME); - if (fileExists(filename)) - return filename; -#endif + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ + filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME); + if (fileExists(filename)) + return filename; + } return NULL; /* cannot find specified artwork file anywhere */ } @@ -730,18 +792,20 @@ char *getCustomSoundFilename(char *basename) if (fileExists(filename)) return filename; -#if defined(CREATE_SPECIAL_EDITION) - free(filename); + if (!strEqual(SND_FALLBACK_FILENAME, UNDEFINED_FILENAME)) + { + free(filename); - if (options.debug) - Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", + basename); - /* 6th try: look for fallback artwork in old default artwork directory */ - /* (needed to prevent errors when trying to access unused artwork files) */ - filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME); - if (fileExists(filename)) - return filename; -#endif + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ + filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME); + if (fileExists(filename)) + return filename; + } return NULL; /* cannot find specified artwork file anywhere */ } @@ -801,18 +865,20 @@ char *getCustomMusicFilename(char *basename) if (fileExists(filename)) return filename; -#if defined(CREATE_SPECIAL_EDITION) - free(filename); + if (!strEqual(MUS_FALLBACK_FILENAME, UNDEFINED_FILENAME)) + { + free(filename); - if (options.debug) - Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", + basename); - /* 6th try: look for fallback artwork in old default artwork directory */ - /* (needed to prevent errors when trying to access unused artwork files) */ - filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME); - if (fileExists(filename)) - return filename; -#endif + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ + filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME); + if (fileExists(filename)) + return filename; + } return NULL; /* cannot find specified artwork file anywhere */ } @@ -910,9 +976,15 @@ void InitTapeDirectory(char *level_subdir) void InitScoreDirectory(char *level_subdir) { - createDirectory(getCommonDataDir(), "common data", PERMS_PUBLIC); - createDirectory(getScoreDir(NULL), "main score", PERMS_PUBLIC); - createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); + int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE); + + if (program.global_scores) + createDirectory(getCommonDataDir(), "common data", permissions); + else + createDirectory(getUserGameDataDir(), "user data", permissions); + + createDirectory(getScoreDir(NULL), "main score", permissions); + createDirectory(getScoreDir(level_subdir), "level score", permissions); } static void SaveUserLevelInfo(); @@ -1262,14 +1334,17 @@ void sortTreeInfo(TreeInfo **node_first) #define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) #define MODE_W_PRIVATE (S_IWUSR) -#define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) +#define MODE_W_PUBLIC_FILE (S_IWUSR | S_IWGRP) #define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) #define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) #define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) +#define DIR_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_X_ALL | MODE_W_ALL) #define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) -#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) +#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC_FILE) +#define FILE_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_W_ALL) + char *getHomeDir() { @@ -1347,7 +1422,10 @@ char *getUserGameDataDir(void) #if defined(PLATFORM_ANDROID) if (user_game_data_dir == NULL) - user_game_data_dir = (char *)SDL_AndroidGetInternalStoragePath(); + user_game_data_dir = (char *)(SDL_AndroidGetExternalStorageState() & + SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? + SDL_AndroidGetExternalStoragePath() : + SDL_AndroidGetInternalStoragePath()); #else if (user_game_data_dir == NULL) user_game_data_dir = getPath2(getPersonalDataDir(), @@ -1357,30 +1435,6 @@ char *getUserGameDataDir(void) return user_game_data_dir; } -void updateUserGameDataDir() -{ -#if defined(PLATFORM_MACOSX) - char *userdata_dir_old = getPath2(getHomeDir(), program.userdata_subdir_unix); - char *userdata_dir_new = getUserGameDataDir(); /* do not free() this */ - - /* convert old Unix style game data directory to Mac OS X style, if needed */ - if (directoryExists(userdata_dir_old) && !directoryExists(userdata_dir_new)) - { - if (rename(userdata_dir_old, userdata_dir_new) != 0) - { - Error(ERR_WARN, "cannot move game data directory '%s' to '%s'", - userdata_dir_old, userdata_dir_new); - - /* continue using Unix style data directory -- this should not happen */ - program.userdata_path = getPath2(getPersonalDataDir(), - program.userdata_subdir_unix); - } - } - - free(userdata_dir_old); -#endif -} - char *getSetupDir() { return getUserGameDataDir(); @@ -1415,6 +1469,9 @@ static boolean posix_process_running_setgid() void createDirectory(char *dir, char *text, int permission_class) { + if (directoryExists(dir)) + return; + /* leave "other" permissions in umask untouched, but ensure group parts of USERDATA_DIR_MODE are not masked */ mode_t dir_mode = (permission_class == PERMS_PRIVATE ? @@ -1423,18 +1480,20 @@ void createDirectory(char *dir, char *text, int permission_class) mode_t group_umask = ~(dir_mode & S_IRWXG); int running_setgid = posix_process_running_setgid(); - /* if we're setgid, protect files against "other" */ - /* else keep umask(0) to make the dir world-writable */ + if (permission_class == PERMS_PUBLIC) + { + /* if we're setgid, protect files against "other" */ + /* else keep umask(0) to make the dir world-writable */ - if (running_setgid) - posix_umask(last_umask & group_umask); - else - dir_mode |= MODE_W_ALL; + if (running_setgid) + posix_umask(last_umask & group_umask); + else + dir_mode = DIR_PERMS_PUBLIC_ALL; + } - if (!directoryExists(dir)) - if (posix_mkdir(dir, dir_mode) != 0) - Error(ERR_WARN, "cannot create %s directory '%s': %s", - text, dir, strerror(errno)); + if (posix_mkdir(dir, dir_mode) != 0) + Error(ERR_WARN, "cannot create %s directory '%s': %s", + text, dir, strerror(errno)); if (permission_class == PERMS_PUBLIC && !running_setgid) chmod(dir, dir_mode); @@ -1454,7 +1513,7 @@ void SetFilePermissions(char *filename, int permission_class) FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); if (permission_class == PERMS_PUBLIC && !running_setgid) - perms |= MODE_W_ALL; + perms = FILE_PERMS_PUBLIC_ALL; chmod(filename, perms); } @@ -1918,7 +1977,7 @@ static boolean loadSetupFileData(void *setup_file_data, char *filename, if (!(file = openFile(filename, MODE_READ))) { - Error(ERR_WARN, "cannot open configuration file '%s'", filename); + Error(ERR_DEBUG, "cannot open configuration file '%s'", filename); return FALSE; } @@ -2316,28 +2375,28 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->imported_by = getStringCopy(parent->imported_by); ti->tested_by = getStringCopy(parent->tested_by); - ti->graphics_set_ecs = NULL; - ti->graphics_set_aga = NULL; - ti->graphics_set = NULL; - ti->sounds_set = NULL; - ti->music_set = NULL; + ti->graphics_set_ecs = getStringCopy(parent->graphics_set_ecs); + ti->graphics_set_aga = getStringCopy(parent->graphics_set_aga); + ti->graphics_set = getStringCopy(parent->graphics_set); + ti->sounds_set = getStringCopy(parent->sounds_set); + ti->music_set = getStringCopy(parent->music_set); ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); - ti->level_filename = NULL; - ti->level_filetype = NULL; + ti->level_filename = getStringCopy(parent->level_filename); + ti->level_filetype = getStringCopy(parent->level_filetype); ti->special_flags = getStringCopy(parent->special_flags); - ti->levels = 0; - ti->first_level = 0; - ti->last_level = 0; + ti->levels = parent->levels; + ti->first_level = parent->first_level; + ti->last_level = parent->last_level; ti->level_group = FALSE; - ti->handicap_level = 0; + ti->handicap_level = parent->handicap_level; ti->readonly = parent->readonly; - ti->handicap = TRUE; - ti->skip_levels = FALSE; + ti->handicap = parent->handicap; + ti->skip_levels = parent->skip_levels; } } @@ -2590,7 +2649,7 @@ static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first) setString(&ti_new->name_sorting, ti_new->name); setString(&ti_new->subdir, STRING_TOP_DIRECTORY); - setString(&ti_new->fullpath, node_first->fullpath); + setString(&ti_new->fullpath, "."); ti_new->sort_priority = node_first->sort_priority;; ti_new->latest_engine = node_first->latest_engine; @@ -3457,20 +3516,132 @@ void LoadLevelArtworkInfo() print_timestamp_done("LoadLevelArtworkInfo"); } -static void SaveUserLevelInfo() +static boolean AddUserLevelSetToLevelInfoExt(char *level_subdir_new) +{ + // get level info tree node of first (original) user level set + char *level_subdir_old = getLoginName(); + LevelDirTree *leveldir_old = getTreeInfoFromIdentifier(leveldir_first, + level_subdir_old); + if (leveldir_old == NULL) // should not happen + return FALSE; + + int draw_deactivation_mask = GetDrawDeactivationMask(); + + // override draw deactivation mask (temporarily disable drawing) + SetDrawDeactivationMask(REDRAW_ALL); + + // load new level set config and add it next to first user level set + LoadLevelInfoFromLevelConf(&leveldir_old->next, NULL, + leveldir_old->basepath, level_subdir_new); + + // set draw deactivation mask to previous value + SetDrawDeactivationMask(draw_deactivation_mask); + + // get level info tree node of newly added user level set + LevelDirTree *leveldir_new = getTreeInfoFromIdentifier(leveldir_first, + level_subdir_new); + if (leveldir_new == NULL) // should not happen + return FALSE; + + // correct top link and parent node link of newly created tree node + leveldir_new->node_top = leveldir_old->node_top; + leveldir_new->node_parent = leveldir_old->node_parent; + + // sort level info tree to adjust position of newly added level set + sortTreeInfo(&leveldir_first); + + return TRUE; +} + +void AddUserLevelSetToLevelInfo(char *level_subdir_new) +{ + if (!AddUserLevelSetToLevelInfoExt(level_subdir_new)) + Error(ERR_EXIT, "internal level set structure corrupted -- aborting"); +} + +boolean UpdateUserLevelSet(char *level_subdir, char *level_name, + char *level_author, int num_levels) +{ + char *filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); + char *filename_tmp = getStringCat2(filename, ".tmp"); + FILE *file = NULL; + FILE *file_tmp = NULL; + char line[MAX_LINE_LEN]; + boolean success = FALSE; + LevelDirTree *leveldir = getTreeInfoFromIdentifier(leveldir_first, + level_subdir); + // update values in level directory tree + + if (level_name != NULL) + setString(&leveldir->name, level_name); + + if (level_author != NULL) + setString(&leveldir->author, level_author); + + if (num_levels != -1) + leveldir->levels = num_levels; + + // update values that depend on other values + + setString(&leveldir->name_sorting, leveldir->name); + + leveldir->last_level = leveldir->first_level + leveldir->levels - 1; + + // sort order of level sets may have changed + sortTreeInfo(&leveldir_first); + + if ((file = fopen(filename, MODE_READ)) && + (file_tmp = fopen(filename_tmp, MODE_WRITE))) + { + while (fgets(line, MAX_LINE_LEN, file)) + { + if (strPrefix(line, "name:") && level_name != NULL) + fprintf(file_tmp, "%-32s%s\n", "name:", level_name); + else if (strPrefix(line, "author:") && level_author != NULL) + fprintf(file_tmp, "%-32s%s\n", "author:", level_author); + else if (strPrefix(line, "levels:") && num_levels != -1) + fprintf(file_tmp, "%-32s%d\n", "levels:", num_levels); + else + fputs(line, file_tmp); + } + + success = TRUE; + } + + if (file) + fclose(file); + + if (file_tmp) + fclose(file_tmp); + + if (success) + success = (rename(filename_tmp, filename) == 0); + + free(filename); + free(filename_tmp); + + return success; +} + +boolean CreateUserLevelSet(char *level_subdir, char *level_name, + char *level_author, int num_levels) { LevelDirTree *level_info; char *filename; FILE *file; int i; - filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + // create user level sub-directory, if needed + createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); + + filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write level info file '%s'", filename); free(filename); - return; + + return FALSE; } level_info = newTreeInfo(); @@ -3478,10 +3649,12 @@ static void SaveUserLevelInfo() /* always start with reliable default values */ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR); - setString(&level_info->name, getLoginName()); - setString(&level_info->author, getRealName()); - level_info->levels = 100; + setString(&level_info->name, level_name); + setString(&level_info->author, level_author); + level_info->levels = num_levels; level_info->first_level = 1; + level_info->sort_priority = LEVELCLASS_PRIVATE_START; + level_info->readonly = FALSE; token_value_position = TOKEN_VALUE_POSITION_SHORT; @@ -3493,11 +3666,14 @@ static void SaveUserLevelInfo() if (i == LEVELINFO_TOKEN_NAME || i == LEVELINFO_TOKEN_AUTHOR || i == LEVELINFO_TOKEN_LEVELS || - i == LEVELINFO_TOKEN_FIRST_LEVEL) + i == LEVELINFO_TOKEN_FIRST_LEVEL || + i == LEVELINFO_TOKEN_SORT_PRIORITY || + i == LEVELINFO_TOKEN_READONLY) fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); /* just to make things nicer :) */ - if (i == LEVELINFO_TOKEN_AUTHOR) + if (i == LEVELINFO_TOKEN_AUTHOR || + i == LEVELINFO_TOKEN_FIRST_LEVEL) fprintf(file, "\n"); } @@ -3509,6 +3685,13 @@ static void SaveUserLevelInfo() freeTreeInfo(level_info); free(filename); + + return TRUE; +} + +static void SaveUserLevelInfo() +{ + CreateUserLevelSet(getLoginName(), getLoginName(), getRealName(), 100); } char *getSetupValue(int type, void *value) @@ -3626,12 +3809,13 @@ void LoadLevelSetup_LastSeries() /* always start with reliable default values */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); -#if defined(CREATE_SPECIAL_EDITION_RND_JUE) - leveldir_current = getTreeInfoFromIdentifier(leveldir_first, - "jue_start"); - if (leveldir_current == NULL) - leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); -#endif + if (!strEqual(DEFAULT_LEVELSET, UNDEFINED_LEVELSET)) + { + leveldir_current = getTreeInfoFromIdentifier(leveldir_first, + DEFAULT_LEVELSET); + if (leveldir_current == NULL) + leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); + } if ((level_setup_hash = loadSetupFileHash(filename))) { @@ -3646,7 +3830,9 @@ void LoadLevelSetup_LastSeries() freeSetupFileHash(level_setup_hash); } else - Error(ERR_WARN, "using default setup values"); + { + Error(ERR_DEBUG, "using default setup values"); + } free(filename); } @@ -3739,7 +3925,7 @@ void LoadLevelSetup_SeriesInfo() LevelStats_setSolved(i, 0); } - checkSeriesInfo(leveldir_current); + checkSeriesInfo(); /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ @@ -3814,7 +4000,9 @@ void LoadLevelSetup_SeriesInfo() freeSetupFileHash(level_setup_hash); } else - Error(ERR_WARN, "using default setup values"); + { + Error(ERR_DEBUG, "using default setup values"); + } free(filename); }