فهرست منبع

VCMIDirs update #2

Changet to tree model based on classes
Karol 11 سال پیش
والد
کامیت
8eb1721050
2فایلهای تغییر یافته به همراه347 افزوده شده و 482 حذف شده
  1. 314 393
      lib/VCMIDirs.cpp
  2. 33 89
      lib/VCMIDirs.h

+ 314 - 393
lib/VCMIDirs.cpp

@@ -11,467 +11,388 @@
 #include "StdInc.h"
 #include "VCMIDirs.h"
 
-namespace bfs = boost::filesystem;
+namespace bfs = boost::filesystem; // Should be in each cpp file
 
-namespace VCMIDirs
+#ifdef _WIN32
+// File: VCMIDirs_win32.h
+//#include "IVCMIDirs.h"
+
+class VCMIDirs_win32 : public IVCMIDirs
 {
-	namespace detail
-	{
-		bfs::path g_user_data_path;
-		bfs::path g_user_cache_path;
-		bfs::path g_user_config_path;
-		bfs::path g_user_save_path;
-		
-		bfs::path g_library_path;
-		bfs::path g_client_path;
-		bfs::path g_server_path;
-
-		std::vector<bfs::path> g_data_paths;
-
-		std::string g_help_string;
-
-		extern bfs::path GetDataPath();
-		extern bfs::path GetCachePath();
-		extern bfs::path GetConfigPath();
-		extern bfs::path GetUserSavePath();
-		
-		extern bfs::path GetLibraryPath();
-		extern bfs::path GetClientPath();
-		extern bfs::path GetServerPath();
-		extern std::vector<bfs::path> GetDataPaths();
-	
-		extern std::string GetHelpString();
-	}
-	
-	void InitAllPathes(void)
-	{
-		detail::g_user_data_path = detail::GetDataPath();
-		detail::g_user_cache_path = detail::GetCachePath();
-		detail::g_user_config_path = detail::GetConfigPath();
-		detail::g_user_save_path = detail::GetUserSavePath();
+	public:
+		boost::filesystem::path userDataPath() const override;
+		boost::filesystem::path userCachePath() const override;
+		boost::filesystem::path userConfigPath() const override;
+		boost::filesystem::path userSavePath() const override;
 
-		detail::g_library_path = detail::GetLibraryPath();
-		detail::g_client_path = detail::GetClientPath();
-		detail::g_server_path = detail::GetServerPath();
+		std::vector<boost::filesystem::path> dataPaths() const override;
 
-		detail::g_data_paths = detail::GetDataPaths();
+		boost::filesystem::path clientPath() const override;
+		boost::filesystem::path serverPath() const override;
 
-		detail::g_help_string = detail::GetHelpString();
+		boost::filesystem::path libraryPath() const override;
+		boost::filesystem::path binaryPath() const override;
 
-		// initialize local directory and create folders to which VCMI needs write access
-		bfs::create_directory(detail::g_user_data_path);
-		bfs::create_directory(detail::g_user_cache_path);
-		bfs::create_directory(detail::g_user_config_path);
-		bfs::create_directory(detail::g_user_save_path);
-	}
+		std::string libraryName(const std::string& basename) const override;
 
-	namespace detail
-	{
-		struct InitAllPathes_ctor
-		{
-			InitAllPathes_ctor() { InitAllPathes(); }
-		} InitAllPathes_ctor_global_obj;
-	};
+		std::string genHelpString() const override;
+};
+// End of file: VCMIDirs_win32.h
+
+// File: VCMIDirs_win32.cpp
+//#include "StdInc.h"
+//#include "VCMIDirs_win32"
+// WinAPI
+#include <Windows.h>	// WideCharToMultiByte
+#include <Shlobj.h>		// SHGetSpecialFolderPathW
 
-	// TODO: Remove _VCMIDirs
-	static _VCMIDirs _VCMIDirsGlobal;
-	_VCMIDirs & get()
+namespace VCMIDirs
+{
+	const IVCMIDirs* get()
 	{
-		puts("VCMIDirs::get() - used of deprecated function :#");
-		return _VCMIDirsGlobal;
+		static VCMIDirs_win32 singleton;
+		return &singleton;
 	}
 }
 
-// FIXME: find way to at least decrease size of this ifdef (along with cleanup in CMake)
-#ifdef _WIN32
-// This part should be moved into separate file (for example: VCMIDirs_win32.cpp)
-// WinAPI
-#include <Windows.h>
-#include <Shlobj.h>
-
-namespace VCMIDirs
+bfs::path VCMIDirs_win32::userDataPath() const
 {
-	namespace detail
+	const char* profile_dir_a;
+	wchar_t profile_dir_w[MAX_PATH];
+
+	// The user's profile folder. A typical path is C:\Users\username.
+	// FIXME: Applications should not create files or folders at this level;
+	// they should put their data under the locations referred to by CSIDL_APPDATA or CSIDL_LOCAL_APPDATA.
+	if (SHGetSpecialFolderPathW(nullptr, profile_dir_w, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
 	{
-		bfs::path GetDataPath()
-		{
-			const char* profile_dir_a;
-			wchar_t profile_dir_w[MAX_PATH];
-
-			// The user's profile folder. A typical path is C:\Users\username.
-			// FIXME: Applications should not create files or folders at this level;
-			// they should put their data under the locations referred to by CSIDL_APPDATA or CSIDL_LOCAL_APPDATA.
-			if (SHGetSpecialFolderPathW(nullptr, profile_dir_w, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
-			{
-				if (profile_dir_a = std::getenv("userprofile")) // STL way succeed
-					return bfs::path(profile_dir_a) / "vcmi";
-				else
-					return "."; // Every thing failed, return current directory.
-			}
-			else
-				return bfs::path(profile_dir_w) / "vcmi";
-
-			//return dataPaths()[0] ???;
-		}
+		// FIXME: Create macro for MS Visual Studio.
+		if (profile_dir_a = std::getenv("userprofile")) // STL way succeed
+			return bfs::path(profile_dir_a) / "vcmi";
+		else
+			return "."; // Every thing failed, return current directory.
+	}
+	else
+		return bfs::path(profile_dir_w) / "vcmi";
 
-		bfs::path GetCachePath()
-		{
-			return GetDataPath();
-		}
+	//return dataPaths()[0] ???;
+}
+bfs::path VCMIDirs_win32::userCachePath() const { return userDataPath(); }
+bfs::path VCMIDirs_win32::userConfigPath() const { return userDataPath() / "config"; }
+bfs::path VCMIDirs_win32::userSavePath() const { return userDataPath() / "Games"; }
 
-		bfs::path GetConfigPath()
-		{
-			return GetDataPath() / "config";
-		}
+std::vector<bfs::path> VCMIDirs_win32::dataPaths() const
+{
+	return std::vector<bfs::path>(1, bfs::path("."));
+}
 
-		bfs::path GetUserSavePath()
-		{
-			return GetDataPath() / "Games";
-		}
+bfs::path VCMIDirs_win32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
+bfs::path VCMIDirs_win32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
 
-		bfs::path GetLibraryPath()
-		{
-			return ".";
-		}
+bfs::path VCMIDirs_win32::libraryPath() const { return "."; }
+bfs::path VCMIDirs_win32::binaryPath() const { return ".";  }
 
-		bfs::path GetClientPath()
+std::string VCMIDirs_win32::genHelpString() const
+{
+	// I think this function should have multiple versions
+	// 1. For various arguments
+	// 2. Inverse functions
+	// and should be moved to vstd
+	// or use http://utfcpp.sourceforge.net/
+	auto utf8_convert = [](const bfs::path& path) -> std::string
+	{
+		const auto& path_string = path.native();
+		auto perform_convert = [&path_string](LPSTR output, int output_size)
 		{
-			return GetLibraryPath() / "VCMI_client.exe";
-		}
+			return WideCharToMultiByte(
+				CP_UTF8,				// Use wchar_t -> utf8 char_t
+				WC_ERR_INVALID_CHARS,	// Fails when invalid char occur
+				path_string.c_str(),	// String to convert
+				path_string.size(),		// String to convert size
+				output,					// Result
+				output_size,			// Result size
+				nullptr, nullptr);		// For the ... CP_UTF8 settings for CodePage, this parameter must be set to NULL
+		};
 
-		bfs::path GetServerPath()
+		int char_count = perform_convert(nullptr, 0); // Result size (0 - obtain size)
+		if (char_count > 0)
 		{
-			return GetLibraryPath() / "VCMI_server.exe";
-		}
-	
-		std::vector<bfs::path> GetDataPaths()
-		{
-			return std::vector<bfs::path>(1, bfs::path("."));
+			std::unique_ptr<char[]> buffer(new char[char_count]);
+			if ((char_count = perform_convert(buffer.get(), char_count)) > 0)
+				return std::string(buffer.get(), char_count);
 		}
 
-		std::string GetHelpString()
-		{
-			// I think this function should have multiple versions
-			// 1. For various arguments
-			// 2. Inverse functions
-			// and should be moved to vstd
-			// or use http://utfcpp.sourceforge.net/
-			auto utf8_convert = [](const bfs::path& path) -> std::string
-			{
-				const auto& path_string = path.native();
-				auto perform_convert = [&path_string](LPSTR output, int output_size)
-				{
-					return WideCharToMultiByte(
-						CP_UTF8,				// Use wchar_t -> utf8 char_t
-						WC_ERR_INVALID_CHARS,	// Fails when invalid char occur
-						path_string.c_str(),	// String to convert
-						path_string.size(),		// String to convert size
-						output,					// Result
-						output_size,			// Result size
-						nullptr, nullptr);		// For the ... CP_UTF8 settings for CodePage, this parameter must be set to NULL
-				};
-
-				int char_count = perform_convert(nullptr, 0); // Result size (0 - obtain size)
-				if (char_count > 0)
-				{
-					std::unique_ptr<char[]> buffer(new char[char_count]);
-					if ((char_count = perform_convert(buffer.get(), char_count)) > 0)
-						return std::string(buffer.get(), char_count);
-				}
-
-				// Conversion failed :C
-				return path.string();
-			};
-
-			std::vector<std::string> temp_vec;
-			for (const bfs::path& path : GetDataPaths())
-				temp_vec.push_back(utf8_convert(path));
-			std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
-
-			
-			return
-				"  game data:   " + gd_string_a + "\n" +
-				"  libraries:   " + utf8_convert(GetLibraryPath()) + "\n" +
-				"  server:      " + utf8_convert(GetServerPath()) + "\n" +
-				"\n" +
-				"  user data:   " + utf8_convert(GetDataPath()) + "\n" +
-				"  user cache:  " + utf8_convert(GetCachePath()) + "\n" +
-				"  user config: " + utf8_convert(GetConfigPath()) + "\n" +
-				"  user saves:  " + utf8_convert(GetUserSavePath()) + "\n"; // Should end without new-line?
-		}
-	}
+		// Conversion failed :C
+		return path.string();
+	};
 
-	std::string libraryName(const std::string& basename)
-	{
-		return basename + ".dll";
-	}
+	std::vector<std::string> temp_vec;
+	for (const bfs::path& path : dataPaths())
+		temp_vec.push_back(utf8_convert(path));
+	std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
+
+
+	return
+		"  game data:   " + gd_string_a + "\n" +
+		"  libraries:   " + utf8_convert(libraryPath()) + "\n" +
+		"  server:      " + utf8_convert(serverPath()) + "\n" +
+		"\n" +
+		"  user data:   " + utf8_convert(userDataPath()) + "\n" +
+		"  user cache:  " + utf8_convert(userCachePath()) + "\n" +
+		"  user config: " + utf8_convert(userConfigPath()) + "\n" +
+		"  user saves:  " + utf8_convert(userSavePath()) + "\n"; // Should end without new-line?
 }
 
-#elif defined (__APPLE__)
-// This part should be moved to separate file (for example: VCMIDirs_apple.cpp)
+std::string libraryName(const std::string& basename) { return basename + ".dll"; }
+// End of file: VCMIDirs_win32.cpp
+#else // UNIX
+// File: IVCMIDirs_unix.h
+//#include "IVCMIDirs.h"
 
-namespace VCMIDirs
+class IVCMIDirs_unix : public IVCMIDirs
 {
-	namespace detail
-	{
-		bfs::path GetDataPath()
-		{
-			// This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
-			// NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
-			// UserPath = path([urls[0] path] + "/vcmi").string();
+	public:
+		boost::filesystem::path clientPath() const override;
+		boost::filesystem::path serverPath() const override;
 
-			// ...so here goes a bit of hardcode instead
+		std::string genHelpString() const override;
+};
+// End of file: IVCMIDirs_unix.h
 
-			const char* home_dir = getenv("HOME"); // Should be std::getenv?
-			if (home_dir == nullptr)
-				home_dir = ".";
-			return bfs::path(home_dir) / "Library" / "Application Support" / "vcmi";
-		}
+// File: IVCMIDirs_unix.cpp
+//#include "StdInc.h"
+//#include "IVCMIDirs_unix.h"
 
-		bfs::path GetCachePath()
-		{
-			return GetDataPath();
-		}
+bfs::path IVCMIDirs_unix::clientPath() const { return binaryPath() / "vcmiclient"; }
+bfs::path IVCMIDirs_unix::clientPath() const { return binaryPath() / "vcmiserver"; }
 
-		bfs::path GetConfigPath()
-		{
-			return GetDataPath() / "config";
-		}
+std::string IVCMIDirs_unix::genHelpString() const
+{
+	std::vector<std::string> temp_vec;
+	for (const bfs::path& path : dataPaths())
+		temp_vec.push_back(path.string());
+	std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
+
+
+	return
+		"  game data:   " + gd_string_a + "\n" +
+		"  libraries:   " + libraryPath().string() + "\n" +
+		"  server:      " + serverPath().string() + "\n" +
+		"\n" +
+		"  user data:   " + userDataPath().string() + "\n" +
+		"  user cache:  " + userCachePath().string() + "\n" +
+		"  user config: " + userConfigPath().string() + "\n" +
+		"  user saves:  " + userSavePath().string() + "\n"; // Should end without new-line?
+}
+// End of file: IVCMIDirs_unix.cpp
 
-		bfs::path GetUserSavePath()
-		{
-			return GetDataPath() / "Games";
-		}
+#ifdef __APPLE__
+// File: VCMIDirs_OSX.h
+//#include "IVCMIDirs_unix.h"
 
-		bfs::path GetLibraryPath()
-		{
-			return ".";
-		}
+class VCMIDirs_OSX : public IVCMIDirs_unix
+{
+	public:
+		boost::filesystem::path userDataPath() const override;
+		boost::filesystem::path userCachePath() const override;
+		boost::filesystem::path userConfigPath() const override;
+		boost::filesystem::path userSavePath() const override;
 
-		bfs::path GetClientPath()
-		{
-			return "./vcmiclient";
-		}
+		std::vector<boost::filesystem::path> dataPaths() const override;
 
-		bfs::path GetServerPath()
-		{
-			return "./vcmiserver";
-		}
+		boost::filesystem::path libraryPath() const override;
+		boost::filesystem::path binaryPath() const override;
 
-		std::vector<bfs::path> GetDataPaths()
-		{
-			return std::vector<std::string>(1, "../Data");
-		}
+		std::string libraryName(const std::string& basename) const override;
+};
+// End of file: VCMIDirs_OSX.h
 
-		std::string GetHelpString()
-		{
-			std::vector<std::string> temp_vec;
-			for (const bfs::path& path : GetDataPaths())
-				temp_vec.push_back(path.string());
-
-			return
-				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
-				"  libraries:   " + GetLibraryPath().string() + "\n" +
-				"  server:      " + GetServerPath().string() + "\n" +
-				"\n" +
-				"  user data:   " + GetDataPath().string() + "\n" +
-				"  user cache:  " + GetCachePath().string() + "\n" +
-				"  user config: " + GetConfigPath().string() + "\n" +
-				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
-		}
-	}
+// File: VCMIDirs_OSX.cpp
+//#include "StdInc.h"
+//#include "VCMIDirs_OSX.h"
 
-	std::string libraryName(const std::string& basename)
+namespace VCMIDirs
+{
+	const IVCMIDirs* get()
 	{
-		return "lib" + basename + ".dylib";
+		static VCMIDirs_OSX singleton;
+		return &singleton;
 	}
 }
-#elif defined __ANDROID__
-// This part should be moved to separate file (for example: VCMIDirs_android.cpp)
 
-namespace VCMIDirs
+bfs::path VCMIDirs_OSX::userDataPath() const
 {
-	namespace detail
-	{
-		bfs::path GetDataPath()
-		{
-			// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
-			return getenv("HOME");
-		}
+	// This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
+	// NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
+	// UserPath = path([urls[0] path] + "/vcmi").string();
 
-		bfs::path GetCachePath()
-		{
-			return GetDataPath() / "cache";
-		}
+	// ...so here goes a bit of hardcode instead
 
-		bfs::path GetConfigPath()
-		{
-			return GetDataPath() / "config";
-		}
+	const char* home_dir = getenv("HOME"); // Should be std::getenv?
+	if (home_dir == nullptr)
+		home_dir = ".";
+	return bfs::path(home_dir) / "Library" / "Application Support" / "vcmi";
+}
+bfs::path VCMIDirs_OSX::userCachePath() const { return userDataPath(); }
+bfs::path VCMIDirs_OSX::userConfigPath() const { return userDataPath() / "config"; }
+bfs::path VCMIDirs_OSX::userSavePath() const { return userDataPath() / "Games"; }
 
-		bfs::path GetUserSavePath()
-		{
-			return GetDataPath() / "Saves"; // Why different than other platforms???
-		}
+std::vector<bfs::path> VCMIDirs_OSX::dataPaths() const
+{
+	return std::vector<bfs::path>(1, "../Data");
+}
 
-		bfs::path GetLibraryPath()
-		{
-			return M_LIB_DIR;
-		}
+bfs::path VCMIDirs_OSX::libraryPath() const { return "."; }
+bfs::path VCMIDirs_OSX::binaryPath() const { return "."; }
 
-		bfs::path GetClientPath()
-		{
-			return bfs::path(M_BIN_DIR) / "vcmiclient";
-		}
+std::string libraryName(const std::string& basename) { return "lib" + basename + ".dylib"; }
+// End of file: VCMIDirs_OSX.cpp
+#else
+// File: VCMIDirs_Linux.h
+//#include "IVCMIDirs_unix.h"
 
-		bfs::path GetServerPath()
-		{
-			return bfs::path(M_BIN_DIR) / "vcmiserver";
-		}
+class VCMIDirs_Linux : public IVCMIDirs_unix
+{
+public:
+	boost::filesystem::path userDataPath() const override;
+	boost::filesystem::path userCachePath() const override;
+	boost::filesystem::path userConfigPath() const override;
+	boost::filesystem::path userSavePath() const override;
 
-		std::vector<bfs::path> GetDataPaths()
-		{
-			return std::vector<bfs::path>(1, GetDataPath());
-		}
+	std::vector<boost::filesystem::path> dataPaths() const override;
 
-		std::string GetHelpString()
-		{
-			std::vector<std::string> temp_vec;
-			for (const bfs::path& path : GetDataPaths())
-				temp_vec.push_back(path.string());
-
-			return
-				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
-				"  libraries:   " + GetLibraryPath().string() + "\n" +
-				"  server:      " + GetServerPath().string() + "\n" +
-				"\n" +
-				"  user data:   " + GetDataPath().string() + "\n" +
-				"  user cache:  " + GetCachePath().string() + "\n" +
-				"  user config: " + GetConfigPath().string() + "\n" +
-				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
-		}
-	}
+	boost::filesystem::path libraryPath() const override;
+	boost::filesystem::path binaryPath() const override;
+
+	std::string libraryName(const std::string& basename) const override;
+};
+// End of file: VCMIDirs_Linux.h
 
-	std::string libraryName(const std::string& basename)
+// File: VCMIDirs_Linux.cpp
+//#include "StdInc.h"
+//#include "VCMIDirs_Linux.h"
+
+namespace VCMIDirs
+{
+	const IVCMIDirs* get()
 	{
-		return "lib" + basename + ".so";
+		static VCMIDirs_Linux singleton;
+		return &singleton;
 	}
 }
-#else
-// This part should be moved to separate file (for example: VCMIDirs_default.cpp)
 
-namespace VCMIDirs
+bfs::path VCMIDirs_Linux::userDataPath() const
 {
-	namespace detail
-	{
-		// $XDG_DATA_HOME, default: $HOME/.local/share
-		bfs::path GetDataPath()
-		{
-			const char* home_dir;
-			if (home_dir = getenv("XDG_DATA_HOME"))
-				return = home_dir;
-			else if (home_dir = getenv("HOME"))
-				return = bfs::path(home_dir) / ".local" / "share" / "vcmi";
-			else
-				return ".";
-		}
-		
-		// $XDG_CACHE_HOME, default: $HOME/.cache
-		bfs::path GetCachePath()
-		{
-			const char* home_dir;
-			if (home_dir = getenv("XDG_CACHE_HOME"))
-				return bfs::path(home_dir) / "vcmi";
-			else if (home_dir = getenv("HOME"))
-				return bfs::path(home_dir) / ".cache" / "vcmi";
-			else
-				return ".";
-		}
+	// $XDG_DATA_HOME, default: $HOME/.local/share
+	const char* home_dir;
+	if (home_dir = getenv("XDG_DATA_HOME"))
+		return home_dir;
+	else if (home_dir = getenv("HOME"))
+		return bfs::path(home_dir) / ".local" / "share" / "vcmi";
+	else
+		return ".";
+}
+bfs::path VCMIDirs_Linux::userCachePath() const
+{
+	// $XDG_CACHE_HOME, default: $HOME/.cache
+	const char* home_dir;
+	if (home_dir = getenv("XDG_CACHE_HOME"))
+		return bfs::path(home_dir) / "vcmi";
+	else if (home_dir = getenv("HOME"))
+		return bfs::path(home_dir) / ".cache" / "vcmi";
+	else
+		return ".";
+}
+bfs::path VCMIDirs_Linux::userConfigPath() const
+{
+	// $XDG_CONFIG_HOME, default: $HOME/.config
+	const char* home_dir;
+	if (home_dir = getenv("XDG_CONFIG_HOME"))
+		return bfs::path(home_dir) / "vcmi";
+	else if (home_dir = getenv("HOME"))
+		return bfs::path(home_dir) / ".config" / "vcmi";
+	else
+		return ".";
+}
+bfs::path VCMIDirs_Linux::userSavePath() const
+{
+	return userDataPath() / "Saves";
+}
 
-		// $XDG_CONFIG_HOME, default: $HOME/.config
-		bfs::path GetConfigPath()
-		{
-			const char* home_dir;
-			if (home_dir = getenv("XDG_CONFIG_HOME"))
-				return bfs:path(home_dir) / "vcmi";
-			else if (home_dir = getenv("HOME"))
-				return bfs::path(home_dir) / ".config" / "vcmi";
-			else
-				return ".";
-		}
+std::vector<bfs::path> VCMIDirs_Linux::dataPaths() const
+{
+	// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
 
-		bfs::path GetUserSavePath()
-		{
-			return GetDataPath() / "Saves"; // Why different than other platforms???
-		}
+	// construct list in reverse.
+	// in specification first directory has highest priority
+	// in vcmi fs last directory has highest priority
+	std::vector<bfs::path> ret;
 
-		bfs::path GetLibraryPath()
-		{
-			return M_LIB_DIR;
-		}
+	const char* home_dir;
+	if (home_dir = getenv("HOME")) // compatibility, should be removed after 0.96
+		ret.push_back(bfs::path(home_dir) / ".vcmi");
+	ret.push_back(M_DATA_DIR);
 
-		bfs::path GetClientPath()
-		{
-			return bfs::path(M_BIN_DIR) / "vcmiclient";
-		}
+	if ((home_dir = getenv("XDG_DATA_DIRS")) != nullptr)
+	{
+		std::string dataDirsEnv = home_dir;
+		std::vector<std::string> dataDirs;
+		boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
+		for (auto & entry : boost::adaptors::reverse(dataDirs))
+			ret.push_back(entry + "/vcmi");
+	}
+	else
+	{
+		ret.push_back("/usr/share/");
+		ret.push_back("/usr/local/share/");
+	}
 
-		bfs::path GetServerPath()
-		{
-			return bfs::path(M_BIN_DIR) / "vcmiserver";
-		}
+	return ret;
+}
 
-		std::vector<bfs::path> GetDataPaths()
-		{
-			// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
-
-			// construct list in reverse.
-			// in specification first directory has highest priority
-			// in vcmi fs last directory has highest priority
-			std::vector<bfs::path> ret;
-
-			const char* home_dir;
-			if (home_dir = getenv("HOME")) // compatibility, should be removed after 0.96
-				ret.push_back(bfs::path(home_dir) / ".vcmi");
-			ret.push_back(M_DATA_DIR);
-
-			if (home_dir = getenv("XDG_DATA_DIRS") != nullptr)
-			{
-				std::string dataDirsEnv = home_dir;
-				std::vector<std::string> dataDirs;
-				boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
-				for (auto & entry : boost::adaptors::reverse(dataDirs))
-					ret.push_back(entry + "/vcmi");
-			}
-			else
-			{
-				ret.push_back("/usr/share/");
-				ret.push_back("/usr/local/share/");
-			}
-
-			return ret;
-		}
+bfs::path VCMIDirs_Linux::libraryPath() const { return M_LIB_PATH; }
+bfs::path VCMIDirs_Linux::binaryPath() const { return M_BIN_DIR; }
 
-		std::string GetHelpString()
-		{
-			std::vector<std::string> temp_vec;
-			for (const bfs::path& path : GetDataPaths())
-				temp_vec.push_back(path.string());
-
-			return
-				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
-				"  libraries:   " + GetLibraryPath().string() + "\n" +
-				"  server:      " + GetServerPath().string() + "\n" +
-				"\n" +
-				"  user data:   " + GetDataPath().string() + "\n" +
-				"  user cache:  " + GetCachePath().string() + "\n" +
-				"  user config: " + GetConfigPath().string() + "\n" +
-				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
-		}
-	}
+std::string VCMIDirs_Linux::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; }
+// End of file VCMIDirs_Linux.cpp
+#ifdef __ANDROID__
+// File: VCMIDirs_Android.h
+//#include "VCMIDirs_Linux.h"
+class VCMIDirs_Android : public VCMIDirs_Linux
+{
+public:
+	boost::filesystem::path userDataPath() const override;
+	boost::filesystem::path userCachePath() const override;
+	boost::filesystem::path userConfigPath() const override;
+	boost::filesystem::path userSavePath() const override;
+
+	std::vector<boost::filesystem::path> dataPaths() const override;
+};
+// End of file: VCMIDirs_Android.h
+
+// File: VCMIDirs_Android.cpp
+//#include "StdInc.h"
+//#include "VCMIDirs_Android.h"
 
-	std::string libraryName(const std::string& basename)
+namespace VCMIDirs
+{
+	const IVCMIDirs* get()
 	{
-		return "lib" + basename + ".so";
+		static VCMIDirs_Android singleton;
+		return &singleton;
 	}
 }
+
+// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
+bfs::path VCMIDirs_Android::userDataPath() const { return getenv("HOME"); }
+bfs::path VCMIDirs_Android::userCachePath() const { return userDataPath() / "cache"; }
+bfs::path VCMIDirs_Android::userConfigPath() const { return userDataPath() / "config"; }
+bfs::path VCMIDirs_Android::userSavePath() const { return userDataPath() / "Saves"; }
+
+std::vector<bfs::path> VCMIDirs_Android::dataPaths() const
+{
+	return std::vector<bfs::path>(1, userDataPath());
+}
+// End of file: VCMIDirs_Android.cpp
+#endif
+#endif
 #endif

+ 33 - 89
lib/VCMIDirs.h

@@ -7,112 +7,56 @@
 * Full text of license available in license.txt file, in main folder
 *
 */
-
 #pragma once
 
-// Boost
-#include <boost/filesystem/path.hpp>
-
 // STL C++
 #include <string>
 #include <vector>
 
-// TODO: Remove _VCMIDirs
-class _VCMIDirs;
-
-// Where to find the various VCMI files. This is mostly useful for linux. 
-namespace VCMIDirs
-{
-	namespace detail
-	{
-		extern DLL_LINKAGE boost::filesystem::path g_user_data_path;
-		extern DLL_LINKAGE boost::filesystem::path g_user_cache_path;
-		extern DLL_LINKAGE boost::filesystem::path g_user_config_path;
-		extern DLL_LINKAGE boost::filesystem::path g_user_save_path;
-
-		extern DLL_LINKAGE boost::filesystem::path g_library_path;
-		extern DLL_LINKAGE boost::filesystem::path g_client_path;
-		extern DLL_LINKAGE boost::filesystem::path g_server_path;
-
-		extern DLL_LINKAGE std::vector<boost::filesystem::path> g_data_paths;
-
-		extern DLL_LINKAGE std::string g_help_string;
-	}
+// Boost
+#include <boost/filesystem/path.hpp>
 
-	/// deprecated: get singleton instance
-	extern DLL_LINKAGE _VCMIDirs & get();
+// TODO: File should be rename to IVCMIDirs.h
 
-	// Path to user-specific data directory
-	inline const boost::filesystem::path& userDataPath() { return detail::g_user_data_path; }
+class IVCMIDirs
+{
+	public:
+		// Path to user-specific data directory
+		virtual boost::filesystem::path userDataPath() const = 0;
 
-	// Path to "cache" directory, can be used for any non-essential files
-	inline const boost::filesystem::path& userCachePath() { return detail::g_user_cache_path; }
+		// Path to "cache" directory, can be used for any non-essential files
+		virtual boost::filesystem::path userCachePath() const = 0;
 
-	// Path to writeable directory with user configs
-	inline const boost::filesystem::path& userConfigPath() { return detail::g_user_config_path; }
+		// Path to writeable directory with user configs
+		virtual boost::filesystem::path userConfigPath() const = 0;
 
-	// Path to saved games
-	inline const boost::filesystem::path& userSavePath() { return detail::g_user_save_path; }
+		// Path to saved games
+		virtual boost::filesystem::path userSavePath() const = 0;
 
-	// Paths to global system-wide data directories. First items have higher priority
-	inline const std::vector<boost::filesystem::path>& dataPaths() { return detail::g_data_paths; }
+		// Paths to global system-wide data directories. First items have higher priority
+		virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
 
-	// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
-	inline const boost::filesystem::path& clientPath() { return detail::g_client_path; }
+		// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
+		virtual boost::filesystem::path clientPath() const = 0;
 
-	// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
-	inline const boost::filesystem::path& serverPath() { return detail::g_server_path; }
+		// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
+		virtual boost::filesystem::path serverPath() const = 0;
 
-	// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
-	inline const boost::filesystem::path& libraryPath() { return detail::g_library_path; }
+		// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
+		virtual boost::filesystem::path libraryPath() const = 0;
 
-	// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
-	extern DLL_LINKAGE std::string libraryName(const std::string& basename);
-	//extern DLL_LINKAGE std::string libraryName(const char* basename);
-	//extern DLL_LINKAGE std::string libraryName(std::string&& basename);
+		// Path where vcmi binaries can be found
+		virtual boost::filesystem::path binaryPath() const = 0;
 
+		// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
+		virtual std::string libraryName(const std::string& basename) const = 0;
+		// virtual std::string libraryName(const char* basename) const = 0; ?
+		// virtual std::string libraryName(std::string&& basename) const = 0;?
 
-	inline const std::string& genHelpString() { return detail::g_help_string; }
-}
+		virtual std::string genHelpString() const = 0;
+};
 
-// TODO: Remove _VCMIDirs
-// This class is deprecated
-class DLL_LINKAGE _VCMIDirs
+namespace VCMIDirs
 {
-public:
-	/// deprecated: Path to user-specific data directory
-	std::string userDataPath() const { return VCMIDirs::userDataPath().string(); }
-
-	/// deprecated: Path to "cache" directory, can be used for any non-essential files
-	std::string userCachePath() const { return VCMIDirs::userCachePath().string(); }
-
-	/// deprecated: Path to writeable directory with user configs
-	std::string userConfigPath() const { return VCMIDirs::userConfigPath().string(); }
-
-	/// deprecated: Path to saved games
-	std::string userSavePath() const { return VCMIDirs::userSavePath().string(); }
-
-	/// deprecated: Paths to global system-wide data directories. First items have higher priority
-	std::vector<std::string> dataPaths() const
-	{
-		std::vector<std::string> result;
-		for (const auto& path : VCMIDirs::dataPaths())
-			result.push_back(path.string());
-		return result;
-	}
-
-	/// deprecated: Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
-	std::string clientPath() const { return VCMIDirs::clientPath().string(); }
-
-	/// deprecated: Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
-	std::string serverPath() const { return VCMIDirs::serverPath().string(); }
-
-	/// deprecated: Path where vcmi libraries can be found (in AI and Scripting subdirectories)
-	std::string libraryPath() const { return VCMIDirs::libraryPath().string(); }
-
-	/// deprecated: Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
-	std::string libraryName(std::string basename) const { return VCMIDirs::libraryName(basename); }
-
-	/// deprecated:
-	std::string genHelpString() const { return VCMIDirs::genHelpString(); }
-};
+	extern DLL_LINKAGE const IVCMIDirs* get();
+}