Merge branch 'api-sorting' into v0.7-alpha

Conflicts:
	src/api/api.cpp
	src/api/api.h
	src/backend/git.cpp
This commit is contained in:
Oliver Hamlet
2014-09-26 18:15:08 +01:00
7 changed files with 648 additions and 315 deletions
+1 -2
View File
@@ -655,8 +655,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/api/api.h \
api_index.dox
INPUT = ../src/api/api.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-18
View File
@@ -1,18 +0,0 @@
/**
@mainpage
@author WrinklyNinja
@version 0..0
@copyright The LOOT API is distributed under the GNU General Public License v3.0. For the full text of the license, see the "GNU GPL v3.txt" file included in the source archive.
@section intro_sec Introduction
LOOT is a utility that helps users avoid serious conflicts between their mods by setting their plugins in an optimal load order. It also provides tens of thousands of plugin-specific messages, including usage notes, requirements, incompatibilities, bug warnings and installation mistake notifications, and thousands of Bash Tag suggestions.
This metadata that LOOT supplies is stored in its masterlist, which is maintained by the LOOT team using information provided by mod authors and users. Users can also add to and modify the metadata used by LOOT through the use of userlist files. The LOOT API provides a way for third-party developers to access this metadata for use in their own programs.
All further API documentation is contained within the documentation for api.h.
@section credit_sec Credits
The LOOT API is written by WrinklyNinja in C/C++ and makes use of the <a href="http://code.google.com/p/yaml-cpp/">yaml-cpp</a> and <a href="http://github.com/WrinklyNinja/libloadorder/">libloadorder</a> libraries and some of the <a href="http://www.boost.org/">Boost</a> libraries. Copyright license information for all these may be found in the "licenses/Licenses.txt" file.
*/
+102 -2
View File
@@ -69,7 +69,6 @@ const unsigned int loot_game_fonv = loot::Game::fonv;
const unsigned int loot_message_say = loot::Message::say;
const unsigned int loot_message_warn = loot::Message::warn;
const unsigned int loot_message_error = loot::Message::error;
const unsigned int loot_message_tag = loot::Message::tag;
// LOOT message languages.
const unsigned int loot_lang_any = loot::Language::any;
@@ -96,7 +95,9 @@ struct _loot_db_int : public loot::Game {
extAddedTagIds(nullptr),
extRemovedTagIds(nullptr),
extMessageArray(nullptr),
extMessageArraySize(0) {
extMessageArraySize(0),
extStringArray(nullptr),
extStringArraySize(0) {
this->SetDetails("", "", "", "", gamePath, "").Init();
}
@@ -115,6 +116,12 @@ struct _loot_db_int : public loot::Game {
delete[] extMessageArray[i].message; //Gotta clear those allocated strings.
delete[] extMessageArray;
}
if (extStringArray != nullptr) {
for (size_t i = 0; i < extStringArraySize; i++)
delete[] extStringArray[i]; //Gotta clear those allocated strings.
delete[] extStringArray;
}
}
loot::MetadataList rawUserMetadata;
@@ -124,6 +131,9 @@ struct _loot_db_int : public loot::Game {
char ** extTagMap;
char ** extStringArray;
size_t extStringArraySize;
unsigned int * extAddedTagIds;
unsigned int * extRemovedTagIds;
@@ -361,6 +371,96 @@ LOOT_API unsigned int loot_eval_lists(loot_db db, const unsigned int language) {
return loot_ok;
}
////////////////////////////////////
// LOOT Functionality Functions
////////////////////////////////////
LOOT_API unsigned int loot_sort_plugins(loot_db db,
char *** const sortedPlugins,
size_t * const numPlugins) {
if (db == nullptr || sortedPlugins == nullptr || numPlugins == nullptr)
return c_error(loot_error_invalid_args, "Null pointer passed.");
//Clear existing array allocation.
if (db->extStringArray != nullptr) {
for (size_t i = 0; i < db->extStringArraySize; ++i) {
delete[] db->extStringArray[i];
}
delete[] db->extStringArray;
db->extStringArray = nullptr;
}
//Initialise output.
*numPlugins = 0;
*sortedPlugins = nullptr;
try {
// Always reload all the plugins.
db->LoadPlugins(false);
//Sort plugins into their load order.
std::list<loot::Plugin> plugins = db->Sort(loot_lang_any, [](const std::string& message) {});
db->extStringArraySize = plugins.size();
db->extStringArray = new char*[db->extStringArraySize];
size_t i = 0;
for (const auto &plugin : plugins) {
db->extStringArray[i] = ToNewCString(plugin.Name());
++i;
}
}
catch (loot::error &e) {
return c_error(e);
}
catch (std::bad_alloc& e) {
return c_error(loot_error_no_mem, e.what());
}
*numPlugins = db->extStringArraySize;
*sortedPlugins = db->extStringArray;
return loot_ok;
}
LOOT_API unsigned int loot_apply_load_order(loot_db db,
const char * const * const loadOrder,
const size_t numPlugins) {
if (db == nullptr || loadOrder == nullptr)
return c_error(loot_error_invalid_args, "Null pointer passed.");
try {
db->SetLoadOrder(loadOrder, numPlugins);
}
catch (loot::error &e) {
return c_error(e);
}
return loot_ok;
}
LOOT_API unsigned int loot_update_masterlist(loot_db db,
const char * const masterlistPath,
const char * const remoteURL,
const char * const remoteBranch,
bool * const updated) {
if (db == nullptr || masterlistPath == nullptr || remoteURL == nullptr || remoteBranch == nullptr || updated == nullptr)
return c_error(loot_error_invalid_args, "Null pointer passed.");
return loot_ok;
}
LOOT_API unsigned int loot_get_masterlist_revision(const char * const masterlistPath,
const bool getShortID,
char ** const revisionID,
char ** const revisionDate,
bool * const isModified) {
if (masterlistPath == nullptr || revisionID == nullptr || revisionDate == nullptr || isModified == nullptr)
return c_error(loot_error_invalid_args, "Null pointer passed.");
return loot_ok;
}
//////////////////////////
// DB Access Functions
//////////////////////////
+515 -272
View File
File diff suppressed because it is too large Load Diff
+26 -18
View File
@@ -624,12 +624,10 @@ namespace loot {
lo_destroy_handle(gh);
}
void Game::SetLoadOrder(const std::list<std::string>& loadOrder) const {
void Game::SetLoadOrder(const char * const * const loadOrder, const size_t numPlugins) const {
BOOST_LOG_TRIVIAL(debug) << "Setting load order for game: " << _name;
lo_game_handle gh = nullptr;
char ** pluginArr = nullptr;
size_t pluginArrSize = 0;
int ret;
if (Id() == Game::tes4)
ret = lo_create_handle(&gh, LIBLO_GAME_TES4, gamePath.string().c_str());
@@ -676,19 +674,7 @@ namespace loot {
throw error(error::liblo_error, err);
}
pluginArrSize = loadOrder.size();
pluginArr = new char*[pluginArrSize];
int i = 0;
for (const auto &plugin : loadOrder) {
pluginArr[i] = new char[plugin.length() + 1];
strcpy(pluginArr[i], plugin.c_str());
++i;
}
if (lo_set_load_order(gh, pluginArr, pluginArrSize) != LIBLO_OK) {
for (size_t i = 0; i < pluginArrSize; i++)
delete[] pluginArr[i];
delete[] pluginArr;
if (lo_set_load_order(gh, loadOrder, numPlugins) != LIBLO_OK) {
const char * e = nullptr;
string err;
lo_get_error_message(&e);
@@ -705,11 +691,33 @@ namespace loot {
throw error(error::liblo_error, err);
}
lo_destroy_handle(gh);
}
void Game::SetLoadOrder(const std::list<std::string>& loadOrder) const {
size_t pluginArrSize = loadOrder.size();
char ** pluginArr = new char*[pluginArrSize];
int i = 0;
for (const auto &plugin : loadOrder) {
pluginArr[i] = new char[plugin.length() + 1];
strcpy(pluginArr[i], plugin.c_str());
++i;
}
try {
SetLoadOrder(pluginArr, pluginArrSize);
}
catch (error &e) {
for (size_t i = 0; i < pluginArrSize; i++)
delete[] pluginArr[i];
delete[] pluginArr;
throw e;
}
for (size_t i = 0; i < pluginArrSize; i++)
delete[] pluginArr[i];
delete[] pluginArr;
lo_destroy_handle(gh);
}
void Game::RedatePlugins() {
+1
View File
@@ -131,6 +131,7 @@ namespace loot {
void GetLoadOrder(std::list<std::string>& loadOrder) const;
void SetLoadOrder(const std::list<std::string>& loadOrder) const; //Modifies game load order, even though const.
void SetLoadOrder(const char * const * const loadOrder, const size_t numPlugins) const; // For API.
void RefreshActivePluginsList();
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
+3 -3
View File
@@ -279,7 +279,7 @@ namespace loot {
}
else {
// Repository exists: check settings are correct, then pull updates.
git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\".";
git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in " + repo_path.string() + ".";
// Open the repository.
BOOST_LOG_TRIVIAL(info) << "Existing repository found, attempting to open it.";
@@ -312,7 +312,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(info) << "Received " << stats->indexed_objects << " of " << stats->total_objects << " objects in " << stats->received_bytes << " bytes.";
// Check that a branch with the correct name exists.
git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\".";
git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in " + repo_path.string() + "\".";
int ret = git_branch_lookup(&git.ref, git.repo, repo_branch.c_str(), GIT_BRANCH_LOCAL);
if (ret == GIT_ENOTFOUND) {
// Branch doesn't exist. Create a new branch using the remote branch's latest commit.
@@ -444,7 +444,7 @@ namespace loot {
bool parsingFailed = false;
std::string parsingError;
git.ui_message = "An error occurred while trying to read information on the updated masterlist. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\".";
git.ui_message = "An error occurred while trying to read information on the updated masterlist. If this error happens again, try deleting the \".git\" folder in " + repo_path.string() + "\".";
do {
// Get some descriptive info about what was checked out.