-/***********************************************************
-* Artsoft Retro-Game Library *
-*----------------------------------------------------------*
-* (c) 1994-2006 Artsoft Entertainment *
-* Holger Schemel *
-* Detmolder Strasse 189 *
-* 33604 Bielefeld *
-* Germany *
-* e-mail: info@artsoft.org *
-*----------------------------------------------------------*
-* setup.c *
-***********************************************************/
+// ============================================================================
+// Artsoft Retro-Game Library
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+// Holger Schemel
+// info@artsoft.org
+// http://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// setup.c
+// ============================================================================
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "platform.h"
#include "hash.h"
+#define USE_FILE_IDENTIFIERS FALSE /* do not use identifiers anymore */
+#define ENABLE_UNUSED_CODE FALSE /* for currently unused functions */
+
#define NUM_LEVELCLASS_DESC 8
static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
checked_free(*artwork_set_ptr);
- if (fileExists(dir))
+ if (directoryExists(dir))
{
*artwork_path_ptr = getStringCopy(getClassicArtworkDir(ti->type));
*artwork_set_ptr = getStringCopy(getClassicArtworkSet(ti->type));
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;
}
static char *getCorrectedArtworkBasename(char *basename)
{
- char *basename_corrected = basename;
-
-#if defined(PLATFORM_MSDOS)
- if (program.filename_prefix != NULL)
- {
- int prefix_len = strlen(program.filename_prefix);
-
- if (strncmp(basename, program.filename_prefix, prefix_len) == 0)
- basename_corrected = &basename[prefix_len];
-
- /* if corrected filename is still longer than standard MS-DOS filename
- size (8 characters + 1 dot + 3 characters file extension), shorten
- filename by writing file extension after 8th basename character */
- if (strlen(basename_corrected) > 8 + 1 + 3)
- {
- static char *msdos_filename = NULL;
-
- checked_free(msdos_filename);
-
- msdos_filename = getStringCopy(basename_corrected);
- strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1);
-
- basename_corrected = msdos_filename;
- }
- }
-#endif
-
- return basename_corrected;
+ return basename;
}
char *getCustomImageFilename(char *basename)
if (!gfx.override_level_graphics)
{
/* 1st try: look for special artwork in current level series directory */
- filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
+ filename = getImg3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
if (fileExists(filename))
return filename;
if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL)
{
/* 2nd try: look for special artwork configured in level series config */
- filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
+ filename = getImg2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
if (fileExists(filename))
return filename;
if (!skip_setup_artwork)
{
/* 3rd try: look for special artwork in configured artwork directory */
- filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
+ filename = getImg2(getSetupArtworkDir(artwork.gfx_current), basename);
if (fileExists(filename))
return filename;
}
/* 4th try: look for default artwork in new default artwork directory */
- filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename);
+ filename = getImg2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename);
if (fileExists(filename))
return filename;
free(filename);
/* 5th try: look for default artwork in old default artwork directory */
- filename = getPath2(options.graphics_directory, basename);
+ filename = getImg2(options.graphics_directory, basename);
if (fileExists(filename))
return filename;
/* 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.graphics_directory, GFX_FALLBACK_FILENAME);
+ filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME);
if (fileExists(filename))
return filename;
#endif
{
/* 1st try: look for special artwork in current level series directory */
directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
- if (fileExists(directory))
+ if (directoryExists(directory))
return directory;
free(directory);
{
/* 2nd try: look for special artwork configured in level series config */
directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
- if (fileExists(directory))
+ if (directoryExists(directory))
return directory;
free(directory);
{
/* 3rd try: look for special artwork in configured artwork directory */
directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
- if (fileExists(directory))
+ if (directoryExists(directory))
return directory;
free(directory);
/* 4th try: look for default artwork in new default artwork directory */
directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR));
- if (fileExists(directory))
+ if (directoryExists(directory))
return directory;
free(directory);
/* 5th try: look for default artwork in old default artwork directory */
directory = getStringCopy(options.music_directory);
- if (fileExists(directory))
+ if (directoryExists(directory))
return directory;
return NULL; /* cannot find specified artwork file anywhere */
void InitUserLevelDirectory(char *level_subdir)
{
- if (!fileExists(getUserLevelDir(level_subdir)))
+ if (!directoryExists(getUserLevelDir(level_subdir)))
{
createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
return cloneTreeNode(node_top, node_parent, node->next,
skip_sets_without_levels);
-#if 1
node_new = getTreeInfoCopy(node); /* copy complete node */
-#else
- node_new = newTreeInfo();
-
- *node_new = *node; /* copy complete node */
-#endif
node_new->node_top = node_top; /* correct top node link */
node_new->node_parent = node_parent; /* correct parent node link */
for (i = 0; i < (depth + 1) * 3; i++)
printf(" ");
+ printf("'%s' / '%s'\n", node->identifier, node->name);
+
+ /*
+ // use for dumping artwork info tree
printf("subdir == '%s' ['%s', '%s'] [%d])\n",
node->subdir, node->fullpath, node->basepath, node->in_user_dir);
+ */
if (node->node_group != NULL)
dumpTreeInfo(node->node_group, depth + 1);
{
static char *user_game_data_dir = NULL;
+#if defined(PLATFORM_ANDROID)
+ if (user_game_data_dir == NULL)
+ user_game_data_dir = (char *)SDL_AndroidGetInternalStoragePath();
+#else
if (user_game_data_dir == NULL)
user_game_data_dir = getPath2(getPersonalDataDir(),
program.userdata_subdir);
+#endif
return user_game_data_dir;
}
char *userdata_dir_new = getUserGameDataDir(); /* do not free() this */
/* convert old Unix style game data directory to Mac OS X style, if needed */
- if (fileExists(userdata_dir_old) && !fileExists(userdata_dir_new))
+ if (directoryExists(userdata_dir_old) && !directoryExists(userdata_dir_new))
{
if (rename(userdata_dir_old, userdata_dir_new) != 0)
{
else
dir_mode |= MODE_W_ALL;
- if (!fileExists(dir))
+ if (!directoryExists(dir))
if (posix_mkdir(dir, dir_mode) != 0)
- Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
+ Error(ERR_WARN, "cannot create %s directory '%s': %s",
+ text, dir, strerror(errno));
if (permission_class == PERMS_PUBLIC && !running_setgid)
chmod(dir, dir_mode);
return addListEntry(list->next, token, value);
}
+#if ENABLE_UNUSED_CODE
#ifdef DEBUG
static void printSetupFileList(SetupFileList *list)
{
printSetupFileList(list->next);
}
#endif
+#endif
#ifdef DEBUG
DEFINE_HASHTABLE_INSERT(insert_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
return remove_hash_entry(hash, token);
}
-#if 0
+#if ENABLE_UNUSED_CODE
+#if DEBUG
static void printSetupFileHash(SetupFileHash *hash)
{
BEGIN_HASH_ITERATION(hash, itr)
END_HASH_ITERATION(hash, itr)
}
#endif
+#endif
#define ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE 1
#define CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING 0
/* find end of token to determine start of value */
for (line_ptr = token; *line_ptr; line_ptr++)
{
-#if 1
/* first look for an explicit token/value separator, like ':' or '=' */
if (*line_ptr == ':' || *line_ptr == '=')
-#else
- if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
-#endif
{
*line_ptr = '\0'; /* terminate token string */
value = line_ptr + 1; /* set beginning of value */
if (*value != ' ' && *value != '\t')
break;
-#if 0
- if (*value == '\0')
- value = "true"; /* treat tokens without value as "true" */
-#endif
-
*token_ptr = token;
*value_ptr = value;
return getTokenValueFromSetupLineExt(line, token, value, NULL, NULL, 0, TRUE);
}
-#if 1
static boolean loadSetupFileData(void *setup_file_data, char *filename,
boolean top_recursion_level, boolean is_hash)
{
char *token, *value, *line_ptr;
void *insert_ptr = NULL;
boolean read_continued_line = FALSE;
- FILE *file;
+ File *file;
int line_nr = 0, token_count = 0, include_count = 0;
#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
token_already_exists_warning = FALSE;
#endif
- if (!(file = fopen(filename, MODE_READ)))
+ if (!(file = openFile(filename, MODE_READ)))
{
Error(ERR_WARN, "cannot open configuration file '%s'", filename);
/* mark this file as already included (to prevent including it again) */
setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true");
- while (!feof(file))
+ while (!checkEndOfFile(file))
{
/* read next line of input file */
- if (!fgets(line, MAX_LINE_LEN, file))
+ if (!getStringFromFile(file, line, MAX_LINE_LEN))
break;
/* check if line was completely read and is terminated by line break */
if (read_continued_line)
{
-#if 0
- /* !!! ??? WHY ??? !!! */
- /* cut leading whitespaces from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- if (*line_ptr != ' ' && *line_ptr != '\t')
- break;
-#endif
-
/* append new line to existing line, if there is enough space */
if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
strcat(previous_line, line_ptr);
char *basename = getBaseName(value);
char *filename_include = getPath2(basepath, basename);
-#if 0
- Error(ERR_INFO, "[including file '%s']", filename_include);
-#endif
-
loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash);
free(basepath);
}
}
- fclose(file);
+ closeFile(file);
#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
if (token_value_separator_warning)
return TRUE;
}
-#else
-
-static boolean loadSetupFileData(void *setup_file_data, char *filename,
- boolean top_recursion_level, boolean is_hash)
-{
- static SetupFileHash *include_filename_hash = NULL;
- char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
- char *token, *value, *line_ptr;
- void *insert_ptr = NULL;
- boolean read_continued_line = FALSE;
- FILE *file;
- int line_nr = 0;
- int token_count = 0;
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- token_value_separator_warning = FALSE;
-#endif
-
- if (!(file = fopen(filename, MODE_READ)))
- {
- Error(ERR_WARN, "cannot open configuration file '%s'", filename);
-
- return FALSE;
- }
-
- /* use "insert pointer" to store list end for constant insertion complexity */
- if (!is_hash)
- insert_ptr = setup_file_data;
-
- /* on top invocation, create hash to mark included files (to prevent loops) */
- if (top_recursion_level)
- include_filename_hash = newSetupFileHash();
-
- /* mark this file as already included (to prevent including it again) */
- setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true");
-
- while (!feof(file))
- {
- /* read next line of input file */
- if (!fgets(line, MAX_LINE_LEN, file))
- break;
-
- /* check if line was completely read and is terminated by line break */
- if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
- line_nr++;
-
- /* cut trailing line break (this can be newline and/or carriage return) */
- for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
- if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* copy raw input line for later use (mainly debugging output) */
- strcpy(line_raw, line);
-
- if (read_continued_line)
- {
- /* cut leading whitespaces from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- if (*line_ptr != ' ' && *line_ptr != '\t')
- break;
-
- /* append new line to existing line, if there is enough space */
- if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
- strcat(previous_line, line_ptr);
-
- strcpy(line, previous_line); /* copy storage buffer to line */
-
- read_continued_line = FALSE;
- }
-
- /* if the last character is '\', continue at next line */
- if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
- {
- line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */
- strcpy(previous_line, line); /* copy line to storage buffer */
-
- read_continued_line = TRUE;
-
- continue;
- }
-
- /* cut trailing comment from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- {
- if (*line_ptr == '#')
- {
- *line_ptr = '\0';
- break;
- }
- }
-
- /* cut trailing whitespaces from input line */
- for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
- if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* ignore empty lines */
- if (*line == '\0')
- continue;
-
- /* cut leading whitespaces from token */
- for (token = line; *token; token++)
- if (*token != ' ' && *token != '\t')
- break;
-
- /* start with empty value as reliable default */
- value = "";
-
- token_value_separator_found = FALSE;
-
- /* find end of token to determine start of value */
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
-#if 1
- /* first look for an explicit token/value separator, like ':' or '=' */
- if (*line_ptr == ':' || *line_ptr == '=')
-#else
- if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
-#endif
- {
- *line_ptr = '\0'; /* terminate token string */
- value = line_ptr + 1; /* set beginning of value */
-
- token_value_separator_found = TRUE;
-
- break;
- }
- }
-
-#if ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE
- /* fallback: if no token/value separator found, also allow whitespaces */
- if (!token_value_separator_found)
- {
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
- if (*line_ptr == ' ' || *line_ptr == '\t')
- {
- *line_ptr = '\0'; /* terminate token string */
- value = line_ptr + 1; /* set beginning of value */
-
- token_value_separator_found = TRUE;
-
- break;
- }
- }
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- if (token_value_separator_found)
- {
- if (!token_value_separator_warning)
- {
- Error(ERR_INFO_LINE, "-");
- Error(ERR_WARN, "missing token/value separator(s) in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
-
- token_value_separator_warning = TRUE;
- }
-
- Error(ERR_INFO, "- line %d: '%s'", line_nr, line_raw);
- }
-#endif
- }
-#endif
-
- /* cut trailing whitespaces from token */
- for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--)
- if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* cut leading whitespaces from value */
- for (; *value; value++)
- if (*value != ' ' && *value != '\t')
- break;
-
-#if 0
- if (*value == '\0')
- value = "true"; /* treat tokens without value as "true" */
-#endif
-
- if (*token)
- {
- if (strEqual(token, "include"))
- {
- if (getHashEntry(include_filename_hash, value) == NULL)
- {
- char *basepath = getBasePath(filename);
- char *basename = getBaseName(value);
- char *filename_include = getPath2(basepath, basename);
-
-#if 0
- Error(ERR_INFO, "[including file '%s']", filename_include);
-#endif
-
- loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash);
-
- free(basepath);
- free(basename);
- free(filename_include);
- }
- else
- {
- Error(ERR_WARN, "ignoring already processed file '%s'", value);
- }
- }
- else
- {
- if (is_hash)
- setHashEntry((SetupFileHash *)setup_file_data, token, value);
- else
- insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value);
-
- token_count++;
- }
- }
- }
-
- fclose(file);
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- if (token_value_separator_warning)
- Error(ERR_INFO_LINE, "-");
-#endif
-
- if (token_count == 0)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
- if (top_recursion_level)
- freeSetupFileHash(include_filename_hash);
-
- return TRUE;
-}
-#endif
-
void saveSetupFileHash(SetupFileHash *hash, char *filename)
{
FILE *file;
void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
char *filename, char *identifier)
{
+#if USE_FILE_IDENTIFIERS
char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER);
if (value == NULL)
Error(ERR_WARN, "config file '%s' has no file identifier", filename);
else if (!checkCookieString(value, identifier))
Error(ERR_WARN, "config file '%s' has wrong file identifier", filename);
+#endif
}
ti->last_level = 0;
ti->level_group = FALSE;
ti->handicap_level = 0;
- ti->readonly = TRUE;
+ ti->readonly = parent->readonly;
ti->handicap = TRUE;
ti->skip_levels = FALSE;
}
return ti_copy;
}
-static void freeTreeInfo(TreeInfo *ti)
+void freeTreeInfo(TreeInfo *ti)
{
if (ti == NULL)
return;
checked_free(ti->special_flags);
}
+ // recursively free child node
+ if (ti->node_group)
+ freeTreeInfo(ti->node_group);
+
+ // recursively free next node
+ if (ti->next)
+ freeTreeInfo(ti->next);
+
checked_free(ti);
}
{
const TreeInfo *entry1 = *((TreeInfo **)object1);
const TreeInfo *entry2 = *((TreeInfo **)object2);
- int class_sorting1, class_sorting2;
+ int class_sorting1 = 0, class_sorting2 = 0;
int compare_result;
if (entry1->type == TREE_TYPE_LEVEL_DIR)
class_sorting1 = LEVELSORTING(entry1);
class_sorting2 = LEVELSORTING(entry2);
}
- else
+ else if (entry1->type == TREE_TYPE_GRAPHICS_DIR ||
+ entry1->type == TREE_TYPE_SOUNDS_DIR ||
+ entry1->type == TREE_TYPE_MUSIC_DIR)
{
class_sorting1 = ARTWORKSORTING(entry1);
class_sorting2 = ARTWORKSORTING(entry2);
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)
/* check if cache entry for this item is invalid or incomplete */
if (value == NULL)
{
-#if 1
Error(ERR_WARN, "cache entry '%s' invalid", token);
-#endif
cached = FALSE;
}
if (modifiedFileTimestamp(filename_artworkinfo, cache_entry))
cached = FALSE;
-#if 0
- if (!cached)
- printf("::: '%s': INVALIDATED FROM CACHE BY TIMESTAMP\n", identifier);
-#endif
-
checked_free(filename_levelinfo);
checked_free(filename_artworkinfo);
}
char *level_directory,
char *directory_name)
{
-#if 0
- static unsigned long progress_delay = 0;
- unsigned long progress_delay_value = 100; /* (in milliseconds) */
-#endif
char *directory_path = getPath2(level_directory, directory_name);
char *filename = getPath2(directory_path, LEVELINFO_FILENAME);
SetupFileHash *setup_file_hash;
leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
}
-#if 0
- if (leveldir_new->levels < 1)
- leveldir_new->levels = 1;
-#endif
-
leveldir_new->last_level =
leveldir_new->first_level + leveldir_new->levels - 1;
(leveldir_new->user_defined || !leveldir_new->handicap ?
leveldir_new->last_level : leveldir_new->first_level);
-#if 1
-#if 1
- DrawInitTextExt(leveldir_new->name, 150, FC_YELLOW,
- leveldir_new->level_group);
-#else
- if (leveldir_new->level_group ||
- DelayReached(&progress_delay, progress_delay_value))
- DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-#endif
-#else
DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-#endif
-
-#if 0
- /* !!! don't skip sets without levels (else artwork base sets are missing) */
-#if 1
- if (leveldir_new->levels < 1 && !leveldir_new->level_group)
- {
- /* skip level sets without levels (which are probably artwork base sets) */
-
- freeSetupFileHash(setup_file_hash);
- free(directory_path);
- free(filename);
-
- return FALSE;
- }
-#endif
-#endif
pushTreeInfo(node_first, leveldir_new);
TreeInfo *node_parent,
char *level_directory)
{
- DIR *dir;
- struct dirent *dir_entry;
+ Directory *dir;
+ DirectoryEntry *dir_entry;
boolean valid_entry_found = FALSE;
- if ((dir = opendir(level_directory)) == NULL)
+ if ((dir = openDirectory(level_directory)) == NULL)
{
Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+
return;
}
- while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
+ while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */
{
- struct stat file_status;
- char *directory_name = dir_entry->d_name;
+ char *directory_name = dir_entry->basename;
char *directory_path = getPath2(level_directory, directory_name);
/* skip entries for current and parent directory */
strEqual(directory_name, ".."))
{
free(directory_path);
+
continue;
}
/* find out if directory entry is itself a directory */
- if (stat(directory_path, &file_status) != 0 || /* cannot stat file */
- (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */
+ if (!dir_entry->is_directory) /* not a directory */
{
free(directory_path);
+
continue;
}
directory_name);
}
- closedir(dir);
+ closeDirectory(dir);
/* special case: top level directory may directly contain "levelinfo.conf" */
if (node_parent == NULL && !valid_entry_found)
sortTreeInfo(&leveldir_first);
-#if 0
+#if ENABLE_UNUSED_CODE
dumpTreeInfo(leveldir_first, 0);
#endif
}
if (setup_file_hash == NULL) /* no config file -- look for artwork files */
{
- DIR *dir;
- struct dirent *dir_entry;
+ Directory *dir;
+ DirectoryEntry *dir_entry;
boolean valid_file_found = FALSE;
- if ((dir = opendir(directory_path)) != NULL)
+ if ((dir = openDirectory(directory_path)) != NULL)
{
- while ((dir_entry = readdir(dir)) != NULL)
+ while ((dir_entry = readDirectory(dir)) != NULL)
{
- char *entry_name = dir_entry->d_name;
-
- if (FileIsArtworkType(entry_name, type))
+ if (FileIsArtworkType(dir_entry->filename, type))
{
valid_file_found = TRUE;
+
break;
}
}
- closedir(dir);
+ closeDirectory(dir);
}
if (!valid_file_found)
if (setup_file_hash) /* (before defining ".color" and ".class_desc") */
{
-#if 0
- checkSetupFileHashIdentifier(setup_file_hash, filename, getCookie("..."));
-#endif
-
/* set all structure fields according to the token/value pairs */
ldi = *artwork_new;
for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
setString(&artwork_new->name_sorting, artwork_new->name);
}
-#if 0
- DrawInitText(artwork_new->name, 150, FC_YELLOW);
-#endif
-
pushTreeInfo(node_first, artwork_new);
freeSetupFileHash(setup_file_hash);
TreeInfo *node_parent,
char *base_directory, int type)
{
- DIR *dir;
- struct dirent *dir_entry;
+ Directory *dir;
+ DirectoryEntry *dir_entry;
boolean valid_entry_found = FALSE;
- if ((dir = opendir(base_directory)) == NULL)
+ if ((dir = openDirectory(base_directory)) == NULL)
{
/* display error if directory is main "options.graphics_directory" etc. */
if (base_directory == OPTIONS_ARTWORK_DIRECTORY(type))
return;
}
- while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
+ while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */
{
- struct stat file_status;
- char *directory_name = dir_entry->d_name;
+ char *directory_name = dir_entry->basename;
char *directory_path = getPath2(base_directory, directory_name);
/* skip directory entries for current and parent directory */
strEqual(directory_name, ".."))
{
free(directory_path);
+
continue;
}
- /* skip directory entries which are not a directory or are not accessible */
- if (stat(directory_path, &file_status) != 0 || /* cannot stat file */
- (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */
+ /* skip directory entries which are not a directory */
+ if (!dir_entry->is_directory) /* not a directory */
{
free(directory_path);
+
continue;
}
directory_name, type);
}
- closedir(dir);
+ closeDirectory(dir);
/* check if this directory directly contains artwork itself */
valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent,
artwork.snd_current_identifier = artwork.snd_current->identifier;
artwork.mus_current_identifier = artwork.mus_current->identifier;
-#if 0
+#if ENABLE_UNUSED_CODE
printf("graphics set == %s\n\n", artwork.gfx_current_identifier);
printf("sounds set == %s\n\n", artwork.snd_current_identifier);
printf("music set == %s\n\n", artwork.mus_current_identifier);
sortTreeInfo(&artwork.snd_first);
sortTreeInfo(&artwork.mus_first);
-#if 0
+#if ENABLE_UNUSED_CODE
dumpTreeInfo(artwork.gfx_first, 0);
dumpTreeInfo(artwork.snd_first, 0);
dumpTreeInfo(artwork.mus_first, 0);
void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
LevelDirTree *level_node)
{
-#if 0
- static unsigned long progress_delay = 0;
- unsigned long progress_delay_value = 100; /* (in milliseconds) */
-#endif
int type = (*artwork_node)->type;
/* recursively check all level directories for artwork sub-directories */
setArtworkInfoCacheEntry(artwork_new, level_node, type);
}
-#if 1
- DrawInitTextExt(level_node->name, 150, FC_YELLOW,
- level_node->level_group);
-#else
- if (level_node->level_group ||
- DelayReached(&progress_delay, progress_delay_value))
- DrawInitText(level_node->name, 150, FC_YELLOW);
-#endif
+ DrawInitText(level_node->name, 150, FC_YELLOW);
if (level_node->node_group != NULL)
LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group);
void LoadLevelArtworkInfo()
{
+ print_timestamp_init("LoadLevelArtworkInfo");
+
DrawInitText("Looking for custom level artwork", 120, FC_GREEN);
+ print_timestamp_time("DrawTimeText");
+
LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all);
+ print_timestamp_time("LoadArtworkInfoFromLevelInfo (gfx)");
LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all);
+ print_timestamp_time("LoadArtworkInfoFromLevelInfo (snd)");
LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all);
+ print_timestamp_time("LoadArtworkInfoFromLevelInfo (mus)");
SaveArtworkInfoCache();
+ print_timestamp_time("SaveArtworkInfoCache");
+
/* needed for reloading level artwork not known at ealier stage */
if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set))
artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
}
+ print_timestamp_time("getTreeInfoFromIdentifier");
+
sortTreeInfo(&artwork.gfx_first);
sortTreeInfo(&artwork.snd_first);
sortTreeInfo(&artwork.mus_first);
-#if 0
+ print_timestamp_time("sortTreeInfo");
+
+#if ENABLE_UNUSED_CODE
dumpTreeInfo(artwork.gfx_first, 0);
dumpTreeInfo(artwork.snd_first, 0);
dumpTreeInfo(artwork.mus_first, 0);
#endif
+
+ print_timestamp_done("LoadLevelArtworkInfo");
}
static void SaveUserLevelInfo()
free(filename);
}
-void SaveLevelSetup_LastSeries()
+static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series)
{
/* ----------------------------------------------------------------------- */
/* ~/.<program>/levelsetup.conf */
/* ----------------------------------------------------------------------- */
+ // check if the current level directory structure is available at this point
+ if (leveldir_current == NULL)
+ return;
+
char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
char *level_subdir = leveldir_current->subdir;
FILE *file;
if (!(file = fopen(filename, MODE_WRITE)))
{
Error(ERR_WARN, "cannot write setup file '%s'", filename);
+
free(filename);
+
return;
}
fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
getCookie("LEVELSETUP")));
+
+ if (deactivate_last_level_series)
+ fprintf(file, "# %s\n# ", "the following level set may have caused a problem and was deactivated");
+
fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
level_subdir));
free(filename);
}
+void SaveLevelSetup_LastSeries()
+{
+ SaveLevelSetup_LastSeries_Ext(FALSE);
+}
+
+void SaveLevelSetup_LastSeries_Deactivate()
+{
+ SaveLevelSetup_LastSeries_Ext(TRUE);
+}
+
static void checkSeriesInfo()
{
static char *level_directory = NULL;
- DIR *dir;
- struct dirent *dir_entry;
+ Directory *dir;
/* check for more levels besides the 'levels' field of 'levelinfo.conf' */
options.level_directory),
leveldir_current->fullpath);
- if ((dir = opendir(level_directory)) == NULL)
+ if ((dir = openDirectory(level_directory)) == NULL)
{
Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
- return;
- }
-
- while ((dir_entry = readdir(dir)) != NULL) /* last directory entry */
- {
- if (strlen(dir_entry->d_name) > 4 &&
- dir_entry->d_name[3] == '.' &&
- strEqual(&dir_entry->d_name[4], LEVELFILE_EXTENSION))
- {
- char levelnum_str[4];
- int levelnum_value;
-
- strncpy(levelnum_str, dir_entry->d_name, 3);
- levelnum_str[3] = '\0';
-
- levelnum_value = atoi(levelnum_str);
-#if 0
- if (levelnum_value < leveldir_current->first_level)
- {
- Error(ERR_WARN, "additional level %d found", levelnum_value);
- leveldir_current->first_level = levelnum_value;
- }
- else if (levelnum_value > leveldir_current->last_level)
- {
- Error(ERR_WARN, "additional level %d found", levelnum_value);
- leveldir_current->last_level = levelnum_value;
- }
-#endif
- }
+ return;
}
- closedir(dir);
+ closeDirectory(dir);
}
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);
/* ----------------------------------------------------------------------- */
{
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)
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)
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"));
char *level_nr_str = int2str(level_nr, 0);
char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
FILE *file;
+ int i;
/* ----------------------------------------------------------------------- */
/* ~/.<program>/levelsetup/<level series>/levelsetup.conf */
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);
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++;
+}