X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=46671d4631c18ca86423f370eb81c7a3a01dbc70;hb=a4bf969413cdda68ab8bb54a2a1181bdc09cf63a;hp=d96e3bf23000d25d6d112ed6b6c6c6c285d57833;hpb=ef86a9fafe44eeffdda3a301ca4a2f586602f481;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index d96e3bf2..46671d46 100644 --- a/src/files.c +++ b/src/files.c @@ -12,6 +12,9 @@ ***********************************************************/ #include +#include +#include +#include #include "files.h" #include "tools.h" @@ -19,70 +22,145 @@ #include "tape.h" #include "joystick.h" -boolean LoadLevelInfo() +#define MAX_LINE_LEN 1000 + +static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ +static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ + +static char *getGlobalDataDir() { - int i; - char filename[MAX_FILENAME_LEN]; - char cookie[MAX_FILENAME_LEN]; - FILE *file; + return GAME_DIR; +} - sprintf(filename,"%s/%s",level_directory,LEVDIR_FILENAME); +static char *getUserDataDir() +{ + static char *userdata_dir = NULL; - if (!(file=fopen(filename,"r"))) + if (!userdata_dir) { - Error(ERR_WARN, "cannot read level info '%s'", filename); - return(FALSE); - } + char *home_dir = getHomeDir(); + char *data_dir = USERDATA_DIRECTORY; - fscanf(file,"%s\n",cookie); - if (strcmp(cookie,LEVELDIR_COOKIE)) /* ungültiges Format? */ - { - Error(ERR_WARN, "wrong format of level info file"); - fclose(file); - return(FALSE); + userdata_dir = checked_malloc(strlen(home_dir) + strlen(data_dir) + 2); + sprintf(userdata_dir, "%s/%s", home_dir, data_dir); } - num_leveldirs = 0; - leveldir_nr = 0; - for(i=0;i 0 ? "/" : ""), level_subdir); + + return userlevel_dir; +} + +static char *getTapeDir(char *level_subdir) +{ + static char *tape_dir = NULL; + char *data_dir = getUserDataDir(); + char *tape_subdir = TAPES_DIRECTORY; + + if (tape_dir) + free(tape_dir); + + tape_dir = checked_malloc(strlen(data_dir) + strlen(tape_subdir) + + strlen(level_subdir) + 3); + sprintf(tape_dir, "%s/%s%s%s", data_dir, tape_subdir, + (strlen(level_subdir) > 0 ? "/" : ""), level_subdir); + + return tape_dir; +} + +static char *getScoreDir(char *level_subdir) +{ + static char *score_dir = NULL; + char *data_dir = getGlobalDataDir(); + char *score_subdir = SCORES_DIRECTORY; + + if (score_dir) + free(score_dir); + + score_dir = checked_malloc(strlen(data_dir) + strlen(score_subdir) + + strlen(level_subdir) + 3); + sprintf(score_dir, "%s/%s%s%s", data_dir, score_subdir, + (strlen(level_subdir) > 0 ? "/" : ""), level_subdir); + + return score_dir; +} - if (!num_leveldirs) +static void createDirectory(char *dir, char *text) +{ + if (access(dir, F_OK) != 0) + if (mkdir(dir, USERDATA_DIR_MODE) != 0) + Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); +} + +static void InitUserDataDirectory() +{ + createDirectory(getUserDataDir(), "user data"); +} + +static void InitTapeDirectory(char *level_subdir) +{ + createDirectory(getTapeDir(""), "main tape"); + createDirectory(getTapeDir(level_subdir), "level tape"); +} + +static void InitScoreDirectory(char *level_subdir) +{ + createDirectory(getScoreDir(""), "main score"); + createDirectory(getScoreDir(level_subdir), "level score"); +} + +static void InitUserLevelDirectory(char *level_subdir) +{ + if (access(getUserLevelDir(level_subdir), F_OK) != 0) { - Error(ERR_WARN, "empty level info '%s'", filename); - return(FALSE); - } + createDirectory(getUserLevelDir(""), "main user level"); + createDirectory(getUserLevelDir(level_subdir), "user level"); - return(TRUE); + SaveUserLevelInfo(); + } } void LoadLevel(int level_nr) { - int i,x,y; + int i, x, y; char filename[MAX_FILENAME_LEN]; char cookie[MAX_FILENAME_LEN]; FILE *file; - sprintf(filename,"%s/%s/%d", - level_directory,leveldir[leveldir_nr].filename,level_nr); + if (leveldir[leveldir_nr].user_defined) + sprintf(filename, "%s/%s/%d", + getUserLevelDir(""), leveldir[leveldir_nr].filename, level_nr); + else + sprintf(filename, "%s/%s/%d", + options.level_directory, leveldir[leveldir_nr].filename, level_nr); - if (!(file = fopen(filename,"r"))) + if (!(file = fopen(filename, "r"))) Error(ERR_WARN, "cannot read level '%s' - creating new level", filename); else { - fgets(cookie,LEVEL_COOKIE_LEN,file); + fgets(cookie, LEVEL_COOKIE_LEN, file); fgetc(file); - if (strcmp(cookie,LEVEL_COOKIE)) /* ungültiges Format? */ + if (strcmp(cookie,LEVEL_COOKIE)) { Error(ERR_WARN, "wrong format of level file '%s'", filename); fclose(file); @@ -97,34 +175,34 @@ void LoadLevel(int level_nr) level.time = (fgetc(file)<<8) | fgetc(file); level.edelsteine = (fgetc(file)<<8) | fgetc(file); - for(i=0;i> 24) & 0xff,file); fputc((tape.random_seed >> 16) & 0xff,file); @@ -361,14 +437,14 @@ void SaveLevelTape(int level_nr) fputc((tape.length >> 8) & 0xff,file); fputc((tape.length >> 0) & 0xff,file); - for(i=0;inext = NULL; freeSetupFileList(setup_file_list); - if (!first_valid_list_entry) - Error(ERR_WARN, "setup file is empty"); + if (first_valid_list_entry == NULL) + Error(ERR_WARN, "setup/info file '%s' is empty", filename); return first_valid_list_entry; } @@ -829,7 +888,7 @@ static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, { if (strcmp(setup_file_list->value, identifier) != 0) { - Error(ERR_WARN, "setup file has wrong version"); + Error(ERR_WARN, "setup/info file has wrong version"); return; } else @@ -840,15 +899,25 @@ static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, checkSetupFileListIdentifier(setup_file_list->next, identifier); else { - Error(ERR_WARN, "setup file has no version information"); + Error(ERR_WARN, "setup/info file has no version information"); return; } } +static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) +{ + ldi->name = getStringCopy("non-existing"); + ldi->levels = 0; + ldi->sort_priority = 999; /* default: least priority */ + ldi->readonly = TRUE; +} + static void setSetupInfoToDefaults(struct SetupInfo *si) { int i; + si->player_name = getStringCopy(getLoginName()); + si->sound = TRUE; si->sound_loops = FALSE; si->sound_music = FALSE; @@ -862,15 +931,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->autorecord = FALSE; si->quick_doors = FALSE; - strncpy(si->login_name, GetLoginName(), MAX_NAMELEN-1); - si->login_name[MAX_NAMELEN-1] = '\0'; - strncpy(si->alias_name, GetLoginName(), MAX_NAMELEN-1); - si->alias_name[MAX_NAMELEN-1] = '\0'; - for (i=0; iinput[i].use_joystick = FALSE; - strcpy(si->input[i].joy.device_name, joystick_device_name[i]); + si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]); si->input[i].joy.xleft = JOYSTICK_XLEFT; si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE; si->input[i].joy.xright = JOYSTICK_XRIGHT; @@ -913,7 +977,9 @@ static void setSetupInfo(int token_nr, char *token_value) break; case TYPE_STRING: - strcpy((char *)setup_value, token_value); + if (*(char **)setup_value != NULL) + free(*(char **)setup_value); + *(char **)setup_value = getStringCopy(token_value); break; default: @@ -993,6 +1059,154 @@ int getLastPlayedLevelOfLevelSeries(char *level_series_name) return last_level_nr; } +static int compareLevelDirInfoEntries(const void *object1, const void *object2) +{ + const struct LevelDirInfo *entry1 = object1; + const struct LevelDirInfo *entry2 = object2; + int compare_result; + + if (entry1->sort_priority != entry2->sort_priority) + compare_result = entry1->sort_priority - entry2->sort_priority; + else + { + char *name1 = getStringToLower(entry1->name); + char *name2 = getStringToLower(entry2->name); + + compare_result = strcmp(name1, name2); + + free(name1); + free(name2); + } + + return compare_result; +} + +static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry) +{ + DIR *dir; + struct stat file_status; + char *directory = NULL; + char *filename = NULL; + struct SetupFileList *setup_file_list = NULL; + struct dirent *dir_entry; + int i, current_entry = start_entry; + + if ((dir = opendir(level_directory)) == NULL) + Error(ERR_EXIT, "cannot read level directory '%s'", level_directory); + + while (current_entry < MAX_LEVDIR_ENTRIES) + { + if ((dir_entry = readdir(dir)) == NULL) /* last directory entry */ + break; + + /* skip entries for current and parent directory */ + if (strcmp(dir_entry->d_name, ".") == 0 || + strcmp(dir_entry->d_name, "..") == 0) + continue; + + /* find out if directory entry is itself a directory */ + directory = getPath2(level_directory, dir_entry->d_name); + if (stat(directory, &file_status) != 0 || /* cannot stat file */ + (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ + { + free(directory); + continue; + } + + if (strlen(dir_entry->d_name) >= MAX_LEVDIR_FILENAME) + { + Error(ERR_WARN, "filename of level directory '%s' too long -- ignoring", + dir_entry->d_name); + continue; + } + + filename = getPath2(directory, LEVELINFO_FILENAME); + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list) + { + checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); + setLevelDirInfoToDefaults(&leveldir[current_entry]); + + ldi = leveldir[current_entry]; + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); + leveldir[current_entry] = ldi; + + leveldir[current_entry].filename = getStringCopy(dir_entry->d_name); + leveldir[current_entry].user_defined = + (level_directory == options.level_directory ? FALSE : TRUE); + + freeSetupFileList(setup_file_list); + current_entry++; + } + else + Error(ERR_WARN, "ignoring level directory '%s'", directory); + + free(directory); + free(filename); + } + + if (current_entry == MAX_LEVDIR_ENTRIES) + Error(ERR_WARN, "using %d level directories -- ignoring the rest", + current_entry); + + closedir(dir); + + if (current_entry == start_entry && start_entry != -1) + Error(ERR_EXIT, "cannot find any valid level series in directory '%s'", + level_directory); + + return current_entry; +} + +void LoadLevelInfo() +{ + InitUserLevelDirectory(getLoginName()); + + num_leveldirs = 0; + leveldir_nr = 0; + + num_leveldirs = LoadLevelInfoFromLevelDir(options.level_directory, + num_leveldirs); + num_leveldirs = LoadLevelInfoFromLevelDir(getUserLevelDir(""), + num_leveldirs); + if (num_leveldirs > 1) + qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo), + compareLevelDirInfoEntries); +} + +static void SaveUserLevelInfo() +{ + char filename[MAX_FILENAME_LEN]; + FILE *file; + int i; + + sprintf(filename, "%s/%s", + getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + + if (!(file = fopen(filename, "w"))) + { + Error(ERR_WARN, "cannot write level info file '%s'", filename); + return; + } + + ldi.name = getLoginName(); + ldi.levels = 100; + ldi.sort_priority = 300; + ldi.readonly = FALSE; + + fprintf(file, "%s\n\n", + getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); + + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + fprintf(file, "%s\n", getSetupLine("", i)); + + fclose(file); + + chmod(filename, SETUP_PERMS); +} + void LoadSetup() { char filename[MAX_FILENAME_LEN]; @@ -1001,7 +1215,7 @@ void LoadSetup() /* always start with reliable default setup values */ setSetupInfoToDefaults(&setup); - sprintf(filename, "%s/%s", SETUP_PATH, SETUP_FILENAME); + sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME); setup_file_list = loadSetupFileList(filename); @@ -1013,6 +1227,18 @@ void LoadSetup() setup.direct_draw = !setup.double_buffering; freeSetupFileList(setup_file_list); + + /* needed to work around problems with fixed length strings */ + if (strlen(setup.player_name) >= MAX_NAMELEN) + setup.player_name[MAX_NAMELEN - 1] = '\0'; + else if (strlen(setup.player_name) < MAX_NAMELEN - 1) + { + char *new_name = checked_malloc(MAX_NAMELEN); + + strcpy(new_name, setup.player_name); + free(setup.player_name); + setup.player_name = new_name; + } } else Error(ERR_WARN, "using default setup values"); @@ -1071,7 +1297,7 @@ static char *getSetupLine(char *prefix, int token_nr) break; case TYPE_STRING: - strcat(entry, (char *)setup_value); + strcat(entry, *(char **)setup_value); break; default: @@ -1087,7 +1313,9 @@ void SaveSetup() char filename[MAX_FILENAME_LEN]; FILE *file; - sprintf(filename, "%s/%s", SETUP_PATH, SETUP_FILENAME); + InitUserDataDirectory(); + + sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME); if (!(file = fopen(filename, "w"))) { @@ -1103,11 +1331,11 @@ void SaveSetup() si = setup; for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++) { + fprintf(file, "%s\n", getSetupLine("", i)); + /* just to make things nicer :) */ - if (i == SETUP_TOKEN_ALIAS_NAME) + if (i == SETUP_TOKEN_PLAYER_NAME) fprintf(file, "\n"); - - fprintf(file, "%s\n", getSetupLine("", i)); } /* handle player specific setup values */ @@ -1137,7 +1365,7 @@ void LoadLevelSetup() leveldir_nr = 0; level_nr = 0; - sprintf(filename, "%s/%s", SETUP_PATH, LEVELSETUP_FILENAME); + sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME); if (level_setup_list) freeSetupFileList(level_setup_list); @@ -1155,7 +1383,11 @@ void LoadLevelSetup() checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE); } else + { + level_setup_list = newSetupFileList(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE); Error(ERR_WARN, "using default setup values"); + } } void SaveLevelSetup() @@ -1164,13 +1396,15 @@ void SaveLevelSetup() struct SetupFileList *list_entry = level_setup_list; FILE *file; + InitUserDataDirectory(); + setTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename); setTokenValue(level_setup_list, leveldir[leveldir_nr].filename, int2str(level_nr, 0)); - sprintf(filename, "%s/%s", SETUP_PATH, LEVELSETUP_FILENAME); + sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME); if (!(file = fopen(filename, "w"))) { @@ -1178,9 +1412,8 @@ void SaveLevelSetup() return; } - fprintf(file, "%s: %s\n\n", - TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE); - + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE)); while (list_entry) { if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)