mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-08-30 04:15:10 +00:00
connection between 2 systems and bug fixes (#14)
This commit is contained in:
@@ -24,6 +24,9 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26495)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
namespace sdv
|
||||
@@ -1738,6 +1741,8 @@ namespace sdv
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // !defined SDV_ANY_INL
|
||||
@@ -65,6 +65,7 @@ namespace sdv
|
||||
bool Startup(const std::string& rssConfig)
|
||||
{
|
||||
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
|
||||
|
||||
if (!pAppControl) return false;
|
||||
if (m_eState != EAppOperationState::not_started) return false;
|
||||
try
|
||||
@@ -78,45 +79,6 @@ namespace sdv
|
||||
{
|
||||
m_eContext = pAppContext->GetContextType();
|
||||
m_uiInstanceID = pAppContext->GetInstanceID();
|
||||
m_uiRetries = pAppContext->GetRetries();
|
||||
}
|
||||
|
||||
// Automatically connect to the server
|
||||
if (m_eContext == EAppContext::external)
|
||||
{
|
||||
// Try to connect
|
||||
m_ptrServerRepository = sdv::com::ConnectToLocalServerRepository(m_uiInstanceID, m_uiRetries);
|
||||
if (!m_ptrServerRepository)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Failed to connect to the server repository." << std::endl;
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = m_ptrServerRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Failed to access the server repository." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Link the local repository to the server repository.
|
||||
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
|
||||
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
|
||||
if (!pLinkCoreRepo)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Cannot link local and server repositories." << std::endl;
|
||||
return false;
|
||||
}
|
||||
pLinkCoreRepo->LinkCoreRepository(m_ptrServerRepository);
|
||||
}
|
||||
|
||||
return bRet;
|
||||
@@ -154,23 +116,6 @@ namespace sdv
|
||||
*/
|
||||
void Shutdown()
|
||||
{
|
||||
// Disconnect local and remote repositories.
|
||||
if (m_ptrServerRepository)
|
||||
{
|
||||
// Link the local repository to the server repository.
|
||||
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
|
||||
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
|
||||
if (!pLinkCoreRepo)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Cannot unlink local and server repositories." << std::endl;
|
||||
} else
|
||||
pLinkCoreRepo->UnlinkCoreRepository();
|
||||
}
|
||||
|
||||
// Disconnect from the server (if connected at all).
|
||||
m_ptrServerRepository.Clear();
|
||||
|
||||
// Shutdown.
|
||||
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
|
||||
try
|
||||
@@ -194,28 +139,86 @@ namespace sdv
|
||||
return m_eState == EAppOperationState::running;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the absolute path to the currently run executable
|
||||
* @return Absolute std::filesystem::path to the currently run executable
|
||||
*/
|
||||
static std::filesystem::path GetAppDirectory()
|
||||
{
|
||||
static std::filesystem::path pathExeDir;
|
||||
if (!pathExeDir.empty())
|
||||
return pathExeDir;
|
||||
#ifdef _WIN32
|
||||
// Windows specific
|
||||
std::wstring ssPath(32768, '\0');
|
||||
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
|
||||
#elif defined __linux__
|
||||
// Linux specific
|
||||
std::string ssPath(PATH_MAX + 1, '\0');
|
||||
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
|
||||
if (nCount < 0 || nCount >= PATH_MAX)
|
||||
return pathExeDir; // some error
|
||||
ssPath.at(nCount) = '\0';
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
pathExeDir = std::filesystem::path{ssPath.c_str()}.parent_path() / ""; // To finish the folder path with (back)slash
|
||||
return pathExeDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the filename of the currently run executable
|
||||
* @return The filename to the currently run executable
|
||||
*/
|
||||
static std::filesystem::path GetAppFilename()
|
||||
{
|
||||
static std::filesystem::path pathExeFilename;
|
||||
if (!pathExeFilename.empty())
|
||||
return pathExeFilename;
|
||||
#ifdef _WIN32
|
||||
// Windows specific
|
||||
std::wstring ssPath(32768, '\0');
|
||||
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
|
||||
#elif defined __linux__
|
||||
// Linux specific
|
||||
std::string ssPath(PATH_MAX + 1, '\0');
|
||||
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
|
||||
if (nCount < 0 || nCount >= PATH_MAX)
|
||||
return pathExeFilename; // some error
|
||||
ssPath.at(nCount) = '\0';
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
pathExeFilename = std::filesystem::path{ssPath.c_str()}.filename();
|
||||
return pathExeFilename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the SDV_FRAMEWORK_RUNTIME environment variable for this application.
|
||||
* @return Path directing to the SDV V-API Framework directory if available or an empty path if not.
|
||||
* @remarks If the environment variable is empty or if the variable contains a relative path, the path will be enhanced
|
||||
* with the application path.
|
||||
* @return Absolute path directing to the SDV Vehicle API Framework directory.
|
||||
*/
|
||||
static std::filesystem::path GetFrameworkRuntimeDirectory()
|
||||
{
|
||||
std::filesystem::path path;
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szFrameworkDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
|
||||
if (!szFrameworkDir) return {};
|
||||
return szFrameworkDir;
|
||||
if (szFrameworkDir) path = szFrameworkDir;
|
||||
#elif defined __unix__
|
||||
const char* szFrameworkDir = getenv("SDV_FRAMEWORK_RUNTIME");
|
||||
if (!szFrameworkDir) return {};
|
||||
return szFrameworkDir;
|
||||
if (szFrameworkDir) path = szFrameworkDir;
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
if (path.empty() || path.is_relative()) path = GetAppDirectory() / path;
|
||||
return path.lexically_normal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set or overwrite the SDV_FRAMEWORK_RUNTIME environment variable for this application.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV V-API Framework directory.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API Framework directory.
|
||||
*/
|
||||
static void SetFrameworkRuntimeDirectory(const std::filesystem::path& rpathDir)
|
||||
{
|
||||
@@ -232,26 +235,30 @@ namespace sdv
|
||||
|
||||
/**
|
||||
* @brief Get the SDV_COMPONENT_INSTALL environment variable for this application.
|
||||
* @return Path directing to the SDV V-API component installation directory if available or an empty path if not.
|
||||
* @remarks If the environment variable is empty, the runtime directory is taken. If the variable contains a relative
|
||||
* path, the path will be enhanced with the application path.
|
||||
* @return Absolute path directing to the SDV Vehicle API component installation directory.
|
||||
*/
|
||||
static std::filesystem::path GetComponentInstallDirectory()
|
||||
{
|
||||
std::filesystem::path path;
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szComponentDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
|
||||
if (!szComponentDir) return {};
|
||||
return szComponentDir;
|
||||
if (szComponentDir) path = szComponentDir;
|
||||
#elif defined __unix__
|
||||
const char* szComponentDir = getenv("SDV_COMPONENT_INSTALL");
|
||||
if (!szComponentDir) return {};
|
||||
return szComponentDir;
|
||||
if (szComponentDir) path = szComponentDir;
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
if (path.empty()) return GetFrameworkRuntimeDirectory();
|
||||
if (path.is_relative()) path = GetAppDirectory() / path;
|
||||
return path.lexically_normal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set or overwrite the SDV_COMPONENT_INSTALL environment variable for this application.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV V-API component installation directory.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API component installation directory.
|
||||
*/
|
||||
static void SetComponentInstallDirectory(const std::filesystem::path& rpathDir)
|
||||
{
|
||||
@@ -527,8 +534,7 @@ namespace sdv
|
||||
EAppOperationState m_eState = EAppOperationState::not_started; ///< Application state.
|
||||
EAppContext m_eContext = EAppContext::no_context; ///< Application context.
|
||||
uint32_t m_uiInstanceID = 0u; ///< Core instance.
|
||||
uint32_t m_uiRetries = 0u; ///< Number of retries to establish a connection.
|
||||
sdv::TObjectPtr m_ptrServerRepository; ///< Server repository interface.
|
||||
uint32_t m_uiConnectRetries = 0u; ///< Number of retries to establish a connection.
|
||||
};
|
||||
} // namespace app
|
||||
} // namespace sdv
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "../interfaces/core_types.h"
|
||||
#include "../interfaces/core.h"
|
||||
@@ -683,9 +685,9 @@ namespace sdv
|
||||
|
||||
/**
|
||||
* @brief Initialize the object. Overload of IObjectControl::Initialize.
|
||||
* @param[in] ssObjectConfig Optional configuration string.
|
||||
* @param[in] sObjectInfo The registration information of this object.
|
||||
*/
|
||||
virtual void Initialize(/*in*/ const u8string& ssObjectConfig) override
|
||||
virtual void Initialize(/*in*/ const SObjectInfo& sObjectInfo) override
|
||||
{
|
||||
// Not started before or ended completely?
|
||||
if (GetObjectState() != EObjectState::initialization_pending && GetObjectState() != EObjectState::destruction_pending)
|
||||
@@ -700,19 +702,19 @@ namespace sdv
|
||||
// Initialize the parameter map.
|
||||
InitParamMap();
|
||||
|
||||
// Copy the configuration
|
||||
m_ssObjectConfig = ssObjectConfig;
|
||||
// Copy the object information
|
||||
m_sSelf = sObjectInfo;
|
||||
|
||||
// Prepare initialization
|
||||
OnPreInitialize();
|
||||
|
||||
// Parse the object configuration if there is any.
|
||||
if (!ssObjectConfig.empty())
|
||||
if (!m_sSelf.ssConfig.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the config TOML.
|
||||
toml::CTOMLParser parser(ssObjectConfig);
|
||||
toml::CTOMLParser parser(m_sSelf.ssConfig);
|
||||
if (!parser.IsValid())
|
||||
{
|
||||
m_eObjectState = EObjectState::config_error;
|
||||
@@ -781,6 +783,15 @@ namespace sdv
|
||||
return m_eObjectState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get information about ourself.
|
||||
* @return The object information about ourself.
|
||||
*/
|
||||
const SObjectInfo& Self() const
|
||||
{
|
||||
return m_sSelf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the component operation mode. Overload of IObjectControl::SetOperationMode.
|
||||
* @param[in] eMode The operation mode, the component should run in.
|
||||
@@ -831,15 +842,11 @@ namespace sdv
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the object configuration for persistence.
|
||||
* @brief Build the object configuration from the parameter map and the stored initial configuration.
|
||||
* @return The object configuration as TOML string.
|
||||
*/
|
||||
virtual u8string GetObjectConfig() const override
|
||||
virtual u8string BuildObjectConfig() const
|
||||
{
|
||||
// During the initialization, return the stored object configuration.
|
||||
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
|
||||
return m_ssObjectConfig;
|
||||
|
||||
// Split path function (splits the group from the parameter names)
|
||||
auto fnSplitPath = [](const u8string& rssPath) -> std::pair<u8string, u8string>
|
||||
{
|
||||
@@ -849,13 +856,10 @@ namespace sdv
|
||||
return std::make_pair(rssPath.substr(0, nPos), rssPath.substr(nPos + 1));
|
||||
};
|
||||
|
||||
// Create a new configuration string from the parameters.
|
||||
auto seqParameters = GetParamPaths();
|
||||
if (seqParameters.empty()) return {};
|
||||
|
||||
// Iterate through the list of parameter names and create the TOML entries for it.
|
||||
auto seqParameters = GetParamPaths();
|
||||
u8string ssGroup;
|
||||
toml::CTOMLParser parser("");
|
||||
toml::CTOMLParser parser(m_sSelf.ssConfig);
|
||||
toml::CNodeCollection table(parser);
|
||||
for (auto ssParamPath : seqParameters)
|
||||
{
|
||||
@@ -863,7 +867,7 @@ namespace sdv
|
||||
auto ptrParam = FindParamObject(ssParamPath);
|
||||
|
||||
// Read only and temporary parameters are not stored
|
||||
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || !ptrParam->Temporary())
|
||||
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || ptrParam->Temporary())
|
||||
continue;
|
||||
|
||||
// Get the value
|
||||
@@ -877,7 +881,9 @@ namespace sdv
|
||||
// Need to add a group?
|
||||
if (prParam.first != ssGroup)
|
||||
{
|
||||
table = parser.AddTable(prParam.first);
|
||||
table = parser.GetDirect(prParam.first);
|
||||
if (!table)
|
||||
table = parser.AddTable(prParam.first);
|
||||
ssGroup = prParam.first;
|
||||
}
|
||||
|
||||
@@ -888,6 +894,20 @@ namespace sdv
|
||||
return parser.GetTOML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the object configuration for persistence. Overload of IObjectControl::GetObjectConfig.
|
||||
* @return The object configuration as TOML string.
|
||||
*/
|
||||
virtual u8string GetObjectConfig() const override
|
||||
{
|
||||
// During the initialization, return the stored object configuration.
|
||||
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
|
||||
return m_sSelf.ssConfig;
|
||||
|
||||
|
||||
return BuildObjectConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shutdown called before the object is destroyed. Overload of IObjectControl::Shutdown.
|
||||
* @attention Implement calls to other SDV objects here as this is no longer considered safe during the destructor of the
|
||||
@@ -930,7 +950,7 @@ namespace sdv
|
||||
* @post Reset by switching to configuration mode.
|
||||
*/
|
||||
void SetObjectIntoRuntimeErrorState()
|
||||
{
|
||||
{
|
||||
if (m_eObjectState == EObjectState::running)
|
||||
m_eObjectState = EObjectState::runtime_error;
|
||||
}
|
||||
@@ -992,6 +1012,12 @@ namespace sdv
|
||||
*/
|
||||
virtual void OnShutdown() {}
|
||||
|
||||
/**
|
||||
* @brief Last function called before destruction. The object integrity is still in tact. It can be assumed that all
|
||||
* dependencies to the object have been released.
|
||||
*/
|
||||
virtual void OnDestroy() {}
|
||||
|
||||
/**
|
||||
* @brief Interface map
|
||||
*/
|
||||
@@ -1002,7 +1028,8 @@ namespace sdv
|
||||
|
||||
private:
|
||||
std::atomic<EObjectState> m_eObjectState = EObjectState::initialization_pending; ///< Object state
|
||||
std::string m_ssObjectConfig; ///< Copy of the configuration TOML.
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Manage module lifetime.
|
||||
SObjectInfo m_sSelf; ///< Information about ourself.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1022,6 +1049,206 @@ namespace sdv
|
||||
END_SDV_INTERFACE_MAP()
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Lifetime control implementation class.
|
||||
*/
|
||||
class CLifetimeControlImpl : public virtual IInterfaceAccess, public IObjectLifetime, protected IObjectDestroy
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Deleted copy constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CLifetimeControlImpl(const CLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CLifetimeControlImpl(CLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~CLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
// Interface map (IObjectDestroy is not exposed)
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(IObjectLifetime)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Deleted copy assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CLifetimeControlImpl& operator=(const CLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CLifetimeControlImpl& operator=(CLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
|
||||
*/
|
||||
virtual void Increment() override
|
||||
{
|
||||
m_uiLifetimeCnt++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
|
||||
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
|
||||
* @return Returns 'true' if the object was destroyed, false if not.
|
||||
*/
|
||||
virtual bool Decrement() override
|
||||
{
|
||||
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
|
||||
{
|
||||
DestroyObject();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
|
||||
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
|
||||
* @return Returns the current counter value.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override
|
||||
{
|
||||
return m_uiLifetimeCnt;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
|
||||
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
|
||||
*/
|
||||
virtual void DestroyObject() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
|
||||
std::atomic_uint32_t m_uiLifetimeCnt = 1; ///< Lifetime reference counter
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Lifetime control implementation class based on shared pointer.
|
||||
* @tparam TClass The type of class deriving CSharedLifetimeControlImpl class.
|
||||
*/
|
||||
template <class TClass>
|
||||
class CSharedLifetimeControlImpl : public std::enable_shared_from_this<TClass>, public CLifetimeControlImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CSharedLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Deleted copy constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CSharedLifetimeControlImpl(const CSharedLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CSharedLifetimeControlImpl(CSharedLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~CSharedLifetimeControlImpl()
|
||||
{
|
||||
}
|
||||
|
||||
// Interface map (IObjectDestroy is not exposed)
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(IObjectLifetime)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Deleted copy assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CSharedLifetimeControlImpl& operator=(const CSharedLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CSharedLifetimeControlImpl& operator=(CSharedLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
|
||||
*/
|
||||
virtual void Increment() override
|
||||
{
|
||||
if (!m_uiLifetimeCnt++)
|
||||
m_ptrLocking = std::enable_shared_from_this<TClass>::shared_from_this();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
|
||||
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
|
||||
* @return Returns 'true' if the object was destroyed, false if not.
|
||||
*/
|
||||
virtual bool Decrement() override
|
||||
{
|
||||
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
|
||||
{
|
||||
DestroyObject();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
|
||||
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
|
||||
* @return Returns the current counter value.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override
|
||||
{
|
||||
return m_uiLifetimeCnt;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
|
||||
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
|
||||
*/
|
||||
virtual void DestroyObject() override
|
||||
{
|
||||
// Reset the locking; this might delete the class if no other references are present.
|
||||
m_ptrLocking.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<TClass> m_ptrLocking; ///< Holder of the instance of the class during lifetime.
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
|
||||
std::atomic_uint32_t m_uiLifetimeCnt = 0; ///< Lifetime reference counter
|
||||
};
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Object control class implementation //
|
||||
/////////////////////////////////////////
|
||||
@@ -1114,6 +1341,7 @@ namespace sdv
|
||||
auto objectPtr = std::move(*iter);
|
||||
m_vecActiveObjects.erase(iter);
|
||||
lockObjects.unlock();
|
||||
objectPtr->OnDestroy();
|
||||
objectPtr = nullptr;
|
||||
if (m_uiActiveObjectCount) --m_uiActiveObjectCount;
|
||||
return;
|
||||
|
||||
@@ -389,7 +389,13 @@ namespace sdv
|
||||
template <typename TIfc>
|
||||
TIfc* GetInterface() const
|
||||
{
|
||||
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
|
||||
try
|
||||
{
|
||||
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
|
||||
} catch (const XSysExcept&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,10 +18,17 @@
|
||||
#include "../interfaces/log.h"
|
||||
#include "../interfaces/repository.h"
|
||||
#include "../interfaces/com.h"
|
||||
#include "../interfaces/app.h"
|
||||
#include "../interfaces/param.h"
|
||||
#include "../interfaces/permission.h"
|
||||
#include "interface_ptr.h"
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#ifdef __GNUC__
|
||||
// Needed for getpid()
|
||||
#include <unistd.h>
|
||||
@@ -49,9 +56,11 @@ namespace sdv
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetObject(const std::string& rssObjectName)
|
||||
{
|
||||
if (!GetCore()) return nullptr;
|
||||
if (!GetCore())
|
||||
return nullptr;
|
||||
IObjectAccess* pRepository = GetCore<IObjectAccess>();
|
||||
if (!pRepository) return nullptr;
|
||||
if (!pRepository)
|
||||
return nullptr;
|
||||
return pRepository->GetObject(rssObjectName);
|
||||
}
|
||||
|
||||
@@ -63,9 +72,11 @@ namespace sdv
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetObject(TObjectID tObjectID)
|
||||
{
|
||||
if (!GetCore()) return nullptr;
|
||||
if (!GetCore())
|
||||
return nullptr;
|
||||
IObjectAccess* pRepository = GetCore<IObjectAccess>();
|
||||
if (!pRepository) return nullptr;
|
||||
if (!pRepository)
|
||||
return nullptr;
|
||||
return pRepository->GetObjectByID(tObjectID);
|
||||
}
|
||||
#else
|
||||
@@ -113,21 +124,23 @@ namespace sdv
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log function enables logging for SDV.
|
||||
* @param[in] eSeverity Severity level of the log message which will be logged, e.g. Info, Warning, Error etc.
|
||||
* @param[in] rssSrcFile Name of the file from which the message is logged.
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged.
|
||||
* @param[in] rssMessage Reference to the log message to be logged.
|
||||
*/
|
||||
* @brief Log function enables logging for SDV.
|
||||
* @param[in] eSeverity Severity level of the log message which will be logged, e.g. Info, Warning, Error etc.
|
||||
* @param[in] rssSrcFile Name of the file from which the message is logged.
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged.
|
||||
* @param[in] rssMessage Reference to the log message to be logged.
|
||||
*/
|
||||
inline void Log(ELogSeverity eSeverity, const u8string& rssSrcFile, uint32_t uiSrcLine, const u8string& rssMessage)
|
||||
{
|
||||
ILogger* pLogger = GetCore() ? GetCore<ILogger>() : nullptr;
|
||||
#ifdef _WIN32
|
||||
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
|
||||
if (pLogger)
|
||||
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
|
||||
#elif defined __unix__
|
||||
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
|
||||
if (pLogger)
|
||||
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
|
||||
#else
|
||||
#error The OS is currently not supported!
|
||||
#error The OS is currently not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -137,34 +150,34 @@ namespace sdv
|
||||
*/
|
||||
#define SDV_LOG(severity, ...) sdv::core::internal::CSDVLogImpl(severity, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Log a trace message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_TRACE(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::trace, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a debug message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a debug message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_DEBUG(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::debug, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log an information message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log an information message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_INFO(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::info, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a warning message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a warning message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_WARNING(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::warning, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log an error message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log an error message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_ERROR(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::error, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a fatal message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a fatal message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_FATAL(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::fatal, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
namespace internal
|
||||
@@ -176,22 +189,22 @@ namespace sdv
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged. Specified by C++ standard.
|
||||
* @param[in] ...args identifier specified by C++ standard that uses the ellipsis notation in the parameters.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&& ...args)
|
||||
template <typename... Args>
|
||||
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&&... args)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
(stream << ... << std::forward<Args>(args));
|
||||
|
||||
Log(eSeverity, szSrcFile ? szSrcFile : "", uiSrcLine, stream.str().c_str());
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Create a utility
|
||||
* @param[in] rssUtilityName Reference to the utility name.
|
||||
* @param[in] rssUtilityConfig Optional reference to the utility configuration.
|
||||
* @return Smart pointer to the utility or NULL when the utility could not be found.
|
||||
*/
|
||||
*/
|
||||
inline TObjectPtr CreateUtility(const std::string& rssUtilityName, const std::string& rssUtilityConfig = std::string())
|
||||
{
|
||||
TInterfaceAccessPtr ptrRepository = GetObject("RepositoryService");
|
||||
@@ -199,8 +212,529 @@ namespace sdv
|
||||
if (!pUtilityCreate) return nullptr;
|
||||
return pUtilityCreate->CreateUtility(rssUtilityName, rssUtilityConfig);
|
||||
}
|
||||
} // namespace core
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object smart pointer.
|
||||
* @param[in] pParameters Pointer to the parameter map interface of an object.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const IParameters* pParameters, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
any_t any = pParameters->GetParam(rssParamName);
|
||||
if (any.empty())
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The parameter could not be found.");
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the parameter interface.
|
||||
* @param[in] rptrObject Reference to object smart pointer to the the parameter of.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const TInterfaceAccessPtr& rptrObject, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
const IParameters* pParameters = rptrObject.GetInterface<IParameters>();
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
return GetParameter(pParameters, rssParamName, bNoExcept);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object with the supplied name.
|
||||
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
|
||||
if (!ptrObject)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
|
||||
}
|
||||
return GetParameter(ptrObject, rssParamName, bNoExcept);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object with the supplied name. Resolve enums and bitmask objects in the returned
|
||||
* parameter string.
|
||||
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter as a text string or an empty string when the object or the parameter could
|
||||
* not be found and bNoExcept was set.
|
||||
*/
|
||||
inline std::string GetParameterExpand(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
|
||||
if (!ptrObject)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
|
||||
}
|
||||
|
||||
const IParameters* pParameters = ptrObject.GetInterface<IParameters>();
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
any_t any = pParameters->GetParam(rssParamName);
|
||||
if (any.empty())
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The parameter could not be found.");
|
||||
}
|
||||
|
||||
SParamInfo sParamInfo = pParameters->GetParamInfo(rssParamName);
|
||||
if (sParamInfo.get_switch() == EParamType::enum_param)
|
||||
{
|
||||
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sEnumInfo.seqLabels)
|
||||
{
|
||||
if (rsLabel.anyValue == any)
|
||||
return rsLabel.ssLabel;
|
||||
}
|
||||
}
|
||||
if (sParamInfo.get_switch() == EParamType::bitmask_param)
|
||||
{
|
||||
uint64_t uiValue = static_cast<uint64_t>(any);
|
||||
std::stringstream sstreamValue;
|
||||
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sBitmaskInfo.seqLabels)
|
||||
{
|
||||
uint64_t uiValueLabel = static_cast<uint64_t>(rsLabel.anyValue);
|
||||
if (uiValue & uiValueLabel)
|
||||
{
|
||||
if (sstreamValue.rdbuf()->in_avail()) // Has characters
|
||||
sstreamValue << "|";
|
||||
sstreamValue << rsLabel.ssLabel;
|
||||
uiValue = uiValue & ~uiValueLabel;
|
||||
}
|
||||
}
|
||||
if (uiValue) // Not all bits have labels
|
||||
{
|
||||
if (sstreamValue.rdbuf()->in_avail()) // Has characters
|
||||
sstreamValue << "|";
|
||||
sstreamValue << uiValue;
|
||||
}
|
||||
return sstreamValue.str();
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
/// Internal namespace
|
||||
namespace internal
|
||||
{
|
||||
/**
|
||||
* @brief Trim whitespace at the begin and end of the text.
|
||||
* @param[in] rssText Reference to the text to trim whitespace for.
|
||||
* @return The trimmed text.
|
||||
*/
|
||||
inline std::string TrimWhitespace(const std::string& rssText)
|
||||
{
|
||||
size_t nFirst = rssText.find_first_not_of(" \t\r\n");
|
||||
if (nFirst == std::string::npos) return "";
|
||||
size_t nLast = rssText.find_last_not_of(" \t\r\n");
|
||||
return rssText.substr(nFirst, (nLast - nFirst + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to safely check if a string contains a valid, unescaped $(...) sequence.
|
||||
* @param[in] rssText The text to check.
|
||||
* @return Returns whether the text represents a valid variable.
|
||||
*/
|
||||
inline bool ContainsValidVariable(const std::string& rssText)
|
||||
{
|
||||
size_t nLength = rssText.length();
|
||||
size_t nIndex = 0;
|
||||
|
||||
while (nIndex < nLength)
|
||||
{
|
||||
if (rssText[nIndex] == '\\')
|
||||
{
|
||||
// Skip the escape and the escaped character
|
||||
nIndex += 2;
|
||||
}
|
||||
else if (rssText[nIndex] == '$')
|
||||
{
|
||||
// Check if it forms the start of a token sequence '$( '
|
||||
if (nIndex + 1 < nLength && rssText[nIndex + 1] == '(')
|
||||
{
|
||||
size_t nClose = rssText.find(')', nIndex + 2);
|
||||
if (nClose != std::string::npos)
|
||||
{
|
||||
// Found a valid structural candidate
|
||||
return true;
|
||||
}
|
||||
}
|
||||
nIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Resolves embedded object parameter variables formatted as $(object:param) within a text string.
|
||||
* @param[in] rssText The source text containing potential variables and backslash escapes.
|
||||
* @param[in] bRecursive If true, continues resolving until no more unescaped variables remain.
|
||||
* @param[in] bNoExcept If true, returns an empty string for errors; if false, throws std::runtime_error.
|
||||
* @return The fully resolved text string.
|
||||
*/
|
||||
inline std::string ResolveText(const std::string& rssText, bool bRecursive = true, bool bNoExcept = true)
|
||||
{
|
||||
std::string ssCurrentText = rssText;
|
||||
bool bMayHaveMoreVariables = true;
|
||||
|
||||
while (bMayHaveMoreVariables)
|
||||
{
|
||||
bMayHaveMoreVariables = false;
|
||||
std::string ssResult = "";
|
||||
ssResult.reserve(ssCurrentText.length()); // Pre-allocate memory for performance
|
||||
|
||||
size_t nLength = ssCurrentText.length();
|
||||
size_t nIndex = 0;
|
||||
|
||||
while (nIndex < nLength)
|
||||
{
|
||||
char cCurrent = ssCurrentText[nIndex];
|
||||
|
||||
// Handle backslash escape sequences
|
||||
if (cCurrent == '\\')
|
||||
{
|
||||
// Check if the next character is a '$'
|
||||
if (nIndex + 1 < nLength && ssCurrentText[nIndex + 1] == '$')
|
||||
{
|
||||
ssResult.push_back('$'); // Strip the escape character, keep the literal '$'
|
||||
nIndex += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssResult.push_back('\\'); // Preserve other backslashes for paths
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
// Identify potential variables
|
||||
else if (cCurrent == '$')
|
||||
{
|
||||
// extension 2: Only throw an error or treat as a variable if it is
|
||||
// explicitly part of a dynamic sequence tracking towards a '$(...)' match.
|
||||
if (nIndex + 1 >= nLength || ssCurrentText[nIndex + 1] != '(')
|
||||
{
|
||||
// It is a loose literal '$' (like currency). Keep it and do not throw.
|
||||
ssResult.push_back('$');
|
||||
nIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t nVarStart = nIndex + 2; // Position right after "$("
|
||||
size_t nVarEnd = ssCurrentText.find(')', nVarStart);
|
||||
|
||||
// Validate that a matching closing parenthesis exists
|
||||
if (nVarEnd == std::string::npos)
|
||||
{
|
||||
if (!bNoExcept)
|
||||
throw std::runtime_error(
|
||||
"Format error: Missing closing parenthesis ')' for variable starting at index "
|
||||
+ std::to_string(nIndex));
|
||||
return "";
|
||||
}
|
||||
|
||||
// Extract the inner payload block
|
||||
std::string sVariableContent = ssCurrentText.substr(nVarStart, nVarEnd - nVarStart);
|
||||
size_t nColonPos = sVariableContent.find(':');
|
||||
|
||||
// Validate that the delimiter ':' separates object and parameter names
|
||||
if (nColonPos == std::string::npos)
|
||||
{
|
||||
if (!bNoExcept)
|
||||
throw std::runtime_error("Format error: Variable content '" + sVariableContent
|
||||
+ "' lacks an 'object:param' colon separator");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Extract and clean whitespace before/after tokens, preserving inner spaces
|
||||
std::string sObjName = internal::TrimWhitespace(sVariableContent.substr(0, nColonPos));
|
||||
std::string sParamName = internal::TrimWhitespace(sVariableContent.substr(nColonPos + 1));
|
||||
|
||||
// Request the parameter.
|
||||
std::string ssValue = GetParameterExpand(sObjName, sParamName, bNoExcept);
|
||||
|
||||
// Add the parameter to the string
|
||||
ssResult.append(ssValue);
|
||||
|
||||
nIndex = nVarEnd + 1; // Move parsing index past the ')'
|
||||
}
|
||||
else
|
||||
{
|
||||
ssResult.push_back(cCurrent);
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
ssCurrentText = ssResult;
|
||||
|
||||
// Exit immediately if recursive resolution was disabled
|
||||
if (!bRecursive) break;
|
||||
|
||||
// extension 2: Intelligently analyze if a recursive processing loop is required
|
||||
if (internal::ContainsValidVariable(ssCurrentText))
|
||||
bMayHaveMoreVariables = true;
|
||||
}
|
||||
|
||||
return ssCurrentText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current access permission.
|
||||
* @return The current access permission.
|
||||
*/
|
||||
inline EAccessPermission GetCurrentAccessPermission()
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl)
|
||||
return EAccessPermission::not_set;
|
||||
return pPermissionControl->GetCurrentPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current transmission from this thread and prepare a transfer to another thread.
|
||||
* @return Transfer ID identifying the permission of this thread.
|
||||
*/
|
||||
inline TPermissionTransferID TransferCurrentPermission()
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return 0u;
|
||||
return pPermissionControl->TransferCurrentPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Class managing the lifetime of an access permission.
|
||||
*/
|
||||
class CAccessPermission
|
||||
{
|
||||
// Friend functions
|
||||
friend CAccessPermission RestrictAccessPermission(EAccessPermission);
|
||||
friend CAccessPermission SetAccessPermission(TPermissionTransferID);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CAccessPermission() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] tPermissionID The access permission to manage.
|
||||
*/
|
||||
CAccessPermission(TPermissionID tPermissionID) : m_tPermissionID(tPermissionID)
|
||||
{}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Copy constructor is deleted.
|
||||
* @param[in] rPermission Reference to the permission to copy from.
|
||||
*/
|
||||
CAccessPermission(const CAccessPermission& rPermission) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param[in] rPermission Reference to the permission to move from.
|
||||
*/
|
||||
CAccessPermission(CAccessPermission&& rPermission) : m_tPermissionID(rPermission.m_tPermissionID)
|
||||
{
|
||||
rPermission.m_tPermissionID = 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CAccessPermission()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator is deleted.
|
||||
* @param[in] rPermission Reference to the permission to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CAccessPermission& operator=(const CAccessPermission& rPermission) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param[in] rPermission Reference to the permission to move from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CAccessPermission& operator=(CAccessPermission&& rPermission)
|
||||
{
|
||||
m_tPermissionID = rPermission.m_tPermissionID;
|
||||
rPermission.m_tPermissionID = 0u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boolean operator.
|
||||
* @return Returns whether a valid permission ID is assigned to this class.
|
||||
*/
|
||||
operator bool() const
|
||||
{
|
||||
return m_tPermissionID ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does the access permission class contain a valid permission ID.
|
||||
* @return Returns whether a valid permission ID is assigned to this class.
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return m_tPermissionID ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release the permission.
|
||||
*/
|
||||
void Release()
|
||||
{
|
||||
if (!m_tPermissionID) return;
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return;
|
||||
pPermissionControl->ReleaseAccessPermission(m_tPermissionID);
|
||||
m_tPermissionID = 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
TPermissionID m_tPermissionID = 0u; ///< Permission ID to be managed by this class.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Restrict the current access permission.
|
||||
* @param[in] ePermission The permission the access should be restricted to.
|
||||
* @return The access permission connected to this restriction. The lifetime of the access permission is managed by the
|
||||
* returned class.
|
||||
*/
|
||||
inline CAccessPermission RestrictAccessPermission(EAccessPermission ePermission)
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return {};
|
||||
return pPermissionControl->RestrictAccessPermission(ePermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the access permission from a transfer ID that defined the access permission of a different thread.
|
||||
* @param[in] tTransferID The ID of the transferred access permission.
|
||||
* @return The access permission for the current thread. The lifetime of the access permission is managed by the returned
|
||||
* class.
|
||||
*/
|
||||
inline CAccessPermission SetAccessPermission(TPermissionTransferID tTransferID)
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return {};
|
||||
return pPermissionControl->SetAccessPermission(tTransferID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Secure thread implementation based on std::thread transferring the permissions from the creation thread to the
|
||||
* execution thread.
|
||||
*/
|
||||
class secure_thread : public std::thread
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
secure_thread() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor is deleted.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
*/
|
||||
secure_thread(const secure_thread& rthread) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
*/
|
||||
secure_thread(secure_thread&& rthread) : std::thread(static_cast<std::thread&&>(rthread))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor for thread execution.
|
||||
* @tparam F The function to execute.
|
||||
* @tparam Args The argument types of the function to execute.
|
||||
* @param[in] f Reference to the function.
|
||||
* @param[in] args Reference to zero or more arguments.
|
||||
*/
|
||||
template <class F, class... Args>
|
||||
explicit secure_thread(F&& f, Args&&... args)
|
||||
{
|
||||
static_cast<std::thread&>(*this) = std::thread(
|
||||
[](TPermissionTransferID tTransferID, auto&& function, auto&&... arguments)
|
||||
{
|
||||
CAccessPermission permission = SetAccessPermission(tTransferID);
|
||||
std::invoke(std::forward<decltype(function)>(function), std::forward<decltype(arguments)>(arguments)...);
|
||||
}, TransferCurrentPermission(), std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
secure_thread& operator=(secure_thread&& rthread)
|
||||
{
|
||||
static_cast<std::thread&>(*this) = static_cast<std::thread&&>(rthread);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace core
|
||||
}// namespace sdv
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Comparison operators
|
||||
* @param[in] e1 First permission
|
||||
* @param[in] e2 Second permission
|
||||
* @return Result of the comparison
|
||||
*/
|
||||
inline bool operator<(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) < static_cast<int32_t>(e2); }
|
||||
inline bool operator<=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) <= static_cast<int32_t>(e2); }
|
||||
inline bool operator>(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) > static_cast<int32_t>(e2); }
|
||||
inline bool operator>=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) >= static_cast<int32_t>(e2); }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
namespace sdv
|
||||
{
|
||||
namespace app
|
||||
{
|
||||
/**
|
||||
@@ -208,11 +742,11 @@ namespace sdv
|
||||
* @param[in] rssAttribute Name of the attribute.
|
||||
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
|
||||
*/
|
||||
inline any_t GetAppAttribute(const std::string& rssAttribute)
|
||||
inline any_t GetAppSettingsAttribute(const std::string& rssAttribute)
|
||||
{
|
||||
const IAttributes* ptrAppAttributes = core::GetObject<IAttributes>("AppControlService");
|
||||
if (!ptrAppAttributes) return {};
|
||||
return ptrAppAttributes->Get(rssAttribute);
|
||||
const IParameters* pParameters = core::GetObject<IParameters>("AppSettingsService");
|
||||
if (!pParameters) return {};
|
||||
return pParameters->GetParam(rssAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +755,7 @@ namespace sdv
|
||||
*/
|
||||
inline bool ConsoleIsSilent()
|
||||
{
|
||||
return GetAppAttribute("console.info_level") == "silent";
|
||||
return GetAppSettingsAttribute("Console.Reporting") == "Silent";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +764,7 @@ namespace sdv
|
||||
*/
|
||||
inline bool ConsoleIsVerbose()
|
||||
{
|
||||
return GetAppAttribute("console.info_level") == "verbose";
|
||||
return GetAppSettingsAttribute("Console.Reporting") == "Verbose";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +773,7 @@ namespace sdv
|
||||
*/
|
||||
inline uint32_t GetAppInstanceID()
|
||||
{
|
||||
return GetAppAttribute("app.instance_id");
|
||||
return GetAppSettingsAttribute("Application.Instance");
|
||||
}
|
||||
} // namespace app
|
||||
|
||||
@@ -247,64 +781,81 @@ namespace sdv
|
||||
{
|
||||
/**
|
||||
* @brief Create a repository connection to a local server.
|
||||
* @param[in] uiInstanceID Optionally the instance ID of the target system to connect to or 0 (default) to connect to the
|
||||
* instance identified by app-control.
|
||||
* @param[in] nRetries Number of retries to connect (optional, default 30, minimum 3).
|
||||
* @return Returns a smart pointer to the repository proxy. Disconnection takes place when IObjectDestroy::DestroyObject is
|
||||
* called.
|
||||
*/
|
||||
inline TObjectPtr ConnectToLocalServerRepository(uint32_t uiInstanceID = 0, size_t nRetries = 30)
|
||||
inline TObjectPtr ConnectToLocalServerRepository(size_t nRetries = 30)
|
||||
{
|
||||
com::IClientConnect* pClientConnect = core::GetObject<com::IClientConnect>("ConnectionService");
|
||||
if (!pClientConnect)
|
||||
// This function works with main, external and maintenance applications.
|
||||
const app::IAppContext* pAppContext = core::GetCore<app::IAppContext>();
|
||||
if (!pAppContext) return {};
|
||||
switch (pAppContext->GetContextType())
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Could not access the connection service." << std::endl;
|
||||
case app::EAppContext::main:
|
||||
case app::EAppContext::external:
|
||||
case app::EAppContext::maintenance:
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
const sdv::app::IAppConnections* pConnections = core::GetObject<sdv::app::IAppConnections>("AppSettingsService");
|
||||
if (!pConnections) return {};
|
||||
std::string ssConnectionConfig = pConnections->GetConnectionConfig("Default");
|
||||
if (ssConnectionConfig.empty()) return {};
|
||||
|
||||
sdv::core::IRepositoryControl* pRepository = core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
|
||||
if (!pRepository) return {};
|
||||
auto tConnectSvcID = pRepository->CreateObject("ClientConnectService", "ClientDefault", ssConnectionConfig);
|
||||
if (!tConnectSvcID) return {};
|
||||
|
||||
sdv::TInterfaceAccessPtr ptrConnectSvc = core::GetObject(tConnectSvcID);
|
||||
sdv::com::IClientConnect* pClientConnect = ptrConnectSvc.GetInterface<sdv::com::IClientConnect>();
|
||||
if (!pClientConnect)
|
||||
{
|
||||
pRepository->DestroyObject("ClientDefault");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Connect the client to the server and return the server repository interface.
|
||||
std::string ssConnectString = R"code([Client]
|
||||
Type = "Local"
|
||||
)code";
|
||||
if (uiInstanceID)
|
||||
ssConnectString += "Instance = " + std::to_string(uiInstanceID) + R"code(
|
||||
)code";
|
||||
try
|
||||
{
|
||||
// Try to connect (30 times with 1 second in between).
|
||||
size_t nCnt = 0;
|
||||
sdv::TObjectPtr ptrRepository;
|
||||
while (!ptrRepository && nCnt < nRetries)
|
||||
sdv::TObjectPtr ptrRemoteRepo;
|
||||
while (!ptrRemoteRepo && nCnt < std::max(nRetries, static_cast<size_t>(3u)))
|
||||
{
|
||||
nCnt++;
|
||||
ptrRepository = pClientConnect->Connect(ssConnectString);
|
||||
if (!ptrRepository)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
if (pClientConnect->IsConnected() || pClientConnect->Connect())
|
||||
{
|
||||
ptrRemoteRepo = pClientConnect->GetRemoteRepository();
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return ptrRepository;
|
||||
return ptrRemoteRepo;
|
||||
}
|
||||
catch (const XAccessDenied& /*rExcept*/)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Access denied trying to connect to a local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
|
||||
app::GetAppInstanceID() << "." << std::endl;
|
||||
return {};
|
||||
}
|
||||
catch (const XNotFound& /*rExcept*/)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " not found." << std::endl;
|
||||
app::GetAppInstanceID() << " not found." << std::endl;
|
||||
return {};
|
||||
}
|
||||
catch (const XInvalidState& rExcept)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "The local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " is in an invalid state: " << rExcept.what() <<
|
||||
app::GetAppInstanceID() << " is in an invalid state: " << rExcept.what() <<
|
||||
std::endl;
|
||||
return {};
|
||||
}
|
||||
@@ -312,12 +863,11 @@ Type = "Local"
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Timeout occurred trying to connect to a local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
|
||||
app::GetAppInstanceID() << "." << std::endl;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace com
|
||||
} // namespace sdv
|
||||
|
||||
#endif // !defined LOCAL_SERVICE_ACCESS_H
|
||||
@@ -435,12 +435,14 @@ namespace sdv
|
||||
* @tparam TInfoConstruct The type of the variables that are provided to the constructor function of the parameter
|
||||
* information.
|
||||
* @param[in] rtVar Reference to the parameter variable.
|
||||
* @param[in] bReadOnly When set, the parameter is read-only (even when writable) and will not be initialized.
|
||||
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable
|
||||
* parameters.
|
||||
* @param[in] tConstruct The construct function arguments.
|
||||
*/
|
||||
template <typename... TInfoConstruct>
|
||||
CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
|
||||
CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
|
||||
|
||||
/**
|
||||
* @brief Set a value. Overload of CParamGuardian::Set.
|
||||
@@ -993,7 +995,7 @@ namespace sdv
|
||||
} \
|
||||
std::vector<std::shared_ptr<sdv::CSdvParamInfo>> vecParamInfo; \
|
||||
[[maybe_unused]] uint32_t uiFlags = 0; \
|
||||
[[maybe_unused]] std::string ssGroup; \
|
||||
[[maybe_unused]] std::string ssGroup; \
|
||||
[[maybe_unused]] bool bLockable = false;
|
||||
|
||||
/**
|
||||
@@ -1107,8 +1109,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, unit_string, ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
unit_string, ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1126,7 +1129,7 @@ namespace sdv
|
||||
* @param description_string The description of the parameter.
|
||||
*/
|
||||
#define SDV_PARAM_NUMBER_ENTRY(var, name_string, default_val, low_limit, high_limit, unit_string, description_string) \
|
||||
{ \
|
||||
{ \
|
||||
auto prLowLimit = sdv::internal::SLowerLimit() low_limit; \
|
||||
sdv::any_t anyLower; \
|
||||
if (prLowLimit.second != sdv::internal::ELimitType::no_limit) anyLower = prLowLimit.first; \
|
||||
@@ -1144,8 +1147,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, \
|
||||
name_string, default_val, anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
|
||||
prHighLimit.second != sdv::internal::ELimitType::up_to_limit, unit_string, ssGroup, description_string, \
|
||||
uiFlags); \
|
||||
if (ptrParamInfo)vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
@@ -1181,8 +1185,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, pattern_string, unit_string, ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
pattern_string, unit_string, ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1213,8 +1218,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1238,11 +1244,12 @@ namespace sdv
|
||||
std::vector<std::shared_ptr<sdv::CSdvParamInfo>> vecParamInfoMember; \
|
||||
if constexpr (bStatic) \
|
||||
{ \
|
||||
vecParamInfoMember = sdv::internal::SMemberMap<decltype(member)>::BuildStatic(); \
|
||||
vecParamInfoMember = sdv::internal::SMemberMap<std::decay_t<decltype(member)>>::BuildStatic(); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
auto ptrMemberMap = std::make_shared<sdv::internal::SMemberMap<decltype(member)>>(pObject->member, pObject); \
|
||||
auto ptrMemberMap = \
|
||||
std::make_shared<sdv::internal::SMemberMap<std::decay_t<decltype(member)>>>(pObject->member, pObject); \
|
||||
if (ptrMemberMap) \
|
||||
{ \
|
||||
ptrMemberMap->BuildMap(); \
|
||||
@@ -1388,13 +1395,15 @@ namespace sdv
|
||||
* @tparam TVar Type of the variable.
|
||||
* @tparam TConstruct The arguments for the parameter info construct function.
|
||||
* @param[in] rtVar Reference to the parameter.
|
||||
* @param[in] bReadOnly When set, the parameter is read only and will not be initialized.
|
||||
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
|
||||
* @param[in] tConstruct The construct function arguments.
|
||||
* @return Smart pointer to the parameter information structure.
|
||||
*/
|
||||
template <typename TVar, typename... TConstruct>
|
||||
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty, TConstruct... tConstruct);
|
||||
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
|
||||
TConstruct... tConstruct);
|
||||
|
||||
/**
|
||||
* @brief Register a member parameter map into this parameter map.
|
||||
|
||||
@@ -412,13 +412,14 @@ namespace sdv
|
||||
|
||||
template <typename TVar>
|
||||
template <typename... TInfoConstruct>
|
||||
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct) :
|
||||
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
|
||||
TInfoConstruct... tConstruct) :
|
||||
CParamGuardian(bLockable, bAutoDirty, rtVar, tConstruct...), m_rtVar(rtVar)
|
||||
{
|
||||
// Assign the default value
|
||||
if constexpr (!CSdvParamInfo::TypeIsReadOnly<TVar>())
|
||||
{
|
||||
m_rtVar = DefaultVal().get<TVar>();
|
||||
if (!bReadOnly) m_rtVar = DefaultVal().get<TVar>();
|
||||
UpdateDirty(DefaultVal());
|
||||
ResetDirty();
|
||||
}
|
||||
@@ -678,10 +679,10 @@ namespace sdv
|
||||
}
|
||||
|
||||
template <typename TVar, typename... TConstruct>
|
||||
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty,
|
||||
TConstruct... tConstruct)
|
||||
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable,
|
||||
bool bAutoDirty, TConstruct... tConstruct)
|
||||
{
|
||||
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bLockable, bAutoDirty, tConstruct...);
|
||||
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bReadOnly, bLockable, bAutoDirty, tConstruct...);
|
||||
m_vecParamMapRegistration.push_back(SParamRegistration(ptrParam));
|
||||
return ptrParam;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
namespace serdes
|
||||
{
|
||||
@@ -378,7 +379,25 @@ namespace sdv
|
||||
|
||||
inline CRawDataBypass& GetRawDataBypass()
|
||||
{
|
||||
#if defined __GNUC__ && defined _WIN32
|
||||
// https://dev.azure.com/SW4ZF/AZP-431_DivDI_Vehicle_API/_workitems/edit/610009
|
||||
// In MINGW GCC implementation of thread_local, there is an issue with complex classes being used after the destruction.
|
||||
// This is caused by an architectural bug (https://github.com/msys2/MINGW-packages/issues/2519) causing the emutls (GCC
|
||||
// Emulated TLS) managing the memory allocation to be executed before the __cxa_thread_exit, the thread cleanup callback
|
||||
// of Windows. The solution is to use trivial data only (pointer, reference, integers, etc.). A workaround is
|
||||
// implemented to use a reference of the permission list and map instead of an instance to the list and map.
|
||||
static auto fnCreateBypass = []() -> CRawDataBypass&
|
||||
{
|
||||
static std::mutex mtx;
|
||||
static std::list<CRawDataBypass> lstRawDataBypasses;
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
lstRawDataBypasses.resize(lstRawDataBypasses.size() + 1);
|
||||
return lstRawDataBypasses.back();
|
||||
};
|
||||
thread_local static CRawDataBypass& bypass = fnCreateBypass();
|
||||
#else
|
||||
thread_local static CRawDataBypass bypass;
|
||||
#endif
|
||||
return bypass;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <cctype>
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
// Resolve conflict
|
||||
@@ -59,6 +60,8 @@
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
|
||||
#include "simple_toml.h"
|
||||
|
||||
namespace sdv
|
||||
{
|
||||
/**
|
||||
@@ -148,7 +151,36 @@ namespace sdv{
|
||||
{
|
||||
/**
|
||||
* @brief The SDV core loader
|
||||
*/
|
||||
* @details The SDV core loader class searches for the core library and does the first startup. The core library uses
|
||||
* the following environment variables to identify its location:
|
||||
* - SDV_FRAMEWORK_RUNTIME directs to the Vehicle API core location.
|
||||
* - SDV_COMPONENT_INSTALL directs to the location of the component installations.
|
||||
* - SDV_FRAMEWORK_DEV_TOOLS directs to the location of the development tools used during the build process of SDV
|
||||
* components.
|
||||
* - SDV_FRAMEWORK_DEV_INCLUDE directs to the header file location to allow building components for use with the
|
||||
* Vehicle API framework.
|
||||
*
|
||||
* The SDV core loader supports different core stacks to coexist. For this there is a location procedure for the core
|
||||
* systems:
|
||||
* 1. Check for a "sdv_core_reloc.toml" file that contain one or more paths to the core system. The paths defined in the
|
||||
* file override the global environment variables for this application and all child applications.
|
||||
* 2. Check for the environment variables. If the SDV_FRAMEWORK_RUNTIM variable is set, it is used to extract all other
|
||||
* variables as well, if not set.
|
||||
* 3. If no variable is set, use the location of the EXE as core location. This might work in some situations if the
|
||||
* path variable has been set properly.
|
||||
*
|
||||
* If none of the above strategies work, the core cannot be loaded.
|
||||
*
|
||||
* The "sdv_core_reloc.toml" file has the following format:
|
||||
* @code
|
||||
* [CoreLocation]
|
||||
* Version = 100 # Version; currently supported 100 for version 1.0
|
||||
* Runtime = "<core runtime directory>"
|
||||
* Install = "<component install directory>" # Typically identical to runtime directory
|
||||
* DevTools = "<development tools directory>" # Typically identical to runtime directory
|
||||
* Include = "<include directory>" # Typically in the include subdirectory
|
||||
* @endcode
|
||||
*/
|
||||
class CSDVCoreLoader
|
||||
{
|
||||
public:
|
||||
@@ -189,77 +221,50 @@ namespace sdv{
|
||||
{
|
||||
if (m_bInit) return; // Prevent trying to load again.
|
||||
m_bInit = true;
|
||||
bool bRelocFileError = false;
|
||||
std::string ssRelocFileInfo = "";
|
||||
std::string ssEnvironmentInfo = "";
|
||||
|
||||
// Check for the executable directory
|
||||
std::filesystem::path pathCoreLib;
|
||||
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
|
||||
pathCoreLib = GetExecDirectory() / "core_services.sdv";
|
||||
// Step 1: check for the "sdv_core_reloc.toml"
|
||||
ProcessRelocationFile();
|
||||
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
|
||||
{
|
||||
// Check for the library in the relocation directory
|
||||
auto relocFolder = GetRelocationPath();
|
||||
if (!relocFolder.empty())
|
||||
{
|
||||
auto coreLibFolder = std::filesystem::path(relocFolder) / "core_services.sdv";
|
||||
if (coreLibFolder.is_relative())
|
||||
coreLibFolder = (GetExecDirectory() / coreLibFolder).lexically_normal();
|
||||
|
||||
if (std::filesystem::exists(coreLibFolder))
|
||||
pathCoreLib = coreLibFolder;
|
||||
}
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
bRelocFileError = true; // we found the file but not the core library, we must run into an error
|
||||
ssRelocFileInfo = "Error: Invalid \"sdv_core_reloc.toml\" file found (but no core library), it contains: " + relocFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
// Step 2: check for environment variables (either set globally or overwritten by the sdv_core_reloc.toml).
|
||||
#ifdef _WIN32
|
||||
std::wstring ssPathCoreTemp(32768, '\0');
|
||||
GetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
|
||||
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
std::wstring ssPathCoreTemp(32768, '\0');
|
||||
GetEnvironmentVariable(
|
||||
L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
|
||||
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
#else
|
||||
std::string ssPathCoreTemp = std::getenv("SDV_FRAMEWORK_RUNTIME") ? std::getenv("SDV_FRAMEWORK_RUNTIME") : "";
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
std::string ssPathCoreTemp = std::getenv("SDV_FRAMEWORK_RUNTIME") ? std::getenv("SDV_FRAMEWORK_RUNTIME") : "";
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
#endif
|
||||
if (pathCoreLib.is_relative())
|
||||
pathCoreLib = (GetExecDirectory() / pathCoreLib).lexically_normal();
|
||||
if (m_pathCoreLib.is_relative())
|
||||
m_pathCoreLib = (GetExecDirectory() / m_pathCoreLib).lexically_normal();
|
||||
|
||||
if (!pathCoreLib.empty())
|
||||
ssEnvironmentInfo = "System environment path: " + pathCoreLib.generic_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Depend on system path to find the library
|
||||
if (pathCoreLib.empty())
|
||||
pathCoreLib = "core_services.sdv";
|
||||
|
||||
// Open the library only if there is no or a valid 'sdv_core_reloc.toml' file
|
||||
if (!bRelocFileError)
|
||||
// Step 3: check for the executable directory or otherwise check globally
|
||||
if (m_pathCoreLib.empty())
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
|
||||
m_pathCoreLib = GetExecDirectory() / "core_services.sdv";
|
||||
else
|
||||
m_pathCoreLib = "core_services.sdv";
|
||||
}
|
||||
|
||||
ssEnvironmentInfo = "System environment path: " + m_pathCoreLib.generic_string();
|
||||
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(pathCoreLib.native().c_str()));
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(m_pathCoreLib.native().c_str()));
|
||||
#elif defined __unix__
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(pathCoreLib.native().c_str(), RTLD_LAZY));
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(m_pathCoreLib.native().c_str(), RTLD_LAZY));
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!m_tModule)
|
||||
{
|
||||
@@ -275,16 +280,12 @@ namespace sdv{
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
if (ssRelocFileInfo.empty() && ssEnvironmentInfo.empty())
|
||||
std::cerr << "No environment variable set and no realocation file found." << std::endl;
|
||||
if (!ssRelocFileInfo.empty())
|
||||
std::cerr << ssRelocFileInfo << std::endl;
|
||||
if (!ssEnvironmentInfo.empty())
|
||||
std::cerr << ssEnvironmentInfo << std::endl;
|
||||
|
||||
std::cerr << "Could not load \"core_services.sdv\" library";
|
||||
if (!ssError.empty()) std::cerr << ": " << ssError;
|
||||
std::cerr << std::endl;
|
||||
m_ssErrMsg = "Could not load \"core_services.sdv\" library";
|
||||
if (!ssError.empty())
|
||||
m_ssErrMsg += ": " + ssError;
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,7 +302,8 @@ namespace sdv{
|
||||
#endif
|
||||
if (!fnSDVCore)
|
||||
{
|
||||
std::cerr << "The library \"core_services.sdv\" doesn't expose the SDVCore function." << std::endl;
|
||||
m_ssErrMsg = "The library \"core_services.sdv\" doesn't expose the SDVCore function.";
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +313,8 @@ namespace sdv{
|
||||
m_pCore = fnSDVCore();
|
||||
if (!m_pCore)
|
||||
{
|
||||
std::cerr << "The library \"core_services.sdv\" doesn't provide a valid interface." << std::endl;
|
||||
m_ssErrMsg = "The library \"core_services.sdv\" doesn't provide a valid interface.";
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -321,7 +324,6 @@ namespace sdv{
|
||||
*/
|
||||
operator TInterfaceAccessPtr() const { return m_pCore; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Get the directory of the executable.
|
||||
* @return Path to the directory.
|
||||
@@ -346,86 +348,170 @@ namespace sdv{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the folder path in the file 'sdv_core_reloc.toml'.
|
||||
* @return Path content, empty string if not found.
|
||||
*/
|
||||
static std::string GetRelocationPath()
|
||||
* @brief Get the path to the core library.
|
||||
* @return Returns a reference to the path to the core library.
|
||||
*/
|
||||
const std::filesystem::path& GetCoreLibPath() const
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
|
||||
{
|
||||
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
|
||||
std::string ssLine;
|
||||
while (std::getline(fstream, ssLine))
|
||||
{
|
||||
size_t nPos = 0;
|
||||
auto fnSkipWhitespace = [&]() { while (std::isspace(ssLine[nPos])) nPos++; };
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] == '#') continue; // Rest of the line is comments
|
||||
if (ssLine.substr(nPos, 9) != "directory") continue; // not the keq of interest: skip line
|
||||
nPos += 9;
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] != '=')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting assignment character '=' following"
|
||||
" keyword 'directory'." << std::endl;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] != '\"')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
|
||||
" a string begin'." << std::endl;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
size_t nStart = nPos;
|
||||
while (nPos < ssLine.length() && ssLine[nPos] != '\"')
|
||||
{
|
||||
// Check for escape character
|
||||
if (ssLine[nPos] == '\\') nPos++;
|
||||
|
||||
// Skip character
|
||||
nPos++;
|
||||
}
|
||||
if (nPos >= ssLine.length() || ssLine[nPos] != '\"')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
|
||||
" a string end'." << std::endl;
|
||||
break;
|
||||
}
|
||||
std::string ssDirectory = ssLine.substr(nStart, nPos - nStart);
|
||||
while (ssDirectory.empty())
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting a valid value following the assignment"
|
||||
" of the 'directory' key." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return ssDirectory;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return m_pathCoreLib;
|
||||
}
|
||||
|
||||
bool m_bInit = false; ///< Is the loader initialized?
|
||||
core::TModuleID m_tModule = 0; ///< Module ID
|
||||
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
|
||||
/**
|
||||
* @brief Has loaded successfully?
|
||||
* @return Returns whether loading was successful.
|
||||
*/
|
||||
bool HasLoaded() const
|
||||
{
|
||||
return m_bInit && m_tModule && m_pCore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the error message if loading was unsuccessful.
|
||||
* @return Returns the a reference to the string containing the error message or an empty string if not available.
|
||||
*/
|
||||
const std::string& GetErrorMsg() const
|
||||
{
|
||||
return m_ssErrMsg;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Check for the 'sdv_core_reloc.toml' file containing the information about core relocation.
|
||||
* @details Set the environment variables following the information from the core relocation file.
|
||||
*/
|
||||
static void ProcessRelocationFile()
|
||||
{
|
||||
if (!std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml")) return;
|
||||
|
||||
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
|
||||
if (!fstream.is_open()) return;
|
||||
|
||||
std::stringstream sstreamContent;
|
||||
sstreamContent << fstream.rdbuf();
|
||||
fstream.close();
|
||||
|
||||
try
|
||||
{
|
||||
sdv::toml::simple_parser::CParser parser(sstreamContent.str());
|
||||
if (parser.Root().GetDirect("CoreLocation.Version").GetValue<uint32_t>() != SDVFrameworkInterfaceVersion)
|
||||
{
|
||||
std::cerr << "Invalid version in sdv_core_reloc.toml" << std::endl;
|
||||
return; // Version not supported
|
||||
}
|
||||
|
||||
const auto& sRuntimeNode = parser.Root().GetDirect("CoreLocation.Runtime");
|
||||
if (sRuntimeNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathRuntime = sRuntimeNode.GetValue<std::string>();
|
||||
if (pathRuntime.is_relative())
|
||||
pathRuntime = (GetExecDirectory() / pathRuntime).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", pathRuntime.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + pathRuntime.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_RUNTIME", pathRuntime.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sInstallNode = parser.Root().GetDirect("CoreLocation.Install");
|
||||
if (sInstallNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathInstall = sInstallNode.GetValue<std::string>();
|
||||
if (pathInstall.is_relative())
|
||||
pathInstall = (GetExecDirectory() / pathInstall).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_COMPONENT_INSTALL", pathInstall.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_COMPONENT_INSTALL=") + pathInstall.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_COMPONENT_INSTALL", pathInstall.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sDevToolsNode = parser.Root().GetDirect("CoreLocation.DevTools");
|
||||
if (sDevToolsNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathDevTools = sDevToolsNode.GetValue<std::string>();
|
||||
if (pathDevTools.is_relative())
|
||||
pathDevTools = (GetExecDirectory() / pathDevTools).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_TOOLS=") + pathDevTools.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sIncludeNode = parser.Root().GetDirect("CoreLocation.Include");
|
||||
if (sIncludeNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathInclude = sIncludeNode.GetValue<std::string>();
|
||||
if (pathInclude.is_relative())
|
||||
pathInclude = (GetExecDirectory() / pathInclude).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_INCLUDE=") + pathInclude.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{}
|
||||
}
|
||||
|
||||
bool m_bInit = false; ///< Is the loader initialized?
|
||||
core::TModuleID m_tModule = 0; ///< Module ID
|
||||
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
|
||||
std::filesystem::path m_pathCoreLib; ///< Path to the core library.
|
||||
std::string m_ssErrMsg; ///< Error message for failed loading.
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
#ifndef NO_SDV_CORE_FUNC
|
||||
/**
|
||||
* @brief Access to the core.
|
||||
* @return Smart pointer to the core services interface.
|
||||
* @brief Access to the core loader.
|
||||
* @return Reference to the one core loader instance.
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetCore()
|
||||
inline internal::CSDVCoreLoader& GetCoreLoader()
|
||||
{
|
||||
static internal::CSDVCoreLoader core;
|
||||
core.Load();
|
||||
return core;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to the core interfaces.
|
||||
* @return Smart pointer to the core services interfaces.
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetCore()
|
||||
{
|
||||
return GetCoreLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to specific interface of the core.
|
||||
* @tparam TInterface Type of interface to return.
|
||||
|
||||
@@ -546,10 +546,10 @@ namespace sdv
|
||||
if (m_ptrValue) m_ptrValue->Receive(anyVal);
|
||||
}
|
||||
|
||||
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
|
||||
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
|
||||
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding an receive subscription.
|
||||
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of a callback function.
|
||||
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
|
||||
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
|
||||
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding a subscription.
|
||||
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of callback func.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
1010
export/support/simple_toml.h
Normal file
1010
export/support/simple_toml.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,12 +11,14 @@
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SDV_CONFIG_H
|
||||
#define SDV_CONFIG_H
|
||||
#ifndef SDV_TOML_H
|
||||
#define SDV_TOML_H
|
||||
|
||||
#include <charconv>
|
||||
#include "../interfaces/toml.h"
|
||||
#include "interface_ptr.h"
|
||||
#include "local_service_access.h"
|
||||
#include "interface_ptr.h"
|
||||
|
||||
namespace sdv::toml
|
||||
{
|
||||
@@ -82,6 +84,18 @@ namespace sdv::toml
|
||||
*/
|
||||
ENodeType GetType() const;
|
||||
|
||||
/**
|
||||
* @brief Get the index of this node within the parent collection.
|
||||
* @return The index of the node within the parent collection node or npos when no parent is available.
|
||||
*/
|
||||
uint32_t GetIndex() const;
|
||||
|
||||
/**
|
||||
* @brief Is the node defined as inline node?
|
||||
* @return The inline flag.
|
||||
*/
|
||||
bool IsInline() const;
|
||||
|
||||
/**
|
||||
* @brief Return any associated comment text for this node.
|
||||
* @return The node comment or an empty string when there is not comment for this node.
|
||||
@@ -132,6 +146,12 @@ namespace sdv::toml
|
||||
*/
|
||||
virtual void Clear();
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically, remove redundant whitespace.
|
||||
* @param[in] bRemoveComments When set, the comments are removed from the node.
|
||||
*/
|
||||
void AutomaticFormat(bool bRemoveComments);
|
||||
|
||||
/**
|
||||
* @brief Get the TOML string from this node including all children.
|
||||
* @return The TOML string.
|
||||
@@ -228,23 +248,29 @@ namespace sdv::toml
|
||||
*/
|
||||
CNode GetDirect(const sdv::u8string& rssNode) const;
|
||||
|
||||
/**
|
||||
* @brief Return the node name for a node in the collection. If the collection is an array, provides the index between
|
||||
* square brackets.
|
||||
* @param[in] nIndex Index to return the node name for.
|
||||
* @return Name of the node or an empty string if the index is larger than the amount of nodes in the collection.
|
||||
*/
|
||||
std::string GetNodeNameByIndex(size_t nIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Insert a value node before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
|
||||
* Otherwise the name must be unique within this collection.
|
||||
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
|
||||
* @return Returns the node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNode InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue);
|
||||
CNode InsertValue(const std::string& rssInsertBefore, const std::string& rssName, const sdv::any_t& ranyValue);
|
||||
|
||||
/**
|
||||
* @brief Add a value node to the collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
|
||||
@@ -254,20 +280,18 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert an array collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
|
||||
* Otherwise the name must be unique within this collection.
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNodeCollection InsertArray(size_t nIndex, const std::string& rssName);
|
||||
CNodeCollection InsertArray(const std::string& rssInsertBefore, const std::string& rssName);
|
||||
|
||||
/**
|
||||
* @brief Add an array collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @return Returns the collection node when successfully added or an empty node when not.
|
||||
@@ -276,22 +300,20 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert a table collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
|
||||
* case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
* as inline collection if the this collection is also inline, as standard when not.
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNodeCollection InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
|
||||
CNodeCollection InsertTable(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
|
||||
|
||||
/**
|
||||
* @brief Add a table collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
@@ -302,12 +324,12 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert a table array collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
|
||||
* if not existing already, and adding a table to the array.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
|
||||
* which case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
@@ -315,12 +337,10 @@ namespace sdv::toml
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not. The collection node represents
|
||||
* a table collection.
|
||||
*/
|
||||
CNodeCollection InsertTableArray(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
|
||||
CNodeCollection InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
|
||||
|
||||
/**
|
||||
* @brief Add a table array collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
|
||||
* if not existing already, and adding a table to the array.
|
||||
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
|
||||
@@ -335,10 +355,10 @@ namespace sdv::toml
|
||||
/**
|
||||
* @brief Insert a TOML string to the collection. All nodes specified in the TOML will be added in the collection except
|
||||
* when the nodes already exist. Comment and whitespace are preserved when possible.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
|
||||
* might be transferred to inline or they might be inserted at a different location.
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssTOML Reference to the TOML string containing the nodes. The TOML string can be empty, which is not an
|
||||
* error. If required the TOML nodes are converted to inline nodes.
|
||||
* @param[in] bAllowPartial When set, duplicate nodes (already present in this collection) will be ignored and do not
|
||||
@@ -346,7 +366,7 @@ namespace sdv::toml
|
||||
* @return Returns 1 if the complete TOMl could be inserted, 0 if no TOML could be inserted or -1 when the TOML could be
|
||||
* partially inserted.
|
||||
*/
|
||||
int InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial = false);
|
||||
int InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML, bool bAllowPartial = false);
|
||||
|
||||
/**
|
||||
* @brief Add a TOML string to this collection. All nodes specified in the TOML will be added in the collection except
|
||||
@@ -372,16 +392,11 @@ namespace sdv::toml
|
||||
class CTOMLParser : public CNodeCollection
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
CTOMLParser() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor providing automatic processing.
|
||||
* @param[in] rssConfig Reference to the configuration.
|
||||
*/
|
||||
CTOMLParser(const std::string& rssConfig);
|
||||
CTOMLParser(const std::string& rssConfig = "");
|
||||
|
||||
/**
|
||||
* @brief Process a configuration. This will clear any previous configuration.
|
||||
@@ -414,6 +429,52 @@ namespace sdv::toml
|
||||
ITOMLParser* m_pParser = nullptr; ///< Pointer to the parser interface.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare flags
|
||||
*/
|
||||
enum class ECompareFlags : uint32_t
|
||||
{
|
||||
compare_ignore_whitespace = 1, ///< Compare, but ignore whitespace
|
||||
compare_ignore_comments = 2, ///< Compare, but ignore comments
|
||||
compare_ignore_inline = 8, ///< Compare, but ignore inline or explicit
|
||||
compare_ignore_all = 255, ///< Compare with all ignore flags
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare result
|
||||
*/
|
||||
enum class ECompareResult : int32_t
|
||||
{
|
||||
compare_identical = 0, ///< The comparison resulted into identical TOML strings
|
||||
compare_different = 1, ///< The comparison resulted into different TOML strings
|
||||
compare_error = -1 ///< The comparison could not be done due to a failure
|
||||
};
|
||||
|
||||
/// Internal namespace
|
||||
namespace internal
|
||||
{
|
||||
/**
|
||||
* @brief Compare the content of the node with the content of another node.
|
||||
* @attention This function changes the nodes dependable on the provided flags.
|
||||
* @param[in] rnode1 First node interface to compare with the second node.
|
||||
* @param[in] rnode2 Second node interface to compare with the first node.
|
||||
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
|
||||
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
|
||||
} // namespace internal;
|
||||
|
||||
/**
|
||||
* @brief Compare the content of TOML string with the content of another TOML string.
|
||||
* @param[in] rssToml1 Reference to the first TOML string to compare with the second TOML string.
|
||||
* @param[in] rssToml2 Reference to the second TOML string to compare with the first TOML string.
|
||||
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
|
||||
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
|
||||
|
||||
inline CNode::CNode(const TInterfaceAccessPtr& rptrNode)
|
||||
{
|
||||
m_pNodeInfo = rptrNode.GetInterface<INodeInfo>();
|
||||
@@ -461,6 +522,16 @@ namespace sdv::toml
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetType() : ENodeType::node_invalid;
|
||||
}
|
||||
|
||||
inline uint32_t CNode::GetIndex() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetIndex() : npos;
|
||||
}
|
||||
|
||||
inline bool CNode::IsInline() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->IsInline() : true;
|
||||
}
|
||||
|
||||
inline std::string CNode::GetComment() const
|
||||
{
|
||||
if (!m_pNodeInfo) return {};
|
||||
@@ -527,7 +598,9 @@ namespace sdv::toml
|
||||
{
|
||||
INodeUpdate* pNodeUpdate = m_ptrNode.GetInterface<INodeUpdate>();
|
||||
if (!pNodeUpdate) return false;
|
||||
return pNodeUpdate->DeleteNode();
|
||||
bool bRet = pNodeUpdate->DeleteNode();
|
||||
Clear(); // Not valid any more.
|
||||
return bRet;
|
||||
}
|
||||
|
||||
inline void CNode::Clear()
|
||||
@@ -536,6 +609,11 @@ namespace sdv::toml
|
||||
m_pNodeInfo = nullptr;
|
||||
}
|
||||
|
||||
inline void CNode::AutomaticFormat(bool bRemoveComments)
|
||||
{
|
||||
if (m_pNodeInfo) m_pNodeInfo->AutomaticFormat(bRemoveComments);
|
||||
}
|
||||
|
||||
inline sdv::u8string CNode::GetTOML() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetTOML() : sdv::u8string();
|
||||
@@ -605,76 +683,86 @@ namespace sdv::toml
|
||||
return m_pCollection ? CNode(m_pCollection->GetNodeDirect(rssNode)) : CNode();
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue)
|
||||
inline std::string CNodeCollection::GetNodeNameByIndex(size_t nIndex) const
|
||||
{
|
||||
if (!m_pCollection) return {};
|
||||
if (nIndex >= m_pCollection->GetCount()) return {};
|
||||
if (GetType() == ENodeType::node_array) return "[" + std::to_string(nIndex) + "]";
|
||||
TInterfaceAccessPtr ptrNode = m_pCollection->GetNode(static_cast<uint32_t>(nIndex));
|
||||
const auto* pAccess = ptrNode.GetInterface<INodeInfo>();
|
||||
if (!pAccess) return {};
|
||||
return pAccess->GetName();
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::InsertValue(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
const sdv::any_t& ranyValue)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNode(pInsert->InsertValue(static_cast<uint32_t>(nIndex), rssName, ranyValue));
|
||||
return CNode(pInsert->InsertValue(rssInsertBefore, rssName, ranyValue));
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::AddValue(const std::string& rssName, const sdv::any_t& ranyValue)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNode(pInsert->InsertValue(npos, rssName, ranyValue));
|
||||
return CNode(pInsert->InsertValue("", rssName, ranyValue));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertArray(size_t nIndex, const std::string& rssName)
|
||||
inline CNodeCollection CNodeCollection::InsertArray(const std::string& rssInsertBefore, const std::string& rssName)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertArray(static_cast<uint32_t>(nIndex), rssName));
|
||||
return CNodeCollection(pInsert->InsertArray(rssInsertBefore, rssName));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddArray(const std::string& rssName)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertArray(npos, rssName));
|
||||
return CNodeCollection(pInsert->InsertArray("", rssName));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
inline CNodeCollection CNodeCollection::InsertTable(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTable(static_cast<uint32_t>(nIndex), rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTable(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddTable(const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTable(npos, rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTable("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertTableArray(size_t nIndex, const std::string& rssName,
|
||||
inline CNodeCollection CNodeCollection::InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTableArray(static_cast<uint32_t>(nIndex), rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTableArray(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddTableArray(const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTableArray(npos, rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTableArray("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline int CNodeCollection::InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial /*= false*/)
|
||||
inline int CNodeCollection::InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML,
|
||||
bool bAllowPartial /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return 0;
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(static_cast<uint32_t>(nIndex), rssTOML, !bAllowPartial);
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(rssInsertBefore, rssTOML, !bAllowPartial);
|
||||
switch (eRet)
|
||||
{
|
||||
case INodeCollectionInsert::EInsertResult::insert_success:
|
||||
@@ -691,7 +779,7 @@ namespace sdv::toml
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return 0;
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(npos, rssTOML, !bAllowPartial);
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML("", rssTOML, !bAllowPartial);
|
||||
switch (eRet)
|
||||
{
|
||||
case INodeCollectionInsert::EInsertResult::insert_success:
|
||||
@@ -746,6 +834,59 @@ namespace sdv::toml
|
||||
m_ptrParserUtil.Clear();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
inline ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
|
||||
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
|
||||
{
|
||||
if (!rnode1 || !rnode2) return ECompareResult::compare_error;
|
||||
|
||||
// Format the nodes when ignore whitespace and/or comments
|
||||
bool bIgnoreComments = uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_comments);
|
||||
bool bIgnoreWhitespace = bIgnoreComments ||
|
||||
(uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_whitespace));
|
||||
if (bIgnoreWhitespace)
|
||||
{
|
||||
INodeInfo* pNodeInfo1 = rnode1.GetInterface().GetInterface<INodeInfo>();
|
||||
if (!pNodeInfo1) return ECompareResult::compare_error;
|
||||
pNodeInfo1->AutomaticFormat(bIgnoreComments);
|
||||
INodeInfo* pNodeInfo2 = rnode2.GetInterface().GetInterface<INodeInfo>();
|
||||
if (!pNodeInfo2) return ECompareResult::compare_error;
|
||||
pNodeInfo2->AutomaticFormat(bIgnoreComments);
|
||||
}
|
||||
|
||||
// Convert to standard if ignoring inline
|
||||
INodeCollectionConvert* pConvert1 = rnode1.GetInterface().GetInterface<INodeCollectionConvert>();
|
||||
INodeCollectionConvert* pConvert2 = rnode2.GetInterface().GetInterface<INodeCollectionConvert>();
|
||||
if (pConvert1 && pConvert2 && uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_inline))
|
||||
{
|
||||
// Making inline nodes as standard, might only change the upper node.
|
||||
// Making standard nodes inline, will have all child nodes be made inline as well, because inline nodes can only
|
||||
// have inline nodes.
|
||||
pConvert1->MakeInline();
|
||||
pConvert2->MakeInline();
|
||||
}
|
||||
|
||||
// Generate the TOMLs and compare
|
||||
return rnode1.GetTOML() == rnode2.GetTOML() ? ECompareResult::compare_identical : ECompareResult::compare_different;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
inline ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
|
||||
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTOMLParser parser1(rssToml1);
|
||||
CTOMLParser parser2(rssToml2);
|
||||
return internal::CompareNodes(parser1, parser2, uiCompareFlags);
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException&)
|
||||
{
|
||||
return ECompareResult::compare_error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !defined SDV_CONFIG_H
|
||||
#endif // !defined SDV_TOML_H
|
||||
Reference in New Issue
Block a user