1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

VCMIDirs update #3

bfs = boost::filesystem;
- Updateting filenames (std::string -> bfs::path) #1
- Added platform detection, and some specyfic boost::filesystem includes
to Global.h
- Updated CBasicLogConfigurator. Now class uses bfs::path pathes.
This commit is contained in:
Karol 2014-08-10 23:42:39 +02:00
parent 5d5db77fc9
commit a302f6c7ad
10 changed files with 303 additions and 226 deletions

View File

@ -49,6 +49,50 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
#endif
/* ---------------------------------------------------------------------------- */
/* System detection. */
/* ---------------------------------------------------------------------------- */
// Based on: http://sourceforge.net/p/predef/wiki/OperatingSystems/
// and on: http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
// TODO?: Should be moved to vstd\os_detect.h (and then included by Global.h)
#ifdef _WIN16 // Defined for 16-bit environments
#error "16-bit Windows isn't supported"
#elif defined(_WIN64) // Defined for 64-bit environments
#define VCMI_WINDOWS
#define VCMI_WINDOWS_64
#elif defined(_WIN32) // Defined for both 32-bit and 64-bit environments
#define VCMI_WINDOWS
#define VCMI_WINDOWS_32
#elif defined(_WIN32_WCE)
#error "Windows CE isn't supported"
#elif defined(__linux__) || defined(__gnu_linux__) || defined(linux) || defined(__linux)
#define VCMI_UNIX
#define VCMI_LINUX
#ifdef __ANDROID__
#define VCMI_ANDROID
#endif
#elif defined(__APPLE__) && defined(__MACH__)
#define VCMI_UNIX
#define VCMI_APPLE
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
#define VCMI_IOS
#define VCMI_IOS_SIM
#elif TARGET_OS_IPHONE
#define VCMI_IOS
#elif TARGET_OS_MAC
#define VCMI_MAC
#else
//#warning "Unknown Apple target."?
#endif
#else
#error "VCMI supports only Windows, OSX, Linux and Android targets"
#endif
#ifdef VCMI_IOS
#error "iOS system isn't yet supported."
#endif
/* ---------------------------------------------------------------------------- */
/* Commonly used C++, Boost headers */
/* ---------------------------------------------------------------------------- */
@ -99,6 +143,8 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
@ -112,13 +158,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/variant.hpp>
#include <boost/math/special_functions/round.hpp>
#ifdef ANDROID
#include <android/log.h>
#ifdef VCMI_ANDROID
#include <android/log.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI 3.14159265358979323846
#endif
/* ---------------------------------------------------------------------------- */

View File

@ -51,6 +51,7 @@
#endif
namespace po = boost::program_options;
namespace bfs = boost::filesystem;
/*
* CMT.cpp, part of VCMI engine
@ -72,13 +73,12 @@ int preferredDriverIndex = -1;
SDL_Window * mainWindow = nullptr;
SDL_Renderer * mainRenderer = nullptr;
SDL_Texture * screenTexture = nullptr;
#endif // VCMI_SDL1
extern boost::thread_specific_ptr<bool> inGuiThread;
SDL_Surface *screen = nullptr, //main screen surface
*screen2 = nullptr,//and hlp surface (used to store not-active interfaces layer)
*screen2 = nullptr, //and hlp surface (used to store not-active interfaces layer)
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
std::queue<SDL_Event> events;
@ -106,24 +106,23 @@ void endGame();
#include <getopt.h>
#endif
void startGameFromFile(const std::string &fname)
void startGameFromFile(const bfs::path &fname)
{
StartInfo si;
try //attempt retrieving start info from given file
{
if(!fname.size() || !boost::filesystem::exists(fname))
throw std::runtime_error("Startfile \"" + fname + "\" does not exist!");
if(fname.empty() || !bfs::exists(fname))
throw std::runtime_error("Startfile \"" + fname.string() + "\" does not exist!");
CLoadFile out(fname);
if(!out.sfile || !*out.sfile)
{
throw std::runtime_error("Cannot read from startfile \"" + fname + "\"!");
}
// TODO: CLoadFile should take boost::path as an argument
CLoadFile out(fname.string());
if (!out.sfile || !*out.sfile)
throw std::runtime_error("Cannot read from startfile \"" + fname.string() +"\"!");
out >> si;
}
catch(std::exception &e)
{
logGlobal->errorStream() << "Failed to start from the file: " + fname << ". Error: " << e.what()
logGlobal->errorStream() << "Failed to start from the file: " << fname << ". Error: " << e.what()
<< " Falling back to main menu.";
GH.curInt = CGPreGame::create();
return;
@ -218,7 +217,7 @@ int main(int argc, char** argv)
("help,h", "display help and exit")
("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("start", po::value<std::string>(), "starts game from saved StartInfo file")
("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
("onlyAI", "runs without human player, all players will be default AI")
("noGUI", "runs without GUI, implies --onlyAI")
("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
@ -271,15 +270,15 @@ int main(int argc, char** argv)
CStopWatch total, pomtime;
std::cout.flags(std::ios::unitbuf);
console = new CConsoleHandler;
*console->cb = std::bind(&processCommand, _1);
*console->cb = processCommand;
console->start();
atexit(dispose);
const auto logPath = VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt";
CBasicLogConfigurator logConfig(logPath, console);
const bfs::path log_path = VCMIDirs::get().userCachePath() / "VCMI_Client_log.txt";
CBasicLogConfigurator logConfig(log_path, console);
logConfig.configureDefault();
logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
logGlobal->infoStream() << "The log file will be saved to " << logPath;
logGlobal->infoStream() << "The log file will be saved to " << log_path;
#ifdef __ANDROID__
// boost will crash without this
@ -430,15 +429,15 @@ int main(int argc, char** argv)
session["autoSkip"].Bool() = vm.count("autoSkip");
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
std::string fileToStartFrom; //none by default
bfs::path fileToStartFrom; //none by default
if(vm.count("start"))
fileToStartFrom = vm["start"].as<std::string>();
fileToStartFrom = vm["start"].as<bfs::path>();
if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom))
if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom))
startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
else
{
if(fileToStartFrom.size())
if(!fileToStartFrom.empty())
{
logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom
<< "). Falling back to main menu.";
@ -584,7 +583,8 @@ void processCommand(const std::string &message)
{
std::cout<<"Command accepted.\t";
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
const bfs::path out_path =
VCMIDirs::get().userCachePath() / "extracted";
auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
{
@ -593,18 +593,19 @@ void processCommand(const std::string &message)
for (auto & filename : list)
{
std::string outName = outPath + filename.getName();
const bfs::path file_path = out_path / (filename.getName() + ".TXT");
std::string outName = file_path.string();
bfs::create_directories(file_path.parent_path());
boost::filesystem::create_directories(outName.substr(0, outName.find_last_of("/")));
std::ofstream file(outName + ".TXT");
bfs::ofstream file(file_path);
auto text = CResourceHandler::get()->load(filename)->readAll();
file.write((char*)text.first.get(), text.second);
}
std::cout << "\rExtracting done :)\n";
std::cout << " Extracted files can be found in " << outPath << " directory\n";
std::cout << " Extracted files can be found in " << out_path << " directory\n";
}
else if(cn=="crash")
{
@ -710,15 +711,13 @@ void processCommand(const std::string &message)
{
CDefEssential * cde = CDefHandler::giveDefEss(URI);
std::string outName = URI;
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
const bfs::path out_path = VCMIDirs::get().userCachePath() / "extraced" / URI;
bfs::create_directories(out_path);
boost::filesystem::create_directories(outPath + outName);
for (size_t i=0; i<cde->ourImages.size(); i++)
for (size_t i = 0; i < cde->ourImages.size(); ++i)
{
std::string filename = outPath + outName + '/' + boost::lexical_cast<std::string>(i) + ".bmp";
SDL_SaveBMP(cde->ourImages[i].bitmap, filename.c_str());
const bfs::path file_path = out_path / (boost::lexical_cast<std::string>(i) + ".bmp");
SDL_SaveBMP(cde->ourImages[i].bitmap, file_path.string().c_str());
}
}
else
@ -731,14 +730,12 @@ void processCommand(const std::string &message)
if (CResourceHandler::get()->existsResource(ResourceID(URI)))
{
std::string outName = URI;
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
std::string fullPath = outPath + outName;
const bfs::path out_path = VCMIDirs::get().userCachePath() / "extracted" / URI;
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
std::ofstream outFile(outPath + outName, std::ofstream::binary);
bfs::create_directories(out_path.parent_path());
bfs::ofstream outFile(out_path, bfs::ofstream::binary);
outFile.write((char*)data.first.get(), data.second);
}
else

View File

@ -777,8 +777,8 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
{
if(ps.name.size())
{
std::string filename = VCMIDirs::get().libraryPath() + "/AI/" + VCMIDirs::get().libraryName(ps.name);
if(boost::filesystem::exists(filename))
boost::filesystem::path ai_path = VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(ps.name);
if (boost::filesystem::exists(ai_path))
return ps.name;
}
@ -865,8 +865,9 @@ CServerHandler::~CServerHandler()
void CServerHandler::callServer()
{
setThreadName("CServerHandler::callServer");
std::string logName = VCMIDirs::get().userCachePath() + "/server_log.txt";
std::string comm = VCMIDirs::get().serverPath() + " --port=" + port + " > " + logName;
// TODO: Make more boost::filesystem::path based
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > " + logName;
int result = std::system(comm.c_str());
if (result == 0)
logNetwork->infoStream() << "Server closed correctly";

View File

@ -111,9 +111,10 @@ template<typename rett>
shared_ptr<rett> createAnyAI(std::string dllname, std::string methodName)
{
logGlobal->infoStream() << "Opening " << dllname;
std::string filename = VCMIDirs::get().libraryName(dllname);
auto ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
const boost::filesystem::path file_path =
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(dllname);
// TODO: createAny Should take boost::filesystem::path in argument.
auto ret = createAny<rett>(file_path.string(), methodName);
ret->dllName = dllname;
return ret;
}

View File

@ -11,11 +11,24 @@
#include "StdInc.h"
#include "VCMIDirs.h"
namespace bfs = boost::filesystem; // Should be in each cpp file
namespace bfs = boost::filesystem;
#ifdef _WIN32
// File: VCMIDirs_win32.h
//#include "IVCMIDirs.h"
bfs::path IVCMIDirs::userSavePath() const { return userDataPath() / "Saves"; }
void IVCMIDirs::init()
{
// TODO: Log errors
bfs::create_directory(userDataPath());
bfs::create_directory(userCachePath());
bfs::create_directory(userConfigPath());
bfs::create_directory(userSavePath());
}
#ifdef VCMI_WINDOWS
#include <Windows.h>
#include <Shlobj.h>
#include <Shellapi.h>
class VCMIDirs_win32 : public IVCMIDirs
{
@ -23,7 +36,6 @@ class VCMIDirs_win32 : public IVCMIDirs
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;
@ -36,23 +48,69 @@ class VCMIDirs_win32 : public IVCMIDirs
std::string libraryName(const std::string& basename) const override;
std::string genHelpString() const override;
void init() 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
namespace VCMIDirs
void VCMIDirs_win32::init()
{
const IVCMIDirs& get()
// Call base (init dirs)
IVCMIDirs::init();
auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to)
{
static VCMIDirs_win32 singleton;
return singleton;
}
if (!bfs::is_directory(from))
return; // Nothing to do here. Flies away.
if (bfs::is_empty(from))
{
bfs::remove(from);
return; // Nothing to do here. Flies away.
}
if (!bfs::is_directory(to))
{
// IVCMIDirs::init() should create all destination directories.
// TODO: Log fact, that we shouldn't be here.
bfs::create_directory(to);
}
// Why the hell path strings should be end with double null :/
auto make_double_nulled = [](const bfs::path& path) -> std::unique_ptr<wchar_t[]>
{
const std::wstring& path_str = path.native();
std::unique_ptr<wchar_t[]> result(new wchar_t[path_str.length() + 2]);
size_t i = 0;
for (const wchar_t ch : path_str)
result[i++] = ch;
result[i++] = L'\0';
result[i++] = L'\0';
return result;
};
auto from_dnulled = make_double_nulled(from / L"*.*");
auto to_dnulled = make_double_nulled(to);
SHFILEOPSTRUCTW file_op;
file_op.hwnd = GetConsoleWindow();
file_op.wFunc = FO_MOVE;
file_op.pFrom = from_dnulled.get();
file_op.pTo = to_dnulled.get();
file_op.fFlags = 0;
file_op.hNameMappings = nullptr;
file_op.lpszProgressTitle = nullptr;
const int error_code = SHFileOperationW(&file_op);
if (error_code != 0); // TODO: Log error. User should try to move files.
else if (file_op.fAnyOperationsAborted); // TODO: Log warn. User aborted operation. User should move files.
else if (!bfs::is_empty(from)); // TODO: Log warn. Some files not moved. User should try to move files.
else // TODO: Log fact that we moved files succefully.
bfs::remove(from);
};
moveDirIfExists(userDataPath() / "Games", userSavePath());
}
bfs::path VCMIDirs_win32::userDataPath() const
@ -65,7 +123,12 @@ bfs::path VCMIDirs_win32::userDataPath() const
// 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
{
// FIXME: Create macro for MS Visual Studio.
// FIXME: Use _wdupenv_s on MS Visual Studio.
// or: define _CRT_SECURE_NO_WARNINGS in preprocessor global settings.
// warning C4996: 'getenv': This function or variable may be unsafe.
// Consider using _dupenv_s instead.
// To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
// See online help for details.
if (profile_dir_a = std::getenv("userprofile")) // STL way succeed
return bfs::path(profile_dir_a) / "vcmi";
else
@ -78,7 +141,6 @@ bfs::path VCMIDirs_win32::userDataPath() const
}
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"; }
std::vector<bfs::path> VCMIDirs_win32::dataPaths() const
{
@ -93,61 +155,26 @@ bfs::path VCMIDirs_win32::binaryPath() const { return "."; }
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 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 : dataPaths())
temp_vec.push_back(utf8_convert(path));
std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
temp_vec.push_back(path.string());
std::string gd_string_a = boost::algorithm::join(temp_vec, ";");
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?
" 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?
}
std::string VCMIDirs_win32::libraryName(const std::string& basename) const { return basename + ".dll"; }
// End of file: VCMIDirs_win32.cpp
#else // UNIX
// File: IVCMIDirs_UNIX.h
//#include "IVCMIDirs.h"
#elif defined(VCMI_UNIX)
class IVCMIDirs_UNIX : public IVCMIDirs
{
public:
@ -156,11 +183,6 @@ class IVCMIDirs_UNIX : public IVCMIDirs
std::string genHelpString() const override;
};
// End of file: IVCMIDirs_UNIX.h
// File: IVCMIDirs_UNIX.cpp
//#include "StdInc.h"
//#include "IVCMIDirs_UNIX.h"
bfs::path IVCMIDirs_UNIX::clientPath() const { return binaryPath() / "vcmiclient"; }
bfs::path IVCMIDirs_UNIX::clientPath() const { return binaryPath() / "vcmiserver"; }
@ -170,32 +192,27 @@ 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";");
std::string gd_string_a = boost::algorithm::join(temp_vec, ":");
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" +
" 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
#ifdef __APPLE__
// File: VCMIDirs_OSX.h
//#include "IVCMIDirs_UNIX.h"
#ifdef VCMI_APPLE
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;
std::vector<boost::filesystem::path> dataPaths() const override;
@ -203,20 +220,50 @@ class VCMIDirs_OSX : public IVCMIDirs_UNIX
boost::filesystem::path binaryPath() const override;
std::string libraryName(const std::string& basename) const override;
void init() override;
};
// End of file: VCMIDirs_OSX.h
// File: VCMIDirs_OSX.cpp
//#include "StdInc.h"
//#include "VCMIDirs_OSX.h"
namespace VCMIDirs
void VCMIDirs_OSX::init()
{
const IVCMIDirs& get()
// Call base (init dirs)
IVCMIDirs_UNIX::init();
auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to)
{
static VCMIDirs_OSX singleton;
return singleton;
}
if (!bfs::is_directory(from))
return; // Nothing to do here. Flies away.
if (bfs::is_empty(from))
{
bfs::remove(from);
return; // Nothing to do here. Flies away.
}
if (!bfs::is_directory(to))
{
// IVCMIDirs::init() should create all destination directories.
// TODO: Log fact, that we shouldn't be here.
bfs::create_directory(to);
}
for (bfs::directory_iterator file(from); file != bfs::directory_iterator(); ++file)
{
const boost::filesystem::path& src_file_path = file->path();
const boost::filesystem::path dst_file_path = to / src_file_path.filename();
// TODO: Aplication should ask user what to do when file exists:
// replace/ignore/stop process/replace all/ignore all
if (!boost::filesystem::exists(dst_file_path))
bfs::rename(src_file_path, dst_file_path);
}
if (!bfs::is_empty(from)); // TODO: Log warn. Some files not moved. User should try to move files.
else
bfs::remove(from);
};
moveDirIfExists(userDataPath() / "Games", userSavePath());
}
bfs::path VCMIDirs_OSX::userDataPath() const
@ -234,7 +281,6 @@ bfs::path VCMIDirs_OSX::userDataPath() const
}
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"; }
std::vector<bfs::path> VCMIDirs_OSX::dataPaths() const
{
@ -245,18 +291,13 @@ bfs::path VCMIDirs_OSX::libraryPath() const { return "."; }
bfs::path VCMIDirs_OSX::binaryPath() const { return "."; }
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"
#elif defined(VCMI_LINUX)
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<boost::filesystem::path> dataPaths() const override;
@ -265,20 +306,6 @@ public:
std::string libraryName(const std::string& basename) const override;
};
// End of file: VCMIDirs_Linux.h
// File: VCMIDirs_Linux.cpp
//#include "StdInc.h"
//#include "VCMIDirs_Linux.h"
namespace VCMIDirs
{
const IVCMIDirs& get()
{
static VCMIDirs_Linux singleton;
return singleton;
}
}
bfs::path VCMIDirs_Linux::userDataPath() const
{
@ -313,10 +340,6 @@ bfs::path VCMIDirs_Linux::userConfigPath() const
else
return ".";
}
bfs::path VCMIDirs_Linux::userSavePath() const
{
return userDataPath() / "Saves";
}
std::vector<bfs::path> VCMIDirs_Linux::dataPaths() const
{
@ -328,8 +351,6 @@ std::vector<bfs::path> VCMIDirs_Linux::dataPaths() const
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)
@ -353,46 +374,50 @@ bfs::path VCMIDirs_Linux::libraryPath() const { return M_LIB_PATH; }
bfs::path VCMIDirs_Linux::binaryPath() const { return M_BIN_DIR; }
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"
#ifdef VCMI_ANDROID
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"
namespace VCMIDirs
{
const IVCMIDirs& get()
{
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
#endif // VCMI_ANDROID
#endif // VCMI_APPLE, VCMI_LINUX
#endif // VCMI_WINDOWS, VCMI_UNIX
// Getters for interfaces are separated for clarity.
namespace VCMIDirs
{
const IVCMIDirs& get()
{
#ifdef VCMI_WINDOWS
static VCMIDirs_win32 singleton;
#elif defined(VCMI_ANDROID)
static VCMIDirs_Android singleton;
#elif defined(VCMI_LINUX)
static VCMIDirs_Linux singleton;
#elif defined(VCMI_APPLE)
static VCMIDirs_OSX singleton;
#endif
static bool initialized = false;
if (!initialized)
{
singleton.init();
initialized = true;
}
return singleton;
}
}

View File

@ -16,9 +16,9 @@
// Boost
#include <boost/filesystem/path.hpp>
// TODO: File should be rename to IVCMIDirs.h
// TODO: File should be renamed to IVCMIDirs.h
class IVCMIDirs
class DLL_LINKAGE IVCMIDirs
{
public:
// Path to user-specific data directory
@ -31,7 +31,7 @@ class IVCMIDirs
virtual boost::filesystem::path userConfigPath() const = 0;
// Path to saved games
virtual boost::filesystem::path userSavePath() const = 0;
virtual boost::filesystem::path userSavePath() const;
// Paths to global system-wide data directories. First items have higher priority
virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
@ -54,6 +54,11 @@ class IVCMIDirs
// virtual std::string libraryName(std::string&& basename) const = 0;?
virtual std::string genHelpString() const = 0;
// Creates not existed, but required directories.
// Updates directories what change name/path between versions.
// Function called automatically.
virtual void init();
};
namespace VCMIDirs

View File

@ -69,7 +69,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
std::string URI = prefix + config["path"].String();
int depth = 16;
if (!config["depth"].isNull())
depth = config["depth"].Float();
depth = (int)config["depth"].Float();
ResourceID resID(URI, EResType::DIRECTORY);
@ -136,12 +136,13 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
}
};
// TODO: CFilesystemLoader: Should take boost::filesystem::path in argument
for (auto & path : VCMIDirs::get().dataPaths())
{
if (boost::filesystem::is_directory(path)) // some of system-provided paths may not exist
initialLoader->addLoader(new CFilesystemLoader("", path, 0, true), false);
initialLoader->addLoader(new CFilesystemLoader("", path.string(), 0, true), false);
}
initialLoader->addLoader(new CFilesystemLoader("", VCMIDirs::get().userDataPath(), 0, true), false);
initialLoader->addLoader(new CFilesystemLoader("", VCMIDirs::get().userDataPath().string(), 0, true), false);
recurseInDir("CONFIG", 0);// look for configs
recurseInDir("DATA", 0); // look for archives
@ -166,9 +167,10 @@ void CResourceHandler::initialize()
// |-saves
// |-config
// TODO: CFilesystemLoader should take boost::filesystem::path
knownLoaders["root"] = new CFilesystemList();
knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath());
knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath());
knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath().string());
knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath().string());
auto localFS = new CFilesystemList();
localFS->addLoader(knownLoaders["saves"], true);

View File

@ -3,16 +3,17 @@
#include "../CConfigHandler.h"
CBasicLogConfigurator::CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console) : filePath(filePath),
console(console), appendToLogFile(false)
{
CBasicLogConfigurator::CBasicLogConfigurator(const boost::filesystem::path & file_path, CConsoleHandler * const console) :
file_path(file_path), console(console), appendToLogFile(false) {}
}
CBasicLogConfigurator::CBasicLogConfigurator(boost::filesystem::path && file_path, CConsoleHandler * const console) :
file_path(std::move(file_path)), console(console), appendToLogFile(false) {}
void CBasicLogConfigurator::configureDefault()
{
CLogger::getGlobalLogger()->addTarget(make_unique<CLogConsoleTarget>(console));
CLogger::getGlobalLogger()->addTarget(make_unique<CLogFileTarget>(filePath, appendToLogFile));
// TODO: CLogFileTarget should take boost::filesystem::path as an argument
CLogger::getGlobalLogger()->addTarget(make_unique<CLogFileTarget>(file_path.string(), appendToLogFile));
appendToLogFile = true;
}
@ -21,7 +22,8 @@ void CBasicLogConfigurator::configure()
try
{
const JsonNode & loggingNode = settings["logging"];
if(loggingNode.isNull()) throw std::runtime_error("Settings haven't been loaded.");
if(loggingNode.isNull())
throw std::runtime_error("Settings haven't been loaded.");
// Configure loggers
const JsonNode & loggers = loggingNode["loggers"];
@ -67,8 +69,9 @@ void CBasicLogConfigurator::configure()
}
CLogger::getGlobalLogger()->addTarget(std::move(consoleTarget));
// TODO: CLogFileTarget should take boost::filesystem::path as an argument
// Add file target
auto fileTarget = make_unique<CLogFileTarget>(filePath, appendToLogFile);
auto fileTarget = make_unique<CLogFileTarget>(file_path.string(), appendToLogFile);
const JsonNode & fileNode = loggingNode["file"];
if(!fileNode.isNull())
{
@ -87,7 +90,7 @@ void CBasicLogConfigurator::configure()
logGlobal->infoStream() << "Initialized logging system based on settings successfully.";
}
ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level) const
ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level)
{
static const std::map<std::string, ELogLevel::ELogLevel> levelMap = boost::assign::map_list_of
("trace", ELogLevel::TRACE)
@ -95,18 +98,15 @@ ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & leve
("info", ELogLevel::INFO)
("warn", ELogLevel::WARN)
("error", ELogLevel::ERROR);
const auto & levelPair = levelMap.find(level);
if(levelPair != levelMap.end())
{
return levelPair->second;
}
else
{
throw std::runtime_error("Log level " + level + " unknown.");
}
}
EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName) const
EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName)
{
static const std::map<std::string, EConsoleTextColor::EConsoleTextColor> colorMap = boost::assign::map_list_of
("default", EConsoleTextColor::DEFAULT)
@ -117,13 +117,10 @@ EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(cons
("white", EConsoleTextColor::WHITE)
("gray", EConsoleTextColor::GRAY)
("teal", EConsoleTextColor::TEAL);
const auto & colorPair = colorMap.find(colorName);
if(colorPair != colorMap.end())
{
return colorPair->second;
}
else
{
throw std::runtime_error("Color " + colorName + " unknown.");
}
}

View File

@ -22,7 +22,8 @@ class JsonNode;
class DLL_LINKAGE CBasicLogConfigurator
{
public:
CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console);
CBasicLogConfigurator(const boost::filesystem::path & file_path, CConsoleHandler * const console);
CBasicLogConfigurator(boost::filesystem::path && file_path, CConsoleHandler * const console);
/// Configures the logging system by parsing the logging settings. It adds the console target and the file target to the global logger.
/// Doesn't throw, but logs on success or fault.
@ -30,12 +31,15 @@ public:
/// Configures a default logging system by adding the console target and the file target to the global logger.
void configureDefault();
private:
ELogLevel::ELogLevel getLogLevel(const std::string & level) const;
EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName) const;
// Gets ELogLevel enum from string. (Should be moved to CLogger as a separate function?)
// Throws: std::runtime_error
static ELogLevel::ELogLevel getLogLevel(const std::string & level);
// Gets EConsoleTextColor enum from strings. (Should be moved to CLogger as a separate function?)
// Throws: std::runtime_error
static EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName);
std::string filePath;
boost::filesystem::path file_path;
CConsoleHandler * console;
bool appendToLogFile;
};

View File

@ -596,7 +596,7 @@ int main(int argc, char** argv)
#endif
console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console);
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Server_log.txt", console);
logConfig.configureDefault();
preinitDLL(console);