X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=884571eb3b4915e770bd52cbba1152ec490976cd;hb=2ae6ae8ed951e87fcba7c363705cd6ddea8de91c;hp=b3d280c64b8357cc40aabeb64d3225d05935dff4;hpb=370a25a79d2e8df1e6e3e4cb4be39496d0190c28;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index b3d280c6..884571eb 100644 --- a/src/files.c +++ b/src/files.c @@ -1,24 +1,24 @@ /*********************************************************** -* Rocks'n'Diamonds -- McDuffin Strikes Back! * +* Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* (c) 1995-98 Artsoft Entertainment * -* Holger Schemel * -* Oststrasse 11a * -* 33604 Bielefeld * -* phone: ++49 +521 290471 * -* email: aeglos@valinor.owl.de * +* (c) 1995-2000 Artsoft Entertainment * +* Holger Schemel * +* Detmolder Strasse 189 * +* 33604 Bielefeld * +* Germany * +* e-mail: info@artsoft.org * *----------------------------------------------------------* -* files.h * +* files.c * ***********************************************************/ #include #include #include -#include + +#include "libgame/libgame.h" #include "files.h" #include "tools.h" -#include "misc.h" #include "tape.h" #include "joystick.h" @@ -46,8 +46,7 @@ #define TAPE_COOKIE_10 "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0" /* file names and filename extensions */ -#ifndef MSDOS -#define USERDATA_DIRECTORY ".rocksndiamonds" +#if !defined(PLATFORM_MSDOS) #define LEVELSETUP_DIRECTORY "levelsetup" #define SETUP_FILENAME "setup.conf" #define LEVELSETUP_FILENAME "levelsetup.conf" @@ -56,7 +55,6 @@ #define TAPEFILE_EXTENSION "tape" #define SCOREFILE_EXTENSION "score" #else -#define USERDATA_DIRECTORY "userdata" #define LEVELSETUP_DIRECTORY "lvlsetup" #define SETUP_FILENAME "setup.cnf" #define LEVELSETUP_FILENAME "lvlsetup.cnf" @@ -64,14 +62,33 @@ #define LEVELFILE_EXTENSION "lvl" #define TAPEFILE_EXTENSION "tap" #define SCOREFILE_EXTENSION "sco" -#define ERROR_FILENAME "error.out" #endif +#if defined(PLATFORM_WIN32) +#ifndef S_IRGRP +#define S_IRGRP S_IRUSR +#endif +#ifndef S_IROTH +#define S_IROTH S_IRUSR +#endif +#ifndef S_IWGRP +#define S_IWGRP S_IWUSR +#endif +#ifndef S_IWOTH +#define S_IWOTH S_IWUSR +#endif +#ifndef S_IXGRP +#define S_IXGRP S_IXUSR +#endif +#ifndef S_IXOTH +#define S_IXOTH S_IXUSR +#endif +#endif /* PLATFORM_WIN32 */ + /* file permissions for newly written files */ #define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) #define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) #define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) -#define USERDATA_DIR_MODE (MODE_R_ALL | MODE_X_ALL | S_IWUSR) #define LEVEL_PERMS (MODE_R_ALL | MODE_W_ALL) #define SCORE_PERMS LEVEL_PERMS #define TAPE_PERMS LEVEL_PERMS @@ -187,21 +204,6 @@ char *getLevelClassDescription(struct LevelDirInfo *ldi) static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ -char *getUserDataDir() -{ - static char *userdata_dir = NULL; - - if (!userdata_dir) - { - char *home_dir = getHomeDir(); - char *data_dir = USERDATA_DIRECTORY; - - userdata_dir = getPath2(home_dir, data_dir); - } - - return userdata_dir; -} - static char *getSetupDir() { return getUserDataDir(); @@ -287,7 +289,7 @@ static char *getLevelFilename(int nr) filename = getPath3((leveldir_current->user_defined ? getUserLevelDir("") : options.level_directory), - leveldir_current->filename, + leveldir_current->fullpath, basename); return filename; @@ -321,18 +323,6 @@ static char *getScoreFilename(int nr) return filename; } -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(getUserDataDir(), "user data"); @@ -421,26 +411,37 @@ static void setLevelInfoToDefaults() switch (LEVELCLASS(leveldir_current)) { case LEVELCLASS_TUTORIAL: - strcpy(level.author, PROGRAM_AUTHOR_STRING); - break; + strcpy(level.author, PROGRAM_AUTHOR_STRING); + break; case LEVELCLASS_CONTRIBUTION: - strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN); - level.author[MAX_LEVEL_AUTHOR_LEN] = '\0'; - break; + strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN); + level.author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; case LEVELCLASS_USER: - strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN); - level.author[MAX_LEVEL_AUTHOR_LEN] = '\0'; - break; + strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN); + level.author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; default: - /* keep default value */ - break; + /* keep default value */ + break; } } } +static int checkLevelElement(int element) +{ + if (element >= EL_FIRST_RUNTIME_EL) + { + Error(ERR_WARN, "invalid level element %d", element); + element = EL_CHAR_FRAGE; + } + + return element; +} + void LoadLevel(int level_nr) { int i, x, y; @@ -510,7 +511,7 @@ void LoadLevel(int level_nr) for(x=0; x<3; x++) { if (i < STD_ELEMENT_CONTENTS) - level.yam_content[i][x][y] = fgetc(file); + level.yam_content[i][x][y] = checkLevelElement(fgetc(file)); else level.yam_content[i][x][y] = EL_LEERRAUM; } @@ -520,7 +521,7 @@ void LoadLevel(int level_nr) level.amoeba_speed = fgetc(file); level.time_magic_wall = fgetc(file); level.time_wheel = fgetc(file); - level.amoeba_content = fgetc(file); + level.amoeba_content = checkLevelElement(fgetc(file)); level.double_speed = (fgetc(file) == 1 ? TRUE : FALSE); level.gravity = (fgetc(file) == 1 ? TRUE : FALSE); @@ -566,9 +567,10 @@ void LoadLevel(int level_nr) for(y=0; y<3; y++) for(x=0; x<3; x++) level.yam_content[i][x][y] = - (encoding_16bit ? - getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) : - fgetc(file)); + checkLevelElement(encoding_16bit ? + getFile16BitInteger(file, + BYTE_ORDER_BIG_ENDIAN) : + fgetc(file)); getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN); } @@ -591,9 +593,9 @@ void LoadLevel(int level_nr) for(y=0; yfilename = NULL; + ldi->fullpath = NULL; + ldi->basepath = NULL; ldi->name = getStringCopy(ANONYMOUS_NAME); ldi->name_short = NULL; ldi->name_sorting = NULL; @@ -1412,11 +1420,55 @@ static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) ldi->first_level = 0; ldi->last_level = 0; ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ - ldi->readonly = TRUE; + ldi->level_group = FALSE; + ldi->parent_link = FALSE; ldi->user_defined = FALSE; + ldi->readonly = TRUE; ldi->color = 0; ldi->class_desc = NULL; ldi->handicap_level = 0; + ldi->cl_first = -1; + ldi->cl_cursor = -1; + + ldi->node_parent = NULL; + ldi->node_group = NULL; + ldi->next = NULL; +} + +static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi, + struct LevelDirInfo *parent) +{ + if (parent == NULL) + { + setLevelDirInfoToDefaults(ldi); + return; + } + + /* first copy all values from the parent structure ... */ + *ldi = *parent; + + /* ... then set all fields to default that cannot be inherited from parent. + This is especially important for all those fields that can be set from + the 'levelinfo.conf' config file, because the function 'setSetupInfo()' + calls 'free()' for all already set token values which requires that no + other structure's pointer may point to them! + */ + + ldi->filename = NULL; + ldi->fullpath = NULL; + ldi->basepath = NULL; + ldi->name = getStringCopy(ANONYMOUS_NAME); + ldi->name_short = NULL; + ldi->name_sorting = NULL; + ldi->author = getStringCopy(parent->author); + ldi->imported_from = getStringCopy(parent->imported_from); + + ldi->level_group = FALSE; + ldi->parent_link = FALSE; + + ldi->node_parent = parent; + ldi->node_group = NULL; + ldi->next = NULL; } static void setSetupInfoToDefaults(struct SetupInfo *si) @@ -1440,6 +1492,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->team_mode = FALSE; si->handicap = TRUE; si->time_limit = TRUE; + si->fullscreen = FALSE; for (i=0; iinput[i].joy.ylower = JOYSTICK_YLOWER; si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0); si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0); - si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KEY_UNDEFINDED); - si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED); - si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KEY_UNDEFINDED); - si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KEY_UNDEFINDED); - si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KEY_UNDEFINDED); - si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KEY_UNDEFINDED); + si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED); + si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED); + si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED); + si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED); + si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED); + si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED); } } @@ -1478,8 +1531,8 @@ static void setSetupInfo(int token_nr, char *token_value) *(boolean *)setup_value = get_string_boolean_value(token_value); break; - case TYPE_KEYSYM: - *(KeySym *)setup_value = getKeySymFromX11KeyName(token_value); + case TYPE_KEY: + *(Key *)setup_value = getKeyFromX11KeyName(token_value); break; case TYPE_INTEGER: @@ -1529,31 +1582,15 @@ static void decodeSetupFileList(struct SetupFileList *setup_file_list) } } -struct LevelDirInfo *getLevelDirInfoFromLevelDirName(char *level_dir_name) -{ - struct LevelDirInfo *leveldir_node = leveldir_first; - - if (level_dir_name == NULL) - return NULL; - - while (leveldir_node) - { - if (strcmp(level_dir_name, leveldir_node->name) == 0) - return leveldir_node; /* return success value */ - - leveldir_node = leveldir_node->next; - } - - return NULL; -} - static int compareLevelDirInfoEntries(const void *object1, const void *object2) { const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1); const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2); int compare_result; - if (entry1->sort_priority == entry2->sort_priority) + if (entry1->parent_link || entry2->parent_link) + compare_result = (entry1->parent_link ? -1 : +1); + else if (entry1->sort_priority == entry2->sort_priority) { char *name1 = getStringToLower(entry1->name_sorting); char *name2 = getStringToLower(entry2->name_sorting); @@ -1571,7 +1608,31 @@ static int compareLevelDirInfoEntries(const void *object1, const void *object2) return compare_result; } -static void LoadLevelInfoFromLevelDir(char *level_directory) +static void createParentLevelDirNode(struct LevelDirInfo *node_parent) +{ + struct LevelDirInfo *leveldir_new = newLevelDirInfo(); + + setLevelDirInfoToDefaults(leveldir_new); + + leveldir_new->node_parent = node_parent; + leveldir_new->parent_link = TRUE; + + leveldir_new->name = ".. (parent directory)"; + leveldir_new->name_short = getStringCopy(leveldir_new->name); + leveldir_new->name_sorting = getStringCopy(leveldir_new->name); + + leveldir_new->filename = ".."; + leveldir_new->fullpath = getStringCopy(node_parent->fullpath); + + leveldir_new->sort_priority = node_parent->sort_priority; + leveldir_new->class_desc = getLevelClassDescription(leveldir_new); + + pushLevelDirInfo(&node_parent->node_group, leveldir_new); +} + +static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first, + struct LevelDirInfo *node_parent, + char *level_directory) { DIR *dir; struct dirent *dir_entry; @@ -1585,26 +1646,29 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { + struct SetupFileList *setup_file_list = NULL; struct stat file_status; - char *directory = NULL; + char *directory_name = dir_entry->d_name; + char *directory_path = getPath2(level_directory, directory_name); char *filename = NULL; - struct SetupFileList *setup_file_list = NULL; /* skip entries for current and parent directory */ - if (strcmp(dir_entry->d_name, ".") == 0 || - strcmp(dir_entry->d_name, "..") == 0) + if (strcmp(directory_name, ".") == 0 || + strcmp(directory_name, "..") == 0) + { + free(directory_path); 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 */ + if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ { - free(directory); + free(directory_path); continue; } - filename = getPath2(directory, LEVELINFO_FILENAME); + filename = getPath2(directory_path, LEVELINFO_FILENAME); setup_file_list = loadSetupFileList(filename); if (setup_file_list) @@ -1613,8 +1677,9 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) int i; checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); - setLevelDirInfoToDefaults(leveldir_new); + setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent); + /* set all structure fields according to the token/value pairs */ ldi = *leveldir_new; for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); @@ -1628,7 +1693,19 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) if (leveldir_new->name_sorting == NULL) leveldir_new->name_sorting = getStringCopy(leveldir_new->name); - leveldir_new->filename = getStringCopy(dir_entry->d_name); + leveldir_new->filename = getStringCopy(directory_name); + + if (node_parent == NULL) /* top level group */ + { + leveldir_new->basepath = level_directory; + leveldir_new->fullpath = leveldir_new->filename; + } + else /* sub level group */ + { + leveldir_new->basepath = node_parent->basepath; + leveldir_new->fullpath = getPath2(node_parent->fullpath, + directory_name); + } if (leveldir_new->levels < 1) leveldir_new->levels = 1; @@ -1637,7 +1714,8 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) leveldir_new->first_level + leveldir_new->levels - 1; leveldir_new->user_defined = - (level_directory == options.level_directory ? FALSE : TRUE); + (leveldir_new->basepath == options.level_directory ? FALSE : TRUE); + leveldir_new->color = LEVELCOLOR(leveldir_new); leveldir_new->class_desc = getLevelClassDescription(leveldir_new); @@ -1646,15 +1724,25 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) leveldir_new->last_level : leveldir_new->first_level); - pushLevelDirInfo(leveldir_new); /* add new LevelDirInfo to list */ + pushLevelDirInfo(node_first, leveldir_new); freeSetupFileList(setup_file_list); valid_entry_found = TRUE; + + if (leveldir_new->level_group) + { + /* create node to link back to current level directory */ + createParentLevelDirNode(leveldir_new); + + /* step into sub-directory and look for more level series */ + LoadLevelInfoFromLevelDir(&leveldir_new->node_group, + leveldir_new, directory_path); + } } else - Error(ERR_WARN, "ignoring level directory '%s'", directory); + Error(ERR_WARN, "ignoring level directory '%s'", directory_path); - free(directory); + free(directory_path); free(filename); } @@ -1671,22 +1759,18 @@ void LoadLevelInfo() DrawInitText("Loading level series:", 120, FC_GREEN); - LoadLevelInfoFromLevelDir(options.level_directory); - LoadLevelInfoFromLevelDir(getUserLevelDir("")); + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir("")); - num_leveldirs = numLevelDirInfo(leveldir_first); - leveldir_current = leveldir_first; + leveldir_current = getFirstValidLevelSeries(leveldir_first); - if (num_leveldirs == 0) + if (leveldir_first == NULL) Error(ERR_EXIT, "cannot find any valid level series in any directory"); + sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); + #if 0 - if (num_leveldirs > 1) - qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo), - compareLevelDirInfoEntries); -#else - if (num_leveldirs > 1) - sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); + dumpLevelDirInfo(leveldir_first, 0); #endif } @@ -1793,12 +1877,12 @@ static char *getSetupLine(char *prefix, int token_nr) strcat(entry, (*(boolean *)setup_value ? "on" : "off")); break; - case TYPE_KEYSYM: + case TYPE_KEY: { - KeySym keysym = *(KeySym *)setup_value; - char *keyname = getKeyNameFromKeySym(keysym); + Key key = *(Key *)setup_value; + char *keyname = getKeyNameFromKey(key); - strcat(entry, getX11KeyNameFromKeySym(keysym)); + strcat(entry, getX11KeyNameFromKey(key)); for (i=strlen(entry); i<50; i++) strcat(entry, " "); @@ -1902,7 +1986,7 @@ void LoadLevelSetup_LastSeries() char *last_level_series = getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES); - leveldir_current = getLevelDirInfoFromLevelDirName(last_level_series); + leveldir_current = getLevelDirInfoFromFilename(last_level_series); if (leveldir_current == NULL) leveldir_current = leveldir_first; @@ -1959,7 +2043,7 @@ static void checkSeriesInfo() level_directory = getPath2((leveldir_current->user_defined ? getUserLevelDir("") : options.level_directory), - leveldir_current->filename); + leveldir_current->fullpath); if ((dir = opendir(level_directory)) == NULL) { @@ -2094,46 +2178,3 @@ void SaveLevelSetup_SeriesInfo() chmod(filename, SETUP_PERMS); } - -#ifdef MSDOS -void initErrorFile() -{ - char *filename; - - InitUserDataDirectory(); - - filename = getPath2(getUserDataDir(), ERROR_FILENAME); - unlink(filename); - free(filename); -} - -FILE *openErrorFile() -{ - char *filename; - FILE *error_file; - - filename = getPath2(getUserDataDir(), ERROR_FILENAME); - error_file = fopen(filename, "a"); - free(filename); - - return error_file; -} - -void dumpErrorFile() -{ - char *filename; - FILE *error_file; - - filename = getPath2(getUserDataDir(), ERROR_FILENAME); - error_file = fopen(filename, "r"); - free(filename); - - if (error_file != NULL) - { - while (!feof(error_file)) - fputc(fgetc(error_file), stderr); - - fclose(error_file); - } -} -#endif