added support for multiple user game data directories
[rocksndiamonds.git] / src / libgame / setup.c
index 206db77e4de949a765822011b9ddd738a68917ca..74c21fe33bdad1fe05195ff196b84a3f20278f56 100644 (file)
 
 #include "platform.h"
 
-#if !defined(PLATFORM_WIN32)
-#include <pwd.h>
-#include <sys/param.h>
-#endif
-
 #include "setup.h"
 #include "joystick.h"
 #include "text.h"
@@ -126,9 +121,9 @@ static char *getScoreDir(char *level_subdir)
   if (score_dir == NULL)
   {
     if (program.global_scores)
-      score_dir = getPath2(getCommonDataDir(),   score_subdir);
+      score_dir = getPath2(getCommonDataDir(),       score_subdir);
     else
-      score_dir = getPath2(getUserGameDataDir(), score_subdir);
+      score_dir = getPath2(getMainUserGameDataDir(), score_subdir);
   }
 
   if (level_subdir != NULL)
@@ -143,6 +138,32 @@ static char *getScoreDir(char *level_subdir)
   return score_dir;
 }
 
+static char *getUserSubdir(int nr)
+{
+  static char user_subdir[16] = { 0 };
+
+  sprintf(user_subdir, "%03d", nr);
+
+  return user_subdir;
+}
+
+static char *getUserDir(int nr)
+{
+  static char *user_dir = NULL;
+  char *main_data_dir = getMainUserGameDataDir();
+  char *users_subdir = USERS_DIRECTORY;
+  char *user_subdir = getUserSubdir(nr);
+
+  checked_free(user_dir);
+
+  if (nr != -1)
+    user_dir = getPath3(main_data_dir, users_subdir, user_subdir);
+  else
+    user_dir = getPath2(main_data_dir, users_subdir);
+
+  return user_dir;
+}
+
 static char *getLevelSetupDir(char *level_subdir)
 {
   static char *levelsetup_dir = NULL;
@@ -164,7 +185,7 @@ static char *getCacheDir(void)
   static char *cache_dir = NULL;
 
   if (cache_dir == NULL)
-    cache_dir = getPath2(getUserGameDataDir(), CACHE_DIRECTORY);
+    cache_dir = getPath2(getMainUserGameDataDir(), CACHE_DIRECTORY);
 
   return cache_dir;
 }
@@ -174,7 +195,7 @@ static char *getNetworkDir(void)
   static char *network_dir = NULL;
 
   if (network_dir == NULL)
-    network_dir = getPath2(getUserGameDataDir(), NETWORK_DIRECTORY);
+    network_dir = getPath2(getMainUserGameDataDir(), NETWORK_DIRECTORY);
 
   return network_dir;
 }
@@ -197,7 +218,7 @@ char *getLevelDirFromTreeInfo(TreeInfo *node)
 char *getUserLevelDir(char *level_subdir)
 {
   static char *userlevel_dir = NULL;
-  char *data_dir = getUserGameDataDir();
+  char *data_dir = getMainUserGameDataDir();
   char *userlevel_subdir = LEVELS_DIRECTORY;
 
   checked_free(userlevel_dir);
@@ -346,7 +367,7 @@ char *getUserGraphicsDir(void)
   static char *usergraphics_dir = NULL;
 
   if (usergraphics_dir == NULL)
-    usergraphics_dir = getPath2(getUserGameDataDir(), GRAPHICS_DIRECTORY);
+    usergraphics_dir = getPath2(getMainUserGameDataDir(), GRAPHICS_DIRECTORY);
 
   return usergraphics_dir;
 }
@@ -356,7 +377,7 @@ char *getUserSoundsDir(void)
   static char *usersounds_dir = NULL;
 
   if (usersounds_dir == NULL)
-    usersounds_dir = getPath2(getUserGameDataDir(), SOUNDS_DIRECTORY);
+    usersounds_dir = getPath2(getMainUserGameDataDir(), SOUNDS_DIRECTORY);
 
   return usersounds_dir;
 }
@@ -366,7 +387,7 @@ char *getUserMusicDir(void)
   static char *usermusic_dir = NULL;
 
   if (usermusic_dir == NULL)
-    usermusic_dir = getPath2(getUserGameDataDir(), MUSIC_DIRECTORY);
+    usermusic_dir = getPath2(getMainUserGameDataDir(), MUSIC_DIRECTORY);
 
   return usermusic_dir;
 }
@@ -1072,7 +1093,7 @@ void InitScoreDirectory(char *level_subdir)
   if (program.global_scores)
     createDirectory(getCommonDataDir(), "common data", permissions);
   else
-    createDirectory(getUserGameDataDir(), "user data", permissions);
+    createDirectory(getMainUserGameDataDir(), "main user data", permissions);
 
   createDirectory(getScoreDir(NULL), "main score", permissions);
   createDirectory(getScoreDir(level_subdir), "level score", permissions);
@@ -1084,7 +1105,7 @@ void InitUserLevelDirectory(char *level_subdir)
 {
   if (!directoryExists(getUserLevelDir(level_subdir)))
   {
-    createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
+    createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
     createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
     createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
 
@@ -1097,7 +1118,7 @@ void InitNetworkLevelDirectory(char *level_subdir)
 {
   if (!directoryExists(getNetworkLevelDir(level_subdir)))
   {
-    createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
+    createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
     createDirectory(getNetworkDir(), "network data", PERMS_PRIVATE);
     createDirectory(getNetworkLevelDir(NULL), "main network level", PERMS_PRIVATE);
     createDirectory(getNetworkLevelDir(level_subdir), "network level", PERMS_PRIVATE);
@@ -1113,7 +1134,7 @@ void InitLevelSetupDirectory(char *level_subdir)
 
 static void InitCacheDirectory(void)
 {
-  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
   createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
 }
 
@@ -1361,18 +1382,18 @@ void dumpTreeInfo(TreeInfo *node, int depth)
 {
   int i;
 
-  Print("Dumping TreeInfo:\n");
+  Debug("tree", "Dumping TreeInfo:");
 
   while (node)
   {
     for (i = 0; i < (depth + 1) * 3; i++)
-      Print(" ");
+      DebugContinued("", " ");
 
-    Print("'%s' / '%s'\n", node->identifier, node->name);
+    DebugContinued("tree", "'%s' / '%s'\n", node->identifier, node->name);
 
     /*
     // use for dumping artwork info tree
-    Print("subdir == '%s' ['%s', '%s'] [%d])\n",
+    Debug("tree", "subdir == '%s' ['%s', '%s'] [%d])",
          node->subdir, node->fullpath, node->basepath, node->in_user_dir);
     */
 
@@ -1504,10 +1525,10 @@ char *getHomeDir(void)
   {
     if ((dir = getenv("HOME")) == NULL)
     {
-      struct passwd *pwd;
+      dir = getUnixHomeDir();
 
-      if ((pwd = getpwuid(getuid())) != NULL)
-       dir = getStringCopy(pwd->pw_dir);
+      if (dir != NULL)
+       dir = getStringCopy(dir);
       else
        dir = ".";
     }
@@ -1557,23 +1578,31 @@ char *getPersonalDataDir(void)
   return personal_data_dir;
 }
 
-char *getUserGameDataDir(void)
+char *getMainUserGameDataDir(void)
 {
-  static char *user_game_data_dir = NULL;
+  static char *main_user_data_dir = NULL;
 
 #if defined(PLATFORM_ANDROID)
-  if (user_game_data_dir == NULL)
-    user_game_data_dir = (char *)(SDL_AndroidGetExternalStorageState() &
+  if (main_user_data_dir == NULL)
+    main_user_data_dir = (char *)(SDL_AndroidGetExternalStorageState() &
                                  SDL_ANDROID_EXTERNAL_STORAGE_WRITE ?
                                  SDL_AndroidGetExternalStoragePath() :
                                  SDL_AndroidGetInternalStoragePath());
 #else
-  if (user_game_data_dir == NULL)
-    user_game_data_dir = getPath2(getPersonalDataDir(),
+  if (main_user_data_dir == NULL)
+    main_user_data_dir = getPath2(getPersonalDataDir(),
                                  program.userdata_subdir);
 #endif
 
-  return user_game_data_dir;
+  return main_user_data_dir;
+}
+
+char *getUserGameDataDir(void)
+{
+  if (user.nr == 0)
+    return getMainUserGameDataDir();
+  else
+    return getUserDir(user.nr);
 }
 
 char *getSetupDir(void)
@@ -1641,9 +1670,20 @@ void createDirectory(char *dir, char *text, int permission_class)
   posix_umask(last_umask);             // restore previous umask
 }
 
+void InitMainUserDataDirectory(void)
+{
+  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+}
+
 void InitUserDataDirectory(void)
 {
-  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+
+  if (user.nr != 0)
+  {
+    createDirectory(getUserDir(-1), "users", PERMS_PRIVATE);
+    createDirectory(getUserDir(user.nr), "user data", PERMS_PRIVATE);
+  }
 }
 
 void SetFilePermissions(char *filename, int permission_class)
@@ -1891,7 +1931,7 @@ SetupFileHash *newSetupFileHash(void)
     create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
 
   if (new_hash == NULL)
-    Error(ERR_EXIT, "create_hashtable() failed -- out of memory");
+    Fail("create_hashtable() failed -- out of memory");
 
   return new_hash;
 }
@@ -1924,7 +1964,7 @@ void setHashEntry(SetupFileHash *hash, char *token, char *value)
   // change value; if it does not exist, insert it as new
   if (!change_hash_entry(hash, token, value_copy))
     if (!insert_hash_entry(hash, getStringCopy(token), value_copy))
-      Error(ERR_EXIT, "cannot insert into hash -- aborting");
+      Fail("cannot insert into hash -- aborting");
 }
 
 char *removeHashEntry(SetupFileHash *hash, char *token)
@@ -3540,7 +3580,7 @@ void LoadLevelInfo(void)
   leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
   if (leveldir_first == NULL)
-    Error(ERR_EXIT, "cannot find any valid level series in any directory");
+    Fail("cannot find any valid level series in any directory");
 
   sortTreeInfo(&leveldir_first);
 
@@ -3766,6 +3806,34 @@ static TreeInfo *getDummyArtworkInfo(int type)
   return artwork_new;
 }
 
+void SetCurrentArtwork(int type)
+{
+  ArtworkDirTree **current_ptr = ARTWORK_CURRENT_PTR(artwork, type);
+  ArtworkDirTree *first_node = ARTWORK_FIRST_NODE(artwork, type);
+  char *setup_set = SETUP_ARTWORK_SET(setup, type);
+  char *default_subdir = ARTWORK_DEFAULT_SUBDIR(type);
+
+  // set current artwork to artwork configured in setup menu
+  *current_ptr = getTreeInfoFromIdentifier(first_node, setup_set);
+
+  // if not found, set current artwork to default artwork
+  if (*current_ptr == NULL)
+    *current_ptr = getTreeInfoFromIdentifier(first_node, default_subdir);
+
+  // if not found, set current artwork to first artwork in tree
+  if (*current_ptr == NULL)
+    *current_ptr = getFirstValidTreeInfoEntry(first_node);
+}
+
+void ChangeCurrentArtworkIfNeeded(int type)
+{
+  char *current_identifier = ARTWORK_CURRENT_IDENTIFIER(artwork, type);
+  char *setup_set = SETUP_ARTWORK_SET(setup, type);
+
+  if (!strEqual(current_identifier, setup_set))
+    SetCurrentArtwork(type);
+}
+
 void LoadArtworkInfo(void)
 {
   LoadArtworkInfoCache();
@@ -3801,29 +3869,9 @@ void LoadArtworkInfo(void)
     artwork.mus_first = getDummyArtworkInfo(TREE_TYPE_MUSIC_DIR);
 
   // before sorting, the first entries will be from the user directory
-  artwork.gfx_current =
-    getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
-  if (artwork.gfx_current == NULL)
-    artwork.gfx_current =
-      getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR);
-  if (artwork.gfx_current == NULL)
-    artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
-
-  artwork.snd_current =
-    getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
-  if (artwork.snd_current == NULL)
-    artwork.snd_current =
-      getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR);
-  if (artwork.snd_current == NULL)
-    artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
-
-  artwork.mus_current =
-    getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
-  if (artwork.mus_current == NULL)
-    artwork.mus_current =
-      getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR);
-  if (artwork.mus_current == NULL)
-    artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
+  SetCurrentArtwork(ARTWORK_TYPE_GRAPHICS);
+  SetCurrentArtwork(ARTWORK_TYPE_SOUNDS);
+  SetCurrentArtwork(ARTWORK_TYPE_MUSIC);
 
   artwork.gfx_current_identifier = artwork.gfx_current->identifier;
   artwork.snd_current_identifier = artwork.snd_current->identifier;
@@ -3925,39 +3973,9 @@ void LoadLevelArtworkInfo(void)
   print_timestamp_time("SaveArtworkInfoCache");
 
   // needed for reloading level artwork not known at ealier stage
-
-  if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set))
-  {
-    artwork.gfx_current =
-      getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
-    if (artwork.gfx_current == NULL)
-      artwork.gfx_current =
-       getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR);
-    if (artwork.gfx_current == NULL)
-      artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
-  }
-
-  if (!strEqual(artwork.snd_current_identifier, setup.sounds_set))
-  {
-    artwork.snd_current =
-      getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
-    if (artwork.snd_current == NULL)
-      artwork.snd_current =
-       getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR);
-    if (artwork.snd_current == NULL)
-      artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
-  }
-
-  if (!strEqual(artwork.mus_current_identifier, setup.music_set))
-  {
-    artwork.mus_current =
-      getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
-    if (artwork.mus_current == NULL)
-      artwork.mus_current =
-       getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR);
-    if (artwork.mus_current == NULL)
-      artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
-  }
+  ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_GRAPHICS);
+  ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_SOUNDS);
+  ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_MUSIC);
 
   print_timestamp_time("getTreeInfoFromIdentifier");
 
@@ -4053,7 +4071,7 @@ void AddTreeSetToTreeInfo(TreeInfo *tree_node, char *tree_dir,
                          char *tree_subdir_new, int type)
 {
   if (!AddTreeSetToTreeInfoExt(tree_node, tree_dir, tree_subdir_new, type))
-    Error(ERR_EXIT, "internal tree info structure corrupted -- aborting");
+    Fail("internal tree info structure corrupted -- aborting");
 }
 
 void AddUserLevelSetToLevelInfo(char *level_subdir_new)
@@ -4095,7 +4113,7 @@ TreeInfo *getArtworkTreeInfoForUserLevelSet(int type)
     ti = getTreeInfoFromIdentifier(artwork_first_node,
                                   ARTWORK_DEFAULT_SUBDIR(type));
     if (ti == NULL)
-      Error(ERR_EXIT, "cannot find default graphics -- should not happen");
+      Fail("cannot find default graphics -- should not happen");
   }
 
   return ti;