Merge branch 'next' of https://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
@@ -900,8 +900,10 @@ namespace canvas
|
||||
else if( name == "coord" )
|
||||
_attributes_dirty |= COORDS;
|
||||
else if ( name == "svg")
|
||||
{
|
||||
_hasSVG = true;
|
||||
_attributes_dirty |= SVG;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -242,8 +242,13 @@ void Client::makeRequest(const Request_ptr& r)
|
||||
if( r->isComplete() )
|
||||
return;
|
||||
|
||||
if (r->url().empty()) {
|
||||
r->setFailure(EINVAL, "no URL specified on request");
|
||||
return;
|
||||
}
|
||||
|
||||
if( r->url().find("://") == std::string::npos ) {
|
||||
r->setFailure(EINVAL, "malformed URL");
|
||||
r->setFailure(EINVAL, "malformed URL: '" + r->url() + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,11 @@ public:
|
||||
path = ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
// return zip data for this computed URL
|
||||
if (path.find("/catalogTest1/movies") == 0) {
|
||||
path = "/catalogTest1/movies-data.zip";
|
||||
}
|
||||
|
||||
localPath.append(path);
|
||||
|
||||
@@ -152,7 +157,7 @@ int parseTest()
|
||||
SG_CHECK_EQUAL(cat->description(), "First test catalog");
|
||||
|
||||
// check the packages too
|
||||
SG_CHECK_EQUAL(cat->packages().size(), 4);
|
||||
SG_CHECK_EQUAL(cat->packages().size(), 5);
|
||||
|
||||
pkg::PackageRef p1 = cat->packages().front();
|
||||
SG_CHECK_EQUAL(p1->catalog(), cat.ptr());
|
||||
@@ -326,7 +331,7 @@ void testAddCatalog(HTTP::Client* cl)
|
||||
p.append("org.flightgear.test.catalog1");
|
||||
p.append("catalog.xml");
|
||||
SG_VERIFY(p.exists());
|
||||
SG_CHECK_EQUAL(root->allPackages().size(), 4);
|
||||
SG_CHECK_EQUAL(root->allPackages().size(), 5);
|
||||
SG_CHECK_EQUAL(root->catalogs().size(), 1);
|
||||
|
||||
pkg::PackageRef p1 = root->getPackageById("alpha");
|
||||
@@ -559,6 +564,43 @@ void testInstallTarPackage(HTTP::Client* cl)
|
||||
SG_VERIFY(p.exists());
|
||||
}
|
||||
|
||||
void testInstallArchiveType(HTTP::Client* cl)
|
||||
{
|
||||
global_catalogVersion = 0;
|
||||
SGPath rootPath(simgear::Dir::current().path());
|
||||
rootPath.append("pkg_install_archive_type");
|
||||
simgear::Dir pd(rootPath);
|
||||
pd.removeChildren();
|
||||
|
||||
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
|
||||
// specify a test dir
|
||||
root->setHTTPClient(cl);
|
||||
|
||||
pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
|
||||
waitForUpdateComplete(cl, root);
|
||||
|
||||
pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.movies");
|
||||
SG_CHECK_EQUAL(p1->id(), "movies");
|
||||
pkg::InstallRef ins = p1->install();
|
||||
|
||||
SG_VERIFY(ins->isQueued());
|
||||
|
||||
waitForUpdateComplete(cl, root);
|
||||
SG_VERIFY(p1->isInstalled());
|
||||
SG_VERIFY(p1->existingInstall() == ins);
|
||||
|
||||
// verify on disk state
|
||||
SGPath p(rootPath);
|
||||
p.append("org.flightgear.test.catalog1");
|
||||
p.append("Aircraft");
|
||||
p.append("movies");
|
||||
|
||||
SG_CHECK_EQUAL(p, ins->path());
|
||||
|
||||
p.append("movie-list.json");
|
||||
SG_VERIFY(p.exists());
|
||||
}
|
||||
|
||||
void testDisableDueToVersion(HTTP::Client* cl)
|
||||
{
|
||||
global_catalogVersion = 0;
|
||||
@@ -915,7 +957,9 @@ int main(int argc, char* argv[])
|
||||
testRefreshCatalog(&cl);
|
||||
|
||||
testInstallTarPackage(&cl);
|
||||
|
||||
|
||||
testInstallArchiveType(&cl);
|
||||
|
||||
testDisableDueToVersion(&cl);
|
||||
|
||||
testOfflineMode(&cl);
|
||||
|
||||
@@ -57,6 +57,10 @@ public:
|
||||
throw sg_exception("no package download URLs");
|
||||
}
|
||||
|
||||
if (m_owner->package()->properties()->hasChild("archive-type")) {
|
||||
setArchiveTypeFromExtension(m_owner->package()->properties()->getStringValue("archive-type"));
|
||||
}
|
||||
|
||||
// TODO randomise order of m_urls
|
||||
|
||||
m_extractPath = aOwner->path().dir();
|
||||
@@ -165,7 +169,12 @@ protected:
|
||||
|
||||
// build a path like /path/to/packages/org.some.catalog/Aircraft/extract_xxxx/MyAircraftDir
|
||||
SGPath extractedPath = m_extractPath;
|
||||
extractedPath.append(m_owner->package()->dirName());
|
||||
if (m_owner->package()->properties()->hasChild("archive-path")) {
|
||||
extractedPath.append(m_owner->package()->properties()->getStringValue("archive-path"));
|
||||
} else {
|
||||
extractedPath.append(m_owner->package()->dirName());
|
||||
}
|
||||
|
||||
|
||||
// rename it to path/to/packages/org.some.catalog/Aircraft/MyAircraftDir
|
||||
bool ok = extractedPath.rename(m_owner->path());
|
||||
@@ -175,6 +184,8 @@ protected:
|
||||
}
|
||||
|
||||
// extract_xxxx directory is now empty, so remove it
|
||||
// (note it might not be empty if the archive contained some other
|
||||
// files, but we delete those in such a case
|
||||
if (m_extractPath.exists()) {
|
||||
simgear::Dir(m_extractPath).remove();
|
||||
}
|
||||
@@ -196,7 +207,22 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void setArchiveTypeFromExtension(const std::string& ext)
|
||||
{
|
||||
if (ext.empty())
|
||||
return;
|
||||
|
||||
if (ext == "zip") {
|
||||
m_archiveType = ZIP;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ext == "tar.gz") || (ext == "tgz")) {
|
||||
m_archiveType = TAR_GZ;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
|
||||
{
|
||||
unz_file_info fileInfo;
|
||||
@@ -262,14 +288,22 @@ private:
|
||||
{
|
||||
const std::string u(url());
|
||||
const size_t ul(u.length());
|
||||
if (u.rfind(".zip") == (ul - 4)) {
|
||||
return extractUnzip();
|
||||
|
||||
if (m_archiveType == AUTO_DETECT) {
|
||||
if (u.rfind(".zip") == (ul - 4)) {
|
||||
m_archiveType = ZIP;
|
||||
} else if (u.rfind(".tar.gz") == (ul - 7)) {
|
||||
m_archiveType = TAR_GZ;
|
||||
}
|
||||
// we will fall through to the error case now
|
||||
}
|
||||
|
||||
if (u.rfind(".tar.gz") == (ul - 7)) {
|
||||
|
||||
if (m_archiveType == ZIP) {
|
||||
return extractUnzip();
|
||||
} else if (m_archiveType == TAR_GZ) {
|
||||
return extractTar();
|
||||
}
|
||||
|
||||
|
||||
SG_LOG(SG_IO, SG_WARN, "unsupported archive format:" << u);
|
||||
return false;
|
||||
}
|
||||
@@ -330,7 +364,14 @@ private:
|
||||
m_owner->installResult(aReason);
|
||||
}
|
||||
|
||||
enum ArchiveType {
|
||||
AUTO_DETECT = 0,
|
||||
ZIP,
|
||||
TAR_GZ
|
||||
};
|
||||
|
||||
InstallRef m_owner;
|
||||
ArchiveType m_archiveType = AUTO_DETECT;
|
||||
string_list m_urls;
|
||||
SG_MD5_CTX m_md5;
|
||||
std::string m_buffer;
|
||||
|
||||
@@ -99,10 +99,8 @@ public:
|
||||
/**
|
||||
* human-readable name - note this is probably not localised,
|
||||
* although this is not ruled out for the future.
|
||||
*
|
||||
* Deprecated - please use nameForVariant
|
||||
*/
|
||||
SG_DEPRECATED(std::string name() const);
|
||||
std::string name() const;
|
||||
|
||||
/**
|
||||
* Human readable name of a variant
|
||||
@@ -112,12 +110,9 @@ public:
|
||||
std::string nameForVariant(const unsigned int vIndex) const;
|
||||
|
||||
/**
|
||||
* syntactic sugar to get the localised description
|
||||
*
|
||||
* Deprecated - please use getLocalisedProp to get the variant-specific
|
||||
* description.
|
||||
* syntactic sugar to get the localised description of the main aircraft
|
||||
*/
|
||||
SG_DEPRECATED(std::string description() const);
|
||||
std::string description() const;
|
||||
|
||||
/**
|
||||
* access the raw property data in the package
|
||||
|
||||
@@ -778,6 +778,11 @@ bool Root::removeCatalogById(const std::string& aId)
|
||||
|
||||
void Root::requestThumbnailData(const std::string& aUrl)
|
||||
{
|
||||
if (aUrl.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "requestThumbnailData: empty URL requested");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = d->thumbnailCache.find(aUrl);
|
||||
if (it == d->thumbnailCache.end()) {
|
||||
bool cachedOnDisk = d->checkPersistentCache(aUrl);
|
||||
|
||||
@@ -177,4 +177,18 @@
|
||||
<file-size-bytes>360</file-size-bytes>
|
||||
<md5>acf9eb89cf396eb42f8823d9cdf17584</md5>
|
||||
</package>
|
||||
|
||||
|
||||
<package>
|
||||
<id>movies</id>
|
||||
<name>movies files for test catalog aircraft</name>
|
||||
<revision>10</revision>
|
||||
<dir>movies</dir>
|
||||
<!-- url has no file extension, instead we set arcive-type -->
|
||||
<url>http://localhost:2000/catalogTest1/movies?wierd=foo;bar=thing</url>
|
||||
<archive-type>zip</archive-type>
|
||||
<archive-path>movies_6789</archive-path>
|
||||
<file-size-bytes>232</file-size-bytes>
|
||||
<md5>e5f89c3f1ed1bdda16174c868f3c7b30</md5>
|
||||
</package>
|
||||
</PropertyList>
|
||||
|
||||
BIN
simgear/package/catalogTest1/movies-data.zip
Normal file
BIN
simgear/package/catalogTest1/movies-data.zip
Normal file
Binary file not shown.
3
simgear/package/catalogTest1/movies_6789/movie-list.json
Normal file
3
simgear/package/catalogTest1/movies_6789/movie-list.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"id": "awesomething"
|
||||
}
|
||||
@@ -69,6 +69,9 @@ void SGEventMgr::init()
|
||||
return;
|
||||
}
|
||||
|
||||
// The event manager dtor and ctor are not called on reset, so reset the flag here.
|
||||
_shutdown = false;
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,14 @@
|
||||
|
||||
#include "exception.hxx"
|
||||
#include "subsystem_mgr.hxx"
|
||||
#include "commands.hxx"
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include "SGSmplstat.hxx"
|
||||
|
||||
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
|
||||
const char SUBSYSTEM_NAME_SEPARATOR = '.';
|
||||
|
||||
using std::string;
|
||||
using State = SGSubsystem::State;
|
||||
@@ -136,6 +139,26 @@ void SGSubsystem::set_name(const std::string &n)
|
||||
_name = n;
|
||||
}
|
||||
|
||||
std::string SGSubsystem::typeName() const
|
||||
{
|
||||
auto pos = _name.find(SUBSYSTEM_NAME_SEPARATOR);
|
||||
if (pos == std::string::npos) {
|
||||
return _name;
|
||||
}
|
||||
|
||||
return _name.substr(0, pos);
|
||||
}
|
||||
|
||||
std::string SGSubsystem::instanceName() const
|
||||
{
|
||||
auto pos = _name.find(SUBSYSTEM_NAME_SEPARATOR);
|
||||
if (pos == std::string::npos) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return _name.substr(pos+1);
|
||||
}
|
||||
|
||||
void SGSubsystem::set_group(SGSubsystemGroup* group)
|
||||
{
|
||||
_group = group;
|
||||
@@ -156,6 +179,7 @@ SGSubsystemMgr* SGSubsystem::get_manager() const
|
||||
std::string SGSubsystem::nameForState(State s)
|
||||
{
|
||||
switch (s) {
|
||||
case State::INVALID: return "invalid";
|
||||
case State::INIT: return "init";
|
||||
case State::REINIT: return "reinit";
|
||||
case State::POSTINIT: return "post-init";
|
||||
@@ -215,11 +239,13 @@ SGSubsystemGroup::~SGSubsystemGroup ()
|
||||
void
|
||||
SGSubsystemGroup::init ()
|
||||
{
|
||||
assert(_state == State::BIND);
|
||||
forEach([this](SGSubsystem* s){
|
||||
this->notifyWillChange(s, State::INIT);
|
||||
s->init();
|
||||
this->notifyDidChange(s, State::INIT);
|
||||
});
|
||||
_state = State::INIT;
|
||||
}
|
||||
|
||||
SGSubsystem::InitStatus
|
||||
@@ -232,11 +258,13 @@ SGSubsystemGroup::incrementalInit()
|
||||
|
||||
// termination test
|
||||
if (_initPosition >= static_cast<int>(_members.size())) {
|
||||
_state = State::INIT;
|
||||
return INIT_DONE;
|
||||
}
|
||||
|
||||
if (_initPosition < 0) {
|
||||
// first call
|
||||
assert(_state == State::BIND);
|
||||
_initPosition = 0;
|
||||
notifyWillChange(_members.front()->subsystem, State::INIT);
|
||||
}
|
||||
@@ -278,11 +306,13 @@ void SGSubsystemGroup::reverseForEach(std::function<void(SGSubsystem*)> f)
|
||||
void
|
||||
SGSubsystemGroup::postinit ()
|
||||
{
|
||||
assert(_state == State::INIT);
|
||||
forEach([this](SGSubsystem* s){
|
||||
this->notifyWillChange(s, State::POSTINIT);
|
||||
s->postinit();
|
||||
this->notifyDidChange(s, State::POSTINIT);
|
||||
});
|
||||
_state = State::POSTINIT;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -303,6 +333,7 @@ SGSubsystemGroup::shutdown ()
|
||||
s->shutdown();
|
||||
this->notifyDidChange(s, State::SHUTDOWN);
|
||||
});
|
||||
_state = State::SHUTDOWN;
|
||||
_initPosition = -1;
|
||||
}
|
||||
|
||||
@@ -314,6 +345,7 @@ SGSubsystemGroup::bind ()
|
||||
s->bind();
|
||||
this->notifyDidChange(s, State::BIND);
|
||||
});
|
||||
_state = State::BIND;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -324,6 +356,7 @@ SGSubsystemGroup::unbind ()
|
||||
s->unbind();
|
||||
this->notifyDidChange(s, State::UNBIND);
|
||||
});
|
||||
_state = State::UNBIND;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -419,6 +452,16 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
|
||||
member->min_step_sec = min_step_sec;
|
||||
subsystem->set_group(this);
|
||||
notifyDidChange(subsystem, State::ADD);
|
||||
|
||||
if (_state != State::INVALID) {
|
||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when adding after init");
|
||||
// transition to the correct state
|
||||
// bind
|
||||
|
||||
// init
|
||||
|
||||
// post-init
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -456,6 +499,16 @@ SGSubsystemGroup::remove_subsystem(const string &name)
|
||||
if (it != _members.end()) {
|
||||
// found it, great
|
||||
const auto sub = (*it)->subsystem;
|
||||
|
||||
if (_state != State::INVALID) {
|
||||
// transition out correctly
|
||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when removing before shutdown");
|
||||
|
||||
// shutdown
|
||||
|
||||
// unbind
|
||||
}
|
||||
|
||||
notifyWillChange(sub, State::REMOVE);
|
||||
delete *it;
|
||||
_members.erase(it);
|
||||
@@ -562,7 +615,6 @@ void SGSubsystemGroup::set_manager(SGSubsystemMgr *manager)
|
||||
// Implementation of SGSubsystemGroup::Member
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SGSubsystemGroup::Member::Member ()
|
||||
: name(""),
|
||||
subsystem(0),
|
||||
@@ -614,10 +666,29 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
|
||||
// Implementation of SGSubsystemMgr.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
SGSubsystemMgr* global_defaultSubsystemManager = nullptr;
|
||||
|
||||
void registerSubsystemCommands();
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
SGSubsystemMgr::SGSubsystemMgr () :
|
||||
_groups(MAX_GROUPS)
|
||||
{
|
||||
if (global_defaultSubsystemManager == nullptr) {
|
||||
// register ourselves as the default
|
||||
global_defaultSubsystemManager = this;
|
||||
}
|
||||
|
||||
// disabled until subsystemfactory is removed from FlightGear
|
||||
#if 0
|
||||
auto commandManager = SGCommandMgr::instance();
|
||||
if (commandManager && !commandManager->getCommand("add-subsystem")) {
|
||||
registerSubsystemCommands();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < MAX_GROUPS; i++) {
|
||||
auto g = new SGSubsystemGroup;
|
||||
g->set_manager(this);
|
||||
@@ -628,7 +699,24 @@ SGSubsystemMgr::SGSubsystemMgr () :
|
||||
SGSubsystemMgr::~SGSubsystemMgr ()
|
||||
{
|
||||
_destructorActive = true;
|
||||
_groups.clear();
|
||||
_groups.clear();
|
||||
|
||||
// if we were the global one, null out the pointer so it doesn't dangle.
|
||||
// don't do anything clever to track multiple subsystems for now; if we
|
||||
// a smarter scheme, let's wait until it's clearer what that might be.
|
||||
if (global_defaultSubsystemManager == this) {
|
||||
global_defaultSubsystemManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SGSubsystemMgr* SGSubsystemMgr::getManager(const std::string& id)
|
||||
{
|
||||
if (id.empty()) {
|
||||
return global_defaultSubsystemManager;
|
||||
}
|
||||
|
||||
// remove me when if/when we supprot multiple subsystem instances
|
||||
throw sg_exception("multiple subsystem instances not supported yet");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -784,7 +872,7 @@ SGSubsystemMgr::get_subsystem (const string &name) const
|
||||
SGSubsystem*
|
||||
SGSubsystemMgr::get_subsystem(const std::string &name, const std::string& instanceName) const
|
||||
{
|
||||
return get_subsystem(name + "-" + instanceName);
|
||||
return get_subsystem(name + SUBSYSTEM_NAME_SEPARATOR + instanceName);
|
||||
}
|
||||
|
||||
|
||||
@@ -825,10 +913,15 @@ namespace {
|
||||
|
||||
using SybsystemRegistrationVec = std::vector<RegisteredSubsystemData>;
|
||||
|
||||
SybsystemRegistrationVec global_registrations;
|
||||
|
||||
SybsystemRegistrationVec &getGlobalRegistrations()
|
||||
{
|
||||
static SybsystemRegistrationVec global_registrations;
|
||||
return global_registrations;
|
||||
}
|
||||
|
||||
SybsystemRegistrationVec::const_iterator findRegistration(const std::string& name)
|
||||
{
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
auto it = std::find_if(global_registrations.begin(),
|
||||
global_registrations.end(),
|
||||
[name](const RegisteredSubsystemData& d)
|
||||
@@ -844,6 +937,7 @@ void SGSubsystemMgr::registerSubsystem(const std::string& name,
|
||||
double updateInterval,
|
||||
std::initializer_list<Dependency> deps)
|
||||
{
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (findRegistration(name) != global_registrations.end()) {
|
||||
throw sg_exception("duplicate subsystem registration for: " + name);
|
||||
}
|
||||
@@ -857,6 +951,7 @@ void SGSubsystemMgr::registerSubsystem(const std::string& name,
|
||||
auto SGSubsystemMgr::defaultGroupFor(const char* name) -> GroupType
|
||||
{
|
||||
auto it = findRegistration(name);
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (it == global_registrations.end()) {
|
||||
throw sg_exception("unknown subsystem registration for: " + std::string(name));
|
||||
}
|
||||
@@ -867,6 +962,7 @@ auto SGSubsystemMgr::defaultGroupFor(const char* name) -> GroupType
|
||||
double SGSubsystemMgr::defaultUpdateIntervalFor(const char* name)
|
||||
{
|
||||
auto it = findRegistration(name);
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (it == global_registrations.end()) {
|
||||
throw sg_exception("unknown subsystem registration for: " + std::string(name));
|
||||
}
|
||||
@@ -878,6 +974,7 @@ const SGSubsystemMgr::DependencyVec&
|
||||
SGSubsystemMgr::dependsFor(const char* name)
|
||||
{
|
||||
auto it = findRegistration(name);
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (it == global_registrations.end()) {
|
||||
throw sg_exception("unknown subsystem registration for: " + std::string(name));
|
||||
}
|
||||
@@ -889,6 +986,7 @@ SGSubsystemRef
|
||||
SGSubsystemMgr::create(const std::string& name)
|
||||
{
|
||||
auto it = findRegistration(name);
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (it == global_registrations.end()) {
|
||||
return {}; // or should this throw with a 'not registered'?
|
||||
}
|
||||
@@ -910,6 +1008,7 @@ SGSubsystemRef
|
||||
SGSubsystemMgr::createInstance(const std::string& name, const std::string& instanceName)
|
||||
{
|
||||
auto it = findRegistration(name);
|
||||
auto &global_registrations = getGlobalRegistrations();
|
||||
if (it == global_registrations.end()) {
|
||||
return {}; // or should this throw with a 'not registered'?
|
||||
}
|
||||
@@ -923,7 +1022,7 @@ SGSubsystemMgr::createInstance(const std::string& name, const std::string& insta
|
||||
throw sg_exception("SGSubsystemMgr::create: functor failed to create an instsance of " + name);
|
||||
}
|
||||
|
||||
const auto combinedName = name + "-" + instanceName;
|
||||
const auto combinedName = name + SUBSYSTEM_NAME_SEPARATOR + instanceName;
|
||||
ref->set_name(combinedName);
|
||||
return ref;
|
||||
}
|
||||
@@ -966,5 +1065,218 @@ void SGSubsystemMgr::notifyDelegatesDidChange(SGSubsystem* sub, State state)
|
||||
{ d->didChange(sub, state); });
|
||||
}
|
||||
|
||||
void SGSubsystemMgr::set_root_node(SGPropertyNode_ptr node)
|
||||
{
|
||||
_rootNode = node;
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr
|
||||
SGSubsystemMgr::root_node() const
|
||||
{
|
||||
return _rootNode;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
do_check_subsystem_running(const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
return (manager->get_subsystem(arg->getStringValue("name")) != nullptr);
|
||||
}
|
||||
|
||||
|
||||
SGSubsystemMgr::GroupType mapGroupNameToType(const std::string& s)
|
||||
{
|
||||
if (s == "init") return SGSubsystemMgr::INIT;
|
||||
if (s == "general") return SGSubsystemMgr::GENERAL;
|
||||
if (s == "fdm") return SGSubsystemMgr::FDM;
|
||||
if (s == "post-fdm") return SGSubsystemMgr::POST_FDM;
|
||||
if (s == "display") return SGSubsystemMgr::DISPLAY;
|
||||
if (s == "sound") return SGSubsystemMgr::SOUND;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "unrecognized subsystem group:" << s);
|
||||
return SGSubsystemMgr::GENERAL;
|
||||
}
|
||||
|
||||
bool
|
||||
do_add_subsystem (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
std::string subsystem = arg->getStringValue("subsystem");
|
||||
|
||||
// allow override of the name but defaultt o the subsystem name
|
||||
std::string name = arg->getStringValue("name");
|
||||
std::string instanceName = arg->getStringValue("instance");
|
||||
|
||||
if (name.empty()) {
|
||||
// default name to subsystem name, but before we parse any instance name
|
||||
name = subsystem;
|
||||
}
|
||||
|
||||
auto separatorPos = subsystem.find(SUBSYSTEM_NAME_SEPARATOR);
|
||||
if (separatorPos != std::string::npos) {
|
||||
if (!instanceName.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "Specified a composite subsystem name and an instance name, please do one or the other: "
|
||||
<< instanceName << " and " << subsystem);
|
||||
return false;
|
||||
}
|
||||
|
||||
instanceName = subsystem.substr(separatorPos + 1);
|
||||
subsystem = subsystem.substr(0, separatorPos);
|
||||
}
|
||||
|
||||
SGSubsystem* sub = nullptr;
|
||||
if (!instanceName.empty()) {
|
||||
sub = manager->createInstance(subsystem, instanceName);
|
||||
} else {
|
||||
sub = manager->create(subsystem);
|
||||
}
|
||||
|
||||
if (!sub)
|
||||
return false;
|
||||
|
||||
std::string groupArg = arg->getStringValue("group");
|
||||
SGSubsystemMgr::GroupType group = SGSubsystemMgr::GENERAL;
|
||||
if (!groupArg.empty()) {
|
||||
group = mapGroupNameToType(groupArg);
|
||||
}
|
||||
|
||||
double minTime = arg->getDoubleValue("min-time-sec", 0.0);
|
||||
|
||||
const auto combinedName = subsystem + SUBSYSTEM_NAME_SEPARATOR + instanceName;
|
||||
manager->add(combinedName.c_str(),
|
||||
sub,
|
||||
group,
|
||||
minTime);
|
||||
|
||||
if (arg->getBoolValue("do-bind-init", false)) {
|
||||
sub->bind();
|
||||
sub->init();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_remove_subsystem(const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
std::string name = arg->getStringValue("subsystem");
|
||||
|
||||
SGSubsystem* instance = manager->get_subsystem(name);
|
||||
if (!instance) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// is it safe to always call these? let's assume so!
|
||||
instance->shutdown();
|
||||
instance->unbind();
|
||||
|
||||
// unplug from the manager (this also deletes the instance!)
|
||||
manager->remove(name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in command: reinitialize one or more subsystems.
|
||||
*
|
||||
* subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if
|
||||
* none is specified, reinitialize all of them.
|
||||
*/
|
||||
bool do_reinit (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
bool result = true;
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
|
||||
auto subsystems = arg->getChildren("subsystem");
|
||||
if (subsystems.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "do_reinit: reinit-ing subsystem manager");
|
||||
manager->reinit();
|
||||
} else {
|
||||
for (auto sub : subsystems) {
|
||||
const char * name = sub->getStringValue();
|
||||
SGSubsystem* subsystem = manager->get_subsystem(name);
|
||||
if (subsystem == nullptr) {
|
||||
result = false;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found" );
|
||||
} else {
|
||||
subsystem->reinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in command: suspend one or more subsystems.
|
||||
*
|
||||
* subsystem[*] - the name(s) of the subsystem(s) to suspend.
|
||||
*/
|
||||
bool do_suspend (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
bool result = true;
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
|
||||
for (auto subNode : arg->getChildren("subsystem")) {
|
||||
const char * name = subNode->getStringValue();
|
||||
SGSubsystem * subsystem = manager->get_subsystem(name);
|
||||
if (subsystem == nullptr) {
|
||||
result = false;
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
|
||||
} else {
|
||||
subsystem->suspend();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in command: suspend one or more subsystems.
|
||||
*
|
||||
* subsystem[*] - the name(s) of the subsystem(s) to suspend.
|
||||
*/
|
||||
bool do_resume (const SGPropertyNode * arg, SGPropertyNode * root)
|
||||
{
|
||||
bool result = true;
|
||||
auto manager = SGSubsystemMgr::getManager({});
|
||||
|
||||
for (auto subNode : arg->getChildren("subsystem")) {
|
||||
const char * name = subNode->getStringValue();
|
||||
SGSubsystem * subsystem = manager->get_subsystem(name);
|
||||
if (subsystem == nullptr) {
|
||||
result = false;
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
|
||||
} else {
|
||||
subsystem->resume();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct CommandDef {
|
||||
const char * name;
|
||||
SGCommandMgr::command_t command;
|
||||
};
|
||||
|
||||
CommandDef built_ins[] = {
|
||||
{ "add-subsystem", do_add_subsystem },
|
||||
{ "remove-subsystem", do_remove_subsystem },
|
||||
{ "subsystem-running", do_check_subsystem_running },
|
||||
{ "reinit", do_reinit },
|
||||
{ "suspend", do_suspend },
|
||||
{ "resume", do_resume },
|
||||
};
|
||||
|
||||
void registerSubsystemCommands()
|
||||
{
|
||||
auto commandManager = SGCommandMgr::instance();
|
||||
for (auto b : built_ins) {
|
||||
commandManager->addCommand(b.name, b.command);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace implementing subsystem commands
|
||||
|
||||
// end of subsystem_mgr.cxx
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/props/propsfwd.hxx>
|
||||
|
||||
class TimingInfo
|
||||
{
|
||||
@@ -275,9 +276,23 @@ public:
|
||||
*/
|
||||
void stamp(const std::string& name);
|
||||
|
||||
/**
|
||||
* composite name for this subsystem (type name & optional instance name)
|
||||
*/
|
||||
std::string name() const
|
||||
{ return _name; }
|
||||
|
||||
/**
|
||||
* @brief the type (class)-specific part of the subsystem name.
|
||||
*/
|
||||
std::string typeName() const;
|
||||
|
||||
/**
|
||||
* @brief the instance part of the subsystem name. Empty if this
|
||||
* subsystem is not instanced
|
||||
*/
|
||||
std::string instanceName() const;
|
||||
|
||||
virtual bool is_group() const
|
||||
{ return false; }
|
||||
|
||||
@@ -287,7 +302,8 @@ public:
|
||||
SGSubsystemGroup* get_group() const;
|
||||
|
||||
enum class State {
|
||||
ADD,
|
||||
INVALID = -1,
|
||||
ADD = 0,
|
||||
BIND,
|
||||
INIT,
|
||||
POSTINIT,
|
||||
@@ -311,7 +327,11 @@ protected:
|
||||
|
||||
void set_group(SGSubsystemGroup* group);
|
||||
|
||||
std::string _name;
|
||||
/// composite name for the subsystem (type name and instance name if this
|
||||
/// is an instanced subsystem. (Since this member was originally defined as
|
||||
/// protected, not private, we can't rename it easily)
|
||||
std::string _name;
|
||||
|
||||
bool _suspended = false;
|
||||
|
||||
eventTimeVec timingInfo;
|
||||
@@ -400,6 +420,9 @@ private:
|
||||
using MemberVec = std::vector<Member*>;
|
||||
MemberVec _members;
|
||||
|
||||
// track the state of this group, so we can transition added/removed
|
||||
// members correctly
|
||||
SGSubsystem::State _state = SGSubsystem::State::INVALID;
|
||||
double _fixedUpdateTime;
|
||||
double _updateTimeRemainder;
|
||||
|
||||
@@ -433,6 +456,8 @@ typedef SGSharedPtr<SGSubsystemGroup> SGSubsystemGroupRef;
|
||||
class SGSubsystemMgr : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
SGSubsystemMgr(const SGSubsystemMgr&) = delete;
|
||||
SGSubsystemMgr& operator=(const SGSubsystemMgr&) = delete;
|
||||
|
||||
/**
|
||||
* Types of subsystem groups.
|
||||
@@ -483,6 +508,18 @@ public:
|
||||
void reportTiming();
|
||||
void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
|
||||
|
||||
/**
|
||||
* @brief set the root property node for this subsystem manager
|
||||
* subsystems can retrieve this value during init/bind (or at any time)
|
||||
* to base their own properties trees off of.
|
||||
*/
|
||||
void set_root_node(SGPropertyNode_ptr node);
|
||||
|
||||
/**
|
||||
* @brief retrieve the root property node for this subsystem manager
|
||||
*/
|
||||
SGPropertyNode_ptr root_node() const;
|
||||
|
||||
template<class T>
|
||||
T* get_subsystem() const
|
||||
{
|
||||
@@ -621,6 +658,13 @@ public:
|
||||
|
||||
void addDelegate(Delegate * d);
|
||||
void removeDelegate(Delegate * d);
|
||||
|
||||
/**
|
||||
* @brief return a particular subsystem manager by name. Passing an
|
||||
* empty string retrived the default/global subsystem manager, assuming it
|
||||
* has been created.
|
||||
*/
|
||||
static SGSubsystemMgr* getManager(const std::string& id);
|
||||
private:
|
||||
friend class SGSubsystem;
|
||||
friend class SGSubsystemGroup;
|
||||
@@ -631,6 +675,7 @@ private:
|
||||
std::vector<SGSubsystemGroupRef> _groups;
|
||||
unsigned int _initPosition = 0;
|
||||
bool _destructorActive = false;
|
||||
SGPropertyNode_ptr _rootNode;
|
||||
|
||||
// non-owning reference, this is to accelerate lookup
|
||||
// by name which otherwise needs a full walk of the entire tree
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
using std::string;
|
||||
using std::cout;
|
||||
@@ -26,6 +27,13 @@ public:
|
||||
wasInited = true;
|
||||
}
|
||||
|
||||
void bind() override
|
||||
{
|
||||
auto node = get_manager()->root_node();
|
||||
if (node)
|
||||
node->setIntValue("mysub/foo", 42);
|
||||
}
|
||||
|
||||
void update(double dt) override
|
||||
{
|
||||
|
||||
@@ -44,6 +52,13 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void bind() override
|
||||
{
|
||||
auto node = get_manager()->root_node();
|
||||
if (node)
|
||||
node->setIntValue("anothersub/bar", 172);
|
||||
}
|
||||
|
||||
void update(double dt) override
|
||||
{
|
||||
lastUpdateTime = dt;
|
||||
@@ -155,7 +170,9 @@ void testRegistrationAndCreation()
|
||||
SG_VERIFY(anotherSub);
|
||||
SG_CHECK_EQUAL(anotherSub->name(), AnotherSub::subsystemName());
|
||||
SG_CHECK_EQUAL(anotherSub->name(), std::string("anothersub"));
|
||||
|
||||
SG_CHECK_EQUAL(anotherSub->typeName(), std::string("anothersub"));
|
||||
SG_CHECK_EQUAL(anotherSub->instanceName(), std::string());
|
||||
|
||||
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
|
||||
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
|
||||
|
||||
@@ -221,18 +238,21 @@ void testSubGrouping()
|
||||
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
|
||||
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
|
||||
|
||||
SG_CHECK_EQUAL(radio1->name(), std::string("fake-radio-nav1"));
|
||||
SG_CHECK_EQUAL(radio2->name(), std::string("fake-radio-nav2"));
|
||||
|
||||
SG_CHECK_EQUAL(radio1->name(), std::string("fake-radio.nav1"));
|
||||
SG_CHECK_EQUAL(radio2->name(), std::string("fake-radio.nav2"));
|
||||
SG_CHECK_EQUAL(radio1->typeName(), std::string("fake-radio"));
|
||||
SG_CHECK_EQUAL(radio2->instanceName(), std::string("nav2"));
|
||||
|
||||
instruments->set_subsystem(radio1);
|
||||
instruments->set_subsystem(radio2);
|
||||
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-did-add"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-add"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-add"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-add"));
|
||||
|
||||
// lookup of the group should also work
|
||||
SG_CHECK_EQUAL(manager->get_subsystem<InstrumentGroup>(), instruments);
|
||||
|
||||
manager->bind();
|
||||
manager->init();
|
||||
|
||||
SG_VERIFY(instruments->wasInited);
|
||||
@@ -241,24 +261,27 @@ void testSubGrouping()
|
||||
|
||||
SG_VERIFY(d->hasEvent("instruments-will-init"));
|
||||
SG_VERIFY(d->hasEvent("instruments-did-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav2-did-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
|
||||
|
||||
manager->update(0.5);
|
||||
SG_CHECK_EQUAL_EP(0.5, instruments->lastUpdateTime);
|
||||
SG_CHECK_EQUAL_EP(0.5, radio1->lastUpdateTime);
|
||||
SG_CHECK_EQUAL_EP(0.5, radio2->lastUpdateTime);
|
||||
|
||||
SG_CHECK_EQUAL(radio1, instruments->get_subsystem("fake-radio-nav1"));
|
||||
SG_CHECK_EQUAL(radio2, instruments->get_subsystem("fake-radio-nav2"));
|
||||
SG_CHECK_EQUAL(0, instruments->get_subsystem("fake-radio"));
|
||||
|
||||
|
||||
SG_CHECK_EQUAL(radio1, instruments->get_subsystem("fake-radio.nav1"));
|
||||
SG_CHECK_EQUAL(radio2, instruments->get_subsystem("fake-radio.nav2"));
|
||||
|
||||
// type-safe lookup of instanced
|
||||
SG_CHECK_EQUAL(radio1, manager->get_subsystem<FakeRadioSub>("nav1"));
|
||||
SG_CHECK_EQUAL(radio2, manager->get_subsystem<FakeRadioSub>("nav2"));
|
||||
|
||||
bool ok = manager->remove("fake-radio-nav2");
|
||||
bool ok = manager->remove("fake-radio.nav2");
|
||||
SG_VERIFY(ok);
|
||||
SG_VERIFY(instruments->get_subsystem("fake-radio-nav2") == nullptr);
|
||||
SG_VERIFY(instruments->get_subsystem("fake-radio.nav2") == nullptr);
|
||||
|
||||
manager->update(1.0);
|
||||
SG_CHECK_EQUAL_EP(1.0, instruments->lastUpdateTime);
|
||||
@@ -270,7 +293,7 @@ void testSubGrouping()
|
||||
manager->unbind();
|
||||
SG_VERIFY(d->hasEvent("instruments-will-unbind"));
|
||||
SG_VERIFY(d->hasEvent("instruments-did-unbind"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-unbind"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-unbind"));
|
||||
|
||||
}
|
||||
|
||||
@@ -291,16 +314,13 @@ void testIncrementalInit()
|
||||
instruments->set_subsystem(radio1);
|
||||
instruments->set_subsystem(radio2);
|
||||
|
||||
manager->bind();
|
||||
for ( ; ; ) {
|
||||
auto status = manager->incrementalInit();
|
||||
if (status == SGSubsystemMgr::INIT_DONE)
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto ev : d->events) {
|
||||
std::cerr << "ev:" << ev.nameForEvent() << std::endl;
|
||||
}
|
||||
|
||||
SG_VERIFY(mySub->wasInited);
|
||||
|
||||
SG_VERIFY(d->hasEvent("mysub-will-init"));
|
||||
@@ -313,11 +333,11 @@ void testIncrementalInit()
|
||||
// SG_VERIFY(d->hasEvent("instruments-did-init"));
|
||||
|
||||
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav1-did-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-init"));
|
||||
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav2-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio-nav2-did-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-init"));
|
||||
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
|
||||
|
||||
|
||||
|
||||
@@ -338,6 +358,7 @@ void testSuspendResume()
|
||||
instruments->set_subsystem(radio1);
|
||||
instruments->set_subsystem(radio2);
|
||||
|
||||
manager->bind();
|
||||
manager->init();
|
||||
manager->update(1.0);
|
||||
|
||||
@@ -350,7 +371,7 @@ void testSuspendResume()
|
||||
|
||||
SG_VERIFY(d->hasEvent("anothersub-will-suspend"));
|
||||
SG_VERIFY(d->hasEvent("anothersub-did-suspend"));
|
||||
SG_VERIFY(!d->hasEvent("radio1-will-suspend"));
|
||||
SG_VERIFY(!d->hasEvent("fake-radio.nav1-will-suspend"));
|
||||
|
||||
manager->update(0.5);
|
||||
|
||||
@@ -392,6 +413,32 @@ void testSuspendResume()
|
||||
SG_CHECK_EQUAL_EP(5.0, radio2->lastUpdateTime);
|
||||
}
|
||||
|
||||
void testPropertyRoot()
|
||||
{
|
||||
SGSharedPtr<SGSubsystemMgr> manager = new SGSubsystemMgr;
|
||||
SGPropertyNode_ptr props(new SGPropertyNode);
|
||||
manager->set_root_node(props);
|
||||
|
||||
auto d = new RecorderDelegate;
|
||||
manager->addDelegate(d);
|
||||
|
||||
manager->add<MySub1>();
|
||||
auto anotherSub = manager->add<AnotherSub>();
|
||||
auto instruments = manager->add<InstrumentGroup>();
|
||||
|
||||
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
|
||||
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
|
||||
|
||||
instruments->set_subsystem(radio1);
|
||||
instruments->set_subsystem(radio2);
|
||||
|
||||
manager->bind();
|
||||
manager->init();
|
||||
|
||||
SG_CHECK_EQUAL(props->getIntValue("mysub/foo"), 42);
|
||||
SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -402,6 +449,7 @@ int main(int argc, char* argv[])
|
||||
testSubGrouping();
|
||||
testIncrementalInit();
|
||||
testSuspendResume();
|
||||
testPropertyRoot();
|
||||
|
||||
cout << __FILE__ << ": All tests passed" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -72,10 +72,14 @@ void SGTime::init( const SGGeod& location, const SGPath& root, time_t init_time
|
||||
cur_time = time(NULL);
|
||||
}
|
||||
|
||||
char* gmt = asctime(gmtime(&cur_time));
|
||||
char* local = asctime(localtime(&cur_time));
|
||||
gmt[strlen(gmt) - 1] = '\0';
|
||||
local[strlen(local) - 1] = '\0';
|
||||
SG_LOG( SG_EVENT, SG_DEBUG,
|
||||
"Current greenwich mean time = " << asctime(gmtime(&cur_time)));
|
||||
"Current greenwich mean time = " << gmt);
|
||||
SG_LOG( SG_EVENT, SG_DEBUG,
|
||||
"Current local time = " << asctime(localtime(&cur_time)));
|
||||
"Current local time = " << local);
|
||||
|
||||
if ( !root.isNull()) {
|
||||
if (!static_tzContainer.get()) {
|
||||
|
||||
Reference in New Issue
Block a user