From da8cfef49c463644cba7e5c3f998c306432ac0d3 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Fri, 4 Jun 2021 02:20:03 +0200 Subject: [PATCH] Updated include files --- INCLUDE/Hazelnupp.cpp | 187 ++++++++++++++++++++++++++-- INCLUDE/Hazelnupp.h | 274 +++++++++++++++++++++++++----------------- 2 files changed, 344 insertions(+), 117 deletions(-) diff --git a/INCLUDE/Hazelnupp.cpp b/INCLUDE/Hazelnupp.cpp index 89ee463..0f07f8d 100644 --- a/INCLUDE/Hazelnupp.cpp +++ b/INCLUDE/Hazelnupp.cpp @@ -1,6 +1,6 @@ #include "Hazelnupp.h" -/*** FloatValue.cpp ***/ +/*** ../Hazelnupp/FloatValue.cpp ***/ #include @@ -77,7 +77,7 @@ const std::vector& FloatValue::GetList() const } -/*** Hazelnupp.cpp ***/ +/*** ../Hazelnupp/Hazelnupp.cpp ***/ #include #include @@ -133,12 +133,15 @@ void Hazelnupp::Parse(const int argc, const char* const* argv) // Apply constraints such as default values, and required parameters. // Types have already been enforced. - ApplyConstraints(); + // Dont apply constraints when we are just printind the param docs + if ((!catchHelp) || (!HasParam("--help"))) + ApplyConstraints(); } catch (const HazelnuppConstraintTypeMissmatch& hctm) { if (crashOnFail) { + std::cout << GenerateDocumentation() << std::endl; std::cerr << "Fatal error: Command-line parameter value-type mismatch at \"" << hctm.What() << "\"!"; quick_exit(-1009); } @@ -149,6 +152,7 @@ void Hazelnupp::Parse(const int argc, const char* const* argv) { if (crashOnFail) { + std::cout << GenerateDocumentation() << std::endl; std::cerr << "Fatal error: Missing required command-line parameter \"" << hctm.What() << "\"!"; quick_exit(-1010); } @@ -156,6 +160,13 @@ void Hazelnupp::Parse(const int argc, const char* const* argv) throw hctm; // yeet } + // Catch --help parameter + if ((catchHelp) && (HasParam("--help"))) + { + std::cout << GenerateDocumentation() << std::endl; + quick_exit(0); + } + return; } @@ -354,6 +365,162 @@ bool Hazelnupp::GetCrashOnFail() const return crashOnFail; } +void Hazelnupp::SetCatchHelp(bool catchHelp) +{ + this->catchHelp = catchHelp; + return; +} + +bool Hazelnupp::GetCatchHelp() const +{ + return catchHelp; +} + +void Hazelnupp::SetBriefDescription(const std::string& description) +{ + briefDescription = description; + return; +} + +const std::string& Hazelnupp::GetBriefDescription() +{ + return briefDescription; +} + +void Hazelnp::Hazelnupp::RegisterDescription(const std::string& parameter, const std::string& description) +{ + parameterDescriptions[parameter] = description; + return; +} + +const std::string Hazelnp::Hazelnupp::GetDescription(const std::string& parameter) const +{ + // Do we already have a description for this parameter? + const auto par = parameterDescriptions.find(parameter); + if (par == parameterDescriptions.end()) + // No? Then return "" + return ""; + + // We do? Then return it + return par->second; +} + +void Hazelnp::Hazelnupp::ClearDescription(const std::string& parameter) +{ + // This will just do nothing if the entry does not exist + parameterDescriptions.erase(parameter); + return; +} + +std::string Hazelnupp::GenerateDocumentation() const +{ + std::stringstream ss; + + // Add brief, if available + if (briefDescription.length() > 0) + ss << briefDescription << std::endl; + + // Collect parameter information + struct ParamDocEntry + { + std::string abbreviation; + std::string description; + std::string type; + bool required = false; + bool typeIsForced = false; + std::string defaultVal; + }; + std::unordered_map paramInfos; + + // Collect descriptions + for (const auto& it : parameterDescriptions) + { + // Do we already have that param in the paramInfo set? + if (paramInfos.find(it.first) == paramInfos.end()) + // No? Create it. + paramInfos[it.first] = ParamDocEntry(); + + paramInfos[it.first].description = it.second; + } + + // Collect abbreviations + // first value is abbreviation, second is long form + for (const auto& it : abbreviations) + { + // Do we already have that param in the paramInfo set? + if (paramInfos.find(it.second) == paramInfos.end()) + // No? Create it. + paramInfos[it.second] = ParamDocEntry(); + + paramInfos[it.second].abbreviation = it.first; + } + + // Collect constraints + for (const auto& it : constraints) + { + // Do we already have that param in the paramInfo set? + if (paramInfos.find(it.first) == paramInfos.end()) + // No? Create it. + paramInfos[it.first] = ParamDocEntry(); + + ParamDocEntry& cached = paramInfos[it.first]; + cached.required = it.second.required; + cached.typeIsForced = it.second.constrainType; + cached.type = DataTypeToString(it.second.wantedType); + + std::stringstream defaultValueSs; + for (const std::string& s : it.second.defaultValue) + { + defaultValueSs << '\'' << s << '\''; + + // Add a space if we are not at the last entry + if ((void*)&s != (void*)&it.second.defaultValue.back()) + defaultValueSs << " "; + } + cached.defaultVal = defaultValueSs.str(); + } + + // Now generate the documentatino body + if (paramInfos.size() > 0) + { + ss << std::endl + << "==== AVAILABLE PARAMETERS ====" + << std::endl << std::endl; + + for (const auto& it : paramInfos) + { + const ParamDocEntry& pde = it.second; + + // Put name + ss << it.first << " "; + + // Put abbreviation + if (pde.abbreviation.length() > 0) + ss << pde.abbreviation << " "; + + // Put type + if (pde.typeIsForced) + ss << pde.type << " "; + + // Put default value + if (pde.defaultVal.length() > 0) + ss << "default=[" << pde.defaultVal << "] "; + + // Put required tag, but only if no default value + if ((pde.required) && (pde.defaultVal.length() == 0)) + ss << "[[REQUIRED]] "; + + // Put brief description + if (pde.description.length() > 0) + ss << pde.description; + + ss << std::endl << std::endl; + } + } + + return ss.str(); +} + void Hazelnupp::ApplyConstraints() { // Enforce required parameters / default values @@ -468,7 +635,7 @@ const ParamConstraint* Hazelnupp::GetConstraintForKey(const std::string& key) co } -/*** IntValue.cpp ***/ +/*** ../Hazelnupp/IntValue.cpp ***/ #include @@ -545,7 +712,7 @@ const std::vector& IntValue::GetList() const } -/*** ListValue.cpp ***/ +/*** ../Hazelnupp/ListValue.cpp ***/ #include @@ -644,7 +811,7 @@ const std::vector& ListValue::GetList() const } -/*** Parameter.cpp ***/ +/*** ../Hazelnupp/Parameter.cpp ***/ using namespace Hazelnp; @@ -676,7 +843,7 @@ const ::Value* Parameter::GetValue() const } -/*** StringTools.cpp ***/ +/*** ../Hazelnupp/StringTools.cpp ***/ using namespace Hazelnp; @@ -865,7 +1032,7 @@ std::string StringTools::ToLower(const std::string& str) } -/*** StringValue.cpp ***/ +/*** ../Hazelnupp/StringValue.cpp ***/ #include @@ -934,7 +1101,7 @@ const std::vector& StringValue::GetList() const } -/*** Value.cpp ***/ +/*** ../Hazelnupp/Value.cpp ***/ using namespace Hazelnp; @@ -952,7 +1119,7 @@ DATA_TYPE Value::GetDataType() const } -/*** VoidValue.cpp ***/ +/*** ../Hazelnupp/VoidValue.cpp ***/ using namespace Hazelnp; diff --git a/INCLUDE/Hazelnupp.h b/INCLUDE/Hazelnupp.h index 6ab6c05..a04e934 100644 --- a/INCLUDE/Hazelnupp.h +++ b/INCLUDE/Hazelnupp.h @@ -1,6 +1,6 @@ #pragma once -/*** StringTools.h ***/ +/*** ../Hazelnupp/StringTools.h ***/ #include #include @@ -42,7 +42,7 @@ namespace Hazelnp }; } -/*** HazelnuppException.h ***/ +/*** ../Hazelnupp/HazelnuppException.h ***/ #include @@ -112,8 +112,9 @@ namespace Hazelnp }; } -/*** DataType.h ***/ +/*** ../Hazelnupp/DataType.h ***/ +#include namespace Hazelnp { @@ -127,9 +128,32 @@ namespace Hazelnp STRING, LIST }; + + static inline std::string DataTypeToString(DATA_TYPE type) + { + switch (type) + { + case DATA_TYPE::VOID: + return "VOID"; + + case DATA_TYPE::INT: + return "INT"; + + case DATA_TYPE::FLOAT: + return "FLOAT"; + + case DATA_TYPE::STRING: + return "STRING"; + + case DATA_TYPE::LIST: + return "LIST"; + } + + return ""; + } } -/*** ParamConstraint.h ***/ +/*** ../Hazelnupp/ParamConstraint.h ***/ #include #include @@ -198,7 +222,7 @@ namespace Hazelnp }; } -/*** Value.h ***/ +/*** ../Hazelnupp/Value.h ***/ #include #include @@ -249,56 +273,7 @@ namespace Hazelnp }; } -/*** ListValue.h ***/ - -#include - -namespace Hazelnp -{ - /** Specializations for list values (uses std::vector) - */ - class ListValue : public Value - { - public: - ListValue(); - ~ListValue() override; - - //! Will return a deeopopy of this object - Value* Deepcopy() const override; - - //! Will return a string suitable for an std::ostream; - std::string GetAsOsString() const override; - - //! Will add this value to the list - void AddValue(const Value* value); - - //! Will return the raw value - const std::vector& GetValue() const; - - operator std::vector() const; - - //! Throws HazelnuppValueNotConvertibleException - long long int GetInt64() const override; - //! Throws HazelnuppValueNotConvertibleException - int GetInt32() const override; - - //! Throws HazelnuppValueNotConvertibleException - long double GetFloat64() const override; - //! Throws HazelnuppValueNotConvertibleException - double GetFloat32() const override; - - //! Throws HazelnuppValueNotConvertibleException - std::string GetString() const override; - - //! Will return this values list - const std::vector& GetList() const override; - - private: - std::vector value; - }; -} - -/*** VoidValue.h ***/ +/*** ../Hazelnupp/VoidValue.h ***/ namespace Hazelnp @@ -335,7 +310,7 @@ namespace Hazelnp }; } -/*** Parameter.h ***/ +/*** ../Hazelnupp/Parameter.h ***/ #include #include @@ -365,53 +340,7 @@ namespace Hazelnp }; } -/*** StringValue.h ***/ - -#include - -namespace Hazelnp -{ - /** Specializations for string values (uses std::string) - */ - class StringValue : public Value - { - public: - StringValue(const std::string& value); - ~StringValue() override {}; - - //! Will return a deeopopy of this object - Value* Deepcopy() const override; - - //! Will return a string suitable for an std::ostream; - std::string GetAsOsString() const override; - - //! Will return the raw value - const std::string& GetValue() const; - - operator std::string() const; - - //! Throws HazelnuppValueNotConvertibleException - long long int GetInt64() const override; - //! Throws HazelnuppValueNotConvertibleException - int GetInt32() const override; - - //! Throws HazelnuppValueNotConvertibleException - long double GetFloat64() const override; - //! Throws HazelnuppValueNotConvertibleException - double GetFloat32() const override; - - //! Will return this value as a string - std::string GetString() const override; - - //! Throws HazelnuppValueNotConvertibleException - const std::vector& GetList() const override; - - private: - std::string value; - }; -} - -/*** IntValue.h ***/ +/*** ../Hazelnupp/IntValue.h ***/ namespace Hazelnp @@ -458,7 +387,7 @@ namespace Hazelnp }; } -/*** Hazelnupp.h ***/ +/*** ../Hazelnupp/Hazelnupp.h ***/ #include #include @@ -513,6 +442,32 @@ namespace Hazelnp //! Gets whether the application crashes on an exception whilst parsing, and prints to stderr. bool GetCrashOnFail() const; + //! Sets whether the Hazelnupp should automatically catch the --help parameter, print the parameter documentation to stdout, and exit or not. + void SetCatchHelp(bool catchHelp); + + //! Retruns whether the Hazelnupp should automatically catch the --help parameter, print the parameter documentation to stdout, and exit or not. + bool GetCatchHelp() const; + + //! Sets a brief description of the application to be automatically added to the documentation. + void SetBriefDescription(const std::string& description); + + //! Returns the brief description of the application to be automatically added to the documentation. + const std::string& GetBriefDescription(); + + //! Willl register a short description for a parameter. + //! Will overwrite existing descriptions for that parameter. + void RegisterDescription(const std::string& parameter, const std::string& description); + + //! Will return a short description for a parameter, if it exists. + //! Empty string if it does not exist. + const std::string GetDescription(const std::string& parameter) const; + + //! Will delete the description of a parameter if it exists. + void ClearDescription(const std::string& parameter); + + //! Will generate a text-based documentation suited to show the user, for example on --help. + std::string GenerateDocumentation() const; + private: //! Will translate the c-like args to an std::vector void PopulateRawArgs(const int argc, const char* const* argv); @@ -535,20 +490,125 @@ namespace Hazelnp std::string executableName; //! The path of the executable. Always argv[0] std::unordered_map parameters; - // These are abbreviations. Like, -f for --force. + //! These are abbreviations. Like, -f for --force. std::unordered_map abbreviations; - // Parameter constraints, mapped to keys + //! Parameter constraints, mapped to keys std::unordered_map constraints; + //! Raw argv std::vector rawArgs; + //! Short descriptions for parameters + std::unordered_map parameterDescriptions; + + //! A brief description of the application to be added to the generated documentation. Optional. + std::string briefDescription; + + //! If set to true, Hazelnupp will automatically catch the --help parameter, print the parameter documentation to stdout and exit. + bool catchHelp = true; + //! If set to true, Hazelnupp will crash the application with output to stderr when an exception is thrown whilst parsing. bool crashOnFail = true; }; } -/*** FloatValue.h ***/ +/*** ../Hazelnupp/ListValue.h ***/ + +#include + +namespace Hazelnp +{ + /** Specializations for list values (uses std::vector) + */ + class ListValue : public Value + { + public: + ListValue(); + ~ListValue() override; + + //! Will return a deeopopy of this object + Value* Deepcopy() const override; + + //! Will return a string suitable for an std::ostream; + std::string GetAsOsString() const override; + + //! Will add this value to the list + void AddValue(const Value* value); + + //! Will return the raw value + const std::vector& GetValue() const; + + operator std::vector() const; + + //! Throws HazelnuppValueNotConvertibleException + long long int GetInt64() const override; + //! Throws HazelnuppValueNotConvertibleException + int GetInt32() const override; + + //! Throws HazelnuppValueNotConvertibleException + long double GetFloat64() const override; + //! Throws HazelnuppValueNotConvertibleException + double GetFloat32() const override; + + //! Throws HazelnuppValueNotConvertibleException + std::string GetString() const override; + + //! Will return this values list + const std::vector& GetList() const override; + + private: + std::vector value; + }; +} + +/*** ../Hazelnupp/StringValue.h ***/ + +#include + +namespace Hazelnp +{ + /** Specializations for string values (uses std::string) + */ + class StringValue : public Value + { + public: + StringValue(const std::string& value); + ~StringValue() override {}; + + //! Will return a deeopopy of this object + Value* Deepcopy() const override; + + //! Will return a string suitable for an std::ostream; + std::string GetAsOsString() const override; + + //! Will return the raw value + const std::string& GetValue() const; + + operator std::string() const; + + //! Throws HazelnuppValueNotConvertibleException + long long int GetInt64() const override; + //! Throws HazelnuppValueNotConvertibleException + int GetInt32() const override; + + //! Throws HazelnuppValueNotConvertibleException + long double GetFloat64() const override; + //! Throws HazelnuppValueNotConvertibleException + double GetFloat32() const override; + + //! Will return this value as a string + std::string GetString() const override; + + //! Throws HazelnuppValueNotConvertibleException + const std::vector& GetList() const override; + + private: + std::string value; + }; +} + +/*** ../Hazelnupp/FloatValue.h ***/ #include