diff --git a/Hazelnupp/FloatValue.cpp b/Hazelnupp/FloatValue.cpp index 001444a..67295c6 100644 --- a/Hazelnupp/FloatValue.cpp +++ b/Hazelnupp/FloatValue.cpp @@ -1,4 +1,5 @@ #include "FloatValue.h" +#include FloatValue::FloatValue(const long double& value) : @@ -7,3 +8,15 @@ FloatValue::FloatValue(const long double& value) { return; } + +Value* FloatValue::Deepcopy() const +{ + return new FloatValue(value); +} + +std::string FloatValue::GetAsOsString() const +{ + std::stringstream ss; + ss << "FloatValue: " << value; + return ss.str(); +} diff --git a/Hazelnupp/FloatValue.h b/Hazelnupp/FloatValue.h index cfa2402..3af98b9 100644 --- a/Hazelnupp/FloatValue.h +++ b/Hazelnupp/FloatValue.h @@ -1,11 +1,21 @@ #pragma once #include "Value.h" +#include class FloatValue : public Value { public: FloatValue(const long double& value); + Value* Deepcopy() const override; + + friend std::ostream& operator<< (std::ostream& os, const FloatValue& v) + { + return os << v.GetAsOsString(); + } + + std::string GetAsOsString() const override; + private: long double value; }; diff --git a/Hazelnupp/Hazelnupp.cpp b/Hazelnupp/Hazelnupp.cpp index 4f1f2cc..5fa9681 100644 --- a/Hazelnupp/Hazelnupp.cpp +++ b/Hazelnupp/Hazelnupp.cpp @@ -1,17 +1,141 @@ #include "Hazelnupp.h" +#include "VoidValue.h" +#include "IntValue.h" +#include "FloatValue.h" +#include "StringValue.h" +#include "ListValue.h" +#include "StringTools.h" +#include Hazelnupp::Hazelnupp() { return; } -Hazelnupp::Hazelnupp(int argc, const char* const* argv) +Hazelnupp::Hazelnupp(const int argc, const char* const* argv) { Parse(argc, argv); return; } -void Hazelnupp::Parse(int argc, const char* const* argv) +void Hazelnupp::Parse(const int argc, const char* const* argv) { + // Populate raw arguments + PopulateRawArgs(argc, argv); + + + executableName = std::string(rawArgs[0]); + + std::size_t i = 1; + while (i < rawArgs.size()) + { + if ((rawArgs[i].length() > 2) && (rawArgs[i].substr(0, 2) == "--")) + { + Parameter* param = nullptr; + i = ParseNextParameter(i, param); + + parameters.insert(std::pair(param->Key(), param)); + } + else + i++; + } + + std::cout << "Terminated." << std::endl; + return; } + +std::size_t Hazelnupp::ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par) +{ + std::size_t i = parIndex; + const std::string key = rawArgs[parIndex]; + std::vector values; + + // Get values + for (i++; i < rawArgs.size(); i++) + // If not another parameter + if ((rawArgs[i].length() < 2) || (rawArgs[i].substr(0, 2) != "--")) + values.emplace_back(rawArgs[i]); + else + { + break; + } + + Value* parsedVal = EvaluateValues(values); + out_Par = new Parameter(key, parsedVal); + + delete parsedVal; + parsedVal = nullptr; + + return i; +} + +void Hazelnupp::PopulateRawArgs(const int argc, const char* const* argv) +{ + rawArgs.reserve(argc); + for (int i = 0; i < argc; i++) + rawArgs.emplace_back(std::string(argv[i])); + + return; +} + +bool Hazelnupp::HasParam(const std::string& key) const +{ + return parameters.find(key) != parameters.end(); +} + +Value* Hazelnupp::EvaluateValues(const std::vector& values) +{ + // Void-type + if (values.size() == 0) + { + return new VoidValue; + } + + // List-type + else if (values.size() > 1) + { + ListValue* newList = new ListValue(); + for (const std::string& val : values) + { + Value* tmp = EvaluateValues(std::vector({ val })); + newList->AddValue(tmp); + delete tmp; + } + return newList; + } + + // Now we're only dealing with a single value + const std::string& val = values[0]; + + // String + if (!StringTools::IsNumeric(val, true)) + return new StringValue(val); + + // Numeric + bool isInt; + long double num; + + if (StringTools::ParseNumber(val, isInt, num)) + { + // Integer + if (isInt) + return new IntValue((long long int)num); + + // Double + return new FloatValue(num); + } + + // Failed + return nullptr; +} + +const std::string& Hazelnupp::GetExecutableName() const +{ + return executableName; +} + +const Value* Hazelnupp::operator[](const std::string& key) +{ + return parameters[key]->Value(); +} diff --git a/Hazelnupp/Hazelnupp.h b/Hazelnupp/Hazelnupp.h index 27c553d..a48d667 100644 --- a/Hazelnupp/Hazelnupp.h +++ b/Hazelnupp/Hazelnupp.h @@ -1,15 +1,40 @@ #pragma once #include "Parameter.h" #include +#include class Hazelnupp { public: Hazelnupp(); - Hazelnupp(int argc, const char* const* argv); + Hazelnupp(const int argc, const char* const* argv); //! Will parse command line arguments - void Parse(int argc, const char* const* argv); + 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); + + //! Will check wether a parameter exists given a key, or not + bool HasParam(const std::string& key) const; + +private: + //! Will translate the c-like args to an std::vector + void PopulateRawArgs(const int argc, const char* const* argv); + + //! Will parse the next parameter. Returns the index of the next parameter. + std::size_t ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par); + + Value* EvaluateValues(const std::vector& values); + + std::string executableName; //! The path of the executable. Always argv[0] std::unordered_map parameters; + + std::vector rawArgs; + + // EvaluateValues + friend class ListValue; }; diff --git a/Hazelnupp/Hazelnupp.vcxproj b/Hazelnupp/Hazelnupp.vcxproj index 036164b..71eb82d 100644 --- a/Hazelnupp/Hazelnupp.vcxproj +++ b/Hazelnupp/Hazelnupp.vcxproj @@ -145,6 +145,7 @@ + @@ -156,6 +157,7 @@ + diff --git a/Hazelnupp/Hazelnupp.vcxproj.filters b/Hazelnupp/Hazelnupp.vcxproj.filters index 56b3caa..9f6c39e 100644 --- a/Hazelnupp/Hazelnupp.vcxproj.filters +++ b/Hazelnupp/Hazelnupp.vcxproj.filters @@ -42,6 +42,9 @@ Quelldateien + + Quelldateien + @@ -71,5 +74,8 @@ Headerdateien + + Headerdateien + \ No newline at end of file diff --git a/Hazelnupp/IntValue.cpp b/Hazelnupp/IntValue.cpp index 9437d40..c536c8e 100644 --- a/Hazelnupp/IntValue.cpp +++ b/Hazelnupp/IntValue.cpp @@ -1,4 +1,5 @@ #include "IntValue.h" +#include IntValue::IntValue(const long long int& value) : @@ -7,3 +8,15 @@ IntValue::IntValue(const long long int& value) { return; } + +Value* IntValue::Deepcopy() const +{ + return new IntValue(value); +} + +std::string IntValue::GetAsOsString() const +{ + std::stringstream ss; + ss << "IntValue: " << value; + return ss.str(); +} diff --git a/Hazelnupp/IntValue.h b/Hazelnupp/IntValue.h index bf1de1c..3d5acc4 100644 --- a/Hazelnupp/IntValue.h +++ b/Hazelnupp/IntValue.h @@ -6,6 +6,10 @@ class IntValue : public Value public: IntValue(const long long int& value); + Value* Deepcopy() const override; + + std::string GetAsOsString() const override; + private: long long int value; }; diff --git a/Hazelnupp/ListValue.cpp b/Hazelnupp/ListValue.cpp index e591d43..0e8d46b 100644 --- a/Hazelnupp/ListValue.cpp +++ b/Hazelnupp/ListValue.cpp @@ -1,4 +1,12 @@ #include "ListValue.h" +#include "Hazelnupp.h" +#include + +ListValue::ListValue() : + Value(DATA_TYPE::LIST) +{ + return; +} ListValue::~ListValue() { @@ -10,8 +18,36 @@ ListValue::~ListValue() return; } +Value* ListValue::Deepcopy() const +{ + ListValue* newList = new ListValue(); + + for (const Value* val : value) + newList->AddValue(val); + + return newList; +} + void ListValue::AddValue(const Value* value) { - this->value.emplace_back(new Value(*value)); + this->value.emplace_back(value->Deepcopy()); return; } + +std::string ListValue::GetAsOsString() const +{ + std::stringstream ss; + + ss << "ListValue: ["; + + for (const Value* val : value) + { + ss << *val; + if (val != value.back()) + ss << ", "; + } + + ss << "]"; + + return ss.str(); +} diff --git a/Hazelnupp/ListValue.h b/Hazelnupp/ListValue.h index 2ca79d0..baca3f0 100644 --- a/Hazelnupp/ListValue.h +++ b/Hazelnupp/ListValue.h @@ -5,11 +5,21 @@ class ListValue : public Value { public: + ListValue(); ~ListValue(); + Value* Deepcopy() const override; + //! Will add this value to the list void AddValue(const Value* value); + std::string GetAsOsString() const override; + + friend std::ostream& operator<< (std::ostream& os, const ListValue& v) + { + return os << v.GetAsOsString(); + } + private: std::vector value; }; diff --git a/Hazelnupp/Parameter.cpp b/Hazelnupp/Parameter.cpp index 24e5fec..49477d0 100644 --- a/Hazelnupp/Parameter.cpp +++ b/Hazelnupp/Parameter.cpp @@ -1,9 +1,19 @@ #include "Parameter.h" -Parameter::Parameter(const std::string& key, const Value& value) +Parameter::Parameter(const std::string& key, const ::Value* value) : - key { key }, - value { value } + key{ key } { + this->value = value->Deepcopy(); return; } + +const std::string& Parameter::Key() const +{ + return key; +} + +const ::Value* Parameter::Value() const +{ + return value; +} diff --git a/Hazelnupp/Parameter.h b/Hazelnupp/Parameter.h index 6f4dc63..ab123cc 100644 --- a/Hazelnupp/Parameter.h +++ b/Hazelnupp/Parameter.h @@ -1,13 +1,22 @@ #pragma once #include "Value.h" #include +#include class Parameter { public: - explicit Parameter(const std::string& key, const Value& value); + explicit Parameter(const std::string& key, const Value* value); + const std::string& Key() const; + const Value* Value() const; + + friend std::ostream& operator<< (std::ostream& os, const Parameter& p) + { + return os << "{ Key: \"" << p.key << "\" -> " << *p.value << " }"; + } + private: std::string key; - Value value; + ::Value* value; }; diff --git a/Hazelnupp/StringTools.cpp b/Hazelnupp/StringTools.cpp new file mode 100644 index 0000000..67b71fc --- /dev/null +++ b/Hazelnupp/StringTools.cpp @@ -0,0 +1,188 @@ +#include "StringTools.h" + +bool StringTools::Contains(const std::string& str, const char c) +{ + for (const char& i : str) + if (i == c) + return true; + + return false; +} + +std::string StringTools::Replace(const std::string str, const char find, const std::string subst) +{ + std::stringstream ss; + + for (std::size_t i = 0; i < str.length(); i++) + { + if (str[i] != find) ss << str[i]; + else ss << subst; + } + + return ss.str(); +} + +std::string StringTools::Replace(const std::string str, const std::string find, const std::string subst) +{ + if (find.length() == 0) return str; + + std::stringstream ss; + + std::size_t posFound = 0; + std::size_t lastFound = 0; + + while (posFound != std::string::npos) + { + lastFound = posFound; + posFound = str.find(find, posFound); + + if (posFound != std::string::npos) + { + ss << str.substr(lastFound, posFound - lastFound) << subst; + posFound += find.length(); + } + else + { + ss << str.substr(lastFound, (str.length()) - lastFound); + } + } + + return ss.str(); +} + + +bool StringTools::IsNumeric(const std::string str, const bool allowDecimalPoint) +{ + if (str.length() == 0) return false; + + bool alreadyParsedDecimalPoint = false; + std::size_t digitCount = 0; + + for (std::size_t i = 0; i < str.length(); i++) + { + if (!( + ((str[i] >= '0') && (str[i] <= '9')) || + ((str[i] == '-') && (i == 0)) || + ((str[i] == '.') && (allowDecimalPoint) && (!alreadyParsedDecimalPoint) && (digitCount > 0)) + )) return false; + + + // Here we just have to check for the character. Not for any other conditions. + // Why? Because if these conditions failed, the function would have already returned false. + if (((str[i] >= '0') && (str[i] <= '9'))) digitCount++; + if (str[i] == '.') alreadyParsedDecimalPoint = true; + } + + // Even if we did not find any invalid chars, we should still return false, if we found no digits at all. + return digitCount > 0; +} + +bool StringTools::ParseNumber(const std::string str, bool& out_isInt, long double& out_number) +{ + bool isNormalNum = true; + + bool isNegative = false; + bool isDecimal = false; + + if (str.length() == 0) return false; + if (str[0] == '-') isNegative = true; + if (Contains(str, '.')) isDecimal = true; + + if (isDecimal) + { + try + { + out_number = std::stold(str); + out_isInt = false; + } + catch (std::invalid_argument) + { + return false; + } + catch (std::out_of_range) + { + return false; + } + } + else + { + try + { + out_number = (long double)std::stoll(str); + out_isInt = true; + } + catch (std::invalid_argument) + { + return false; + } + catch (std::out_of_range) + { + return false; + } + } + + return true; +} + +std::vector StringTools::SplitString(const std::string str, const char delimiter) +{ + if (str.length() == 0) return std::vector(); + + return SplitString(str, delimiter); +} + +std::vector StringTools::SplitString(const std::string str, const std::string delimiter) +{ + if (str.length() == 0) return std::vector(); + + std::vector parts; + + if (delimiter.length() == 0) // If the delimiter is "" (empty), just split between every single char. Not useful, but logical + { + for (std::size_t i = 0; i < str.length(); i++) + { + parts.push_back(std::string({ str[i] })); + } + return parts; + } + + std::size_t posFound = 0; + std::size_t lastFound = 0; + + while (posFound != std::string::npos) + { + lastFound = posFound; + posFound = str.find(delimiter, posFound); + + std::string found; + + if (posFound != std::string::npos) + { + found = str.substr(lastFound, posFound - lastFound); + posFound += delimiter.length(); + } + else + { + found = str.substr(lastFound, str.length() - lastFound); + } + + parts.push_back(found); + } + + return parts; +} + +std::string StringTools::ToLower(const std::string str) +{ + std::stringstream ss; + for (std::size_t i = 0; i < str.length(); i++) + { + if ((str[i] >= 'A') && (str[i] <= 'Z')) ss << (char)(((int)str[i]) + 32); + else if (str[i] == -60) ss << (char)-28; // AE => ae + else if (str[i] == -42) ss << (char)-10; // OE => oe + else if (str[i] == -36) ss << (char)-4; // UE => ue + else ss << str[i]; + } + + return ss.str(); +} diff --git a/Hazelnupp/StringTools.h b/Hazelnupp/StringTools.h new file mode 100644 index 0000000..365a4fc --- /dev/null +++ b/Hazelnupp/StringTools.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include +#include +#include + +/// +/// Internal helper class. Feel free to use it tho, lol +/// +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); +}; diff --git a/Hazelnupp/StringValue.cpp b/Hazelnupp/StringValue.cpp index c6a38fb..db5c7f3 100644 --- a/Hazelnupp/StringValue.cpp +++ b/Hazelnupp/StringValue.cpp @@ -1,4 +1,5 @@ #include "StringValue.h" +#include StringValue::StringValue(const std::string& value) : @@ -7,3 +8,15 @@ StringValue::StringValue(const std::string& value) { return; } + +Value* StringValue::Deepcopy() const +{ + return new StringValue(value); +} + +std::string StringValue::GetAsOsString() const +{ + std::stringstream ss; + ss << "StringValue: " << value; + return ss.str(); +} diff --git a/Hazelnupp/StringValue.h b/Hazelnupp/StringValue.h index c2301d1..f1676d9 100644 --- a/Hazelnupp/StringValue.h +++ b/Hazelnupp/StringValue.h @@ -7,6 +7,15 @@ class StringValue : public Value public: StringValue(const std::string& value); + Value* Deepcopy() const override; + + friend std::ostream& operator<< (std::ostream& os, const StringValue& v) + { + return os << v.GetAsOsString(); + } + + std::string GetAsOsString() const override; + private: std::string value; }; diff --git a/Hazelnupp/Value.h b/Hazelnupp/Value.h index 2df5fe2..df7619a 100644 --- a/Hazelnupp/Value.h +++ b/Hazelnupp/Value.h @@ -1,8 +1,21 @@ #pragma once #include "DataType.h" +#include class Value { +public: + //! Will return a deeopopy of this object + virtual Value* Deepcopy() const = 0; + + friend std::ostream& operator<< (std::ostream& os, const Value& v) + { + return os << v.GetAsOsString(); + } + + //! Will return a string suitable for an std::ostream; + virtual std::string GetAsOsString() const = 0; + protected: Value(DATA_TYPE type); diff --git a/Hazelnupp/VoidValue.cpp b/Hazelnupp/VoidValue.cpp index edd1fda..9bc48d2 100644 --- a/Hazelnupp/VoidValue.cpp +++ b/Hazelnupp/VoidValue.cpp @@ -6,3 +6,13 @@ VoidValue::VoidValue() { return; } + +Value* VoidValue::Deepcopy() const +{ + return new VoidValue(); +} + +std::string VoidValue::GetAsOsString() const +{ + return "VoidValue"; +} diff --git a/Hazelnupp/VoidValue.h b/Hazelnupp/VoidValue.h index cfcb2fb..2b6db54 100644 --- a/Hazelnupp/VoidValue.h +++ b/Hazelnupp/VoidValue.h @@ -5,4 +5,13 @@ class VoidValue : public Value { public: VoidValue(); + + Value* Deepcopy() const override; + + friend std::ostream& operator<< (std::ostream& os, const VoidValue& v) + { + return os << "VoidValue"; + } + + std::string GetAsOsString() const override; }; diff --git a/Hazelnupp/main.cpp b/Hazelnupp/main.cpp index f385484..d8f08e2 100644 --- a/Hazelnupp/main.cpp +++ b/Hazelnupp/main.cpp @@ -1,6 +1,27 @@ #include +#include +#include "Hazelnupp.h" -int main() +int main(int argc, char** argv) { - std::cout << "Hello World!\n"; + std::string arg0 = "meinpfad"; + std::string arg1 = "--word"; + std::string arg2 = "1"; + std::string arg3 = "--alfred"; + std::string arg4 = "banane7"; + + std::array testArgv = { + arg0.data(), + arg1.data(), + arg2.data(), + arg3.data(), + arg4.data() + }; + + Hazelnupp args(testArgv.size(), testArgv.data()); + //Hazelnupp args(argc, argv); + + //std::cout << args.GetExecutableName() << std::endl; + + return 0; }