CommandLine parser initial
This commit is contained in:
parent
3846b91662
commit
f5cab30f21
11 changed files with 592 additions and 22 deletions
|
|
@ -16,4 +16,5 @@ add_subdirectory(Containers)
|
||||||
add_subdirectory(Math)
|
add_subdirectory(Math)
|
||||||
add_subdirectory(Allocators)
|
add_subdirectory(Allocators)
|
||||||
add_subdirectory(Strings)
|
add_subdirectory(Strings)
|
||||||
add_subdirectory(Tokenizer)
|
add_subdirectory(Tokenizer)
|
||||||
|
add_subdirectory(CommandLine)
|
||||||
22
CommandLine/CMakeLists.txt
Normal file
22
CommandLine/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
|
project(CommandLine)
|
||||||
|
|
||||||
|
### ---------------------- Static Library --------------------- ###
|
||||||
|
file(GLOB SOURCES "./private/*.cpp")
|
||||||
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Tokenizer)
|
||||||
|
|
||||||
|
### -------------------------- Tests -------------------------- ###
|
||||||
|
enable_testing()
|
||||||
|
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||||
|
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||||
|
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
|
||||||
|
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)
|
||||||
345
CommandLine/private/CommandLine.cpp
Normal file
345
CommandLine/private/CommandLine.cpp
Normal file
|
|
@ -0,0 +1,345 @@
|
||||||
|
|
||||||
|
#include "CommandLine.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
const char* regexSpace = "\n|\t| |\r";
|
||||||
|
const char* regexFalse = "N|n|(False)|(false)";
|
||||||
|
const char* regexTrue = "Y|y|(True)|(true)";
|
||||||
|
const char* regexInt = "((\\-)|(\\+))?[0-9]+";
|
||||||
|
const char* regexFloat = R"(((\-)|(\+))?([0-9]+)(\.)([0-9]*)?)";
|
||||||
|
const char* regexString = "'{'-'}*'";
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const Arg& arg) {
|
||||||
|
mId = arg.mId;
|
||||||
|
switch (arg.mType) {
|
||||||
|
case CommandLine::Arg::INT: mType = INT; mInt = arg.mInt; break;
|
||||||
|
case CommandLine::Arg::FLOAT: mType = FLOAT; mFloat = arg.mFloat; break;
|
||||||
|
case CommandLine::Arg::BOOL: mType = BOOL; mBool = arg.mBool; break;
|
||||||
|
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); mStr = arg.mStr; break;
|
||||||
|
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); mFile = arg.mFile; break;
|
||||||
|
}
|
||||||
|
mOptional = arg.mOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, Type type) {
|
||||||
|
mId = id;
|
||||||
|
switch (type) {
|
||||||
|
case CommandLine::Arg::INT: mType = INT; new (&mInt) IntArg(); break;
|
||||||
|
case CommandLine::Arg::FLOAT: mType = FLOAT; new (&mFloat) FloatArg(); break;
|
||||||
|
case CommandLine::Arg::BOOL: mType = BOOL; new (&mBool) BoolArg(); break;
|
||||||
|
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); break;
|
||||||
|
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); break;
|
||||||
|
}
|
||||||
|
mOptional = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, const Range<alni>& aAcceptingRange) {
|
||||||
|
mId = id;
|
||||||
|
mType = FLOAT;
|
||||||
|
mInt = { 0, 0, aAcceptingRange };
|
||||||
|
mOptional = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, const Range<alnf>& aAcceptingRange) {
|
||||||
|
mId = id;
|
||||||
|
mType = FLOAT;
|
||||||
|
mFloat = { 0, 0, aAcceptingRange };
|
||||||
|
mOptional = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, const Range<alni>& aAcceptingRange, alni aDefault) {
|
||||||
|
mId = id;
|
||||||
|
mType = INT;
|
||||||
|
mInt = { 0, aDefault, aAcceptingRange };
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, const Range<alnf>& aAcceptingRange, alnf aDefault) {
|
||||||
|
mId = id;
|
||||||
|
mType = FLOAT;
|
||||||
|
mFloat = { 0, aDefault, aAcceptingRange };
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, bool aDefault) {
|
||||||
|
mId = id;
|
||||||
|
mType = BOOL;
|
||||||
|
mBool.mDefault = aDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::Arg(const String& id, const char* aDefault) {
|
||||||
|
mId = id;
|
||||||
|
mType = STR;
|
||||||
|
new (&mStr) StringArg();
|
||||||
|
mStr.mDefault = aDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::Arg::~Arg() {
|
||||||
|
switch (mType) {
|
||||||
|
case CommandLine::Arg::STR:
|
||||||
|
mStr.~StringArg();
|
||||||
|
break;
|
||||||
|
case CommandLine::Arg::FILE_IN:
|
||||||
|
mFile.~FileInputArg();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::CommandLine(const init_list<Arg>& args) {
|
||||||
|
bool optional_start = false;
|
||||||
|
|
||||||
|
for (auto& arg : args) {
|
||||||
|
ASSERT(!mArgs.presents(arg.mId) && "Argument Redefinition")
|
||||||
|
|
||||||
|
auto copy_arg = new Arg(arg);
|
||||||
|
|
||||||
|
mArgs.put(arg.mId, copy_arg);
|
||||||
|
mArgsOrder.pushBack(mArgs.get(arg.mId));
|
||||||
|
|
||||||
|
if (arg.mOptional) {
|
||||||
|
mOptionals++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optional_start) {
|
||||||
|
ASSERT(arg.mOptional && "Not Optional Argument After Optionals")
|
||||||
|
}
|
||||||
|
else if (arg.mOptional) {
|
||||||
|
optional_start = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mTokenizer.build({
|
||||||
|
{ regexSpace, TokType::SPACE },
|
||||||
|
{ regexFalse, TokType::BOOL_FALSE },
|
||||||
|
{ regexTrue, TokType::BOOL_TRUE },
|
||||||
|
{ regexInt, TokType::INT },
|
||||||
|
{ regexFloat, TokType::FLOAT },
|
||||||
|
{ regexString, TokType::STR },
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT(mTokenizer.isBuild() && "Internal Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLine::~CommandLine() {
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
delete arg.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommandLine::parse(char argc, const char* argv[], bool logError, ualni skipArgs) {
|
||||||
|
// discard some arguments
|
||||||
|
argc -= (char) skipArgs;
|
||||||
|
argv += skipArgs;
|
||||||
|
|
||||||
|
if (argc < mArgs.size() - mOptionals) {
|
||||||
|
ErrInvalidArgCount();
|
||||||
|
if (logError) {
|
||||||
|
ErrLog();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ualni idx = 0;
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
if (idx < argc) {
|
||||||
|
parseArg(*arg.data(), argv[idx]);
|
||||||
|
} else {
|
||||||
|
initDefault(*arg.data());
|
||||||
|
}
|
||||||
|
if (mError) {
|
||||||
|
if (logError) ErrLog();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//set_working_dir();
|
||||||
|
}
|
||||||
|
|
||||||
|
alni CommandLine::getInt(const String& id) { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; }
|
||||||
|
alnf CommandLine::getFloat(const String& id) { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; }
|
||||||
|
bool CommandLine::getBool(const String& id) { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; }
|
||||||
|
const String& CommandLine::getString(const String& id) { auto& arg = getArg(id, Arg::STR); return arg.mStr.mStr; }
|
||||||
|
File& CommandLine::getFile(const String& id) { auto& arg = getArg(id, Arg::FILE_IN); return arg.mFile.mFile; }
|
||||||
|
|
||||||
|
|
||||||
|
CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) {
|
||||||
|
auto idx = mArgs.presents(id);
|
||||||
|
ASSERT(idx && "Invalid Id")
|
||||||
|
auto& arg = mArgs.getSlotVal(idx);
|
||||||
|
ASSERT(arg->mType == type && "Invalid Type Requested")
|
||||||
|
return *arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLine::ErrInvalidArgCount() { mError = { "Invalid Number Of Arguments Passed", nullptr }; }
|
||||||
|
void CommandLine::ErrInvalidArgSyntax(Arg* arg) { mError = { "Invalid Syntax Of Argument", arg }; }
|
||||||
|
void CommandLine::ErrInvalidArgType(Arg* arg) { mError = { "Invalid Type Of Argument", arg }; }
|
||||||
|
void CommandLine::ErrFileNotExists(Arg* arg) { mError = { "File Not Exists", arg }; }
|
||||||
|
void CommandLine::ErrFileCouldNotOpen(Arg* arg) { mError = { "Could Not Open File", arg }; }
|
||||||
|
void CommandLine::ErrValNotinRange(Arg* arg) { mError = { "Value Not In Range", arg }; }
|
||||||
|
|
||||||
|
void CommandLine::ErrLog() {
|
||||||
|
printf("\nERROR : Invalid Command Line\n");
|
||||||
|
|
||||||
|
if (mError.mArg) {
|
||||||
|
alni idx = 0;
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
if (mError.mArg == arg.data()) break;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nArgument: %lli\n", idx);
|
||||||
|
ArgLog(*mError.mArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Error Description: %s. \n", mError.mDescr);
|
||||||
|
|
||||||
|
printf("\nExpected Arguments are: \n");
|
||||||
|
ualni idx = 0;
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
printf(" -- %lli -- \n", idx);
|
||||||
|
ArgLog(*arg.data());
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nNote regex for types are:\n");
|
||||||
|
printf(" False - %s\n", regexFalse);
|
||||||
|
printf(" True - %s\n", regexTrue);
|
||||||
|
printf(" Int - %s\n", regexInt);
|
||||||
|
printf(" Float - %s\n", regexFloat);
|
||||||
|
printf(" String - %s\n", regexString);
|
||||||
|
printf(" File - else\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLine::ArgLog(Arg& arg) {
|
||||||
|
switch (arg.mType) {
|
||||||
|
case Arg::INT: {
|
||||||
|
printf("Type : Int\n");
|
||||||
|
printf("Range : %lli - %lli\n", arg.mInt.mAcceptingRange.mBegin, arg.mInt.mAcceptingRange.mEnd);
|
||||||
|
if (arg.mOptional) {
|
||||||
|
printf("Default : %lli\n", arg.mInt.mDefault);
|
||||||
|
}
|
||||||
|
printf("Given : %lli\n", arg.mInt.mVal);
|
||||||
|
} break;
|
||||||
|
case Arg::FLOAT: {
|
||||||
|
printf("Type : Float\n");
|
||||||
|
printf("Range : %f - %f\n", (halnf) arg.mFloat.mAcceptingRange.mBegin, (halnf) arg.mFloat.mAcceptingRange.mEnd);
|
||||||
|
if (arg.mOptional) {
|
||||||
|
printf("Default : %f\n", arg.mFloat.mDefault);
|
||||||
|
}
|
||||||
|
printf("Given : %f\n", arg.mFloat.mVal);
|
||||||
|
} break;
|
||||||
|
case Arg::BOOL: {
|
||||||
|
printf("Type : Bool\n");
|
||||||
|
if (arg.mOptional) {
|
||||||
|
printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False");
|
||||||
|
}
|
||||||
|
printf("Given : %s\n", arg.mBool.mFlag ? "True" : "False");
|
||||||
|
} break;
|
||||||
|
case Arg::STR: {
|
||||||
|
printf("Type : String\n");
|
||||||
|
if (arg.mOptional) {
|
||||||
|
printf("Default : %s\n", arg.mStr.mDefault.read());
|
||||||
|
}
|
||||||
|
printf("Given : %s\n", arg.mStr.mStr.read());
|
||||||
|
} break;
|
||||||
|
case Arg::FILE_IN: {
|
||||||
|
printf("Type : File Input\n");
|
||||||
|
printf("Given Path : %s\n", arg.mFile.mFilepath.read());
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLine::initDefault(Arg& arg) {
|
||||||
|
switch (arg.mType) {
|
||||||
|
case Arg::INT: arg.mInt.mVal = arg.mInt.mDefault; break;
|
||||||
|
case Arg::FLOAT: arg.mFloat.mVal = arg.mFloat.mDefault; break;
|
||||||
|
case Arg::BOOL: arg.mBool.mFlag = arg.mBool.mDefault; break;
|
||||||
|
case Arg::STR: arg.mStr.mStr = arg.mStr.mDefault; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLine::parseArg(Arg& arg, const char* src) {
|
||||||
|
mTokenizer.reset();
|
||||||
|
mTokenizer.bindSource(src);
|
||||||
|
|
||||||
|
auto tok = mTokenizer.readTok();
|
||||||
|
if (tok < TokType::INT || tok > TokType::STR) {
|
||||||
|
ErrInvalidArgSyntax(&arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto val = mTokenizer.extractVal();
|
||||||
|
|
||||||
|
switch (arg.mType) {
|
||||||
|
case Arg::INT: {
|
||||||
|
if (tok != TokType::INT) {
|
||||||
|
ErrInvalidArgType(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto converted = String::Logic::convertStringToValue(val.read(), arg.mInt.mVal);
|
||||||
|
if (converted && arg.mInt.mVal < arg.mInt.mAcceptingRange.mBegin || arg.mInt.mVal > arg.mInt.mAcceptingRange.mEnd) {
|
||||||
|
ErrValNotinRange(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Arg::FLOAT: {
|
||||||
|
if (tok != TokType::FLOAT) {
|
||||||
|
ErrInvalidArgType(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto converted = String::Logic::convertStringToValue(val.read(), arg.mFloat.mVal);
|
||||||
|
if (converted && arg.mFloat.mVal < arg.mFloat.mAcceptingRange.mBegin || arg.mFloat.mVal > arg.mFloat.mAcceptingRange.mEnd) {
|
||||||
|
ErrValNotinRange(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Arg::STR: {
|
||||||
|
if (tok != TokType::STR) {
|
||||||
|
ErrInvalidArgType(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arg.mStr.mStr = val;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Arg::BOOL: {
|
||||||
|
if (tok != TokType::BOOL_FALSE && tok != TokType::BOOL_TRUE) {
|
||||||
|
ErrInvalidArgType(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arg.mBool.mFlag = bool(val);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Arg::FILE_IN: {
|
||||||
|
if (tok != TokType::STR) {
|
||||||
|
ErrInvalidArgType(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.mFile.mFilepath = val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO : replace
|
||||||
|
if (!File::exists(arg.mFile.mFilepath.cstr())) {
|
||||||
|
ErrFileNotExists(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.mFile.mFile.open(arg.mFile.mFilepath.cstr(), osfile_openflags::LOAD);
|
||||||
|
if (!arg.mFile.mFile.opened) {
|
||||||
|
ErrFileCouldNotOpen(&arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.mIsPassed = true;
|
||||||
|
}
|
||||||
105
CommandLine/public/CommandLine.hpp
Normal file
105
CommandLine/public/CommandLine.hpp
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Tokenizer.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
// TODO : replace
|
||||||
|
class File {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandLine {
|
||||||
|
|
||||||
|
struct IntArg {
|
||||||
|
alni mVal = 0;
|
||||||
|
alni mDefault = 0;
|
||||||
|
Range<alni> mAcceptingRange = { -(std::numeric_limits<alni>::max() - 1), std::numeric_limits<alni>::max() };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FloatArg {
|
||||||
|
alnf mVal = 0.f;
|
||||||
|
alnf mDefault = 0.f;
|
||||||
|
Range<alnf> mAcceptingRange = { -(std::numeric_limits<alnf>::max() - 1), std::numeric_limits<alnf>::max() };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoolArg {
|
||||||
|
bool mFlag = false;
|
||||||
|
bool mDefault = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringArg {
|
||||||
|
String mStr;
|
||||||
|
String mDefault;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileInputArg {
|
||||||
|
String mFilepath;
|
||||||
|
File mFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Arg {
|
||||||
|
String mId;
|
||||||
|
enum Type { INT, FLOAT, BOOL, STR, FILE_IN } mType;
|
||||||
|
union {
|
||||||
|
IntArg mInt;
|
||||||
|
FloatArg mFloat;
|
||||||
|
BoolArg mBool;
|
||||||
|
StringArg mStr;
|
||||||
|
FileInputArg mFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool mOptional = true;
|
||||||
|
bool mIsPassed = false;
|
||||||
|
|
||||||
|
Arg(const Arg& arg);
|
||||||
|
Arg(const String& id, Type type);
|
||||||
|
Arg(const String& id, const Range<alni>& aAcceptingRange);
|
||||||
|
Arg(const String& id, const Range<alnf>& aAcceptingRange);
|
||||||
|
Arg(const String& id, const Range<alni>& aAcceptingRange, alni aDefault);
|
||||||
|
Arg(const String& id, const Range<alnf>& aAcceptingRange, alnf aDefault);
|
||||||
|
Arg(const String& id, bool aDefault);
|
||||||
|
Arg(const String& id, const char* aDefault);
|
||||||
|
~Arg();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Error {
|
||||||
|
const char* mDescr = nullptr;
|
||||||
|
Arg* mArg = nullptr;
|
||||||
|
operator bool() { return mDescr != nullptr; }
|
||||||
|
} mError;
|
||||||
|
|
||||||
|
CommandLine(const init_list<Arg>& args);
|
||||||
|
~CommandLine();
|
||||||
|
|
||||||
|
bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1);
|
||||||
|
|
||||||
|
alni getInt(const String& id);
|
||||||
|
alnf getFloat(const String& id);
|
||||||
|
bool getBool(const String& id);
|
||||||
|
const String& getString(const String& id);
|
||||||
|
File& getFile(const String& id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, } mType;
|
||||||
|
typedef SimpleTokenizer<char, TokType, TokType::NONE, TokType::FAILURE, TokType::END> Tokenizer;
|
||||||
|
|
||||||
|
Tokenizer mTokenizer;
|
||||||
|
Map<String, Arg*> mArgs;
|
||||||
|
List<Arg*> mArgsOrder;
|
||||||
|
ualni mOptionals = 0;
|
||||||
|
|
||||||
|
Arg& getArg(const String& id, Arg::Type type);
|
||||||
|
void ErrInvalidArgCount();
|
||||||
|
void ErrInvalidArgSyntax(Arg* arg);
|
||||||
|
void ErrInvalidArgType(Arg* arg);
|
||||||
|
void ErrFileNotExists(Arg* arg);
|
||||||
|
void ErrFileCouldNotOpen(Arg* arg);
|
||||||
|
void ErrValNotinRange(Arg* arg);
|
||||||
|
void ErrLog();
|
||||||
|
static void ArgLog(Arg& arg);
|
||||||
|
static void initDefault(Arg& arg);
|
||||||
|
void parseArg(Arg& arg, const char* src);
|
||||||
|
};
|
||||||
|
};
|
||||||
23
CommandLine/tests/TestCommandLine.cpp
Normal file
23
CommandLine/tests/TestCommandLine.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include "Tests.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
static CommandLine createCmdLine() {
|
||||||
|
CommandLine cmd({
|
||||||
|
{ "bool", CommandLine::Arg::BOOL },
|
||||||
|
{ "int", CommandLine::Arg::INT },
|
||||||
|
{ "string", CommandLine::Arg::STR },
|
||||||
|
{ "float", CommandLine::Arg::FLOAT },
|
||||||
|
});
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DEF_STATIC(Simple) {
|
||||||
|
auto cmd = createCmdLine();
|
||||||
|
const char* args[] = { "false", "2", "'str'", "-0.15" };
|
||||||
|
cmd.parse(4, args, true, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DEF(CommandLine) {
|
||||||
|
testSimple();
|
||||||
|
}
|
||||||
18
CommandLine/tests/Tests.cpp
Normal file
18
CommandLine/tests/Tests.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
#include "Tests.hpp"
|
||||||
|
#include "Testing.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleTokenizer, nullptr };
|
||||||
|
tp::ModuleManifest testModule("CommandLineTest", nullptr, nullptr, deps);
|
||||||
|
|
||||||
|
if (!testModule.initialize()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
testCommandLine();
|
||||||
|
|
||||||
|
testModule.deinitialize();
|
||||||
|
}
|
||||||
7
CommandLine/tests/Tests.hpp
Normal file
7
CommandLine/tests/Tests.hpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Testing.hpp"
|
||||||
|
#include "Allocators.hpp"
|
||||||
|
#include "CommandLine.hpp"
|
||||||
|
|
||||||
|
void testCommandLine();
|
||||||
|
|
@ -80,16 +80,6 @@ namespace tp {
|
||||||
goto LOOP;
|
goto LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool toValue(const tChar* in, bool& val) {
|
|
||||||
if (!calcLength(in)) return false;
|
|
||||||
if (isEqual(in, "False") || isEqual(in, "false") || isEqual(in, "0")) {
|
|
||||||
val = false;
|
|
||||||
} else {
|
|
||||||
val = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns 0 : nl1 + 1 : nl2 + 1 : nl3 + 1 : ... : size
|
// returns 0 : nl1 + 1 : nl2 + 1 : nl3 + 1 : ... : size
|
||||||
static void calcLineOffsets(const tChar* aBuff, Index aLength, Buffer<Index>& aOut) {
|
static void calcLineOffsets(const tChar* aBuff, Index aLength, Buffer<Index>& aOut) {
|
||||||
Index lines = 0;
|
Index lines = 0;
|
||||||
|
|
@ -111,34 +101,34 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] static bool convertStringToValue(const tChar* input, alni& output) {
|
static bool convertStringToValue(const tChar* input, alni& output) {
|
||||||
char* endPtr;
|
char* endPtr;
|
||||||
output = std::strtoll(input, &endPtr, 10);
|
output = std::strtoll(input, &endPtr, 10);
|
||||||
return (endPtr == input + calcLength(input));
|
return (endPtr == input + calcLength(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool convertStringToValue(const tChar* input, alnf& output) {
|
static bool convertStringToValue(const tChar* input, alnf& output) {
|
||||||
char* endPtr;
|
char* endPtr;
|
||||||
output = std::strtod(input, &endPtr);
|
output = std::strtod(input, &endPtr);
|
||||||
return (endPtr == input + calcLength(input));
|
return (endPtr == input + calcLength(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool convertStringToValue(const tChar* input, bool& output) {
|
static bool convertStringToValue(const tChar* input, bool& output) {
|
||||||
output = !(isEqualLogic(input, "False") || isEqualLogic(input, "false") || isEqualLogic(input, "0"));
|
output = !(isEqualLogic(input, "False") || isEqualLogic(input, "false") || isEqualLogic(input, "0"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool convertValueToString(alni input, tChar* output, Index bufferSize) {
|
static bool convertValueToString(alni input, tChar* output, Index bufferSize) {
|
||||||
int result = std::snprintf(output, bufferSize, "%lld", input);
|
int result = std::snprintf(output, bufferSize, "%lld", input);
|
||||||
return result >= 0;
|
return result >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool convertValueToString(alnf input, tChar* output, Index bufferSize) {
|
static bool convertValueToString(alnf input, tChar* output, Index bufferSize) {
|
||||||
int result = std::snprintf(output, bufferSize, "%f", input);
|
int result = std::snprintf(output, bufferSize, "%f", input);
|
||||||
return result >= 0;
|
return result >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool convertValueToString(bool input, tChar* output, Index bufferSize) {
|
static bool convertValueToString(bool input, tChar* output, Index bufferSize) {
|
||||||
const char* str = (input ? "true" : "false");
|
const char* str = (input ? "true" : "false");
|
||||||
Index length = calcLength(str);
|
Index length = calcLength(str);
|
||||||
if (length >= bufferSize)
|
if (length >= bufferSize)
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,12 @@ namespace tp {
|
||||||
MODULE_SANITY_CHECK(gModuleStrings)
|
MODULE_SANITY_CHECK(gModuleStrings)
|
||||||
DEBUG_ASSERT(aBuff)
|
DEBUG_ASSERT(aBuff)
|
||||||
auto const len = Logic::calcLength(aBuff);
|
auto const len = Logic::calcLength(aBuff);
|
||||||
resize(len);
|
|
||||||
memCopy(mBuff, aBuff, len);
|
|
||||||
mReferenceCount = 0;
|
mReferenceCount = 0;
|
||||||
mIsConst = false;
|
mIsConst = false;
|
||||||
mEditedIdx = 0;
|
mEditedIdx = 0;
|
||||||
|
mBuff = new tChar[len + 1];
|
||||||
|
mBuff[len] = Logic::getEndChar();
|
||||||
|
memCopy(mBuff, aBuff, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] tChar* getBuffer() {
|
[[nodiscard]] tChar* getBuffer() {
|
||||||
|
|
@ -72,7 +73,12 @@ namespace tp {
|
||||||
typedef StringData<tChar> Data;
|
typedef StringData<tChar> Data;
|
||||||
typedef typename Logic::Index Index;
|
typedef typename Logic::Index Index;
|
||||||
|
|
||||||
enum { STRINGS_POOL_SIZE = 1024, };
|
enum {
|
||||||
|
STRINGS_POOL_SIZE = 1024,
|
||||||
|
MAX_INT_STRING_LENGTH = 10,
|
||||||
|
MAX_BOOL_STRING_LENGTH = 10,
|
||||||
|
MAX_FLOAT_STRING_LENGTH = 10,
|
||||||
|
};
|
||||||
static PoolAlloc<StringData<tChar>, STRINGS_POOL_SIZE> sStringPool;
|
static PoolAlloc<StringData<tChar>, STRINGS_POOL_SIZE> sStringPool;
|
||||||
static Data sNullString;
|
static Data sNullString;
|
||||||
|
|
||||||
|
|
@ -137,8 +143,9 @@ namespace tp {
|
||||||
|
|
||||||
// output will be null if in TextEditing mode
|
// output will be null if in TextEditing mode
|
||||||
tChar* resize(uint1 size) {
|
tChar* resize(uint1 size) {
|
||||||
if (!mData->getEditor()) mData->resize(size);
|
makeModifiable();
|
||||||
return mData->getBuffer();
|
mData->resize(size);
|
||||||
|
return write();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -160,6 +167,40 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // Syntax sugars
|
public: // Syntax sugars
|
||||||
|
|
||||||
|
explicit StringTemplate(alni val) {
|
||||||
|
auto raw = new tChar[MAX_INT_STRING_LENGTH];
|
||||||
|
Logic::convertValueToString(val, raw, MAX_INT_STRING_LENGTH);
|
||||||
|
mData = new (sStringPool.allocate(0)) StringData(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit StringTemplate(alnf val) {
|
||||||
|
auto raw = new tChar[MAX_FLOAT_STRING_LENGTH];
|
||||||
|
Logic::convertValueToString(val, raw, MAX_FLOAT_STRING_LENGTH);
|
||||||
|
mData = new (sStringPool.allocate(0)) StringData(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit StringTemplate(bool val) {
|
||||||
|
auto raw = new tChar[MAX_BOOL_STRING_LENGTH];
|
||||||
|
Logic::convertValueToString(val, raw, MAX_BOOL_STRING_LENGTH);
|
||||||
|
mData = new (sStringPool.allocate(0)) StringData(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator alni() {
|
||||||
|
alni out;
|
||||||
|
return Logic::convertStringToValue(read(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator alnf() {
|
||||||
|
alnf out;
|
||||||
|
return Logic::convertStringToValue(read(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() {
|
||||||
|
bool out;
|
||||||
|
return Logic::convertStringToValue(read(), out);
|
||||||
|
}
|
||||||
|
|
||||||
Index size() const {
|
Index size() const {
|
||||||
return Logic::calcLength(read());
|
return Logic::calcLength(read());
|
||||||
}
|
}
|
||||||
|
|
@ -181,11 +222,18 @@ namespace tp {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const StringTemplate& in) const {
|
||||||
|
if (&in == this) return true;
|
||||||
|
if (in.mData == mData) return true;
|
||||||
|
return Logic::isEqualLogic(in.read(), read());
|
||||||
|
}
|
||||||
|
|
||||||
public: // Debugging
|
public: // Debugging
|
||||||
[[nodiscard]] ualni getReferenceCount() const { return mData->mReferenceCount; }
|
[[nodiscard]] ualni getReferenceCount() const { return mData->mReferenceCount; }
|
||||||
[[nodiscard]] bool getIsConstFlag() const { return mData->mIsConst; }
|
[[nodiscard]] bool getIsConstFlag() const { return mData->mIsConst; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename tChar>
|
template<typename tChar>
|
||||||
PoolAlloc<StringData<tChar>, StringTemplate<tChar>::STRINGS_POOL_SIZE> StringTemplate<tChar>::sStringPool;
|
PoolAlloc<StringData<tChar>, StringTemplate<tChar>::STRINGS_POOL_SIZE> StringTemplate<tChar>::sStringPool;
|
||||||
|
|
||||||
|
|
@ -193,4 +241,9 @@ namespace tp {
|
||||||
StringData<tChar> StringTemplate<tChar>::sNullString;
|
StringData<tChar> StringTemplate<tChar>::sNullString;
|
||||||
|
|
||||||
using String = StringTemplate<int1>;
|
using String = StringTemplate<int1>;
|
||||||
|
|
||||||
|
template<typename tChar>
|
||||||
|
ualni hash(StringTemplate<tChar> in) {
|
||||||
|
return hash(in.read());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
||||||
|
extern ModuleManifest gModuleTokenizer;
|
||||||
|
|
||||||
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal>
|
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal>
|
||||||
class TransitionMatrix;
|
class TransitionMatrix;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
#include "AutomataGraph.h"
|
#include "AutomataGraph.h"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
extern ModuleManifest gModuleTokenizer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace tp::RegEx {
|
namespace tp::RegEx {
|
||||||
|
|
||||||
struct AstNode {
|
struct AstNode {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue