#define MAX_COOKIE_LEN 256
+
static void setTreeInfoToDefaults(TreeInfo *, int);
static int compareTreeInfoEntries(const void *, const void *);
static int token_value_position = TOKEN_VALUE_POSITION_DEFAULT;
static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT;
-static SetupFileHash *artworkinfo_hash = NULL;
+static SetupFileHash *artworkinfo_cache_old = NULL;
+static SetupFileHash *artworkinfo_cache_new = NULL;
+static boolean use_artworkinfo_cache = TRUE;
/* ------------------------------------------------------------------------- */
return levelsetup_dir;
}
+static char *getCacheDir()
+{
+ static char *cache_dir = NULL;
+
+ if (cache_dir == NULL)
+ cache_dir = getPath2(getUserGameDataDir(), CACHE_DIRECTORY);
+
+ return cache_dir;
+}
+
static char *getLevelDirFromTreeInfo(TreeInfo *node)
{
static char *level_dir = NULL;
{
createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
- createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE);
+ createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
SaveUserLevelInfo();
}
{
createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE);
- createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
+ createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE);
+}
+
+void InitCacheDirectory()
+{
+ createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
+ createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
}
/* find end of token to determine start of value */
for (line_ptr = token; *line_ptr; line_ptr++)
{
+#if 1
+ 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 */
}
}
+ /* 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')
static void freeTreeInfo(TreeInfo *ti)
{
+ if (ti == NULL)
+ return;
+
checked_free(ti->subdir);
checked_free(ti->fullpath);
checked_free(ti->basepath);
checked_free(ti->level_filename);
checked_free(ti->level_filetype);
}
+
+ checked_free(ti);
}
void setSetupInfo(struct TokenInfo *token_info,
/* -------------------------------------------------------------------------- */
-/* functions for handling custom artwork info cache */
+/* functions for handling level and custom artwork info cache */
/* -------------------------------------------------------------------------- */
-#define ARTWORKINFO_CACHE_FILENAME "cache.conf"
-
static void LoadArtworkInfoCache()
{
- if (artworkinfo_hash == NULL)
+ InitCacheDirectory();
+
+ if (artworkinfo_cache_old == NULL)
{
- char *filename = getPath2(getSetupDir(), ARTWORKINFO_CACHE_FILENAME);
+ char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE);
/* try to load artwork info hash from already existing cache file */
- artworkinfo_hash = loadSetupFileHash(filename);
+ artworkinfo_cache_old = loadSetupFileHash(filename);
/* if no artwork info cache file was found, start with empty hash */
- if (artworkinfo_hash == NULL)
- artworkinfo_hash = newSetupFileHash();
+ if (artworkinfo_cache_old == NULL)
+ artworkinfo_cache_old = newSetupFileHash();
free(filename);
}
+
+ if (artworkinfo_cache_new == NULL)
+ artworkinfo_cache_new = newSetupFileHash();
}
static void SaveArtworkInfoCache()
{
- char *filename = getPath2(getSetupDir(), ARTWORKINFO_CACHE_FILENAME);
+ char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE);
+
+ InitCacheDirectory();
- saveSetupFileHash(artworkinfo_hash, filename);
+ saveSetupFileHash(artworkinfo_cache_new, filename);
free(filename);
}
-static TreeInfo *getArtworkInfoFromCache(char *identifier, int type)
+static char *getCacheTokenPrefix(char *prefix1, char *prefix2)
+{
+ static char *prefix = NULL;
+
+ checked_free(prefix);
+
+ prefix = getStringCat2WithSeparator(prefix1, prefix2, ".");
+
+ return prefix;
+}
+
+/* (identical to above function, but separate string buffer needed -- nasty) */
+static char *getCacheToken(char *prefix, char *suffix)
+{
+ static char *token = NULL;
+
+ checked_free(token);
+
+ token = getStringCat2WithSeparator(prefix, suffix, ".");
+
+ return token;
+}
+
+static char *getFileTimestamp(char *filename)
+{
+ 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));
+}
+
+static boolean modifiedFileTimestamp(char *filename, char *timestamp_string)
+{
+ struct stat file_status;
+
+ if (timestamp_string == NULL)
+ return TRUE;
+
+ if (stat(filename, &file_status) != 0) /* cannot stat file */
+ return TRUE;
+
+ return (file_status.st_mtime != atoi(timestamp_string));
+}
+
+static TreeInfo *getArtworkInfoCacheEntry(LevelDirTree *level_node, int type)
{
+ char *identifier = level_node->subdir;
char *type_string = ARTWORK_DIRECTORY(type);
- char *token_prefix = getStringCat2WithSeparator(type_string, identifier, ".");
- char *cache_entry = getHashEntry(artworkinfo_hash, token_prefix);
+ char *token_prefix = getCacheTokenPrefix(type_string, identifier);
+ char *token_main = getCacheToken(token_prefix, "CACHED");
+ char *cache_entry = getHashEntry(artworkinfo_cache_old, token_main);
boolean cached = (cache_entry != NULL && strEqual(cache_entry, "true"));
- TreeInfo *artwork_new = NULL;
+ TreeInfo *artwork_info = NULL;
+
+ if (!use_artworkinfo_cache)
+ return NULL;
if (cached)
{
int i;
- printf("::: LOADING existing hash entry for '%s' ...\n", identifier);
-
- artwork_new = newTreeInfo();
- setTreeInfoToDefaults(artwork_new, type);
+ artwork_info = newTreeInfo();
+ setTreeInfoToDefaults(artwork_info, type);
/* set all structure fields according to the token/value pairs */
- ldi = *artwork_new;
+ ldi = *artwork_info;
for (i = 0; artworkinfo_tokens[i].type != -1; i++)
{
- char *token = getStringCat2WithSeparator(token_prefix,
- artworkinfo_tokens[i].text, ".");
- char *value = getHashEntry(artworkinfo_hash, token);
-
- printf("::: - setting '%s' => '%s'\n", token, value);
+ char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text);
+ char *value = getHashEntry(artworkinfo_cache_old, token);
setSetupInfo(artworkinfo_tokens, i, value);
/* check if cache entry for this item is invalid or incomplete */
if (value == NULL)
{
+#if 1
printf("::: - WARNING: cache entry '%s' invalid\n", token);
+#endif
cached = FALSE;
}
-
- checked_free(token);
}
- *artwork_new = ldi;
+ *artwork_info = ldi;
+ }
+
+ if (cached)
+ {
+ char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node),
+ LEVELINFO_FILENAME);
+ char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info),
+ ARTWORKINFO_FILENAME(type));
+
+ /* check if corresponding "levelinfo.conf" file has changed */
+ token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO");
+ cache_entry = getHashEntry(artworkinfo_cache_old, token_main);
+
+ if (modifiedFileTimestamp(filename_levelinfo, cache_entry))
+ cached = FALSE;
+ /* check if corresponding "<artworkinfo>.conf" file has changed */
+ token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO");
+ cache_entry = getHashEntry(artworkinfo_cache_old, token_main);
+
+ if (modifiedFileTimestamp(filename_artworkinfo, cache_entry))
+ cached = FALSE;
+
+#if 0
if (!cached)
- freeTreeInfo(artwork_new);
+ printf("::: '%s': INVALIDATED FROM CACHE BY TIMESTAMP\n", identifier);
+#endif
+
+ checked_free(filename_levelinfo);
+ checked_free(filename_artworkinfo);
}
- free(token_prefix);
+ if (!cached && artwork_info != NULL)
+ {
+ freeTreeInfo(artwork_info);
- return artwork_new;
+ return NULL;
+ }
+
+ return artwork_info;
+}
+
+static void setArtworkInfoCacheEntry(TreeInfo *artwork_info,
+ LevelDirTree *level_node, int type)
+{
+ char *identifier = level_node->subdir;
+ char *type_string = ARTWORK_DIRECTORY(type);
+ char *token_prefix = getCacheTokenPrefix(type_string, identifier);
+ char *token_main = getCacheToken(token_prefix, "CACHED");
+ boolean set_cache_timestamps = TRUE;
+ int i;
+
+ setHashEntry(artworkinfo_cache_new, token_main, "true");
+
+ if (set_cache_timestamps)
+ {
+ char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node),
+ LEVELINFO_FILENAME);
+ char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info),
+ ARTWORKINFO_FILENAME(type));
+ char *timestamp_levelinfo = getFileTimestamp(filename_levelinfo);
+ char *timestamp_artworkinfo = getFileTimestamp(filename_artworkinfo);
+
+ token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO");
+ setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo);
+
+ token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO");
+ setHashEntry(artworkinfo_cache_new, token_main, timestamp_artworkinfo);
+
+ checked_free(filename_levelinfo);
+ checked_free(filename_artworkinfo);
+ checked_free(timestamp_levelinfo);
+ checked_free(timestamp_artworkinfo);
+ }
+
+ ldi = *artwork_info;
+ for (i = 0; artworkinfo_tokens[i].type != -1; i++)
+ {
+ char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text);
+ char *value = getSetupValue(artworkinfo_tokens[i].type,
+ artworkinfo_tokens[i].value);
+ if (value != NULL)
+ setHashEntry(artworkinfo_cache_new, token, value);
+ }
}
if (strEqual(leveldir_new->name, ANONYMOUS_NAME))
setString(&leveldir_new->name, leveldir_new->subdir);
- DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-
if (leveldir_new->identifier == NULL)
leveldir_new->identifier = getStringCopy(leveldir_new->subdir);
(leveldir_new->user_defined || !leveldir_new->handicap ?
leveldir_new->last_level : leveldir_new->first_level);
+ if (leveldir_new->level_group)
+ DrawInitText(leveldir_new->name, 150, FC_YELLOW);
+
#if 0
/* !!! don't skip sets without levels (else artwork base sets are missing) */
#if 1
/* create node to link back to current level directory */
createParentTreeInfoNode(leveldir_new);
- /* step into sub-directory and look for more level series */
+ /* recursively step into sub-directory and look for more level series */
LoadLevelInfoFromLevelDir(&leveldir_new->node_group,
leveldir_new, directory_path);
}
{
InitUserLevelDirectory(getLoginName());
- DrawInitText("Loading level series:", 120, FC_GREEN);
+ DrawInitText("Loading level series", 120, FC_GREEN);
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
if (strEqual(artwork_new->name, ANONYMOUS_NAME))
setString(&artwork_new->name, artwork_new->subdir);
-#if 0
- DrawInitText(artwork_new->name, 150, FC_YELLOW);
-#endif
-
if (artwork_new->identifier == NULL)
artwork_new->identifier = getStringCopy(artwork_new->subdir);
setString(&artwork_new->name_sorting, artwork_new->name);
}
+#if 0
DrawInitText(artwork_new->name, 150, FC_YELLOW);
+#endif
pushTreeInfo(node_first, artwork_new);
{
LoadArtworkInfoCache();
- DrawInitText("Looking for custom artwork:", 120, FC_GREEN);
+ DrawInitText("Looking for custom artwork", 120, FC_GREEN);
LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL,
options.graphics_directory,
void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
LevelDirTree *level_node)
{
+ int type = (*artwork_node)->type;
+
/* recursively check all level directories for artwork sub-directories */
while (level_node)
/* check all tree entries for artwork, but skip parent link entries */
if (!level_node->parent_link)
{
- TreeInfo *topnode_last = *artwork_node;
- char *path = getPath2(getLevelDirFromTreeInfo(level_node),
- ARTWORK_DIRECTORY((*artwork_node)->type));
- TreeInfo *artwork_new = getArtworkInfoFromCache(level_node->subdir,
- (*artwork_node)->type);
- boolean cached = FALSE;
+ TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type);
+ boolean cached = (artwork_new != NULL);
- if (artwork_new != NULL)
+ if (cached)
{
pushTreeInfo(artwork_node, artwork_new);
- cached = TRUE;
}
else
{
- LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path,
- (*artwork_node)->type);
- }
+ TreeInfo *topnode_last = *artwork_node;
+ char *path = getPath2(getLevelDirFromTreeInfo(level_node),
+ ARTWORK_DIRECTORY(type));
-#if 1
- if (!cached && topnode_last != *artwork_node)
-#else
- if (topnode_last != *artwork_node)
-#endif
- {
- free((*artwork_node)->identifier);
- free((*artwork_node)->name);
- free((*artwork_node)->name_sorting);
+ LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path, type);
- (*artwork_node)->identifier = getStringCopy(level_node->subdir);
- (*artwork_node)->name = getStringCopy(level_node->name);
- (*artwork_node)->name_sorting = getStringCopy(level_node->name);
+ if (topnode_last != *artwork_node) /* check for newly added node */
+ {
+ artwork_new = *artwork_node;
- (*artwork_node)->sort_priority = level_node->sort_priority;
- (*artwork_node)->color = LEVELCOLOR((*artwork_node));
+ setString(&artwork_new->identifier, level_node->subdir);
+ setString(&artwork_new->name, level_node->name);
+ setString(&artwork_new->name_sorting, level_node->name_sorting);
-#if 1
- {
- char *identifier = level_node->subdir;
- char *type_string = ARTWORK_DIRECTORY((*artwork_node)->type);
- char *type_identifier =
- getStringCat2WithSeparator(type_string, identifier, ".");
- int i;
-
- printf("::: adding hash entry for set '%s' ...\n", type_identifier);
-
- setHashEntry(artworkinfo_hash, type_identifier, "true");
-
- ldi = **artwork_node;
- for (i = 0; artworkinfo_tokens[i].type != -1; i++)
- {
- char *token = getStringCat2WithSeparator(type_identifier,
- artworkinfo_tokens[i].text,
- ".");
- char *value = getSetupValue(artworkinfo_tokens[i].type,
- artworkinfo_tokens[i].value);
- if (value != NULL)
- {
- setHashEntry(artworkinfo_hash, token, value);
-
- printf("::: - setting '%s' => '%s'\n\n",
- token, value);
- }
-
- checked_free(token);
- }
-
- free(type_identifier);
+ artwork_new->sort_priority = level_node->sort_priority;
+ artwork_new->color = LEVELCOLOR(artwork_new);
}
-#endif
+
+ free(path);
}
- free(path);
+ /* insert artwork info (from old cache or filesystem) into new cache */
+ if (artwork_new != NULL)
+ setArtworkInfoCacheEntry(artwork_new, level_node, type);
}
+#if 1
+ if (level_node->level_group)
+ DrawInitText(level_node->name, 150, FC_YELLOW);
+#endif
+
if (level_node->node_group != NULL)
LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group);
void LoadLevelArtworkInfo()
{
- DrawInitText("Looking for custom level artwork:", 120, FC_GREEN);
+ DrawInitText("Looking for custom level artwork", 120, FC_GREEN);
LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all);
LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all);