From 218b75558aa75b07bd22f0884310a6c2e33e78d8 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 30 Jul 2023 11:46:55 +0200 Subject: [PATCH] Core: Add CommandLineParameters --- include/Nazara/Core/CommandLineParameters.hpp | 40 ++++++++++ include/Nazara/Core/CommandLineParameters.inl | 78 +++++++++++++++++++ .../Core/CommandLineParametersTests.cpp | 37 +++++++++ 3 files changed, 155 insertions(+) create mode 100644 include/Nazara/Core/CommandLineParameters.hpp create mode 100644 include/Nazara/Core/CommandLineParameters.inl create mode 100644 tests/UnitTests/Engine/Core/CommandLineParametersTests.cpp diff --git a/include/Nazara/Core/CommandLineParameters.hpp b/include/Nazara/Core/CommandLineParameters.hpp new file mode 100644 index 000000000..9b8e55d84 --- /dev/null +++ b/include/Nazara/Core/CommandLineParameters.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CORE_COMMANDLINEPARAMETERS_HPP +#define NAZARA_CORE_COMMANDLINEPARAMETERS_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class CommandLineParameters + { + public: + inline bool GetParameter(const std::string& name, std::string_view* value) const; + + inline bool HasFlag(const std::string& flag) const; + + inline bool operator==(const CommandLineParameters& params) const; + inline bool operator!=(const CommandLineParameters& params) const; + + static inline CommandLineParameters Parse(int argc, char** argv); + static inline CommandLineParameters Parse(int argc, const Pointer* argv); + + private: + std::unordered_map m_parameters; + std::unordered_set m_flags; + }; +} + +#include + +#endif // NAZARA_CORE_COMMANDLINEPARAMETERS_HPP diff --git a/include/Nazara/Core/CommandLineParameters.inl b/include/Nazara/Core/CommandLineParameters.inl new file mode 100644 index 000000000..ae29adf5e --- /dev/null +++ b/include/Nazara/Core/CommandLineParameters.inl @@ -0,0 +1,78 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline bool CommandLineParameters::GetParameter(const std::string& name, std::string_view* value) const + { + auto it = m_parameters.find(name); + if (it == m_parameters.end()) + return false; + + if (value) + *value = it->second; + + return true; + } + + inline bool CommandLineParameters::HasFlag(const std::string& flag) const + { + return m_flags.find(flag) != m_flags.end(); + } + + inline bool CommandLineParameters::operator==(const CommandLineParameters& params) const + { + return m_flags == params.m_flags && m_parameters == params.m_parameters; + } + + inline bool CommandLineParameters::operator!=(const CommandLineParameters& params) const + { + return !operator==(params); + } + + inline CommandLineParameters CommandLineParameters::Parse(int argc, char** argv) + { + return Parse(argc, const_cast*>(argv)); + } + + inline CommandLineParameters CommandLineParameters::Parse(int argc, const Pointer* argv) + { + CommandLineParameters cmdParams; + + // Parse commandline parameters + for (int i = 1; i < argc; ++i) + { + const char* value = argv[i]; + if (value[0] != '-' || value[1] != '-') + continue; + + std::string_view arg(value + 2); + if (arg.empty()) + continue; + + std::size_t sepIdx = arg.find_first_of(":= "); + std::string_view name = arg.substr(0, sepIdx); + if (sepIdx != arg.npos) + // --param=value | --param:value | "--param value" + cmdParams.m_parameters.emplace(name, arg.substr(sepIdx + 1)); + else if (i < argc - 1) + { + // Check the following parameter to handle --param value + const char* nextValue = argv[i + 1]; + if (value[0] != '-') + cmdParams.m_parameters.emplace(name, nextValue); + else + cmdParams.m_flags.emplace(name); + } + else + cmdParams.m_flags.emplace(name); + } + + return cmdParams; + } +} + +#include diff --git a/tests/UnitTests/Engine/Core/CommandLineParametersTests.cpp b/tests/UnitTests/Engine/Core/CommandLineParametersTests.cpp new file mode 100644 index 000000000..606650b59 --- /dev/null +++ b/tests/UnitTests/Engine/Core/CommandLineParametersTests.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +SCENARIO("CommandLineParameters", "[CORE][CommandLineParameters]") +{ + WHEN("Parsing no parameters") + { + Nz::CommandLineParameters emptyParams; + + const char* appName = "UnitTests"; + Nz::CommandLineParameters commandLineParameters1 = Nz::CommandLineParameters::Parse(0, static_cast(nullptr)); + CHECK(commandLineParameters1 == emptyParams); + CHECK_FALSE(commandLineParameters1 != emptyParams); + Nz::CommandLineParameters commandLineParameters2 = Nz::CommandLineParameters::Parse(1, &appName); + CHECK(commandLineParameters2 == emptyParams); + CHECK_FALSE(commandLineParameters2 != emptyParams); + } + + WHEN("Parsing simple parameters") + { + std::array params = {"exec", "--flag", "--param1=value", "--param2 value2", "ignored"}; + Nz::CommandLineParameters commandLineParameters = Nz::CommandLineParameters::Parse(Nz::SafeCast(params.size()), params.data()); + + std::string_view value; + + CHECK(commandLineParameters.HasFlag("flag")); + CHECK_FALSE(commandLineParameters.HasFlag("ignored")); + CHECK_FALSE(commandLineParameters.GetParameter("param0", nullptr)); + CHECK(commandLineParameters.GetParameter("param1", nullptr)); + CHECK(commandLineParameters.GetParameter("param1", &value)); + CHECK(value == "value"); + CHECK(commandLineParameters.GetParameter("param2", &value)); + CHECK(value == "value2"); + } +}