rnd-20060820-1-src
[rocksndiamonds.git] / src / libgame / setup.c
index 6f8ffaca24695f5a1d8795bb8ba7339f5b602a42..4f00449473f8cadcb520d70c9a0ea542c40f4797 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Artsoft Retro-Game Library                               *
 *----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment                      *
+* (c) 1994-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
 #include <string.h>
 #include <unistd.h>
 
+#include "platform.h"
+
+#if !defined(PLATFORM_WIN32)
+#include <pwd.h>
+#include <sys/param.h>
+#endif
+
 #include "setup.h"
 #include "joystick.h"
 #include "text.h"
@@ -79,6 +86,9 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
 
 #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;
 
@@ -87,9 +97,9 @@ static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT;
 /* file functions                                                            */
 /* ------------------------------------------------------------------------- */
 
-static char *getLevelClassDescription(TreeInfo *ldi)
+static char *getLevelClassDescription(TreeInfo *ti)
 {
-  int position = ldi->sort_priority / 100;
+  int position = ti->sort_priority / 100;
 
   if (position >= 0 && position < NUM_LEVELCLASS_DESC)
     return levelclass_desc[position];
@@ -100,7 +110,7 @@ static char *getLevelClassDescription(TreeInfo *ldi)
 static char *getUserLevelDir(char *level_subdir)
 {
   static char *userlevel_dir = NULL;
-  char *data_dir = getUserDataDir();
+  char *data_dir = getUserGameDataDir();
   char *userlevel_subdir = LEVELS_DIRECTORY;
 
   checked_free(userlevel_dir);
@@ -132,7 +142,7 @@ static char *getScoreDir(char *level_subdir)
 static char *getLevelSetupDir(char *level_subdir)
 {
   static char *levelsetup_dir = NULL;
-  char *data_dir = getUserDataDir();
+  char *data_dir = getUserGameDataDir();
   char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
 
   checked_free(levelsetup_dir);
@@ -168,7 +178,7 @@ char *getCurrentLevelDir()
 static char *getTapeDir(char *level_subdir)
 {
   static char *tape_dir = NULL;
-  char *data_dir = getUserDataDir();
+  char *data_dir = getUserGameDataDir();
   char *tape_subdir = TAPES_DIRECTORY;
 
   checked_free(tape_dir);
@@ -258,7 +268,7 @@ static char *getUserGraphicsDir()
   static char *usergraphics_dir = NULL;
 
   if (usergraphics_dir == NULL)
-    usergraphics_dir = getPath2(getUserDataDir(), GRAPHICS_DIRECTORY);
+    usergraphics_dir = getPath2(getUserGameDataDir(), GRAPHICS_DIRECTORY);
 
   return usergraphics_dir;
 }
@@ -268,7 +278,7 @@ static char *getUserSoundsDir()
   static char *usersounds_dir = NULL;
 
   if (usersounds_dir == NULL)
-    usersounds_dir = getPath2(getUserDataDir(), SOUNDS_DIRECTORY);
+    usersounds_dir = getPath2(getUserGameDataDir(), SOUNDS_DIRECTORY);
 
   return usersounds_dir;
 }
@@ -278,7 +288,7 @@ static char *getUserMusicDir()
   static char *usermusic_dir = NULL;
 
   if (usermusic_dir == NULL)
-    usermusic_dir = getPath2(getUserDataDir(), MUSIC_DIRECTORY);
+    usermusic_dir = getPath2(getUserGameDataDir(), MUSIC_DIRECTORY);
 
   return usermusic_dir;
 }
@@ -515,22 +525,6 @@ char *getCustomImageFilename(char *basename)
 
   if (!setup.override_level_graphics)
   {
-#if 1
-    /* try special ECS graphics */
-    filename = getPath3(getCurrentLevelDir(), GRAPHICS_ECS_DIRECTORY, basename);
-    if (fileExists(filename) && !setup.prefer_aga_graphics)
-      return filename;
-
-    free(filename);
-
-    /* try special AGA graphics */
-    filename = getPath3(getCurrentLevelDir(), GRAPHICS_AGA_DIRECTORY, basename);
-    if (fileExists(filename) && setup.prefer_aga_graphics)
-      return filename;
-
-    free(filename);
-#endif
-
     /* 1st try: look for special artwork in current level series directory */
     filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
     if (fileExists(filename))
@@ -538,22 +532,9 @@ char *getCustomImageFilename(char *basename)
 
     free(filename);
 
-#if 1
-    if (leveldir_current)
-      printf("::: A -> '%s' [%s]\n", leveldir_current->graphics_set,
-            leveldir_current->subdir);
-#endif
-
     /* check if there is special artwork configured in level series config */
     if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL)
     {
-#if 1
-      printf("::: B -> '%s' ---------> '%s'\n",
-            getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS),
-            leveldir_current->graphics_path);
-      /*     -> getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS)); */
-#endif
-
       /* 2nd try: look for special artwork configured in level series config */
       filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
       if (fileExists(filename))
@@ -793,7 +774,7 @@ char *getCustomMusicDirectory(void)
 
 void InitTapeDirectory(char *level_subdir)
 {
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
   createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE);
   createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
 }
@@ -811,7 +792,7 @@ void InitUserLevelDirectory(char *level_subdir)
 {
   if (!fileExists(getUserLevelDir(level_subdir)))
   {
-    createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+    createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
     createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
     createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE);
 
@@ -821,7 +802,7 @@ void InitUserLevelDirectory(char *level_subdir)
 
 void InitLevelSetupDirectory(char *level_subdir)
 {
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
   createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE);
   createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
 }
@@ -836,6 +817,15 @@ TreeInfo *newTreeInfo()
   return checked_calloc(sizeof(TreeInfo));
 }
 
+TreeInfo *newTreeInfo_setDefaults(int type)
+{
+  TreeInfo *ti = newTreeInfo();
+
+  setTreeInfoToDefaults(ti, type);
+
+  return ti;
+}
+
 void pushTreeInfo(TreeInfo **node_first, TreeInfo *node_new)
 {
   node_new->next = *node_first;
@@ -946,7 +936,7 @@ TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
     }
     else if (!node->parent_link)
     {
-      if (strcmp(identifier, node->identifier) == 0)
+      if (strEqual(identifier, node->identifier))
        return node;
     }
 
@@ -993,51 +983,27 @@ void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets)
   *ti_new = ti_cloned;
 }
 
-static boolean adjustTreeGraphics(TreeInfo *node)
+static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
 {
   boolean settings_changed = FALSE;
 
   while (node)
   {
-#if 1
-    if (node->graphics_ecs_set && !setup.prefer_aga_graphics)
+    if (node->graphics_set_ecs && !setup.prefer_aga_graphics &&
+       !strEqual(node->graphics_set, node->graphics_set_ecs))
     {
-      setString(&node->graphics_set, node->graphics_ecs_set);
-#if 0
-      printf("::: setting graphics for set '%s' to '%s' [ECS]\n",
-            node->subdir, node->graphics_set);
-#endif
-
+      setString(&node->graphics_set, node->graphics_set_ecs);
       settings_changed = TRUE;
     }
-    else if (node->graphics_aga_set && setup.prefer_aga_graphics)
+    else if (node->graphics_set_aga && setup.prefer_aga_graphics &&
+            !strEqual(node->graphics_set, node->graphics_set_aga))
     {
-      setString(&node->graphics_set, node->graphics_aga_set);
-#if 0
-      printf("::: setting graphics for set '%s' to '%s' [AGA]\n",
-            node->subdir, node->graphics_set);
-#endif
-
+      setString(&node->graphics_set, node->graphics_set_aga);
       settings_changed = TRUE;
     }
-    else if (node->graphics_set == NULL)
-    {
-#if 0
-      printf("::: cannot set graphics_set for set '%s'\n", node->subdir);
-#endif
-    }
-#else
-    if (node->graphics_ecs_set)
-      printf("::: SET '%s': found ECS set '%s'\n",
-            node->subdir, node->graphics_ecs_set);
-
-    if (node->graphics_aga_set)
-      printf("::: SET '%s': found AGA set '%s'\n",
-            node->subdir, node->graphics_aga_set);
-#endif
 
     if (node->node_group != NULL)
-      settings_changed |= adjustTreeGraphics(node->node_group);
+      settings_changed |= adjustTreeGraphicsForEMC(node->node_group);
 
     node = node->next;
   }
@@ -1066,8 +1032,9 @@ void dumpTreeInfo(TreeInfo *node, int depth)
   }
 }
 
-void sortTreeInfo(TreeInfo **node_first,
-                 int (*compare_function)(const void *, const void *))
+void sortTreeInfoBySortFunction(TreeInfo **node_first,
+                               int (*compare_function)(const void *,
+                                                       const void *))
 {
   int num_nodes = numTreeInfo(*node_first);
   TreeInfo **sort_array;
@@ -1108,12 +1075,17 @@ void sortTreeInfo(TreeInfo **node_first,
   while (node)
   {
     if (node->node_group != NULL)
-      sortTreeInfo(&node->node_group, compare_function);
+      sortTreeInfoBySortFunction(&node->node_group, compare_function);
 
     node = node->next;
   }
 }
 
+void sortTreeInfo(TreeInfo **node_first)
+{
+  sortTreeInfoBySortFunction(node_first, compareTreeInfoEntries);
+}
+
 
 /* ========================================================================= */
 /* some stuff from "files.c"                                                 */
@@ -1161,14 +1133,36 @@ void sortTreeInfo(TreeInfo **node_first,
 #define FILE_PERMS_PRIVATE     (MODE_R_ALL | MODE_W_PRIVATE)
 #define FILE_PERMS_PUBLIC      (MODE_R_ALL | MODE_W_PUBLIC)
 
-char *getUserDataDir(void)
+char *getHomeDir()
 {
-  static char *userdata_dir = NULL;
+  static char *dir = NULL;
 
-  if (userdata_dir == NULL)
-    userdata_dir = getPath2(getHomeDir(), program.userdata_directory);
+#if defined(PLATFORM_WIN32)
+  if (dir == NULL)
+  {
+    dir = checked_malloc(MAX_PATH + 1);
+
+    if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir)))
+      strcpy(dir, ".");
+  }
+#elif defined(PLATFORM_UNIX)
+  if (dir == NULL)
+  {
+    if ((dir = getenv("HOME")) == NULL)
+    {
+      struct passwd *pwd;
+
+      if ((pwd = getpwuid(getuid())) != NULL)
+       dir = getStringCopy(pwd->pw_dir);
+      else
+       dir = ".";
+    }
+  }
+#else
+  dir = ".";
+#endif
 
-  return userdata_dir;
+  return dir;
 }
 
 char *getCommonDataDir(void)
@@ -1181,8 +1175,8 @@ char *getCommonDataDir(void)
     char *dir = checked_malloc(MAX_PATH + 1);
 
     if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir))
-       && strcmp(dir, "") != 0)        /* empty for Windows 95/98 */
-      common_data_dir = getPath2(dir, program.userdata_directory);
+       && !strEqual(dir, ""))          /* empty for Windows 95/98 */
+      common_data_dir = getPath2(dir, program.userdata_subdir);
     else
       common_data_dir = options.rw_base_directory;
   }
@@ -1194,9 +1188,59 @@ char *getCommonDataDir(void)
   return common_data_dir;
 }
 
+char *getPersonalDataDir(void)
+{
+  static char *personal_data_dir = NULL;
+
+#if defined(PLATFORM_MACOSX)
+  if (personal_data_dir == NULL)
+    personal_data_dir = getPath2(getHomeDir(), "Documents");
+#else
+  if (personal_data_dir == NULL)
+    personal_data_dir = getHomeDir();
+#endif
+
+  return personal_data_dir;
+}
+
+char *getUserGameDataDir(void)
+{
+  static char *user_game_data_dir = NULL;
+
+  if (user_game_data_dir == NULL)
+    user_game_data_dir = getPath2(getPersonalDataDir(),
+                                 program.userdata_subdir);
+
+  return user_game_data_dir;
+}
+
+void updateUserGameDataDir()
+{
+#if defined(PLATFORM_MACOSX)
+  char *userdata_dir_old = getPath2(getHomeDir(), program.userdata_subdir_unix);
+  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 (rename(userdata_dir_old, userdata_dir_new) != 0)
+    {
+      Error(ERR_WARN, "cannot move game data directory '%s' to '%s'",
+           userdata_dir_old, userdata_dir_new);
+
+      /* continue using Unix style data directory -- this should not happen */
+      program.userdata_path = getPath2(getPersonalDataDir(),
+                                      program.userdata_subdir_unix);
+    }
+  }
+
+  free(userdata_dir_old);
+#endif
+}
+
 char *getSetupDir()
 {
-  return getUserDataDir();
+  return getUserGameDataDir();
 }
 
 static mode_t posix_umask(mode_t mask)
@@ -1236,7 +1280,7 @@ void createDirectory(char *dir, char *text, int permission_class)
 
 void InitUserDataDirectory()
 {
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
 }
 
 void SetFilePermissions(char *filename, int permission_class)
@@ -1362,7 +1406,7 @@ char *getListEntry(SetupFileList *list, char *token)
   if (list == NULL)
     return NULL;
 
-  if (strcmp(list->token, token) == 0)
+  if (strEqual(list->token, token))
     return list->value;
   else
     return getListEntry(list->next, token);
@@ -1373,7 +1417,7 @@ SetupFileList *setListEntry(SetupFileList *list, char *token, char *value)
   if (list == NULL)
     return NULL;
 
-  if (strcmp(list->token, token) == 0)
+  if (strEqual(list->token, token))
   {
     checked_free(list->value);
 
@@ -1455,7 +1499,7 @@ static unsigned int get_hash_from_key(void *key)
 
 static int keys_are_equal(void *key1, void *key2)
 {
-  return (strcmp((char *)key1, (char *)key2) == 0);
+  return (strEqual((char *)key1, (char *)key2));
 }
 
 SetupFileHash *newSetupFileHash()
@@ -1703,8 +1747,8 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
 #define LEVELINFO_TOKEN_LATEST_ENGINE          9
 #define LEVELINFO_TOKEN_LEVEL_GROUP            10
 #define LEVELINFO_TOKEN_READONLY               11
-#define LEVELINFO_TOKEN_GRAPHICS_ECS_SET       12
-#define LEVELINFO_TOKEN_GRAPHICS_AGA_SET       13
+#define LEVELINFO_TOKEN_GRAPHICS_SET_ECS       12
+#define LEVELINFO_TOKEN_GRAPHICS_SET_AGA       13
 #define LEVELINFO_TOKEN_GRAPHICS_SET           14
 #define LEVELINFO_TOKEN_SOUNDS_SET             15
 #define LEVELINFO_TOKEN_MUSIC_SET              16
@@ -1732,8 +1776,8 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_BOOLEAN,      &ldi.latest_engine,     "latest_engine"         },
   { TYPE_BOOLEAN,      &ldi.level_group,       "level_group"           },
   { TYPE_BOOLEAN,      &ldi.readonly,          "readonly"              },
-  { TYPE_STRING,       &ldi.graphics_ecs_set,  "graphics_ecs_set"      },
-  { TYPE_STRING,       &ldi.graphics_aga_set,  "graphics_aga_set"      },
+  { TYPE_STRING,       &ldi.graphics_set_ecs,  "graphics_set.ecs"      },
+  { TYPE_STRING,       &ldi.graphics_set_aga,  "graphics_set.aga"      },
   { TYPE_STRING,       &ldi.graphics_set,      "graphics_set"          },
   { TYPE_STRING,       &ldi.sounds_set,        "sounds_set"            },
   { TYPE_STRING,       &ldi.music_set,         "music_set"             },
@@ -1743,164 +1787,170 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_BOOLEAN,      &ldi.skip_levels,       "skip_levels"           }
 };
 
-static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
+static void setTreeInfoToDefaults(TreeInfo *ti, int type)
 {
-  ldi->type = type;
+  ti->type = type;
 
-  ldi->node_top = (ldi->type == TREE_TYPE_LEVEL_DIR ? &leveldir_first :
-                  ldi->type == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first :
-                  ldi->type == TREE_TYPE_SOUNDS_DIR ? &artwork.snd_first :
-                  ldi->type == TREE_TYPE_MUSIC_DIR ? &artwork.mus_first :
-                  NULL);
+  ti->node_top = (ti->type == TREE_TYPE_LEVEL_DIR    ? &leveldir_first :
+                 ti->type == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first :
+                 ti->type == TREE_TYPE_SOUNDS_DIR   ? &artwork.snd_first :
+                 ti->type == TREE_TYPE_MUSIC_DIR    ? &artwork.mus_first :
+                 NULL);
 
-  ldi->node_parent = NULL;
-  ldi->node_group = NULL;
-  ldi->next = NULL;
+  ti->node_parent = NULL;
+  ti->node_group = NULL;
+  ti->next = NULL;
 
-  ldi->cl_first = -1;
-  ldi->cl_cursor = -1;
+  ti->cl_first = -1;
+  ti->cl_cursor = -1;
 
-  ldi->subdir = NULL;
-  ldi->fullpath = NULL;
-  ldi->basepath = NULL;
-  ldi->identifier = NULL;
-  ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_sorting = NULL;
-  ldi->author = getStringCopy(ANONYMOUS_NAME);
+  ti->subdir = NULL;
+  ti->fullpath = NULL;
+  ti->basepath = NULL;
+  ti->identifier = NULL;
+  ti->name = getStringCopy(ANONYMOUS_NAME);
+  ti->name_sorting = NULL;
+  ti->author = getStringCopy(ANONYMOUS_NAME);
 
-  ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
-  ldi->latest_engine = FALSE;                  /* default: get from level */
-  ldi->parent_link = FALSE;
-  ldi->in_user_dir = FALSE;
-  ldi->user_defined = FALSE;
-  ldi->color = 0;
-  ldi->class_desc = NULL;
+  ti->sort_priority = LEVELCLASS_UNDEFINED;    /* default: least priority */
+  ti->latest_engine = FALSE;                   /* default: get from level */
+  ti->parent_link = FALSE;
+  ti->in_user_dir = FALSE;
+  ti->user_defined = FALSE;
+  ti->color = 0;
+  ti->class_desc = NULL;
 
-  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  ti->infotext = getStringCopy(TREE_INFOTEXT(ti->type));
+
+  if (ti->type == TREE_TYPE_LEVEL_DIR)
   {
-    ldi->imported_from = NULL;
-    ldi->imported_by = NULL;
+    ti->imported_from = NULL;
+    ti->imported_by = NULL;
 
-    ldi->graphics_ecs_set = NULL;
-    ldi->graphics_aga_set = NULL;
-    ldi->graphics_set = NULL;
-    ldi->sounds_set = NULL;
-    ldi->music_set = NULL;
-    ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
-    ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
-    ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->graphics_set_ecs = NULL;
+    ti->graphics_set_aga = NULL;
+    ti->graphics_set = NULL;
+    ti->sounds_set = NULL;
+    ti->music_set = NULL;
+    ti->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->music_path = getStringCopy(UNDEFINED_FILENAME);
 
-    ldi->level_filename = NULL;
-    ldi->level_filetype = NULL;
+    ti->level_filename = NULL;
+    ti->level_filetype = NULL;
 
-    ldi->levels = 0;
-    ldi->first_level = 0;
-    ldi->last_level = 0;
-    ldi->level_group = FALSE;
-    ldi->handicap_level = 0;
-    ldi->readonly = TRUE;
-    ldi->handicap = TRUE;
-    ldi->skip_levels = FALSE;
+    ti->levels = 0;
+    ti->first_level = 0;
+    ti->last_level = 0;
+    ti->level_group = FALSE;
+    ti->handicap_level = 0;
+    ti->readonly = TRUE;
+    ti->handicap = TRUE;
+    ti->skip_levels = FALSE;
   }
 }
 
-static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
+static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent)
 {
   if (parent == NULL)
   {
     Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
 
-    setTreeInfoToDefaults(ldi, TREE_TYPE_UNDEFINED);
+    setTreeInfoToDefaults(ti, TREE_TYPE_UNDEFINED);
 
     return;
   }
 
   /* copy all values from the parent structure */
 
-  ldi->type = parent->type;
+  ti->type = parent->type;
+
+  ti->node_top = parent->node_top;
+  ti->node_parent = parent;
+  ti->node_group = NULL;
+  ti->next = NULL;
 
-  ldi->node_top = parent->node_top;
-  ldi->node_parent = parent;
-  ldi->node_group = NULL;
-  ldi->next = NULL;
+  ti->cl_first = -1;
+  ti->cl_cursor = -1;
 
-  ldi->cl_first = -1;
-  ldi->cl_cursor = -1;
+  ti->subdir = NULL;
+  ti->fullpath = NULL;
+  ti->basepath = NULL;
+  ti->identifier = NULL;
+  ti->name = getStringCopy(ANONYMOUS_NAME);
+  ti->name_sorting = NULL;
+  ti->author = getStringCopy(parent->author);
 
-  ldi->subdir = NULL;
-  ldi->fullpath = NULL;
-  ldi->basepath = NULL;
-  ldi->identifier = NULL;
-  ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_sorting = NULL;
-  ldi->author = getStringCopy(parent->author);
+  ti->sort_priority = parent->sort_priority;
+  ti->latest_engine = parent->latest_engine;
+  ti->parent_link = FALSE;
+  ti->in_user_dir = parent->in_user_dir;
+  ti->user_defined = parent->user_defined;
+  ti->color = parent->color;
+  ti->class_desc = getStringCopy(parent->class_desc);
 
-  ldi->sort_priority = parent->sort_priority;
-  ldi->latest_engine = parent->latest_engine;
-  ldi->parent_link = FALSE;
-  ldi->in_user_dir = parent->in_user_dir;
-  ldi->user_defined = parent->user_defined;
-  ldi->color = parent->color;
-  ldi->class_desc = getStringCopy(parent->class_desc);
+  ti->infotext = getStringCopy(parent->infotext);
 
-  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  if (ti->type == TREE_TYPE_LEVEL_DIR)
   {
-    ldi->imported_from = getStringCopy(parent->imported_from);
-    ldi->imported_by = getStringCopy(parent->imported_by);
+    ti->imported_from = getStringCopy(parent->imported_from);
+    ti->imported_by = getStringCopy(parent->imported_by);
 
-    ldi->graphics_ecs_set = NULL;
-    ldi->graphics_aga_set = NULL;
-    ldi->graphics_set = NULL;
-    ldi->sounds_set = NULL;
-    ldi->music_set = NULL;
-    ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
-    ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
-    ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->graphics_set_ecs = NULL;
+    ti->graphics_set_aga = NULL;
+    ti->graphics_set = NULL;
+    ti->sounds_set = NULL;
+    ti->music_set = NULL;
+    ti->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+    ti->music_path = getStringCopy(UNDEFINED_FILENAME);
 
-    ldi->level_filename = NULL;
-    ldi->level_filetype = NULL;
+    ti->level_filename = NULL;
+    ti->level_filetype = NULL;
 
-    ldi->levels = 0;
-    ldi->first_level = 0;
-    ldi->last_level = 0;
-    ldi->level_group = FALSE;
-    ldi->handicap_level = 0;
-    ldi->readonly = TRUE;
-    ldi->handicap = TRUE;
-    ldi->skip_levels = FALSE;
+    ti->levels = 0;
+    ti->first_level = 0;
+    ti->last_level = 0;
+    ti->level_group = FALSE;
+    ti->handicap_level = 0;
+    ti->readonly = TRUE;
+    ti->handicap = TRUE;
+    ti->skip_levels = FALSE;
   }
 }
 
-static void freeTreeInfo(TreeInfo *ldi)
+static void freeTreeInfo(TreeInfo *ti)
 {
-  checked_free(ldi->subdir);
-  checked_free(ldi->fullpath);
-  checked_free(ldi->basepath);
-  checked_free(ldi->identifier);
+  checked_free(ti->subdir);
+  checked_free(ti->fullpath);
+  checked_free(ti->basepath);
+  checked_free(ti->identifier);
 
-  checked_free(ldi->name);
-  checked_free(ldi->name_sorting);
-  checked_free(ldi->author);
+  checked_free(ti->name);
+  checked_free(ti->name_sorting);
+  checked_free(ti->author);
 
-  checked_free(ldi->class_desc);
+  checked_free(ti->class_desc);
 
-  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  checked_free(ti->infotext);
+
+  if (ti->type == TREE_TYPE_LEVEL_DIR)
   {
-    checked_free(ldi->imported_from);
-    checked_free(ldi->imported_by);
+    checked_free(ti->imported_from);
+    checked_free(ti->imported_by);
 
-    checked_free(ldi->graphics_ecs_set);
-    checked_free(ldi->graphics_aga_set);
-    checked_free(ldi->graphics_set);
-    checked_free(ldi->sounds_set);
-    checked_free(ldi->music_set);
+    checked_free(ti->graphics_set_ecs);
+    checked_free(ti->graphics_set_aga);
+    checked_free(ti->graphics_set);
+    checked_free(ti->sounds_set);
+    checked_free(ti->music_set);
 
-    checked_free(ldi->graphics_path);
-    checked_free(ldi->sounds_path);
-    checked_free(ldi->music_path);
+    checked_free(ti->graphics_path);
+    checked_free(ti->sounds_path);
+    checked_free(ti->music_path);
 
-    checked_free(ldi->level_filename);
-    checked_free(ldi->level_filetype);
+    checked_free(ti->level_filename);
+    checked_free(ti->level_filetype);
   }
 }
 
@@ -2063,7 +2113,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
                 getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
   *leveldir_new = ldi;
 
-  if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
+  if (strEqual(leveldir_new->name, ANONYMOUS_NAME))
     setString(&leveldir_new->name, leveldir_new->subdir);
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
@@ -2094,14 +2144,14 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
     leveldir_new->first_level + leveldir_new->levels - 1;
 
   leveldir_new->in_user_dir =
-    (strcmp(leveldir_new->basepath, options.level_directory) != 0);
+    (!strEqual(leveldir_new->basepath, options.level_directory));
 
   /* adjust some settings if user's private level directory was detected */
   if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED &&
       leveldir_new->in_user_dir &&
-      (strcmp(leveldir_new->subdir, getLoginName()) == 0 ||
-       strcmp(leveldir_new->name,   getLoginName()) == 0 ||
-       strcmp(leveldir_new->author, getRealName())  == 0))
+      (strEqual(leveldir_new->subdir, getLoginName()) ||
+       strEqual(leveldir_new->name,   getLoginName()) ||
+       strEqual(leveldir_new->author, getRealName())))
   {
     leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START;
     leveldir_new->readonly = FALSE;
@@ -2175,8 +2225,8 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
     char *directory_path = getPath2(level_directory, directory_name);
 
     /* skip entries for current and parent directory */
-    if (strcmp(directory_name, ".")  == 0 ||
-       strcmp(directory_name, "..") == 0)
+    if (strEqual(directory_name, ".") ||
+       strEqual(directory_name, ".."))
     {
       free(directory_path);
       continue;
@@ -2192,9 +2242,9 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
 
     free(directory_path);
 
-    if (strcmp(directory_name, GRAPHICS_DIRECTORY) == 0 ||
-       strcmp(directory_name, SOUNDS_DIRECTORY) == 0 ||
-       strcmp(directory_name, MUSIC_DIRECTORY) == 0)
+    if (strEqual(directory_name, GRAPHICS_DIRECTORY) ||
+       strEqual(directory_name, SOUNDS_DIRECTORY) ||
+       strEqual(directory_name, MUSIC_DIRECTORY))
       continue;
 
     valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent,
@@ -2221,17 +2271,8 @@ boolean AdjustGraphicsForEMC()
 {
   boolean settings_changed = FALSE;
 
-#if 1
-  printf("::: AdjustGraphicsForEMC()\n");
-
-  settings_changed |= adjustTreeGraphics(leveldir_first_all);
-  settings_changed |= adjustTreeGraphics(leveldir_first);
-
-  if (leveldir_current)
-    printf("::: X -> '%s'\n", leveldir_current->graphics_set);
-  else
-    printf("::: X (leveldir_current == NULL)\n");
-#endif
+  settings_changed |= adjustTreeGraphicsForEMC(leveldir_first_all);
+  settings_changed |= adjustTreeGraphicsForEMC(leveldir_first);
 
   return settings_changed;
 }
@@ -2245,14 +2286,12 @@ void LoadLevelInfo()
   LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
   LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
 
-#if 1
   /* after loading all level set information, clone the level directory tree
      and remove all level sets without levels (these may still contain artwork
      to be offered in the setup menu as "custom artwork", and are therefore
      checked for existing artwork in the function "LoadLevelArtworkInfo()") */
   leveldir_first_all = leveldir_first;
   cloneTree(&leveldir_first, leveldir_first_all, TRUE);
-#endif
 
   AdjustGraphicsForEMC();
 
@@ -2262,7 +2301,7 @@ void LoadLevelInfo()
   if (leveldir_first == NULL)
     Error(ERR_EXIT, "cannot find any valid level series in any directory");
 
-  sortTreeInfo(&leveldir_first, compareTreeInfoEntries);
+  sortTreeInfo(&leveldir_first);
 
 #if 0
   dumpTreeInfo(leveldir_first, 0);
@@ -2280,10 +2319,6 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   TreeInfo *artwork_new = NULL;
   int i;
 
-#if 0
-  printf("::: CHECKING FOR CONFIG FILE '%s'\n", filename);
-#endif
-
   if (fileExists(filename))
     setup_file_hash = loadSetupFileHash(filename);
 
@@ -2311,7 +2346,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
     if (!valid_file_found)
     {
-      if (strcmp(directory_name, ".") != 0)
+      if (!strEqual(directory_name, "."))
        Error(ERR_WARN, "ignoring artwork directory '%s'", directory_path);
 
       free(directory_path);
@@ -2343,7 +2378,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
                   getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
     *artwork_new = ldi;
 
-    if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
+    if (strEqual(artwork_new->name, ANONYMOUS_NAME))
       setString(&artwork_new->name, artwork_new->subdir);
 
 #if 0
@@ -2369,7 +2404,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   }
 
   artwork_new->in_user_dir =
-    (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0);
+    (!strEqual(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)));
 
   /* (may use ".sort_priority" from "setup_file_hash" above) */
   artwork_new->color = ARTWORKCOLOR(artwork_new);
@@ -2378,7 +2413,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
   if (setup_file_hash == NULL) /* (after determining ".user_defined") */
   {
-    if (strcmp(artwork_new->subdir, ".") == 0)
+    if (strEqual(artwork_new->subdir, "."))
     {
       if (artwork_new->user_defined)
       {
@@ -2426,10 +2461,6 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
   struct dirent *dir_entry;
   boolean valid_entry_found = FALSE;
 
-#if 0
-  printf("::: CHECKING BASE DIR '%s'\n", base_directory);
-#endif
-
   if ((dir = opendir(base_directory)) == NULL)
   {
     /* display error if directory is main "options.graphics_directory" etc. */
@@ -2446,8 +2477,8 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
     char *directory_path = getPath2(base_directory, directory_name);
 
     /* skip directory entries for current and parent directory */
-    if (strcmp(directory_name, ".")  == 0 ||
-       strcmp(directory_name, "..") == 0)
+    if (strEqual(directory_name, ".") ||
+       strEqual(directory_name, ".."))
     {
       free(directory_path);
       continue;
@@ -2565,9 +2596,9 @@ void LoadArtworkInfo()
   printf("music set == %s\n\n", artwork.mus_current_identifier);
 #endif
 
-  sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
-  sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
-  sortTreeInfo(&artwork.mus_first, compareTreeInfoEntries);
+  sortTreeInfo(&artwork.gfx_first);
+  sortTreeInfo(&artwork.snd_first);
+  sortTreeInfo(&artwork.mus_first);
 
 #if 0
   dumpTreeInfo(artwork.gfx_first, 0);
@@ -2576,36 +2607,6 @@ void LoadArtworkInfo()
 #endif
 }
 
-void LoadArtworkInfoFromLevelNode(ArtworkDirTree **artwork_node,
-                                 LevelDirTree *level_node,
-                                 char *artwork_directory)
-{
-  TreeInfo *topnode_last = *artwork_node;
-  char *path = getPath2(getLevelDirFromTreeInfo(level_node), artwork_directory);
-
-#if 1
-  printf("::: CHECKING '%s' ...\n", path);
-#endif
-
-  LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path,(*artwork_node)->type);
-
-  if (topnode_last != *artwork_node)
-  {
-    free((*artwork_node)->identifier);
-    free((*artwork_node)->name);
-    free((*artwork_node)->name_sorting);
-
-    (*artwork_node)->identifier   = getStringCopy(level_node->subdir);
-    (*artwork_node)->name         = getStringCopy(level_node->name);
-    (*artwork_node)->name_sorting = getStringCopy(level_node->name);
-
-    (*artwork_node)->sort_priority = level_node->sort_priority;
-    (*artwork_node)->color = LEVELCOLOR((*artwork_node));
-  }
-
-  free(path);
-}
-
 void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
                                  LevelDirTree *level_node)
 {
@@ -2616,28 +2617,6 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
     /* check all tree entries for artwork, but skip parent link entries */
     if (!level_node->parent_link)
     {
-#if 1
-      struct
-      {
-       int type;
-       char *dir;
-      }
-      artwork_type_dirs[] =
-      {
-       { ARTWORK_TYPE_GRAPHICS,        GRAPHICS_DIRECTORY      },
-       { ARTWORK_TYPE_GRAPHICS,        GRAPHICS_ECS_DIRECTORY  },
-       { ARTWORK_TYPE_GRAPHICS,        GRAPHICS_AGA_DIRECTORY  },
-       { ARTWORK_TYPE_SOUNDS,          SOUNDS_DIRECTORY        },
-       { ARTWORK_TYPE_MUSIC,           MUSIC_DIRECTORY         },
-       { -1,                           NULL                    }
-      };
-      int i;
-
-      for (i = 0; artwork_type_dirs[i].type != -1; i++)
-       if ((*artwork_node)->type == artwork_type_dirs[i].type)
-         LoadArtworkInfoFromLevelNode(artwork_node, level_node,
-                                      artwork_type_dirs[i].dir);
-#else
       TreeInfo *topnode_last = *artwork_node;
       char *path = getPath2(getLevelDirFromTreeInfo(level_node),
                            ARTWORK_DIRECTORY((*artwork_node)->type));
@@ -2660,7 +2639,6 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
       }
 
       free(path);
-#endif
     }
 
     if (level_node->node_group != NULL)
@@ -2680,7 +2658,7 @@ void LoadLevelArtworkInfo()
 
   /* needed for reloading level artwork not known at ealier stage */
 
-  if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
+  if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set))
   {
     artwork.gfx_current =
       getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
@@ -2691,7 +2669,7 @@ void LoadLevelArtworkInfo()
       artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
   }
 
-  if (strcmp(artwork.snd_current_identifier, setup.sounds_set) != 0)
+  if (!strEqual(artwork.snd_current_identifier, setup.sounds_set))
   {
     artwork.snd_current =
       getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
@@ -2702,7 +2680,7 @@ void LoadLevelArtworkInfo()
       artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
   }
 
-  if (strcmp(artwork.mus_current_identifier, setup.music_set) != 0)
+  if (!strEqual(artwork.mus_current_identifier, setup.music_set))
   {
     artwork.mus_current =
       getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
@@ -2713,9 +2691,9 @@ void LoadLevelArtworkInfo()
       artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
   }
 
-  sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
-  sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
-  sortTreeInfo(&artwork.mus_first, compareTreeInfoEntries);
+  sortTreeInfo(&artwork.gfx_first);
+  sortTreeInfo(&artwork.snd_first);
+  sortTreeInfo(&artwork.mus_first);
 
 #if 0
   dumpTreeInfo(artwork.gfx_first, 0);
@@ -2853,8 +2831,8 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr)
     char *keyname = getKeyNameFromKey(key);
 
     /* add comment, if useful */
-    if (strcmp(keyname, "(undefined)") != 0 &&
-       strcmp(keyname, "(unknown)") != 0)
+    if (!strEqual(keyname, "(undefined)") &&
+       !strEqual(keyname, "(unknown)"))
     {
       /* add at least one whitespace */
       strcat(line, " ");
@@ -2956,7 +2934,7 @@ static void checkSeriesInfo()
   {
     if (strlen(dir_entry->d_name) > 4 &&
        dir_entry->d_name[3] == '.' &&
-       strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
+       strEqual(&dir_entry->d_name[4], LEVELFILE_EXTENSION))
     {
       char levelnum_str[4];
       int levelnum_value;