Program Listing for File environment.h#
↰ Return to documentation for file (sdv_packager\environment.h)
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
#include <string>
#include <vector>
#include <filesystem>
#include <cstdint>
#include <fstream>
#include <functional>
#include "../../global/cmdlnparser/cmdlnparser.h"
#include "../error_msg.h"
#include <interfaces/config.h>
#include "../../sdv_services/core/app_config_file.h"
#include "../../sdv_services/core/toml_parser/parser_toml.h"
#include <support/toml.h>
inline bool ichar_equals(char cLeft, char cRight)
{
return std::tolower(static_cast<unsigned char>(cLeft)) ==
std::tolower(static_cast<unsigned char>(cRight));
}
inline bool iequals(const std::string& rssLeft, const std::string& rssRight)
{
return std::equal(rssLeft.begin(), rssLeft.end(), rssRight.begin(), rssRight.end(), ichar_equals);
}
class CSdvPackagerEnvironment
{
public:
using CComponentVector = std::vector<std::pair<std::string, std::string>>;
struct SEnvironmentException : std::exception
{
SEnvironmentException(int nCodeParam, const std::string& rssDescriptionParam) :
nCode(nCodeParam), ssDescription(rssDescriptionParam)
{}
virtual const char* what() const noexcept
{
return ssDescription.c_str();
}
int nCode = 0;
std::string ssDescription;
};
enum class EOperatingMode
{
none,
pack,
install,
direct_install,
configure,
uninstall,
verify,
show,
};
enum class EShowMask
{
all = 0x00ff,
info = 0x0001,
modules = 0x0010,
components = 0x0020,
console = 0x01000000,
console_simple = 0x03000000,
xml = 0x10000000,
json = 0x20000000,
};
struct SVersion
{
size_t nMajor = 0;
size_t nMinor = 0;
size_t nPatch = 0;
};
struct SModule
{
std::string ssSearchString;
std::filesystem::path pathRelTarget;
};
CSdvPackagerEnvironment();
CSdvPackagerEnvironment(const std::vector<std::string>& rvecArgs);
template <typename TCharType>
CSdvPackagerEnvironment(size_t nArgs, const TCharType** rgszArgs);
bool Help() const;
void ShowHelp() const;
void ReportInfo() const;
bool Silent() const;
bool Verbose() const;
bool Version() const;
bool CreateManifestOnly() const;
EOperatingMode OperatingMode() const;
bool KeepStructure() const;
const std::vector<SModule>& ModuleList() const;
const std::vector<std::string>& ConfigFileList() const;
const std::filesystem::path& PackagePath() const;
const std::filesystem::path& SourceLocation() const;
const std::filesystem::path& OutputLocation() const;
const std::filesystem::path& TargetLocation() const;
const std::filesystem::path& RootLocation() const;
const std::filesystem::path& InstallLocation() const;
bool Local() const;
uint32_t InstanceID() const;
bool Update() const;
bool Overwrite() const;
const std::filesystem::path& LocalConfigFile(CComponentVector& rvecComponents) const;
const std::vector<std::filesystem::path>& LocalConfigLocations() const;
bool InsertIntoUserConfig(CComponentVector& rvecComponents) const;
bool InsertIntoPlatformConfig(CComponentVector& rvecComponents) const;
bool InsertIntoVehicleInterfaceConfig(CComponentVector& rvecComponents) const;
bool InsertIntoVehicleAbstractionConfig(CComponentVector& rvecComponents) const;
const TParameterVector& ObjectParameters(const std::string& rssObjectInstance) const;
const std::string& InstallName() const;
const std::string& ProductName() const;
const std::string& Description() const;
const std::string& Author() const;
const std::string& Address() const;
const std::string& Copyrights() const;
const std::string& PackageVersion() const;
uint32_t ShowFlags() const;
bool CheckShowFlag(EShowMask eMask) const;
int Error() const;
const std::string& ArgError() const;
private:
void SplitConfigString(const std::string& rssInput, std::filesystem::path& rpath, CComponentVector& rvecComponents);
bool ProcessCommandLine(const std::vector<std::string>& rvecCommands);
CCommandLine m_cmdln;
bool m_bHelp = false;
bool m_bSilent = false;
bool m_bVerbose = false;
bool m_bVersion = false;
bool m_bKeepStructure = false;
bool m_bCreateManifestOnly = false;
bool m_bLocal = false;
bool m_bUpdate = false;
bool m_bOverwrite = false;
EOperatingMode m_eOperatingMode = EOperatingMode::none;
std::vector<SModule> m_vecModules;
std::vector<std::string> m_vecConfigFiles;
std::filesystem::path m_pathSourceLocation;
std::filesystem::path m_pathOutputLocation;
std::filesystem::path m_pathTargetLocation;
std::filesystem::path m_pathRootLocation;
std::filesystem::path m_pathInstallLocation;
std::filesystem::path m_pathPackage;
uint32_t m_uiInstanceID = 1000u;
std::string m_ssInstallName;
std::string m_ssProductName;
std::string m_ssDescription;
std::string m_ssAuthor;
std::string m_ssAddress;
std::string m_ssCopyrights;
std::string m_ssPackageVersion;
std::filesystem::path m_pathConfigLocal;
CComponentVector m_vecConfigLocalComponents;
std::vector<std::filesystem::path> m_vecLocalConfigDirs;
CComponentVector m_vecUserConfigComponents;
CComponentVector m_vecPlatformConfigComponents;
CComponentVector m_vecVehIfcConfigComponents;
CComponentVector m_vecVehAbstrConfigComponents;
std::map<std::string, TParameterVector> m_mapParameters;
bool m_bInsertIntoUserConfig = false;
bool m_bInsertIntoPlatformConfig = false;
bool m_bInsertIntoVehIfcConfig = false;
bool m_bInsertIntoVehAbstrConfig = false;
uint32_t m_uiShowFlags = 0;
int m_nError = NO_ERROR;
std::string m_ssArgError;
};
template <typename TCharType>
CSdvPackagerEnvironment::CSdvPackagerEnvironment(size_t nArgs, const TCharType** rgszArgs) :
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
{
m_cmdln.PrintMaxWidth(80);
m_cmdln.PrintSyntax(false);
try
{
std::vector<std::string> vecCommands;
// COMMANDS (selective argument groups 1-7):
// PACK Pack modules and files into an installation package.
// Usage: sdv_packager PACK <package name> <files> <options>
// INSTALL Install a package into the system.
// Usage: sdv_packager INSTALL <package path> <options>
// DIRECT_INSTALL Directly install modules and files into the system (without the creation of a package).
// Usage: sdv_packager DIRECT_INSTALL <package name> <files> <options>
// CONFIGURE Install a configuration into the system.
// Usage: sdv_packager CONFIGURE <config files> <options>
// UNINSTALL Remove an installation from the system.
// Usage: sdv_packager UNINSTALL <package name> <options>
// VERIFY Verify the consistency and the integrity of an installation package.
// Usage: sdv_packager VERIFY <package path> <options>
// SHOW Show package information.
// Usage: sdv_packager SHOW <ALL|INFO|MODULES|COMPONENTS> <package path> <options>
m_cmdln.DefineDefaultArgument(vecCommands, "COMMAND <...> <options>");
// ARGUMENT SELECTION GROUP #0 - General options:
// -?, --help Show help
// -s, --silent Silent mode
// -v, --verbose Verbose mode
// --version Show version
auto& rArgHelpDef = m_cmdln.DefineOption("?", m_bHelp, "Show help", true, 0, 1, 2, 3, 4, 5, 6, 7);
rArgHelpDef.AddSubOptionName("help");
auto& rArgSilentDef = m_cmdln.DefineOption("s", m_bSilent, "Do not show any information on STDOUT. Not compatible with "
"'--verbose'.");
rArgSilentDef.AddSubOptionName("silent");
auto& rArgVerboseDef = m_cmdln.DefineOption("v", m_bVerbose, "Provide verbose information. Not compatible with "
"'--silent'.");
rArgVerboseDef.AddSubOptionName("verbose");
m_cmdln.DefineSubOption("version", m_bVersion, "Show version information.");
// ARGUMENT SELECTION GROUP #2 & #3, #4 & #5: General options during installation/uninstallation
// -L, --local Local installation
// --instance<id> Instance ID to use for installation
auto& rLocalArgDef = m_cmdln.DefineOption("L", m_bLocal, "Target the local system.", true, 2, 3, 4, 5);
rLocalArgDef.AddSubOptionName("local");
auto& rInstance = m_cmdln.DefineSubOption("instance", m_uiInstanceID, "The instance ID of the SDV server instance when not "
"targeting the local system (default ID is 1000).", true, 2, 3, 4, 5);
// ARGUMENT SELECTION GROUP #1 - Packing:
// -O<path> Optional destination location
// --signature<path> Path to the file to use to sign the package (not implemented yet)
m_cmdln.DefineGroup("Package creation");
m_cmdln.DefineOption("O", m_pathOutputLocation, "The output location (optional, default is current directory).", true, 1);
// ARGUMENT SECLECTION GROUP #1 & #3 - Packing and direct installation:
// -I<path> Optional source location
// --keep_structure Maintain original directory structure
// --create_manifest_only Create a manifest file only
// --set_product<string> Set the product name (if not identical to installation name).
// --set_description<string> Set the package description
// --set_author<string> Set author string
// --set_address<string> Set address string (multi-line)
// --set_copyright<string> Set copyright string
// --set_version<string> Set product version string (also use for updates).
m_cmdln.DefineOption("I", m_pathSourceLocation, "The source location (optional, default is current directory).", true,
1, 3);
m_cmdln.DefineSubOption("keep_structure", m_bKeepStructure, "Maintain the directory structure within the package. In "
"combination with the source location (current directory or directory provided by '-I' option).", true, 1, 3);
m_cmdln.DefineSubOption("create_manifest_only", m_bCreateManifestOnly, "Create manifest, but does not copy module files "
"from specified location. If provided, the manifest will be stored in the output directory (current directory or "
"directory provided by '-O' option).", true, 1);
m_cmdln.DefineSubOption("set_product", m_ssProductName, "Set the product name (default is package name).", true, 1, 3);
m_cmdln.DefineSubOption("set_description", m_ssDescription, "Set the package description.", true, 1, 3);
m_cmdln.DefineSubOption("set_author", m_ssAuthor, "Set author name.", true, 1, 3);
m_cmdln.DefineSubOption("set_address", m_ssAddress, "Set author address information.", true, 1, 3);
m_cmdln.DefineSubOption("set_copyright", m_ssCopyrights, "Set copyright information.", true, 1, 3);
m_cmdln.DefineSubOption("set_version", m_ssPackageVersion, "Set package version (needed to allow updates).", true, 1, 3);
// ARGUMENT SELECTION GROUP #2 & #3 & #5- Installation from package and direct installation:
// -T<path> Optional target location
// -P, --update Use update if a previous package with older version has been found
// -W, --overwrite Use overwrite if a previous package has been found
// --verify_signed Verify whether the package is signed and if not return an error (not implemented)
m_cmdln.DefineGroup("Installation / uninstallation");
auto& rTargetLoc = m_cmdln.DefineOption("T", m_pathTargetLocation, "The target location for package installation. For "
"server based installations, this is the root location containing the instance ID sub-directories with the "
"installations. For local installations, this is the real target directory for installing the content.",
true, 2, 3, 5);
auto& rArgDefUpdate = m_cmdln.DefineOption("P", m_bUpdate, "Update the installation if an older version is existing.",
true, 2, 3);
rArgDefUpdate.AddSubOptionName("update");
auto& rArgDefOverwrite = m_cmdln.DefineOption("W", m_bOverwrite, "Overwrite the installation if an installation is "
"existing (regardless of the installed version).", true, 2, 3);
rArgDefOverwrite.AddSubOptionName("overwrite");
// Configuration
// ARGUMENT SELECTION GROUP #2 & #3, #4 & #5 - Update from package and directly and uninstallation:
// --config_dir<paths...> Local instance only; directory to configuration files to update.
m_cmdln.DefineGroup("Configuration update");
auto& rConfigDir = m_cmdln.DefineSubOption("config_dir", m_vecLocalConfigDirs, "One or more configuration directories "
"to scan for components being updated. Use with local systems only ('--local' option).", true, 2, 3, 4, 5);
// --config_file<path>[+component[=name]+....]] Local instance only; configuration file.
// --user_config[+component[=name]+....]] Server instance only; user configuration.
// --platform_config[+component[=name]+....]] Server instance only; platform config.
// --interface_config[+component[=name]+....]] Server instance only; vehicle interface config.
// --abstract_config[+component[=name]+....]] Server instance only; vehicle abstraction config.
std::string ssConfigFileLocal;
auto& rConfigFile = m_cmdln.DefineSubOption("config_file", ssConfigFileLocal, "Update a user configuration file. For "
"usage, see explanatory text above. Use with local systems only ('--local' option).", true, 2, 3);
std::string ssUserConfigServer, ssPlatformConfigServer, ssInterfaceConfigServer, ssAbstrConfigServer;
auto& rPlatformConfig = m_cmdln.DefineSubOption("platform_config", ssPlatformConfigServer, "Update the platform "
"configuration defining which components of this installation are used to interact with the hardware platform. For "
"usage, see explanatory text above. Use on server only.", true, 2, 3);
auto& rInterfaceConfig = m_cmdln.DefineSubOption("interface_config", ssInterfaceConfigServer, "Update the vehicle "
"interface configuration defining which components of this installation represent the vehicle interface. For usage, "
"see explanatory text above. Use on server only.", true, 2, 3);
auto& rAbstrConfig = m_cmdln.DefineSubOption("abstract_config", ssAbstrConfigServer, "Update the vehicle abstraction "
"configuration defining which components of this installation represent an abstracted vehicle to the application "
"components. For usage, see explanatory text above. Use on server only.", true, 2, 3);
auto& rUserConfig = m_cmdln.DefineSubOption("user_config", ssUserConfigServer, "Update the user configuration defining "
"which components of this installation need to be instantiated automatically. User configuration can only contain "
"complex services. For usage, see explanatory text above. Use on server only.", true, 2, 3);
m_cmdln.DefineSubOption("config_file", m_pathConfigLocal, "Update a user configuration file. usage, see explanatory text "
"above. Use with local systems only ('--local' option).", true, 4);
m_cmdln.DefineSubOption("platform_config", m_bInsertIntoPlatformConfig, "Update the platform "
"configuration defining which components of this installation are used to interact with the hardware platform. Use "
"on server only.", true, 4);
m_cmdln.DefineSubOption("interface_config", m_bInsertIntoVehIfcConfig, "Update the vehicle "
"interface configuration defining which components of this installation represent the vehicle interface. Use on server "
"only.", true, 4);
m_cmdln.DefineSubOption("abstract_config", m_bInsertIntoVehAbstrConfig, "Update the vehicle abstraction "
"configuration defining which components of this installation represent an abstracted vehicle to the application "
"components. Use on server only.", true, 4);
m_cmdln.DefineSubOption("user_config", m_bInsertIntoUserConfig, "Update the user configuration defining "
"which components of this installation need to be instantiated automatically. User configuration can only contain "
"complex services. Use on server only.", true, 4);
// --parameters<component_name>:<param>=<value>[,<param>=<value>...] Parameters for an added component.
// --param_file<TOML_file> Parameters from a file for an added component.
std::vector<std::string> vecParametersRaw;
m_cmdln.DefineSubOption("parameters", vecParametersRaw, "Parameters for a component instance. For usage, see explanatory "
"text above.", true, 2, 3);
std::vector<std::filesystem::path> vecParamFiles;
m_cmdln.DefineSubOption("param_file", vecParamFiles, "Parameters for one or more component instances located in a "
"parameter TOML file. For usage, see explanatory text above.", true, 2, 3);
// ARGUMENT SELECTION GROUP #6 - Package verififcation
m_cmdln.DefineGroup("Verification options");
// --verify_signed Verify whether the package is signed and if not return an error (not implemented)
// ARGUMENT SELECTION GROUP #7 - Show package information
// --show_simple
// --xml (not implemented)
// --json (not implemented)
m_cmdln.DefineGroup("Show options");
bool bShowSimple = false;
m_cmdln.DefineSubOption("show_simple", bShowSimple, "Show package information in simple format.", true, 7);
m_cmdln.Parse(static_cast<size_t>(nArgs), rgszArgs);
// Process the command line
if (!ProcessCommandLine(vecCommands)) return;
// Update show mask
if (bShowSimple)
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::console_simple);
else // TODO: if not XML and JSON, add console
m_uiShowFlags |= static_cast<uint32_t>(EShowMask::console);
// Split the configuration strings, unless in CONFIGURE mode
if (!ssConfigFileLocal.empty())
SplitConfigString(ssConfigFileLocal, m_pathConfigLocal, m_vecConfigLocalComponents);
if (rUserConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoUserConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssUserConfigServer, rpathTemp, m_vecUserConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rPlatformConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoPlatformConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssPlatformConfigServer, rpathTemp, m_vecPlatformConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rInterfaceConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoVehIfcConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssInterfaceConfigServer, rpathTemp, m_vecVehIfcConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
if (rAbstrConfig.OptionAvailableOnCommandLine())
{
m_bInsertIntoVehAbstrConfig = true;
std::filesystem::path rpathTemp;
SplitConfigString(ssAbstrConfigServer, rpathTemp, m_vecVehAbstrConfigComponents);
if (!rpathTemp.empty())
{
m_nError = CMDLN_INVALID_CONFIG_STRING;
m_ssArgError = CMDLN_INVALID_CONFIG_STRING_MSG;
return;
}
}
// Check for the local flag and if set, this is not compatible to server options.
// Also if not set, local options are not allowed.
if (m_bLocal)
{
if (rInstance.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The option '--instance' cannot be used with with local installations ('--local' option).";
return;
}
if (rUserConfig.OptionAvailableOnCommandLine() || rPlatformConfig.OptionAvailableOnCommandLine() ||
rInterfaceConfig.OptionAvailableOnCommandLine() || rAbstrConfig.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration options '--user_config', '--platform_config', '--interface_config' and "
"'--abstract_config' cannot be used with with local installations ('--local' option).";
return;
}
if (!rTargetLoc.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_TARGET_LOCATION_ERROR;
m_ssArgError = "The target location option '-T' must be used when specifying local installations ('--local' "
"option).";
return;
}
} else
{
if (rConfigFile.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration file option '--config_path' can only be used with with local installations "
"('--local' option).";
return;
}
if (rConfigDir.OptionAvailableOnCommandLine())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = "The configuration file option '--config_dir' can only be used with with local installations "
"('--local' option).";
return;
}
}
// Add a parameter to the current instance. If the parameter is already present, the parameter will not be overwritten.
auto itInstance = m_mapParameters.end();
auto fnAddParameter = [&](const std::string& rssObjectInstance, const std::string& rssKey,
const sdv::any_t& rany) -> bool
{
if (itInstance == m_mapParameters.end() || itInstance->first != rssObjectInstance)
{
// Find or create the instance
itInstance = m_mapParameters.find(rssObjectInstance);
if (itInstance == m_mapParameters.end())
{
auto prInsert = m_mapParameters.emplace(rssObjectInstance, std::vector<std::pair<std::string, sdv::any_t>>());
if (!prInsert.second || prInsert.first == m_mapParameters.end())
return false;
itInstance = prInsert.first;
}
}
if (itInstance == m_mapParameters.end()) return false;
// Check for the existence
if (std::find_if(itInstance->second.begin(), itInstance->second.end(), [&](const auto& prParameter)
{ return prParameter.first == rssKey; }) != itInstance->second.end()) return true; // Not an error...
// Add the parameter
itInstance->second.push_back(std::make_pair(rssKey, rany));
return true;
};
// Parameters are only valid when a configuration is supplied.
if (!vecParametersRaw.empty() || !vecParamFiles.empty())
{
// Parameters can only be added when a configuration is created.
if (!m_bInsertIntoUserConfig && !m_bInsertIntoPlatformConfig && !m_bInsertIntoVehIfcConfig
&& !m_bInsertIntoVehAbstrConfig && ssConfigFileLocal.empty())
{
m_nError = CMDLN_INCOMPATIBLE_ARGUMENTS;
m_ssArgError = CMDLN_INCOMPATIBLE_ARGUMENTS_MSG;
return;
}
}
// Process command line parameters
// The list of raw parameters are started with a component instance, followed by parameters.
std::string ssInstance;
for (const std::string& rssParameterRaw : vecParametersRaw)
{
size_t nInstanceSep = rssParameterRaw.find_first_of(':');
if (nInstanceSep == std::string::npos)
nInstanceSep = 0;
else
{
ssInstance = rssParameterRaw.substr(0, nInstanceSep);
++nInstanceSep;
}
size_t nAssignment = rssParameterRaw.find_first_of('=', nInstanceSep);
if (nAssignment == nInstanceSep || nAssignment == std::string::npos)
{
m_nError = CMDLN_INVALID_PARAM_STRING;
m_ssArgError = CMDLN_INVALID_PARAM_STRING_MSG;
return;
}
std::string ssParamName = rssParameterRaw.substr(nInstanceSep, nAssignment - nInstanceSep);
std::string ssParamValue = rssParameterRaw.substr(nAssignment + 1);
if (ssParamName.empty()) // An empty name is not allowed. An empty value is allowed.
{
m_nError = CMDLN_INVALID_PARAM_STRING;
m_ssArgError = CMDLN_INVALID_PARAM_STRING_MSG;
return;
}
// Add the parameter to the instance in the map.
sdv::any_t anyValue;
if (!ssParamValue.empty()) anyValue = ssParamValue;
if (!fnAddParameter(ssInstance, ssParamName, anyValue))
{
m_nError = CMDLN_INVALID_PARAM_STRING;
m_ssArgError = CMDLN_INVALID_PARAM_STRING_MSG;
return;
}
}
// Process parameter files
for (std::filesystem::path& rpathParamFile : vecParamFiles)
{
try
{
// Load the file
std::ifstream fstream(rpathParamFile);
if (!fstream.is_open())
{
m_nError = CMDLN_INVALID_PARAM_FILE;
m_ssArgError = CMDLN_INVALID_PARAM_FILE_MSG;
return;
}
std::string ssContent((std::istreambuf_iterator<char>(fstream)), std::istreambuf_iterator<char>());
fstream.close();
// Split the parameter path from the object instance.
auto fnSplit = [](const std::string& rssNodePath) -> std::pair<std::string, std::string>
{
size_t nSeparator = rssNodePath.find_first_of('.');
if (nSeparator == std::string::npos)
return std::make_pair(rssNodePath, std::string());
return std::make_pair(rssNodePath.substr(0, nSeparator), rssNodePath.substr(nSeparator + 1));
};
// Parse the file
toml_parser::CParser parser(ssContent);
sdv::toml::CNodeCollection root(&parser.Root());
// Lambda function to iterative add parameters
std::function<void(const sdv::toml::CNodeCollection&)> fnProcessObjectInstance =
[&](const sdv::toml::CNodeCollection& rTable)
{
for (size_t nNodeIndex = 0; nNodeIndex < rTable.GetCount(); nNodeIndex++)
{
sdv::toml::CNode node = rTable.Get(nNodeIndex);
switch (node.GetType())
{
case sdv::toml::ENodeType::node_boolean:
case sdv::toml::ENodeType::node_integer:
case sdv::toml::ENodeType::node_floating_point:
case sdv::toml::ENodeType::node_string:
{
auto prParameter = fnSplit(node.GetQualifiedPath());
if (!prParameter.first.empty() && !prParameter.second.empty())
fnAddParameter(prParameter.first, prParameter.second, node.GetValue());
}
break;
case sdv::toml::ENodeType::node_table:
{
sdv::toml::CNodeCollection group(node);
if (!group.IsValid())
break;
fnProcessObjectInstance(group);
}
break;
default:
// Ignore...
break;
}
}
};
fnProcessObjectInstance(root);
}
catch (const sdv::toml::XTOMLParseException& /*rxExcept*/)
{
m_nError = CMDLN_INVALID_PARAM_FILE;
m_ssArgError = CMDLN_INVALID_PARAM_FILE_MSG;
return;
}
}
// Check update and overwrite
if (m_bUpdate && m_bOverwrite)
{
m_nError = CMDLN_UPDATE_OVERWRITE_ERROR;
m_ssArgError = CMDLN_UPDATE_OVERWRITE_ERROR_MSG;
return;
}
} catch (const SArgumentParseException& rsExcept)
{
// If not all fits, but help is requested, this is okay...
// Otherwise throw an environment exception.
if (!m_bHelp)
{
m_nError = CMDLN_ARG_ERR;
m_ssArgError = rsExcept.what();
return;
}
}
}
#endif // !defined ENVIRONMENT_H