mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Mostly implemented API (userlist side of things is missing). As yet untested, though it builds fine.
This commit is contained in:
+11
-13
@@ -14,7 +14,7 @@ project (boss)
|
||||
set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/game.cpp" "${CMAKE_SOURCE_DIR}/src/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/plugin/ModFormat.cpp" "${CMAKE_SOURCE_DIR}/src/plugin/VersionRegex.cpp")
|
||||
|
||||
# Include source and library directories.
|
||||
include_directories ("${BOSS_LIBS_DIR}/alphanum" "${BOSS_LIBS_DIR}/utf8" "${BOSS_LIBS_DIR}/boost" "${BOSS_LIBS_DIR}/yaml-cpp/include" "${CMAKE_SOURCE_DIR}/src")
|
||||
include_directories ("${BOSS_LIBS_DIR}/alphanum" "${BOSS_LIBS_DIR}/utf8" "${BOSS_LIBS_DIR}/boost" "${BOSS_LIBS_DIR}/yaml-cpp/include" "${CMAKE_SOURCE_DIR}/src" "${BOSS_LIBS_DIR}/libloadorder/src")
|
||||
|
||||
##############################
|
||||
# Platform-Specific Settings
|
||||
@@ -37,32 +37,30 @@ ENDIF ()
|
||||
|
||||
# Settings when compiling and cross-compiling on Linux.
|
||||
IF (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
|
||||
set (BOSS_LIBS yaml-cpp boost_filesystem boost_system boost_regex)
|
||||
set (BOSS_LIBS loadorder yaml-cpp boost_filesystem boost_system boost_regex)
|
||||
set (CMAKE_C_FLAGS "-m${BOSS_ARCH}")
|
||||
set (CMAKE_CXX_FLAGS "-m${BOSS_ARCH}")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
set (CMAKE_MODULE_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
|
||||
link_directories ("${BOSS_LIBS_DIR}/yaml-cpp/build/")
|
||||
link_directories ("${BOSS_LIBS_DIR}/yaml-cpp/build")
|
||||
link_directories ("${BOSS_LIBS_DIR}/libloadorder/build")
|
||||
link_directories ("${BOSS_LIBS_DIR}/boost/stage-${BOSS_ARCH}/lib")
|
||||
|
||||
IF (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
link_directories ("${BOSS_LIBS_DIR}/yaml-cpp/build/")
|
||||
link_directories ("${BOSS_LIBS_DIR}/boost/stage-mingw-${BOSS_ARCH}/lib")
|
||||
link_directories ("${BOSS_LIBS_DIR}/boost/stage-mingw-${BOSS_ARCH}/lib")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
# Settings when not cross-compiling.
|
||||
IF (CMAKE_SYSTEM_NAME MATCHES CMAKE_HOST_SYSTEM_NAME)
|
||||
link_directories ("${BOSS_LIBS_DIR}/yaml-cpp/build/")
|
||||
link_directories ("${BOSS_LIBS_DIR}/boost/stage-${BOSS_ARCH}/lib")
|
||||
ENDIF ()
|
||||
|
||||
##############################
|
||||
# Actual Building
|
||||
##############################
|
||||
|
||||
# Build API.
|
||||
add_library (boss "${CMAKE_SOURCE_DIR}/src/api.cpp" ${BOSS_SRC})
|
||||
target_link_libraries (boss ${BOSS_LIBS})
|
||||
|
||||
# Build tester.
|
||||
add_executable (parser-tester "${CMAKE_SOURCE_DIR}/src/tester.cpp" ${BOSS_SRC})
|
||||
target_link_libraries (parser-tester ${BOSS_LIBS})
|
||||
add_executable (tester "${CMAKE_SOURCE_DIR}/src/tester.cpp" ${BOSS_SRC})
|
||||
target_link_libraries (tester ${BOSS_LIBS})
|
||||
|
||||
+361
-25
@@ -22,6 +22,93 @@
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
#include "globals.h"
|
||||
#include "game.h"
|
||||
#include "metadata.h"
|
||||
#include "parsers.h"
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <clocale>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
const unsigned int BOSS_API_OK = 0;
|
||||
const unsigned int BOSS_API_ERROR_LIBLO_ERROR = 1;
|
||||
const unsigned int BOSS_API_ERROR_PARSE_FAIL = 2;
|
||||
const unsigned int BOSS_API_ERROR_CONDITION_EVAL_FAIL = 3;
|
||||
const unsigned int BOSS_API_ERROR_REGEX_EVAL_FAIL = 4;
|
||||
const unsigned int BOSS_API_ERROR_NO_MEM = 5;
|
||||
const unsigned int BOSS_API_ERROR_INVALID_ARGS = 6;
|
||||
const unsigned int BOSS_API_ERROR_NO_TAG_MAP = 7;
|
||||
const unsigned int BOSS_API_RETURN_MAX = BOSS_API_ERROR_NO_TAG_MAP;
|
||||
|
||||
// The following are the games identifiers used by the API.
|
||||
const unsigned int BOSS_API_GAME_TES4 = BOSS_GAME_TES4;
|
||||
const unsigned int BOSS_API_GAME_TES5 = BOSS_GAME_TES5;
|
||||
const unsigned int BOSS_API_GAME_FO3 = BOSS_GAME_FO3;
|
||||
const unsigned int BOSS_API_GAME_FONV = BOSS_GAME_FONV;
|
||||
|
||||
// BOSS message types.
|
||||
const unsigned int BOSS_API_MESSAGE_SAY = 1;
|
||||
const unsigned int BOSS_API_MESSAGE_WARN = 2;
|
||||
const unsigned int BOSS_API_MESSAGE_ERROR = 3;
|
||||
|
||||
struct _boss_db_int {
|
||||
_boss_db_int()
|
||||
: extTagMap(NULL),
|
||||
extAddedTagIds(NULL),
|
||||
extRemovedTagIds(NULL),
|
||||
extMessageArray(NULL),
|
||||
extMessageArraySize(0) {
|
||||
}
|
||||
|
||||
~_boss_db_int() {
|
||||
delete [] extAddedTagIds;
|
||||
delete [] extRemovedTagIds;
|
||||
|
||||
if (extTagMap != NULL) {
|
||||
for (size_t i=0; i < bashTagMap.size(); i++)
|
||||
delete [] extTagMap[i]; //Gotta clear those allocated strings.
|
||||
delete [] extTagMap;
|
||||
}
|
||||
|
||||
if (extMessageArray != NULL) {
|
||||
for (size_t i=0; i < extMessageArraySize; i++)
|
||||
delete [] extMessageArray[i].message; //Gotta clear those allocated strings.
|
||||
delete [] extMessageArray;
|
||||
}
|
||||
}
|
||||
|
||||
boss::Game game;
|
||||
std::list<boss::Plugin> metadata;
|
||||
std::list<boss::Plugin> userMetadata;
|
||||
|
||||
boost::unordered_map<std::string, unsigned int> bashTagMap;
|
||||
|
||||
char ** extTagMap;
|
||||
|
||||
unsigned int * extAddedTagIds;
|
||||
unsigned int * extRemovedTagIds;
|
||||
|
||||
boss_message * extMessageArray;
|
||||
size_t extMessageArraySize;
|
||||
};
|
||||
|
||||
char * extMessageStr;
|
||||
|
||||
// std::string to null-terminated char string converter.
|
||||
char * ToNewCString(std::string str) {
|
||||
char * p = new char[str.length() + 1];
|
||||
return strcpy(p, str.c_str());
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// Error Handling Functions
|
||||
@@ -30,8 +117,18 @@
|
||||
// Outputs a string giving the details of the last time an error or
|
||||
// warning return code was returned by a function. The string exists
|
||||
// until this function is called again or until CleanUpAPI is called.
|
||||
BOSS_API uint32_t boss_get_error_message (uint8_t ** message) {
|
||||
BOSS_API unsigned int boss_get_error_message (char ** message) {
|
||||
if (message == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
*message = "Something went wrong.";
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Frees memory allocated to error string.
|
||||
BOSS_API void boss_cleanup () {
|
||||
delete[] extMessageStr;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,15 +138,22 @@ BOSS_API uint32_t boss_get_error_message (uint8_t ** message) {
|
||||
|
||||
// Returns whether this version of BOSS supports the API from the given
|
||||
// BOSS version. Abstracts BOSS API stability policy away from clients.
|
||||
BOSS_API bool boss_is_compatible (const uint32_t versionMajor, const uint32_t versionMinor, const uint32_t versionPatch) {
|
||||
|
||||
BOSS_API bool boss_is_compatible (const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) {
|
||||
return versionMajor == BOSS_VERSION_MAJOR && versionMinor == BOSS_VERSION_MINOR;
|
||||
}
|
||||
|
||||
// Returns the version string for this version of BOSS.
|
||||
// The string exists until this function is called again or until
|
||||
// CleanUpAPI is called.
|
||||
BOSS_API uint32_t boss_get_version (uint32_t * versionMajor, uint32_t * versionMinor, uint32_t * versionPatch) {
|
||||
BOSS_API unsigned int boss_get_version (unsigned int * versionMajor, unsigned int * versionMinor, unsigned int * versionPatch) {
|
||||
if (versionMajor == NULL || versionMinor == NULL || versionPatch == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
*versionMajor = BOSS_VERSION_MAJOR;
|
||||
*versionMinor = BOSS_VERSION_MINOR;
|
||||
*versionPatch = BOSS_VERSION_PATCH;
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,18 +168,42 @@ BOSS_API uint32_t boss_get_version (uint32_t * versionMajor, uint32_t * versionM
|
||||
// plugins.txt and loadorder.txt (if they both exist) are in sync. If
|
||||
// dataPath == NULL then the API will attempt to detect the data path of
|
||||
// the specified game.
|
||||
BOSS_API uint32_t boss_create_db (boss_db * db, const uint32_t clientGame, const uint8_t * gamePath) {
|
||||
BOSS_API unsigned int boss_create_db (boss_db * db, const unsigned int clientGame, const char * gamePath) {
|
||||
if (db == NULL || (clientGame != BOSS_API_GAME_TES4 && clientGame != BOSS_API_GAME_TES5 && clientGame != BOSS_API_GAME_FO3 && clientGame != BOSS_API_GAME_FONV))
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
//Set the locale to get encoding conversions working correctly.
|
||||
std::setlocale(LC_CTYPE, "");
|
||||
std::locale global_loc = std::locale();
|
||||
std::locale loc(global_loc, new boost::filesystem::detail::utf8_codecvt_facet());
|
||||
boost::filesystem::path::imbue(loc);
|
||||
|
||||
std::string game_path = "";
|
||||
if (gamePath != NULL)
|
||||
game_path = gamePath;
|
||||
|
||||
boss::Game game;
|
||||
try {
|
||||
game = boss::Game(clientGame, game_path); //This also checks to see if the game is installed if game_path is empty and throws an exception if it is not detected.
|
||||
} catch (std::runtime_error& e) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
boss_db retVal;
|
||||
try {
|
||||
retVal = new _boss_db_int;
|
||||
} catch (std::bad_alloc /*&e*/) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
retVal->game = game;
|
||||
*db = retVal;
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Destroys the given DB, freeing any memory allocated as part of its use.
|
||||
BOSS_API void boss_destroy_db (boss_db db) {
|
||||
|
||||
}
|
||||
|
||||
// Frees memory allocated to version and error strings.
|
||||
BOSS_API void boss_cleanup () {
|
||||
|
||||
delete db;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,9 +215,27 @@ BOSS_API void boss_cleanup () {
|
||||
// Can be called multiple times. On error, the database is unchanged.
|
||||
// Paths are case-sensitive if the underlying filesystem is case-sensitive.
|
||||
// masterlistPath and userlistPath are files.
|
||||
BOSS_API uint32_t boss_load_lists (boss_db db, const uint8_t * masterlistPath,
|
||||
const uint8_t * userlistPath) {
|
||||
BOSS_API unsigned int boss_load_lists (boss_db db, const char * masterlistPath,
|
||||
const char * userlistPath) {
|
||||
if (db == NULL || masterlistPath == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
std::list<boss::Plugin> temp;
|
||||
std::list<boss::Plugin> userTemp;
|
||||
try {
|
||||
YAML::Node tempNode = YAML::LoadFile(masterlistPath);
|
||||
temp = tempNode["plugins"].as< std::list<boss::Plugin> >();
|
||||
|
||||
tempNode = YAML::LoadFile(userlistPath);
|
||||
userTemp = tempNode["plugins"].as< std::list<boss::Plugin> >();
|
||||
} catch (YAML::Exception &e) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
db->metadata = temp;
|
||||
db->userMetadata = userTemp;
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Evaluates all conditional lines and regex mods the loaded masterlist.
|
||||
@@ -98,8 +244,29 @@ BOSS_API uint32_t boss_load_lists (boss_db db, const uint8_t * masterlistPath,
|
||||
// is called. Repeated calls re-evaluate the masterlist from scratch each time,
|
||||
// ignoring the results of any previous evaluations. Paths are case-sensitive
|
||||
// if the underlying filesystem is case-sensitive.
|
||||
BOSS_API uint32_t boss_eval_lists (boss_db db) {
|
||||
BOSS_API unsigned int boss_eval_lists (boss_db db) {
|
||||
|
||||
std::list<boss::Plugin> temp = db->metadata;
|
||||
try {
|
||||
for (std::list<boss::Plugin>::iterator it=temp.begin(), endIt=temp.end(); it != endIt; ++it) {
|
||||
it->EvalAllConditions(db->game);
|
||||
}
|
||||
} catch (std::runtime_error& e) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
db->metadata = temp;
|
||||
|
||||
temp = db->userMetadata;
|
||||
try {
|
||||
for (std::list<boss::Plugin>::iterator it=temp.begin(), endIt=temp.end(); it != endIt; ++it) {
|
||||
it->EvalAllConditions(db->game);
|
||||
}
|
||||
} catch (std::runtime_error& e) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
db->userMetadata = temp;
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +277,62 @@ BOSS_API uint32_t boss_eval_lists (boss_db db) {
|
||||
// Returns an array of the Bash Tags encounterred when loading the masterlist
|
||||
// and userlist, and the number of tags in the returned array. The array and
|
||||
// its contents are static and should not be freed by the client.
|
||||
BOSS_API uint32_t boss_get_tag_map (boss_db db, boss_tag ** tagMap, size_t * numTags) {
|
||||
BOSS_API unsigned int boss_get_tag_map (boss_db db, char *** tagMap, size_t * numTags) {
|
||||
if (db == NULL || tagMap == NULL || numTags == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
//Clear existing array allocation.
|
||||
if (db->extTagMap != NULL) {
|
||||
for (size_t i=0, max=db->bashTagMap.size(); i < max; ++i) {
|
||||
delete [] db->extTagMap[i];
|
||||
}
|
||||
delete [] db->extTagMap;
|
||||
}
|
||||
|
||||
//Initialise output.
|
||||
*tagMap = NULL;
|
||||
*numTags = 0;
|
||||
|
||||
boost::unordered_set<std::string> allTags;
|
||||
|
||||
for (std::list<boss::Plugin>::iterator it=db->metadata.begin(), endIt=db->metadata.end(); it != endIt; ++it) {
|
||||
std::list<boss::Tag> tags = it->Tags();
|
||||
for (std::list<boss::Tag>::const_iterator jt=tags.begin(), endJt=tags.end(); jt != endJt; ++jt) {
|
||||
allTags.insert(jt->Name());
|
||||
}
|
||||
}
|
||||
for (std::list<boss::Plugin>::iterator it=db->userMetadata.begin(), endIt=db->userMetadata.end(); it != endIt; ++it) {
|
||||
std::list<boss::Tag> tags = it->Tags();
|
||||
for (std::list<boss::Tag>::const_iterator jt=tags.begin(), endJt=tags.end(); jt != endJt; ++jt) {
|
||||
allTags.insert(jt->Name());
|
||||
}
|
||||
}
|
||||
|
||||
if (allTags.empty())
|
||||
return BOSS_API_OK;
|
||||
|
||||
try {
|
||||
db->extTagMap = new char*[allTags.size()];
|
||||
} catch (std::bad_alloc /*&e*/) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
unsigned int UID = 0;
|
||||
try {
|
||||
for (boost::unordered_set<std::string>::const_iterator it=allTags.begin(), endIt=allTags.end(); it != endIt; ++it) {
|
||||
db->bashTagMap.emplace(*it, UID);
|
||||
//Also allocate memory.
|
||||
db->extTagMap[UID] = ToNewCString(*it);
|
||||
UID++;
|
||||
}
|
||||
} catch (std::bad_alloc /*&e*/) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*tagMap = db->extTagMap;
|
||||
*numTags = allTags.size();
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Returns arrays of Bash Tag UIDs for Bash Tags suggested for addition and removal
|
||||
@@ -121,28 +342,143 @@ BOSS_API uint32_t boss_get_tag_map (boss_db db, boss_tag ** tagMap, size_t * num
|
||||
// case-insensitive. If no Tags are found for an array, the array pointer (*tagIds)
|
||||
// will be NULL. The userlistModified bool is true if the userlist contains Bash Tag
|
||||
// suggestion message additions.
|
||||
BOSS_API uint32_t boss_get_plugin_tags (boss_db db, const uint8_t * plugin,
|
||||
uint32_t ** tagIds_added,
|
||||
size_t * numTags_added,
|
||||
uint32_t **tagIds_removed,
|
||||
size_t *numTags_removed,
|
||||
bool * userlistModified) {
|
||||
BOSS_API unsigned int boss_get_plugin_tags (boss_db db, const char * plugin,
|
||||
unsigned int ** tagIds_added,
|
||||
size_t * numTags_added,
|
||||
unsigned int **tagIds_removed,
|
||||
size_t * numTags_removed,
|
||||
bool * userlistModified) {
|
||||
if (db == NULL || plugin == NULL || tagIds_added == NULL || numTags_added == NULL || tagIds_removed == NULL || numTags_removed == NULL || userlistModified == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
|
||||
//Clear existing array allocations.
|
||||
delete [] db->extAddedTagIds;
|
||||
delete [] db->extRemovedTagIds;
|
||||
|
||||
//Initialise output.
|
||||
*tagIds_added = NULL;
|
||||
*tagIds_removed = NULL;
|
||||
*userlistModified = false;
|
||||
*numTags_added = 0;
|
||||
*numTags_removed = 0;
|
||||
|
||||
boost::unordered_set<std::string> tagsAdded, tagsRemoved;
|
||||
std::list<boss::Plugin>::iterator it = std::find(db->metadata.begin(), db->metadata.end(), boss::Plugin(plugin));
|
||||
if (it != db->metadata.end()) {
|
||||
std::list<boss::Tag> tags = it->Tags();
|
||||
for (std::list<boss::Tag>::const_iterator it=tags.begin(), endIt=tags.end(); it != endIt; ++it) {
|
||||
if (it->IsAddition())
|
||||
tagsAdded.insert(it->Name());
|
||||
else
|
||||
tagsRemoved.insert(it->Name());
|
||||
}
|
||||
}
|
||||
|
||||
it = std::find(db->userMetadata.begin(), db->userMetadata.end(), boss::Plugin(plugin));
|
||||
if (it != db->userMetadata.end()) {
|
||||
*userlistModified = true;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> tagsAddedIDs, tagsRemovedIDs;
|
||||
for (boost::unordered_set<std::string>::const_iterator it=tagsAdded.begin(), endIt=tagsAdded.end(); it != endIt; ++it) {
|
||||
boost::unordered_map<std::string, unsigned int>::const_iterator mapIter = db->bashTagMap.find(*it);
|
||||
if (mapIter != db->bashTagMap.end())
|
||||
tagsAddedIDs.push_back(mapIter->second);
|
||||
}
|
||||
for (boost::unordered_set<std::string>::const_iterator it=tagsRemoved.begin(), endIt=tagsRemoved.end(); it != endIt; ++it) {
|
||||
boost::unordered_map<std::string, unsigned int>::const_iterator mapIter = db->bashTagMap.find(*it);
|
||||
if (mapIter != db->bashTagMap.end())
|
||||
tagsRemovedIDs.push_back(mapIter->second);
|
||||
}
|
||||
|
||||
//Allocate memory.
|
||||
size_t numAdded = tagsAddedIDs.size();
|
||||
size_t numRemoved = tagsRemovedIDs.size();
|
||||
try {
|
||||
if (numAdded != 0) {
|
||||
db->extAddedTagIds = new uint32_t[numAdded];
|
||||
for (size_t i=0; i < numAdded; i++)
|
||||
db->extAddedTagIds[i] = tagsAddedIDs[i];
|
||||
}
|
||||
if (numRemoved != 0) {
|
||||
db->extRemovedTagIds = new uint32_t[numRemoved];
|
||||
for (size_t i=0; i < numRemoved; i++)
|
||||
db->extRemovedTagIds[i] = tagsRemovedIDs[i];
|
||||
}
|
||||
} catch (std::bad_alloc /*&e*/) {
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
//Set outputs.
|
||||
*tagIds_added = db->extAddedTagIds;
|
||||
*tagIds_removed = db->extRemovedTagIds;
|
||||
*numTags_added = numAdded;
|
||||
*numTags_removed = numRemoved;
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Returns the messages attached to the given plugin. Messages are valid until Load,
|
||||
// DestroyBossDb or GetPluginMessages are next called. plugin is case-insensitive.
|
||||
// If no messages are attached, *messages will be NULL and numMessages will equal 0.
|
||||
BOSS_API uint32_t boss_get_plugin_messages (boss_db db, const uint8_t * plugin,
|
||||
boss_message ** messages,
|
||||
size_t * numMessages) {
|
||||
BOSS_API unsigned int boss_get_plugin_messages (boss_db db, const char * plugin,
|
||||
boss_message ** messages,
|
||||
size_t * numMessages) {
|
||||
if (db == NULL || plugin == NULL || messages == NULL || numMessages == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
//Clear existing array allocation.
|
||||
if (db->extMessageArray != NULL) {
|
||||
for (size_t i=0; i < db->extMessageArraySize; ++i) {
|
||||
delete [] db->extMessageArray[i].message;
|
||||
}
|
||||
delete [] db->extMessageArray;
|
||||
}
|
||||
|
||||
//Initialise output.
|
||||
*messages = NULL;
|
||||
*numMessages = 0;
|
||||
|
||||
std::list<boss::Plugin>::iterator it = std::find(db->metadata.begin(), db->metadata.end(), boss::Plugin(plugin));
|
||||
if (it == db->metadata.end()) {
|
||||
it = std::find(db->userMetadata.begin(), db->userMetadata.end(), boss::Plugin(plugin));
|
||||
if (it == db->userMetadata.end())
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
// Writes a minimal masterlist that only contains mods that have Bash Tag suggestions,
|
||||
// and/or dirty messages, plus the Tag suggestions and/or messages themselves and their
|
||||
// conditions, in order to create the Wrye Bash taglist. outputFile is the path to use
|
||||
// for output. If outputFile already exists, it will only be overwritten if overwrite is true.
|
||||
BOSS_API uint32_t boss_write_minimal_list (boss_db db, const uint8_t * outputFile, const bool overwrite) {
|
||||
BOSS_API unsigned int boss_write_minimal_list (boss_db db, const char * outputFile, const bool overwrite) {
|
||||
if (db == NULL || outputFile == NULL)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
if (boost::filesystem::exists(outputFile) && !overwrite)
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
|
||||
std::list<boss::Plugin> temp = db->metadata;
|
||||
for (std::list<boss::Plugin>::iterator it=temp.begin(), endIt=temp.end(); it != endIt; ++it) {
|
||||
boss::Plugin p(it->Name());
|
||||
p.Tags(it->Tags());
|
||||
*it = p;
|
||||
}
|
||||
|
||||
YAML::Emitter yout;
|
||||
yout.SetIndent(2);
|
||||
yout << YAML::BeginMap
|
||||
<< YAML::Key << "plugins" << YAML::Value << temp
|
||||
<< YAML::EndMap;
|
||||
|
||||
std::ofstream out(outputFile);
|
||||
if (out.fail())
|
||||
return BOSS_API_ERROR_INVALID_ARGS;
|
||||
out << yout.c_str();
|
||||
out.close();
|
||||
|
||||
return BOSS_API_OK;
|
||||
}
|
||||
|
||||
@@ -68,67 +68,40 @@ extern "C"
|
||||
// All API strings are uint8_t* strings encoded in UTF-8. Strings returned
|
||||
// by the API should not have their memory freed by the client: the API will
|
||||
// clean up after itself.
|
||||
// All API numbers and error codes are uint32_t integers.
|
||||
// All API numbers and error codes are unsigned int integers.
|
||||
|
||||
// Abstracts the definition of BOSS's internal state while still providing
|
||||
// type safety across the API.
|
||||
typedef struct _boss_db_int * boss_db;
|
||||
|
||||
// boss_tag structure gives the Unique ID number (UID) for each Bash Tag and
|
||||
// the corresponding Tag name string.
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
const uint8_t * name; // don't use char for utf-8 since char can be signed
|
||||
} boss_tag;
|
||||
|
||||
// boss_message structure gives the type of message and it contents.
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
const uint8_t * message;
|
||||
unsigned int type;
|
||||
const char * message;
|
||||
} boss_message;
|
||||
|
||||
|
||||
// The following are the possible codes that the API can return.
|
||||
BOSS_API extern const uint32_t BOSS_API_OK;
|
||||
BOSS_API extern const uint32_t BOSS_API_OK_NO_UPDATE_NECESSARY;
|
||||
BOSS_API extern const uint32_t BOSS_API_WARN_BAD_FILENAME;
|
||||
BOSS_API extern const uint32_t BOSS_API_WARN_LO_MISMATCH;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_FILE_WRITE_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_FILE_DELETE_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_FILE_NOT_UTF8;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_FILE_NOT_FOUND;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_FILE_RENAME_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_TIMESTAMP_READ_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_TIMESTAMP_WRITE_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_PARSE_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_CONDITION_EVAL_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_REGEX_EVAL_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_NO_MEM;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_INVALID_ARGS;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_NETWORK_FAIL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_NO_INTERNET_CONNECTION;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_NO_TAG_MAP;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_PLUGINS_FULL;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_GAME_NOT_FOUND;
|
||||
BOSS_API extern const uint32_t BOSS_API_ERROR_PLUGIN_BEFORE_MASTER;
|
||||
BOSS_API extern const uint32_t BOSS_API_RETURN_MAX;
|
||||
BOSS_API extern const unsigned int BOSS_API_OK;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_LIBLO_ERROR;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_PARSE_FAIL;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_CONDITION_EVAL_FAIL;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_REGEX_EVAL_FAIL;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_NO_MEM;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_INVALID_ARGS;
|
||||
BOSS_API extern const unsigned int BOSS_API_ERROR_NO_TAG_MAP;
|
||||
BOSS_API extern const unsigned int BOSS_API_RETURN_MAX;
|
||||
|
||||
// The following are the games identifiers used by the API.
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_OBLIVION;
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_FALLOUT3;
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_FALLOUTNV;
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_NEHRIM;
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_SKYRIM;
|
||||
BOSS_API extern const uint32_t BOSS_API_GAME_MORROWIND;
|
||||
BOSS_API extern const unsigned int BOSS_API_GAME_TES4;
|
||||
BOSS_API extern const unsigned int BOSS_API_GAME_TES5;
|
||||
BOSS_API extern const unsigned int BOSS_API_GAME_FO3;
|
||||
BOSS_API extern const unsigned int BOSS_API_GAME_FONV;
|
||||
|
||||
// BOSS message types.
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_SAY;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_TAG;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_REQUIREMENT;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_INCOMPATIBILITY;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_DIRTY;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_WARN;
|
||||
BOSS_API extern const uint32_t BOSS_API_MESSAGE_ERROR;
|
||||
BOSS_API extern const unsigned int BOSS_API_MESSAGE_SAY;
|
||||
BOSS_API extern const unsigned int BOSS_API_MESSAGE_WARN;
|
||||
BOSS_API extern const unsigned int BOSS_API_MESSAGE_ERROR;
|
||||
|
||||
|
||||
|
||||
@@ -138,8 +111,11 @@ BOSS_API extern const uint32_t BOSS_API_MESSAGE_ERROR;
|
||||
|
||||
// Outputs a string giving the details of the last time an error or
|
||||
// warning return code was returned by a function. The string exists
|
||||
// until this function is called again or until CleanUpAPI is called.
|
||||
BOSS_API uint32_t boss_get_error_message (uint8_t ** message);
|
||||
// until this function is called again or until boss_cleanup is called.
|
||||
BOSS_API unsigned int boss_get_error_message (char ** message);
|
||||
|
||||
// Frees memory allocated to error string.
|
||||
BOSS_API void boss_cleanup ();
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
@@ -148,12 +124,12 @@ BOSS_API uint32_t boss_get_error_message (uint8_t ** message);
|
||||
|
||||
// Returns whether this version of BOSS supports the API from the given
|
||||
// BOSS version. Abstracts BOSS API stability policy away from clients.
|
||||
BOSS_API bool boss_is_compatible (const uint32_t versionMajor, const uint32_t versionMinor, const uint32_t versionPatch);
|
||||
BOSS_API bool boss_is_compatible (const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch);
|
||||
|
||||
// Returns the version string for this version of BOSS.
|
||||
// The string exists until this function is called again or until
|
||||
// CleanUpAPI is called.
|
||||
BOSS_API uint32_t boss_get_version (uint32_t * versionMajor, uint32_t * versionMinor, uint32_t * versionPatch);
|
||||
BOSS_API unsigned int boss_get_version (unsigned int * versionMajor, unsigned int * versionMinor, unsigned int * versionPatch);
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
@@ -167,14 +143,11 @@ BOSS_API uint32_t boss_get_version (uint32_t * versionMajor, uint32_t * versionM
|
||||
// plugins.txt and loadorder.txt (if they both exist) are in sync. If
|
||||
// dataPath == NULL then the API will attempt to detect the data path of
|
||||
// the specified game.
|
||||
BOSS_API uint32_t boss_create_db (boss_db * db, const uint32_t clientGame, const uint8_t * gamePath);
|
||||
BOSS_API unsigned int boss_create_db (boss_db * db, const unsigned int clientGame, const char * gamePath);
|
||||
|
||||
// Destroys the given DB, freeing any memory allocated as part of its use.
|
||||
BOSS_API void boss_destroy_db (boss_db db);
|
||||
|
||||
// Frees memory allocated to version and error strings.
|
||||
BOSS_API void boss_cleanup ();
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Database Loading Functions
|
||||
@@ -184,8 +157,8 @@ BOSS_API void boss_cleanup ();
|
||||
// Can be called multiple times. On error, the database is unchanged.
|
||||
// Paths are case-sensitive if the underlying filesystem is case-sensitive.
|
||||
// masterlistPath and userlistPath are files.
|
||||
BOSS_API uint32_t boss_load_lists (boss_db db, const uint8_t * masterlistPath,
|
||||
const uint8_t * userlistPath);
|
||||
BOSS_API unsigned int boss_load_lists (boss_db db, const char * masterlistPath,
|
||||
const char * userlistPath);
|
||||
|
||||
// Evaluates all conditional lines and regex mods the loaded masterlist.
|
||||
// This exists so that Load() doesn't need to be called whenever the mods
|
||||
@@ -193,7 +166,7 @@ BOSS_API uint32_t boss_load_lists (boss_db db, const uint8_t * masterlistPath,
|
||||
// is called. Repeated calls re-evaluate the masterlist from scratch each time,
|
||||
// ignoring the results of any previous evaluations. Paths are case-sensitive
|
||||
// if the underlying filesystem is case-sensitive.
|
||||
BOSS_API uint32_t boss_eval_lists (boss_db db);
|
||||
BOSS_API unsigned int boss_eval_lists (boss_db db);
|
||||
|
||||
|
||||
//////////////////////////
|
||||
@@ -203,7 +176,8 @@ BOSS_API uint32_t boss_eval_lists (boss_db db);
|
||||
// Returns an array of the Bash Tags encounterred when loading the masterlist
|
||||
// and userlist, and the number of tags in the returned array. The array and
|
||||
// its contents are static and should not be freed by the client.
|
||||
BOSS_API uint32_t boss_get_tag_map (boss_db db, boss_tag ** tagMap, size_t * numTags);
|
||||
// The indices of the tagMap are each tag's UID.
|
||||
BOSS_API unsigned int boss_get_tag_map (boss_db db, char *** tagMap, size_t * numTags);
|
||||
|
||||
// Returns arrays of Bash Tag UIDs for Bash Tags suggested for addition and removal
|
||||
// by BOSS's masterlist and userlist, and the number of tags in each array.
|
||||
@@ -212,17 +186,17 @@ BOSS_API uint32_t boss_get_tag_map (boss_db db, boss_tag ** tagMap, size_t * num
|
||||
// case-insensitive. If no Tags are found for an array, the array pointer (*tagIds)
|
||||
// will be NULL. The userlistModified bool is true if the userlist contains Bash Tag
|
||||
// suggestion message additions.
|
||||
BOSS_API uint32_t boss_get_plugin_tags (boss_db db, const uint8_t * plugin,
|
||||
uint32_t ** tagIds_added,
|
||||
BOSS_API unsigned int boss_get_plugin_tags (boss_db db, const char * plugin,
|
||||
unsigned int ** tagIds_added,
|
||||
size_t * numTags_added,
|
||||
uint32_t **tagIds_removed,
|
||||
unsigned int **tagIds_removed,
|
||||
size_t *numTags_removed,
|
||||
bool * userlistModified);
|
||||
|
||||
// Returns the messages attached to the given plugin. Messages are valid until Load,
|
||||
// DestroyBossDb or GetPluginMessages are next called. plugin is case-insensitive.
|
||||
// If no messages are attached, *messages will be NULL and numMessages will equal 0.
|
||||
BOSS_API uint32_t boss_get_plugin_messages (boss_db db, const uint8_t * plugin,
|
||||
BOSS_API unsigned int boss_get_plugin_messages (boss_db db, const char * plugin,
|
||||
boss_message ** messages,
|
||||
size_t * numMessages);
|
||||
|
||||
@@ -230,7 +204,7 @@ BOSS_API uint32_t boss_get_plugin_messages (boss_db db, const uint8_t * plugin,
|
||||
// and/or dirty messages, plus the Tag suggestions and/or messages themselves and their
|
||||
// conditions, in order to create the Wrye Bash taglist. outputFile is the path to use
|
||||
// for output. If outputFile already exists, it will only be overwritten if overwrite is true.
|
||||
BOSS_API uint32_t boss_write_minimal_list (boss_db db, const uint8_t * outputFile, const bool overwrite);
|
||||
BOSS_API unsigned int boss_write_minimal_list (boss_db db, const char * outputFile, const bool overwrite);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+29
-7
@@ -25,6 +25,8 @@
|
||||
#include "globals.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <libloadorder.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -43,7 +45,7 @@ namespace boss {
|
||||
Game::Game()
|
||||
: id(BOSS_GAME_AUTODETECT) {}
|
||||
|
||||
Game::Game(const uint32_t gameCode, const string path, const bool noPathInit)
|
||||
Game::Game(const unsigned int gameCode, const string path, const bool noPathInit)
|
||||
: id(gameCode) {
|
||||
if (Id() == BOSS_GAME_TES4) {
|
||||
name = "TES IV: Oblivion";
|
||||
@@ -91,6 +93,31 @@ namespace boss {
|
||||
throw runtime_error("Game path could not be detected.");
|
||||
} else
|
||||
gamePath = fs::path(path);
|
||||
|
||||
lo_game_handle gh;
|
||||
int ret;
|
||||
char ** pluginArr;
|
||||
size_t pluginArrSize;
|
||||
if (id == BOSS_GAME_TES4)
|
||||
ret = lo_create_handle(&gh, LIBLO_GAME_TES4, gamePath.string().c_str());
|
||||
else if (id == BOSS_GAME_TES5)
|
||||
ret = lo_create_handle(&gh, LIBLO_GAME_TES5, gamePath.string().c_str());
|
||||
else if (id == BOSS_GAME_FO3)
|
||||
ret = lo_create_handle(&gh, LIBLO_GAME_FO3, gamePath.string().c_str());
|
||||
else if (id == BOSS_GAME_FONV)
|
||||
ret = lo_create_handle(&gh, LIBLO_GAME_FNV, gamePath.string().c_str());
|
||||
|
||||
if (ret != LIBLO_OK)
|
||||
throw runtime_error("Active plugin list lookup failed.");
|
||||
else {
|
||||
if (lo_get_active_plugins(gh, &pluginArr, &pluginArrSize) != LIBLO_OK)
|
||||
throw runtime_error("Active plugin list lookup failed.");
|
||||
else {
|
||||
for (size_t i=0; i < pluginArrSize; ++i) {
|
||||
activePlugins.insert(string(pluginArr[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +129,7 @@ namespace boss {
|
||||
return fs::exists(fs::path("..") / pluginsFolderName);
|
||||
}
|
||||
|
||||
uint32_t Game::Id() const {
|
||||
unsigned int Game::Id() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -119,11 +146,6 @@ namespace boss {
|
||||
}
|
||||
|
||||
bool Game::IsActive(const std::string& plugin) const {
|
||||
if (activePlugins.empty()) {
|
||||
//Use libloadorder to fetch the active plugins list. Fill the set
|
||||
//with the lowercased filenames.
|
||||
}
|
||||
|
||||
return activePlugins.find(boost::to_lower_copy(plugin)) != activePlugins.end();
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -36,12 +36,12 @@ namespace boss {
|
||||
class Game {
|
||||
public:
|
||||
Game(); //Sets game to BOSS_GAME_AUTODETECT, with all other vars being empty.
|
||||
Game(const uint32_t gameCode, const std::string path = "", const bool noPathInit = false); //Empty path means constructor will detect its location. If noPathInit is true, then the game's BOSS subfolder will not be created.
|
||||
Game(const unsigned int gameCode, const std::string path = "", const bool noPathInit = false); //Empty path means constructor will detect its location. If noPathInit is true, then the game's BOSS subfolder will not be created.
|
||||
|
||||
bool IsInstalled() const;
|
||||
bool IsInstalledLocally() const;
|
||||
|
||||
uint32_t Id() const;
|
||||
unsigned int Id() const;
|
||||
std::string Name() const; //Returns the game's name, eg. "TES IV: Oblivion".
|
||||
|
||||
boost::filesystem::path GamePath() const;
|
||||
@@ -56,7 +56,7 @@ namespace boss {
|
||||
boost::unordered_map<std::string, bool> conditionCache; //Holds lowercased strings.
|
||||
boost::unordered_map<std::string, uint32_t> crcCache; //Holds lowercased strings.
|
||||
private:
|
||||
uint32_t id;
|
||||
unsigned id;
|
||||
std::string name;
|
||||
|
||||
std::string registryKey;
|
||||
|
||||
+8
-8
@@ -23,14 +23,14 @@
|
||||
#ifndef __BOSS_GLOBALS__
|
||||
#define __BOSS_GLOBALS__
|
||||
|
||||
const int BOSS_GAME_AUTODETECT = 0;
|
||||
const int BOSS_GAME_TES4 = 1;
|
||||
const int BOSS_GAME_TES5 = 2;
|
||||
const int BOSS_GAME_FO3 = 3;
|
||||
const int BOSS_GAME_FONV = 4;
|
||||
const unsigned int BOSS_GAME_AUTODETECT = 0;
|
||||
const unsigned int BOSS_GAME_TES4 = 1;
|
||||
const unsigned int BOSS_GAME_TES5 = 2;
|
||||
const unsigned int BOSS_GAME_FO3 = 3;
|
||||
const unsigned int BOSS_GAME_FONV = 4;
|
||||
|
||||
const int BOSS_VERSION_MAJOR = 3;
|
||||
const int BOSS_VERSION_MINOR = 0;
|
||||
const int BOSS_VERSION_PATCH = 0;
|
||||
const unsigned int BOSS_VERSION_MAJOR = 3;
|
||||
const unsigned int BOSS_VERSION_MINOR = 0;
|
||||
const unsigned int BOSS_VERSION_PATCH = 0;
|
||||
|
||||
#endif
|
||||
|
||||
+49
-13
@@ -23,13 +23,10 @@
|
||||
|
||||
# This is a script that converts a MF 2.3 masterlist to a MF 3 masterlist. It's
|
||||
# a bit hacky, but the YAML parser accepts it. Limitations are:
|
||||
# - Doesn't lowercase condition statements.
|
||||
# - Doesn't strip plugins that no longer belong in the masterlist, ie. without
|
||||
# messages or positioning comments.
|
||||
# - Requirements and incompatibilities do not use their new data structures,
|
||||
# and are just converted to 'say' messages.
|
||||
# - All strings except tags are enclosed in double quotes and escaped, even
|
||||
# those that don't need to be, and those that are already escaped.
|
||||
# - No extraneous comments/messages are removed.
|
||||
# - VAR conditions are not replaced with their conditional statements. SET lines
|
||||
# are stripped, so the old masterlist must be used to check what they are.
|
||||
@@ -38,15 +35,46 @@
|
||||
# - Conditional plugin positions are all made unconditional, so there will be
|
||||
# duplicate entries.
|
||||
|
||||
import re
|
||||
|
||||
def escapeYAMLStr(s):
|
||||
return '"' + s.replace('"', '\\"').replace('\\', '\\\\').strip(' ') + '"'
|
||||
special = ['-', '?', ':', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`']
|
||||
if ('\'' in s):
|
||||
return '"' + s.replace('\\', '\\\\').replace('"', '\\"').strip() + '"'
|
||||
elif (1 in [c in s for c in special]):
|
||||
return '\'' + s.strip() + '\''
|
||||
else:
|
||||
return s;
|
||||
|
||||
def mContent(line):
|
||||
content = line[line.find(':')+1:]
|
||||
return escapeYAMLStr(content)
|
||||
|
||||
inFile = open('masterlist.txt', 'r')
|
||||
outFile = open('masterlist.yaml', 'w')
|
||||
def convertCondition(condition):
|
||||
#IF no longer exists.
|
||||
#IFNOT is now 'not'.
|
||||
#The VAR condition no longer exists.
|
||||
#The '=' comparator is now '=='.
|
||||
#The LANG condition no longer exists.
|
||||
#'&&' is now 'and'.
|
||||
#'||' is now 'or'.
|
||||
|
||||
#Really, these will probably have to be done manually.
|
||||
|
||||
parts = condition.split('"') # Every odd index is quoted and shouldn't be lowercased.
|
||||
|
||||
for i in range(len(parts)):
|
||||
if (i % 2 == 0):
|
||||
parts[i] = parts[i].lower()
|
||||
|
||||
condition = '"'.join(parts)
|
||||
|
||||
condition.replace(' && ', ' and ').replace(' || ', ' or ').replace(' =)', ' ==)')
|
||||
|
||||
return escapeYAMLStr(condition)
|
||||
|
||||
inFile = open('../../BOSS/data/boss-oblivion/masterlist.txt', 'r')
|
||||
outFile = open('../build/masterlist.yaml', 'w')
|
||||
|
||||
outFile.write('---\n');
|
||||
|
||||
@@ -57,7 +85,7 @@ for line in inFile:
|
||||
|
||||
line = line.replace('\n', '')
|
||||
|
||||
if (len(line) == 0):
|
||||
if (len(line.strip()) == 0):
|
||||
continue
|
||||
|
||||
# Skip group lines.
|
||||
@@ -102,14 +130,15 @@ for line in inFile:
|
||||
if ('IF' in line and ':' in line):
|
||||
key = line[:line.find(':')]
|
||||
key = key.replace('GLOBAL', '')
|
||||
condition = key[:key.rfind(' ')].strip(' ')
|
||||
condition = condition.replace('&&', 'and').replace('||', 'or')
|
||||
condition = key[:key.rfind(' ')].strip()
|
||||
elif ('ELSE' in line and ':' in line):
|
||||
condition = condition.replace('IF ', 'IFNOT2 ')
|
||||
condition = condition.replace('IFNOT ', 'IF ')
|
||||
condition = condition.replace('IFNOT2 ', 'IFNOT ')
|
||||
if (condition[0] != 'n'):
|
||||
condition = 'not ' + condition
|
||||
condition = condition.replace('not ', '`~||~`')
|
||||
condition = condition.replace('d f', 'd not f').replace('d c', 'd not c', ', 'and
|
||||
else:
|
||||
condition = ''
|
||||
condition = convertCondition(condition);
|
||||
|
||||
# Write tag lines.
|
||||
if ('TAG:' in line):
|
||||
@@ -141,10 +170,17 @@ for line in inFile:
|
||||
indent = ' '
|
||||
else:
|
||||
indent = ' '
|
||||
prefix = ''
|
||||
if ('INC:' in line):
|
||||
line = 'Incompatible with ' + line.split(':')[1]
|
||||
elif ('REQ:' in line):
|
||||
line = 'Requires ' + line.split(':')[1]
|
||||
else:
|
||||
line = line.split(':')[1]
|
||||
outFile.write(indent + '- type: say\n')
|
||||
if (condition):
|
||||
outFile.write(indent + ' condition: ' + condition + '\n')
|
||||
outFile.write(indent + ' content: ' + mContent(line) + '\n')
|
||||
outFile.write(indent + ' content: ' + escapeYAMLStr(line) + '\n')
|
||||
|
||||
# Write 'warn' messages.
|
||||
if ('DIRTY:' in line or 'WARN:' in line):
|
||||
|
||||
@@ -233,4 +233,8 @@ namespace boss {
|
||||
bool Plugin::IsRegexPlugin() const {
|
||||
return boost::iends_with(name, "\\.esm") || boost::iends_with(name, "\\.esp");
|
||||
}
|
||||
|
||||
bool Plugin::operator == (Plugin rhs) {
|
||||
return name == rhs.Name();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,8 @@ namespace boss {
|
||||
void EvalAllConditions(boss::Game& game);
|
||||
bool HasNameOnly() const;
|
||||
bool IsRegexPlugin() const;
|
||||
|
||||
bool operator == (Plugin rhs);
|
||||
private:
|
||||
std::string name;
|
||||
bool enabled; //Default to true.
|
||||
@@ -145,6 +147,8 @@ namespace boss {
|
||||
return lhs.Name() < rhs.Name();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
+2
-15
@@ -27,21 +27,8 @@ int main() {
|
||||
|
||||
YAML::Node test = YAML::LoadFile("masterlist-example.yaml");
|
||||
|
||||
list<boss::Message> globalMessages;
|
||||
if (test["globals"]) {
|
||||
YAML::Node globals = test["globals"];
|
||||
for (YAML::const_iterator it=globals.begin(); it != globals.end(); ++it) {
|
||||
globalMessages.push_back(it->as<boss::Message>());
|
||||
}
|
||||
}
|
||||
|
||||
list<boss::Plugin> pluginData;
|
||||
if (test["plugins"]) {
|
||||
YAML::Node plugins = test["plugins"];
|
||||
for (YAML::const_iterator it=plugins.begin(); it != plugins.end(); ++it) {
|
||||
pluginData.push_back(it->as<boss::Plugin>());
|
||||
}
|
||||
}
|
||||
list<boss::Message> globalMessages = test["globals"].as< list<boss::Message> >();
|
||||
list<boss::Plugin> pluginData = test["plugins"].as< list<boss::Plugin> >();
|
||||
|
||||
cout << "Testing masterlist generator." << endl;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user