#pragma once /*** ../Hazelnupp/Placeholders.h ***/ #include namespace Hazelnp { namespace Placeholders { //! The only purpose of this is to provide the ability to return an empty string as an error for std::string& methods. static const std::string g_emptyString; } } /*** ../Hazelnupp/StringTools.h ***/ #include #include #include #include namespace Hazelnp { namespace Internal { /** Internal helper class. Feel free to use it tho. */ class StringTools { public: //! Will return wether or not a given char is in a string static bool Contains(const std::string& str, const char c); //! Will replace a part of a string with another string static std::string Replace(const std::string& str, const char find, const std::string& subst); //! Will replace a part of a string with another string static std::string Replace(const std::string& str, const std::string& find, const std::string& subst); //! Will return true if the given string consists only of digits (including signage) static bool IsNumeric(const std::string& str, const bool allowDecimalPoint = false); //! Will convert the number in str to a number. //! Returns wether or not the operation was successful. //! Also returns wether the number is an integer, or floating point. If int, cast out_number to int. static bool ParseNumber(const std::string& str, bool& out_isInt, long double& out_number); //! Will split a string by a delimiter char. The delimiter will be excluded! static std::vector SplitString(const std::string& str, const char delimiter); //! Will split a string by a delimiter string. The delimiter will be excluded! static std::vector SplitString(const std::string& str, const std::string& delimiter); //! Will make a string all lower-case static std::string ToLower(const std::string& str); }; } } /*** ../Hazelnupp/DataType.h ***/ #include namespace Hazelnp { /** The different data types a paramater can be */ enum class DATA_TYPE { VOID, INT, FLOAT, 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 ""; } } /*** ../Hazelnupp/HazelnuppException.h ***/ #include #include #include namespace Hazelnp { /** Generic hazelnupp exception */ class HazelnuppException : public std::exception { public: HazelnuppException() {}; HazelnuppException(const std::string& msg) : message{ msg } {}; //! Will return an error message const std::string& What() const { return message; } protected: std::string message; }; /** Gets thrown when an non-existent key gets dereferenced */ class HazelnuppInvalidKeyException : public HazelnuppException { public: HazelnuppInvalidKeyException() : HazelnuppException() {}; HazelnuppInvalidKeyException(const std::string& msg) : HazelnuppException(msg) {}; }; /** Gets thrown when an attempt is made to retrieve the wrong data type from a value, when the value not convertible */ class HazelnuppValueNotConvertibleException : public HazelnuppException { public: HazelnuppValueNotConvertibleException() : HazelnuppException() {}; HazelnuppValueNotConvertibleException(const std::string& msg) : HazelnuppException(msg) {}; }; /** Gets thrown something bad happens because of parameter constraints */ class HazelnuppConstraintException : public HazelnuppException { public: HazelnuppConstraintException() : HazelnuppException() {}; HazelnuppConstraintException(const std::string& msg) : HazelnuppException(msg) {}; }; /** Gets thrown when a parameter is of a type that does not match the required type, and is not convertible to it */ class HazelnuppConstraintTypeMissmatch : public HazelnuppConstraintException { public: HazelnuppConstraintTypeMissmatch() : HazelnuppConstraintException() {}; HazelnuppConstraintTypeMissmatch(const std::string& msg) : HazelnuppConstraintException(msg) {}; HazelnuppConstraintTypeMissmatch(const std::string& key, const DATA_TYPE requiredType, const DATA_TYPE actualType, const std::string& paramDescription = "") { // Generate descriptive error message std::stringstream ss; ss << "Cannot convert parameter " << key << " to type " << DataTypeToString(requiredType) << ". You supplied type: " << DataTypeToString(actualType) << "."; // Add the parameter description, if provided if (paramDescription.length() > 0) ss << std::endl << key << " => " << paramDescription; message = ss.str(); return; }; }; /** Gets thrown when a parameter constrained to be required is not provided, and has no default value set */ class HazelnuppConstraintMissingValue : public HazelnuppConstraintException { public: HazelnuppConstraintMissingValue() : HazelnuppConstraintException() {}; HazelnuppConstraintMissingValue(const std::string& key, const std::string& paramDescription = "") { // Generate descriptive error message std::stringstream ss; ss << "Missing required parameter " << key << "."; // Add the parameter description, if provided if (paramDescription.length() > 0) ss << std::endl << key << " => " << paramDescription; message = ss.str(); return; }; }; } /*** ../Hazelnupp/ParamConstraint.h ***/ #include #include namespace Hazelnp { struct ParamConstraint { public: //! Empty constructor ParamConstraint() = default; //! Constructs a require constraint. //! Think of the default value like of a list ofparameters. Like {"--width", "800"} static ParamConstraint Require(const std::vector& defaultValue = {}, bool required = true) { ParamConstraint pc; pc.defaultValue = defaultValue; pc.required = required; return pc; } //! Constructs a type-safety constraint static ParamConstraint TypeSafety(DATA_TYPE requiredType, bool constrainType = true) { ParamConstraint pc; pc.constrainType = constrainType; pc.requiredType = requiredType; return pc; } //! Whole constructor ParamConstraint(bool constrainType, DATA_TYPE requiredType, const std::vector& defaultValue, bool required) : constrainType{ constrainType }, requiredType{ requiredType }, defaultValue{ defaultValue }, required{ required } { return; } //! Should this parameter be forced to be of a certain type? //! Remember to set `constrainTo` to the wanted type bool constrainType = false; //! Constrain the parameter to this value. Requires `constrainType` to be set to true. DATA_TYPE requiredType = DATA_TYPE::VOID; //! The default value for this parameter. //! Gets applied if this parameter was not given. //! Think of this like a list of parameters. Like {"--width", "800"} std::vector defaultValue; //! If set to true, and no default value set, //! an error will be produced if this parameter is not supplied by the user. bool required = false; private: //! The parameter this constraint is for. //! This value is automatically set by Hazelnupp. std::string key; friend class CmdArgsInterface; }; } /*** ../Hazelnupp/Value.h ***/ #include #include namespace Hazelnp { /** Abstract class for values */ class Value { public: virtual ~Value() {}; //! Will return a deeopopy of this object virtual Value* Deepcopy() const = 0; //! Will return a string suitable for an std::ostream virtual std::string GetAsOsString() const = 0; //! Will return the data type of this value DATA_TYPE GetDataType() const; friend std::ostream& operator<< (std::ostream& os, const Value& v) { return os << v.GetAsOsString(); } //! Will attempt to return the integer data (long long) virtual long long int GetInt64() const = 0; //! Will attempt to return the integer data (int) virtual int GetInt32() const = 0; //! Will attempt to return the floating-point data (long double) virtual long double GetFloat64() const = 0; //! Will attempt to return the floating-point data (double) virtual double GetFloat32() const = 0; //! Will attempt to return the string-data virtual std::string GetString() const = 0; //! Will attempt to return the list-data virtual const std::vector& GetList() const = 0; protected: Value(DATA_TYPE type); DATA_TYPE type; }; } /*** ../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 namespace Hazelnp { /** Specializations for floating point values (uses long double) */ class FloatValue : public Value { public: FloatValue(const long double& value); ~FloatValue() 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 long double& GetValue() const; operator long double() const; operator double() const; //! Will return the data as a long long int long long int GetInt64() const override; //! Will return the data as an int int GetInt32() const override; //! Will return the data as a long double long double GetFloat64() const override; //! Will return the data as a double double GetFloat32() const override; //! Will return the data as a string std::string GetString() const override; //! Throws HazelnuppValueNotConvertibleException const std::vector& GetList() const override; private: long double value; }; } /*** ../Hazelnupp/IntValue.h ***/ namespace Hazelnp { /** Specializations for integer values (uses long long int) */ class IntValue : public Value { public: IntValue(const long long int& value); ~IntValue() 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 long long int& GetValue() const; operator long long int() const; operator int() const; //! Will return the data as a long long int long long int GetInt64() const override; //! Will return the data as an int int GetInt32() const override; //! Will return the data as a long double long double GetFloat64() const override; //! Will return the data as a double double GetFloat32() const override; //! Will return the data as a string std::string GetString() const override; //! Throws HazelnuppValueNotConvertibleException const std::vector& GetList() const override; private: long long int value; }; } /*** ../Hazelnupp/VoidValue.h ***/ namespace Hazelnp { /** Specializations for void values. These house no value whatsoever, but only communicate information by merely existing. */ class VoidValue : public Value { public: VoidValue(); ~VoidValue() 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; //! 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; //! Returns an empty string std::string GetString() const override; //! Returns an empty list const std::vector& GetList() const; }; } /*** ../Hazelnupp/Parameter.h ***/ #include #include namespace Hazelnp { class Parameter { public: explicit Parameter(const std::string& key, const Value* value); ~Parameter(); //! Will return the key of this parameter const std::string& Key() const; //! Will return the value of this parameter const Value* GetValue() const; friend std::ostream& operator<< (std::ostream& os, const Parameter& p) { return os << "{ Key: \"" << p.key << "\" -> " << *p.value << " }"; } private: std::string key; Hazelnp::Value* value; }; } /*** ../Hazelnupp/CmdArgsInterface.h ***/ #include #include namespace Hazelnp { /** The main class to interface with */ class CmdArgsInterface { public: CmdArgsInterface(); CmdArgsInterface(const int argc, const char* const* argv); ~CmdArgsInterface(); //! Will parse command line arguments void Parse(const int argc, const char* const* argv); //! Will return argv[0], the name of the executable. const std::string& GetExecutableName() const; //! Will return the value given a key const Value& operator[](const std::string& key) const; //! Will check wether a parameter exists given a key, or not bool HasParam(const std::string& key) const; // Abbreviations //! Will register an abbreviation (like -f for --force) void RegisterAbbreviation(const std::string& abbrev, const std::string& target); //! Will return the long form of an abbreviation (like --force for -f) //! Returns "" if no match is found const std::string& GetAbbreviation(const std::string& abbrev) const; //! Will check wether or not an abbreviation is registered bool HasAbbreviation(const std::string& abbrev) const; //! Will delete the abbreviation for a given parameter. //! IMPORTANT: This parameter is the abbreviation! Not the long form! void ClearAbbreviation(const std::string& abbrevation); //! Will delete all abbreviations void ClearAbbreviations(); //! Will register a constraint for a parameter. //! IMPORTANT: Any parameter can only have ONE constraint. Applying a new one will overwrite the old one! //! Construct the ParamConstraint struct yourself to combine Require and TypeSafety! You can also use the ParamConstraint constructor! void RegisterConstraint(const std::string& key, const ParamConstraint& constraint); //! Will return the constraint information for a specific parameter ParamConstraint GetConstraint(const std::string& parameter) const; //! Will the constraint of a specific parameter void ClearConstraint(const std::string& parameter); //! Will delete all constraints void ClearConstraints(); //! Sets whether to crash the application, and print to stderr, when an exception is //! raised whilst parsing, or not. void SetCrashOnFail(bool crashOnFail); //! Gets whether the application crashes on an exception whilst parsing, and prints to stderr. bool GetCrashOnFail() const; //! Sets whether the CmdArgsInterface should automatically catch the --help parameter, print the parameter documentation to stdout, and exit or not. void SetCatchHelp(bool catchHelp); //! Retruns whether the CmdArgsInterface 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; //! Returns whether or not a given parameter has a registered description bool HasDescription(const std::string& parameter) const; //! Will delete the description of a parameter if it exists. void ClearDescription(const std::string& parameter); //! Will delete all parameter descriptions void ClearDescriptions(); //! 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); //! Will replace all args matching an abbreviation with their long form (like -f for --force) void ExpandAbbreviations(); //! Will parse the next parameter. Returns the index of the next parameter. std::size_t ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par); //! Will convert a vector of string-values to an actual Value Value* ParseValue(const std::vector& values, const ParamConstraint* constraint = nullptr); //! Will apply the loaded constraints on the loaded values, exluding types. void ApplyConstraints(); //! Will return a pointer to a paramConstraint given a key. If there is no, it returns nullptr const ParamConstraint* GetConstraintForKey(const std::string& key) const; std::string executableName; //! The path of the executable. Always argv[0] std::unordered_map parameters; //! These are abbreviations. Like, -f for --force. std::unordered_map parameterAbreviations; //! Parameter constraints, mapped to keys std::unordered_map parameterConstraints; //! Raw argv std::vector rawArgs; //! Short descriptions for parameters //! First member is the abbreviation 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, CmdArgsInterface will automatically catch the --help parameter, print the parameter documentation to stdout and exit. bool catchHelp = true; //! If set to true, CmdArgsInterface will crash the application with output to stderr when an exception is thrown whilst parsing. bool crashOnFail = true; }; }