X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=a2cc00ad56206797539e95b97c7ac1181c59435d;hb=61c3da024802ecc0268bab42d7499fc0346e4fd3;hp=d69c6537e238a42b925e202751fe558bf0216e2d;hpb=852a8eef1e8858a40da0be4093eba3deaf468f51;p=rocksndiamonds.git diff --git a/src/libgame/setup.c b/src/libgame/setup.c index d69c6537..a2cc00ad 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -334,7 +334,9 @@ char *setLevelArtworkDir(TreeInfo *ti) checked_free(*artwork_path_ptr); if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr))) + { *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork)); + } else { /* @@ -410,6 +412,19 @@ char *getSolutionTapeFilename(int nr) sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getSolutionTapeDir(), basename); + if (!fileExists(filename)) + { + static char *filename_sln = NULL; + + checked_free(filename_sln); + + sprintf(basename, "%03d.sln", nr); + filename_sln = getPath2(getSolutionTapeDir(), basename); + + if (fileExists(filename_sln)) + return filename_sln; + } + return filename; } @@ -670,10 +685,8 @@ char *getCustomImageFilename(char *basename) #if defined(CREATE_SPECIAL_EDITION) free(filename); - /* !!! INSERT WARNING HERE TO REPORT MISSING ARTWORK FILES !!! */ -#if 0 - printf("::: MISSING ARTWORK FILE '%s'\n", basename); -#endif + 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) */ @@ -743,6 +756,9 @@ char *getCustomSoundFilename(char *basename) #if defined(CREATE_SPECIAL_EDITION) free(filename); + 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); @@ -811,6 +827,9 @@ char *getCustomMusicFilename(char *basename) #if defined(CREATE_SPECIAL_EDITION) free(filename); + 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); @@ -1404,21 +1423,41 @@ static int posix_mkdir(const char *pathname, mode_t mode) #endif } +static boolean posix_process_running_setgid() +{ +#if defined(PLATFORM_UNIX) + return (getgid() != getegid()); +#else + return FALSE; +#endif +} + void createDirectory(char *dir, char *text, int permission_class) { /* 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 ? DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); - mode_t normal_umask = posix_umask(0); + mode_t last_umask = posix_umask(0); mode_t group_umask = ~(dir_mode & S_IRWXG); - posix_umask(normal_umask & group_umask); + 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 (running_setgid) + posix_umask(last_umask & group_umask); + else + dir_mode |= MODE_W_ALL; if (!fileExists(dir)) if (posix_mkdir(dir, dir_mode) != 0) Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); - posix_umask(normal_umask); /* reset normal umask */ + if (permission_class == PERMS_PUBLIC && !running_setgid) + chmod(dir, dir_mode); + + posix_umask(last_umask); /* restore previous umask */ } void InitUserDataDirectory() @@ -1428,8 +1467,14 @@ void InitUserDataDirectory() void SetFilePermissions(char *filename, int permission_class) { - chmod(filename, (permission_class == PERMS_PRIVATE ? - FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC)); + int running_setgid = posix_process_running_setgid(); + int perms = (permission_class == PERMS_PRIVATE ? + FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); + + if (permission_class == PERMS_PUBLIC && !running_setgid) + perms |= MODE_W_ALL; + + chmod(filename, perms); } char *getCookie(char *file_type) @@ -1585,6 +1630,7 @@ SetupFileList *addListEntry(SetupFileList *list, char *token, char *value) return addListEntry(list->next, token, value); } +#if 0 #ifdef DEBUG static void printSetupFileList(SetupFileList *list) { @@ -1597,6 +1643,7 @@ static void printSetupFileList(SetupFileList *list) printSetupFileList(list->next); } #endif +#endif #ifdef DEBUG DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char); @@ -1610,7 +1657,7 @@ DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char); #define remove_hash_entry hashtable_remove #endif -static unsigned int get_hash_from_key(void *key) +unsigned int get_hash_from_key(void *key) { /* djb2 @@ -2369,10 +2416,11 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash, #define LEVELINFO_TOKEN_MUSIC_SET 18 #define LEVELINFO_TOKEN_FILENAME 19 #define LEVELINFO_TOKEN_FILETYPE 20 -#define LEVELINFO_TOKEN_HANDICAP 21 -#define LEVELINFO_TOKEN_SKIP_LEVELS 22 +#define LEVELINFO_TOKEN_SPECIAL_FLAGS 21 +#define LEVELINFO_TOKEN_HANDICAP 22 +#define LEVELINFO_TOKEN_SKIP_LEVELS 23 -#define NUM_LEVELINFO_TOKENS 23 +#define NUM_LEVELINFO_TOKENS 24 static LevelDirTree ldi; @@ -2400,6 +2448,7 @@ static struct TokenInfo levelinfo_tokens[] = { TYPE_STRING, &ldi.music_set, "music_set" }, { TYPE_STRING, &ldi.level_filename, "filename" }, { TYPE_STRING, &ldi.level_filetype, "filetype" }, + { TYPE_STRING, &ldi.special_flags, "special_flags" }, { TYPE_BOOLEAN, &ldi.handicap, "handicap" }, { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" } }; @@ -2476,6 +2525,8 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type) ti->level_filename = NULL; ti->level_filetype = NULL; + ti->special_flags = NULL; + ti->levels = 0; ti->first_level = 0; ti->last_level = 0; @@ -2547,12 +2598,18 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->level_filename = NULL; ti->level_filetype = NULL; + ti->special_flags = getStringCopy(parent->special_flags); + ti->levels = 0; ti->first_level = 0; ti->last_level = 0; ti->level_group = FALSE; ti->handicap_level = 0; +#if 1 + ti->readonly = parent->readonly; +#else ti->readonly = TRUE; +#endif ti->handicap = TRUE; ti->skip_levels = FALSE; } @@ -2598,6 +2655,8 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) ti_copy->level_filename = getStringCopy(ti->level_filename); ti_copy->level_filetype = getStringCopy(ti->level_filetype); + ti_copy->special_flags = getStringCopy(ti->special_flags); + ti_copy->levels = ti->levels; ti_copy->first_level = ti->first_level; ti_copy->last_level = ti->last_level; @@ -2622,7 +2681,7 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) return ti_copy; } -static void freeTreeInfo(TreeInfo *ti) +void freeTreeInfo(TreeInfo *ti) { if (ti == NULL) return; @@ -2659,6 +2718,8 @@ static void freeTreeInfo(TreeInfo *ti) checked_free(ti->level_filename); checked_free(ti->level_filetype); + + checked_free(ti->special_flags); } checked_free(ti); @@ -2681,6 +2742,10 @@ void setSetupInfo(struct TokenInfo *token_info, *(boolean *)setup_value = get_boolean_from_string(token_value); break; + case TYPE_SWITCH3: + *(int *)setup_value = get_switch3_from_string(token_value); + break; + case TYPE_KEY: *(Key *)setup_value = getKeyFromKeyName(token_value); break; @@ -2830,14 +2895,18 @@ static char *getCacheToken(char *prefix, char *suffix) return token; } -static char *getFileTimestamp(char *filename) +static char *getFileTimestampString(char *filename) { +#if 1 + return getStringCopy(i_to_a(getFileTimestampEpochSeconds(filename))); +#else struct stat file_status; if (stat(filename, &file_status) != 0) /* cannot stat file */ return getStringCopy(i_to_a(0)); return getStringCopy(i_to_a(file_status.st_mtime)); +#endif } static boolean modifiedFileTimestamp(char *filename, char *timestamp_string) @@ -2954,8 +3023,8 @@ static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); - char *timestamp_levelinfo = getFileTimestamp(filename_levelinfo); - char *timestamp_artworkinfo = getFileTimestamp(filename_artworkinfo); + char *timestamp_levelinfo = getFileTimestampString(filename_levelinfo); + char *timestamp_artworkinfo = getFileTimestampString(filename_artworkinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo); @@ -2994,8 +3063,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, char *directory_name) { #if 0 - static unsigned long progress_delay = 0; - unsigned long progress_delay_value = 100; /* (in milliseconds) */ + static unsigned int progress_delay = 0; + unsigned int progress_delay_value = 100; /* (in milliseconds) */ #endif char *directory_path = getPath2(level_directory, directory_name); char *filename = getPath2(directory_path, LEVELINFO_FILENAME); @@ -3074,6 +3143,12 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, leveldir_new->in_user_dir = (!strEqual(leveldir_new->basepath, options.level_directory)); +#if 0 + printf("::: '%s' -> %d\n", + leveldir_new->identifier, + leveldir_new->in_user_dir); +#endif + /* adjust some settings if user's private level directory was detected */ if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED && leveldir_new->in_user_dir && @@ -3552,8 +3627,8 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, LevelDirTree *level_node) { #if 0 - static unsigned long progress_delay = 0; - unsigned long progress_delay_value = 100; /* (in milliseconds) */ + static unsigned int progress_delay = 0; + unsigned int progress_delay_value = 100; /* (in milliseconds) */ #endif int type = (*artwork_node)->type; @@ -3743,10 +3818,20 @@ char *getSetupValue(int type, void *value) strcpy(value_string, (*(boolean *)value ? "on" : "off")); break; + case TYPE_SWITCH3: + strcpy(value_string, (*(int *)value == AUTO ? "auto" : + *(int *)value == FALSE ? "off" : "on")); + break; + case TYPE_YES_NO: strcpy(value_string, (*(boolean *)value ? "yes" : "no")); break; + case TYPE_YES_NO_AUTO: + strcpy(value_string, (*(int *)value == AUTO ? "auto" : + *(int *)value == FALSE ? "no" : "yes")); + break; + case TYPE_ECS_AGA: strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS")); break; @@ -3946,10 +4031,17 @@ void LoadLevelSetup_SeriesInfo() char *filename; SetupFileHash *level_setup_hash = NULL; char *level_subdir = leveldir_current->subdir; + int i; /* always start with reliable default values */ level_nr = leveldir_current->first_level; + for (i = 0; i < MAX_LEVELS; i++) + { + LevelStats_setPlayed(i, 0); + LevelStats_setSolved(i, 0); + } + checkSeriesInfo(leveldir_current); /* ----------------------------------------------------------------------- */ @@ -3964,6 +4056,8 @@ void LoadLevelSetup_SeriesInfo() { char *token_value; + /* get last played level in this level set */ + token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL); if (token_value) @@ -3976,6 +4070,8 @@ void LoadLevelSetup_SeriesInfo() level_nr = leveldir_current->last_level; } + /* get handicap level in this level set */ + token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL); if (token_value) @@ -3993,6 +4089,31 @@ void LoadLevelSetup_SeriesInfo() leveldir_current->handicap_level = level_nr; } + /* get number of played and solved levels in this level set */ + + BEGIN_HASH_ITERATION(level_setup_hash, itr) + { + char *token = HASH_ITERATION_TOKEN(itr); + char *value = HASH_ITERATION_VALUE(itr); + + if (strlen(token) == 3 && + token[0] >= '0' && token[0] <= '9' && + token[1] >= '0' && token[1] <= '9' && + token[2] >= '0' && token[2] <= '9') + { + int level_nr = atoi(token); + + if (value != NULL) + LevelStats_setPlayed(level_nr, atoi(value)); /* read 1st column */ + + value = strchr(value, ' '); + + if (value != NULL) + LevelStats_setSolved(level_nr, atoi(value)); /* read 2nd column */ + } + } + END_HASH_ITERATION(hash, itr) + checkSetupFileHashIdentifier(level_setup_hash, filename, getCookie("LEVELSETUP")); @@ -4011,6 +4132,7 @@ void SaveLevelSetup_SeriesInfo() char *level_nr_str = int2str(level_nr, 0); char *handicap_level_str = int2str(leveldir_current->handicap_level, 0); FILE *file; + int i; /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ @@ -4031,8 +4153,24 @@ void SaveLevelSetup_SeriesInfo() getCookie("LEVELSETUP"))); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, level_nr_str)); - fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, - handicap_level_str)); + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, + handicap_level_str)); + + for (i = leveldir_current->first_level; i <= leveldir_current->last_level; + i++) + { + if (LevelStats_getPlayed(i) > 0 || + LevelStats_getSolved(i) > 0) + { + char token[16]; + char value[16]; + + sprintf(token, "%03d", i); + sprintf(value, "%d %d", LevelStats_getPlayed(i), LevelStats_getSolved(i)); + + fprintf(file, "%s\n", getFormattedSetupEntry(token, value)); + } + } fclose(file); @@ -4040,3 +4178,37 @@ void SaveLevelSetup_SeriesInfo() free(filename); } + +int LevelStats_getPlayed(int nr) +{ + return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].played : 0); +} + +int LevelStats_getSolved(int nr) +{ + return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].solved : 0); +} + +void LevelStats_setPlayed(int nr, int value) +{ + if (nr >= 0 && nr < MAX_LEVELS) + level_stats[nr].played = value; +} + +void LevelStats_setSolved(int nr, int value) +{ + if (nr >= 0 && nr < MAX_LEVELS) + level_stats[nr].solved = value; +} + +void LevelStats_incPlayed(int nr) +{ + if (nr >= 0 && nr < MAX_LEVELS) + level_stats[nr].played++; +} + +void LevelStats_incSolved(int nr) +{ + if (nr >= 0 && nr < MAX_LEVELS) + level_stats[nr].solved++; +}