Merge branch 'Storage'
This commit is contained in:
commit
fa4d1d72dc
28 changed files with 1117 additions and 87 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "Externals/asio"]
|
||||||
|
path = Externals/asio
|
||||||
|
url = https://github.com/IlyaShurupov/asio.git
|
||||||
|
|
@ -18,3 +18,4 @@ add_subdirectory(Allocators)
|
||||||
add_subdirectory(Strings)
|
add_subdirectory(Strings)
|
||||||
add_subdirectory(Tokenizer)
|
add_subdirectory(Tokenizer)
|
||||||
add_subdirectory(CommandLine)
|
add_subdirectory(CommandLine)
|
||||||
|
add_subdirectory(Storage)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ file(GLOB SOURCES "./private/*.cpp")
|
||||||
file(GLOB HEADERS "./public/*.hpp")
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Tokenizer)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Tokenizer Storage)
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
### -------------------------- Tests -------------------------- ###
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
|
||||||
120
CommandLine/private/CmdLineInterpreter.cpp
Normal file
120
CommandLine/private/CmdLineInterpreter.cpp
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
#include "CmdLineInterpreter.hpp"
|
||||||
|
|
||||||
|
#define MAX_LINE_LENGTH 1024
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
static bool helpFunction(CmdLineInterpreter* self, const CommandLine& args) {
|
||||||
|
self->help(args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdLineInterpreter::help(const CommandLine& args) const {
|
||||||
|
auto commandName = args.getString("CommandName");
|
||||||
|
auto allCommands = commandName == "_none_";
|
||||||
|
|
||||||
|
if (allCommands) {
|
||||||
|
printf("Commands:\n");
|
||||||
|
for (auto command : mCommands) {
|
||||||
|
printf(" %s\n", command->key.read());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idx = mCommands.presents(commandName);
|
||||||
|
if (!idx) {
|
||||||
|
printf("Command '%s' not found\n", commandName.read());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Command '%s'\n", commandName.read());
|
||||||
|
auto command = &mCommands.getSlotVal(idx);
|
||||||
|
command->args->help();
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdLineInterpreter::CmdLineInterpreter() {
|
||||||
|
auto helpArgs = new CommandLine{
|
||||||
|
{ "CommandName", "_none_" }
|
||||||
|
};
|
||||||
|
|
||||||
|
addCommand("help", helpArgs, (CommandFunction) helpFunction, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CmdLineInterpreter::addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData) {
|
||||||
|
ASSERT(!mCommands.presents(id))
|
||||||
|
mCommands.put(id, { args, function, customData });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdLineInterpreter::run() {
|
||||||
|
char buffer[MAX_LINE_LENGTH];
|
||||||
|
printf("Command Line Interpreter (or type 'exit' to quit):\n");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
printf("%s >> ", mName.read());
|
||||||
|
|
||||||
|
// Read input from the user
|
||||||
|
if (fgets(buffer, MAX_LINE_LENGTH, stdin) == nullptr) {
|
||||||
|
printf("Error reading input.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the trailing newline character if it exists
|
||||||
|
auto length = strlen(buffer);
|
||||||
|
if (length > 0 && buffer[length - 1] == '\n') {
|
||||||
|
buffer[length - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user wants to exit
|
||||||
|
if (strcmp(buffer, "exit") == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the input here
|
||||||
|
processCommand(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CmdLineInterpreter::processCommand(int1* commandString) {
|
||||||
|
ualni commandLen = 0;
|
||||||
|
for (auto i = commandString; *i != 0; i++) {
|
||||||
|
if (*i == ' ') break;
|
||||||
|
commandLen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandString[commandLen] = 0;
|
||||||
|
auto args = commandString + commandLen + 1;
|
||||||
|
|
||||||
|
auto idx = mCommands.presents(commandString);
|
||||||
|
if (!idx) {
|
||||||
|
printf("ERROR: Command '%s' is not found\n", commandString);
|
||||||
|
printf("Please execute 'help' for more information\n\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto command = &mCommands.getSlotVal(idx);
|
||||||
|
|
||||||
|
command->args->parse(args);
|
||||||
|
|
||||||
|
if (command->args->mError) {
|
||||||
|
printf("ERROR: Command call '%s' has invalid arguments\n", commandString);
|
||||||
|
command->args->resetError();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!command->function(command->customData, *command->args)) {
|
||||||
|
printf("ERROR: Command call '%s' failed\n", commandString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdLineInterpreter::~CmdLineInterpreter() {
|
||||||
|
for (auto cmd : mCommands) {
|
||||||
|
delete cmd->val.args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
|
static ModuleManifest* sModuleDependencies[] = { &gModuleTokenizer, &gModuleStorage, nullptr };
|
||||||
|
ModuleManifest tp::gModuleCommandLine = ModuleManifest("CommandLine", nullptr, nullptr, sModuleDependencies);
|
||||||
|
|
||||||
const char* regexSpace = "\n|\t| |\r";
|
const char* regexSpace = "\n|\t| |\r";
|
||||||
const char* regexFalse = "N|n|(False)|(false)";
|
const char* regexFalse = "N|n|(False)|(false)";
|
||||||
const char* regexTrue = "Y|y|(True)|(true)";
|
const char* regexTrue = "Y|y|(True)|(true)";
|
||||||
|
|
@ -18,6 +21,8 @@ CommandLine::Arg::Arg(const Arg& arg) {
|
||||||
case CommandLine::Arg::BOOL: mType = BOOL; mBool = arg.mBool; 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::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;
|
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); mFile = arg.mFile; break;
|
||||||
|
default:
|
||||||
|
ASSERT(false)
|
||||||
}
|
}
|
||||||
mOptional = arg.mOptional;
|
mOptional = arg.mOptional;
|
||||||
}
|
}
|
||||||
|
|
@ -30,6 +35,7 @@ CommandLine::Arg::Arg(const String& id, Type type) {
|
||||||
case CommandLine::Arg::BOOL: mType = BOOL; new (&mBool) BoolArg(); break;
|
case CommandLine::Arg::BOOL: mType = BOOL; new (&mBool) BoolArg(); break;
|
||||||
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); break;
|
case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); break;
|
||||||
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); break;
|
case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); break;
|
||||||
|
default: ASSERT(false)
|
||||||
}
|
}
|
||||||
mOptional = false;
|
mOptional = false;
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +125,13 @@ CommandLine::CommandLine(const init_list<Arg>& args) {
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT(mTokenizer.isBuild() && "Internal Error")
|
ASSERT(mTokenizer.isBuild() && "Internal Error")
|
||||||
|
|
||||||
|
mArgumentTokenizer.build({
|
||||||
|
{ regexSpace, ArgTokType::SPACE },
|
||||||
|
{ "{ - }*", ArgTokType::ARG }
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT(mTokenizer.isBuild() && "Internal Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandLine::~CommandLine() {
|
CommandLine::~CommandLine() {
|
||||||
|
|
@ -153,17 +166,60 @@ bool CommandLine::parse(char argc, const char* argv[], bool logError, ualni skip
|
||||||
}
|
}
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
//set_working_dir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alni CommandLine::getInt(const String& id) { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; }
|
bool CommandLine::parse(const char* args, bool logError) {
|
||||||
alnf CommandLine::getFloat(const String& id) { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; }
|
mArgumentTokenizer.bindSource(args);
|
||||||
bool CommandLine::getBool(const String& id) { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; }
|
mArgumentTokenizer.reset();
|
||||||
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; }
|
ualni argc = 0;
|
||||||
|
auto tok = mArgumentTokenizer.readTok();
|
||||||
|
auto argument = mArgsOrder.first();
|
||||||
|
|
||||||
|
while (tok != ArgTokType::FAILURE && tok != ArgTokType::END) {
|
||||||
|
if (tok != ArgTokType::ARG) {
|
||||||
|
tok = mArgumentTokenizer.readTok();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argument) {
|
||||||
|
ErrInvalidArgCount();
|
||||||
|
if (logError) ErrLog();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseArg(*argument->data, mArgumentTokenizer.extractVal().read());
|
||||||
|
|
||||||
|
if (mError && logError) {
|
||||||
|
ErrLog();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
argc++;
|
||||||
|
argument = argument->next;
|
||||||
|
tok = mArgumentTokenizer.readTok();
|
||||||
|
}
|
||||||
|
|
||||||
|
ualni idx = 0;
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
if (idx >= argc) {
|
||||||
|
initDefault(*arg.data());
|
||||||
|
}
|
||||||
|
if (mError) {
|
||||||
|
if (logError) ErrLog();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
alni CommandLine::getInt(const String& id) const { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; }
|
||||||
|
alnf CommandLine::getFloat(const String& id) const { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; }
|
||||||
|
bool CommandLine::getBool(const String& id) const { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; }
|
||||||
|
const String& CommandLine::getString(const String& id) const { auto& arg = getArg(id, Arg::STR); return arg.mStr.mStr; }
|
||||||
|
const FileLocation& CommandLine::getFile(const String& id) const { auto& arg = getArg(id, Arg::FILE_IN); return arg.mFile.mFileLocation; }
|
||||||
|
|
||||||
|
|
||||||
CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) {
|
CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) {
|
||||||
|
|
@ -174,6 +230,14 @@ CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) {
|
||||||
return *arg;
|
return *arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) const {
|
||||||
|
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::ErrInvalidArgCount() { mError = { "Invalid Number Of Arguments Passed", nullptr }; }
|
||||||
void CommandLine::ErrInvalidArgSyntax(Arg* arg) { mError = { "Invalid Syntax Of Argument", arg }; }
|
void CommandLine::ErrInvalidArgSyntax(Arg* arg) { mError = { "Invalid Syntax Of Argument", arg }; }
|
||||||
void CommandLine::ErrInvalidArgType(Arg* arg) { mError = { "Invalid Type Of Argument", arg }; }
|
void CommandLine::ErrInvalidArgType(Arg* arg) { mError = { "Invalid Type Of Argument", arg }; }
|
||||||
|
|
@ -192,7 +256,7 @@ void CommandLine::ErrLog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nArgument: %lli\n", idx);
|
printf("\nArgument: %lli\n", idx);
|
||||||
ArgLog(*mError.mArg);
|
logArg(*mError.mArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Error Description: %s. \n", mError.mDescr);
|
printf("Error Description: %s. \n", mError.mDescr);
|
||||||
|
|
@ -201,7 +265,7 @@ void CommandLine::ErrLog() {
|
||||||
ualni idx = 0;
|
ualni idx = 0;
|
||||||
for (auto arg : mArgsOrder) {
|
for (auto arg : mArgsOrder) {
|
||||||
printf(" -- %lli -- \n", idx);
|
printf(" -- %lli -- \n", idx);
|
||||||
ArgLog(*arg.data());
|
logArg(*arg.data());
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +278,7 @@ void CommandLine::ErrLog() {
|
||||||
printf(" File - else\n");
|
printf(" File - else\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLine::ArgLog(Arg& arg) {
|
void CommandLine::logArg(const Arg& arg) {
|
||||||
switch (arg.mType) {
|
switch (arg.mType) {
|
||||||
case Arg::INT: {
|
case Arg::INT: {
|
||||||
printf("Type : Int\n");
|
printf("Type : Int\n");
|
||||||
|
|
@ -222,7 +286,7 @@ void CommandLine::ArgLog(Arg& arg) {
|
||||||
if (arg.mOptional) {
|
if (arg.mOptional) {
|
||||||
printf("Default : %lli\n", arg.mInt.mDefault);
|
printf("Default : %lli\n", arg.mInt.mDefault);
|
||||||
}
|
}
|
||||||
printf("Given : %lli\n", arg.mInt.mVal);
|
printf("Value : %lli\n", arg.mInt.mVal);
|
||||||
} break;
|
} break;
|
||||||
case Arg::FLOAT: {
|
case Arg::FLOAT: {
|
||||||
printf("Type : Float\n");
|
printf("Type : Float\n");
|
||||||
|
|
@ -230,26 +294,27 @@ void CommandLine::ArgLog(Arg& arg) {
|
||||||
if (arg.mOptional) {
|
if (arg.mOptional) {
|
||||||
printf("Default : %f\n", arg.mFloat.mDefault);
|
printf("Default : %f\n", arg.mFloat.mDefault);
|
||||||
}
|
}
|
||||||
printf("Given : %f\n", arg.mFloat.mVal);
|
printf("Value : %f\n", arg.mFloat.mVal);
|
||||||
} break;
|
} break;
|
||||||
case Arg::BOOL: {
|
case Arg::BOOL: {
|
||||||
printf("Type : Bool\n");
|
printf("Type : Bool\n");
|
||||||
if (arg.mOptional) {
|
if (arg.mOptional) {
|
||||||
printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False");
|
printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False");
|
||||||
}
|
}
|
||||||
printf("Given : %s\n", arg.mBool.mFlag ? "True" : "False");
|
printf("Value : %s\n", arg.mBool.mFlag ? "True" : "False");
|
||||||
} break;
|
} break;
|
||||||
case Arg::STR: {
|
case Arg::STR: {
|
||||||
printf("Type : String\n");
|
printf("Type : String\n");
|
||||||
if (arg.mOptional) {
|
if (arg.mOptional) {
|
||||||
printf("Default : %s\n", arg.mStr.mDefault.read());
|
printf("Default : %s\n", arg.mStr.mDefault.read());
|
||||||
}
|
}
|
||||||
printf("Given : %s\n", arg.mStr.mStr.read());
|
printf("Value : %s\n", arg.mStr.mStr.read());
|
||||||
} break;
|
} break;
|
||||||
case Arg::FILE_IN: {
|
case Arg::FILE_IN: {
|
||||||
printf("Type : File Input\n");
|
printf("Type : File Input\n");
|
||||||
printf("Given Path : %s\n", arg.mFile.mFilepath.read());
|
printf("Value Path : %s\n", arg.mFile.mFileLocation.getLocation().read());
|
||||||
} break;
|
} break;
|
||||||
|
default: ASSERT(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,7 +370,8 @@ void CommandLine::parseArg(Arg& arg, const char* src) {
|
||||||
ErrInvalidArgType(&arg);
|
ErrInvalidArgType(&arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
arg.mStr.mStr = val;
|
arg.mStr.mStr.resize(val.size() - 2);
|
||||||
|
memCopy(arg.mStr.mStr.write(), val.read() + 1, val.size() - 2);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Arg::BOOL: {
|
case Arg::BOOL: {
|
||||||
|
|
@ -313,7 +379,7 @@ void CommandLine::parseArg(Arg& arg, const char* src) {
|
||||||
ErrInvalidArgType(&arg);
|
ErrInvalidArgType(&arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
arg.mBool.mFlag = bool(val);
|
arg.mBool.mFlag = tok == TokType::BOOL_TRUE;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Arg::FILE_IN: {
|
case Arg::FILE_IN: {
|
||||||
|
|
@ -322,24 +388,23 @@ void CommandLine::parseArg(Arg& arg, const char* src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.mFile.mFilepath = val;
|
arg.mFile.mFileLocation.setLocation(val);
|
||||||
|
|
||||||
/*
|
if (!arg.mFile.mFileLocation.exists()) {
|
||||||
// TODO : replace
|
|
||||||
if (!File::exists(arg.mFile.mFilepath.cstr())) {
|
|
||||||
ErrFileNotExists(&arg);
|
ErrFileNotExists(&arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.mFile.mFile.open(arg.mFile.mFilepath.cstr(), osfile_openflags::LOAD);
|
|
||||||
if (!arg.mFile.mFile.opened) {
|
|
||||||
ErrFileCouldNotOpen(&arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
default: ASSERT(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.mIsPassed = true;
|
arg.mIsPassed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandLine::help() const {
|
||||||
|
printf("Arguments:\n");
|
||||||
|
for (auto arg : mArgsOrder) {
|
||||||
|
logArg(*arg.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
36
CommandLine/public/CmdLineInterpreter.hpp
Normal file
36
CommandLine/public/CmdLineInterpreter.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CommandLine.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class CmdLineInterpreter {
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef bool (*CommandFunction)(void* customData, const CommandLine& args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
CommandLine* args;
|
||||||
|
CommandFunction function;
|
||||||
|
void* customData = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, Command> mCommands;
|
||||||
|
String mName = "InterpName";
|
||||||
|
|
||||||
|
public:
|
||||||
|
CmdLineInterpreter();
|
||||||
|
~CmdLineInterpreter();
|
||||||
|
|
||||||
|
void setName(const String& name) { mName = name; }
|
||||||
|
[[nodiscard]] const String& getName() const { return mName; }
|
||||||
|
|
||||||
|
void help(const CommandLine& args) const;
|
||||||
|
void addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData = nullptr);
|
||||||
|
void run();
|
||||||
|
bool processCommand(int1* command);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
#include "Tokenizer.hpp"
|
#include "Tokenizer.hpp"
|
||||||
#include "Map.hpp"
|
#include "Map.hpp"
|
||||||
|
#include "LocalStorage.hpp"
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
||||||
// TODO : replace
|
extern ModuleManifest gModuleCommandLine;
|
||||||
class File {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CommandLine {
|
struct CommandLine {
|
||||||
|
|
||||||
|
|
@ -35,13 +33,12 @@ namespace tp {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FileInputArg {
|
struct FileInputArg {
|
||||||
String mFilepath;
|
FileLocation mFileLocation;
|
||||||
File mFile;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arg {
|
struct Arg {
|
||||||
String mId;
|
String mId;
|
||||||
enum Type { INT, FLOAT, BOOL, STR, FILE_IN } mType;
|
enum Type { INT, FLOAT, BOOL, STR, FILE_IN, NONE } mType = NONE;
|
||||||
union {
|
union {
|
||||||
IntArg mInt;
|
IntArg mInt;
|
||||||
FloatArg mFloat;
|
FloatArg mFloat;
|
||||||
|
|
@ -73,16 +70,23 @@ namespace tp {
|
||||||
CommandLine(const init_list<Arg>& args);
|
CommandLine(const init_list<Arg>& args);
|
||||||
~CommandLine();
|
~CommandLine();
|
||||||
|
|
||||||
bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1);
|
void resetError() { mError.mDescr = nullptr; }
|
||||||
|
|
||||||
alni getInt(const String& id);
|
bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1);
|
||||||
alnf getFloat(const String& id);
|
bool parse(const char* args, bool logError = true);
|
||||||
bool getBool(const String& id);
|
|
||||||
const String& getString(const String& id);
|
void help() const;
|
||||||
File& getFile(const String& id);
|
|
||||||
|
[[nodiscard]] alni getInt(const String& id) const;
|
||||||
|
[[nodiscard]] alnf getFloat(const String& id) const;
|
||||||
|
[[nodiscard]] bool getBool(const String& id) const;
|
||||||
|
[[nodiscard]] const String& getString(const String& id) const;
|
||||||
|
[[nodiscard]] const FileLocation& getFile(const String& id) const;
|
||||||
|
|
||||||
|
const CommandLine& operator=(const CommandLine&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, } mType;
|
enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, };
|
||||||
typedef SimpleTokenizer<char, TokType, TokType::NONE, TokType::FAILURE, TokType::END> Tokenizer;
|
typedef SimpleTokenizer<char, TokType, TokType::NONE, TokType::FAILURE, TokType::END> Tokenizer;
|
||||||
|
|
||||||
Tokenizer mTokenizer;
|
Tokenizer mTokenizer;
|
||||||
|
|
@ -90,7 +94,12 @@ namespace tp {
|
||||||
List<Arg*> mArgsOrder;
|
List<Arg*> mArgsOrder;
|
||||||
ualni mOptionals = 0;
|
ualni mOptionals = 0;
|
||||||
|
|
||||||
|
enum class ArgTokType { SPACE, ARG, NONE, FAILURE, END, };
|
||||||
|
SimpleTokenizer<char, ArgTokType, ArgTokType::NONE, ArgTokType::FAILURE, ArgTokType::END> mArgumentTokenizer;
|
||||||
|
|
||||||
Arg& getArg(const String& id, Arg::Type type);
|
Arg& getArg(const String& id, Arg::Type type);
|
||||||
|
[[nodiscard]] const Arg& getArg(const String& id, Arg::Type type) const;
|
||||||
|
|
||||||
void ErrInvalidArgCount();
|
void ErrInvalidArgCount();
|
||||||
void ErrInvalidArgSyntax(Arg* arg);
|
void ErrInvalidArgSyntax(Arg* arg);
|
||||||
void ErrInvalidArgType(Arg* arg);
|
void ErrInvalidArgType(Arg* arg);
|
||||||
|
|
@ -98,8 +107,8 @@ namespace tp {
|
||||||
void ErrFileCouldNotOpen(Arg* arg);
|
void ErrFileCouldNotOpen(Arg* arg);
|
||||||
void ErrValNotinRange(Arg* arg);
|
void ErrValNotinRange(Arg* arg);
|
||||||
void ErrLog();
|
void ErrLog();
|
||||||
static void ArgLog(Arg& arg);
|
static void logArg(const Arg& arg);
|
||||||
static void initDefault(Arg& arg);
|
static void initDefault(Arg& arg);
|
||||||
void parseArg(Arg& arg, const char* src);
|
void parseArg(Arg& arg, const char* src);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
34
CommandLine/tests/TestInterpreter.cpp
Normal file
34
CommandLine/tests/TestInterpreter.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "Tests.hpp"
|
||||||
|
#include "CmdLineInterpreter.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
TEST_DEF_STATIC(Simple) {
|
||||||
|
|
||||||
|
struct TestStruct {
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
static bool print(TestStruct* self, const CommandLine& args) {
|
||||||
|
printf("Test Val - %i\n", (int) args.getBool("bool"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TestStruct self;
|
||||||
|
|
||||||
|
CmdLineInterpreter interp;
|
||||||
|
|
||||||
|
interp.addCommand("test", new CommandLine{ { "bool", CommandLine::Arg::BOOL } }, (CmdLineInterpreter::CommandFunction) TestStruct::print);
|
||||||
|
|
||||||
|
printf("test false\n", stdin);
|
||||||
|
printf("help\n", stdin);
|
||||||
|
printf("help test\n", stdin);
|
||||||
|
printf("exit\n", stdin);
|
||||||
|
|
||||||
|
interp.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DEF(Interpreter) {
|
||||||
|
//testSimple();
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,8 @@ int main() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
testCommandLine();
|
// testCommandLine();
|
||||||
|
testInterpreter();
|
||||||
|
|
||||||
testModule.deinitialize();
|
testModule.deinitialize();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
#include "CommandLine.hpp"
|
#include "CommandLine.hpp"
|
||||||
|
|
||||||
void testCommandLine();
|
void testCommandLine();
|
||||||
|
void testInterpreter();
|
||||||
|
|
|
||||||
1
Externals/asio
vendored
Submodule
1
Externals/asio
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d6b95c0188e0359a8cdbdb6571f0cbacf11a538c
|
||||||
29
Storage/CMakeLists.txt
Normal file
29
Storage/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
|
project(Storage)
|
||||||
|
|
||||||
|
set(ASIO_INCLUDE ./../Externals/asio/asio/include)
|
||||||
|
|
||||||
|
### ---------------------- Static Library --------------------- ###
|
||||||
|
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
|
||||||
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
|
target_include_directories(${PROJECT_NAME} PRIVATE ${ASIO_INCLUDE})
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
|
||||||
|
|
||||||
|
|
||||||
|
### -------------------------- Applications -------------------------- ###
|
||||||
|
add_subdirectory(applications)
|
||||||
|
|
||||||
|
### -------------------------- 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)
|
||||||
13
Storage/applications/CMakeLists.txt
Normal file
13
Storage/applications/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
project(Applications)
|
||||||
|
|
||||||
|
file(GLOB SOURCES_CLIENT ./Client.cpp ./SystemAPI.cpp)
|
||||||
|
file(GLOB SOURCES_SERVER ./Server.cpp ./SystemAPI.cpp)
|
||||||
|
|
||||||
|
add_executable(Client ${SOURCES_CLIENT})
|
||||||
|
target_link_libraries(Client Storage CommandLine)
|
||||||
|
|
||||||
|
add_executable(Server ${SOURCES_SERVER})
|
||||||
|
target_link_libraries(Server Storage CommandLine)
|
||||||
64
Storage/applications/Client.cpp
Normal file
64
Storage/applications/Client.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
|
||||||
|
#include "Strings.hpp"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class CharClient {
|
||||||
|
|
||||||
|
typedef void* (*ThreadFunction)(void *);
|
||||||
|
|
||||||
|
Client client;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CharClient(int port, const char* ip) {
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
client.connect(ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
// Create a new thread to handle the client
|
||||||
|
pthread_t threadId;
|
||||||
|
if (pthread_create(&threadId, nullptr, (ThreadFunction) readServerBroadcast, this)) {
|
||||||
|
printf("Failed to create thread for client\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach the thread so it can run independently
|
||||||
|
pthread_detach(threadId);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const auto length = 1024;
|
||||||
|
static char message[length];
|
||||||
|
|
||||||
|
printf(" >> ");
|
||||||
|
fgets(message, length, stdin);
|
||||||
|
|
||||||
|
if (String::Logic::isEqualLogic(message, "exit")) return;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
client.write(message);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* readServerBroadcast(CharClient* self) {
|
||||||
|
while (true) {
|
||||||
|
auto message = self->client.read();
|
||||||
|
pthread_mutex_lock(&self->mutex);
|
||||||
|
printf("Broadcast : %s \n", message);
|
||||||
|
delete[] message;
|
||||||
|
pthread_mutex_unlock(&self->mutex);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
CharClient client(5555, "127.0.0.1");
|
||||||
|
client.start();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
92
Storage/applications/Server.cpp
Normal file
92
Storage/applications/Server.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
#include "Strings.hpp"
|
||||||
|
#include "List.hpp"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class ChatServer {
|
||||||
|
|
||||||
|
struct SharedData {
|
||||||
|
List<Server::Socket> clients;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
SharedData mSharedData;
|
||||||
|
Server server;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ChatServer(int port) {
|
||||||
|
server.start(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ChatServer() {
|
||||||
|
DEBUG_ASSERT(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start() {
|
||||||
|
while (true) {
|
||||||
|
auto clientSocket = server.accept();
|
||||||
|
|
||||||
|
// add client
|
||||||
|
pthread_mutex_lock(&mSharedData.mutex);
|
||||||
|
mSharedData.clients.pushBack(clientSocket);
|
||||||
|
pthread_mutex_unlock(&mSharedData.mutex);
|
||||||
|
|
||||||
|
// Create a new thread to handle the client
|
||||||
|
pthread_t threadId;
|
||||||
|
if (pthread_create(&threadId, nullptr, (void* (*)(void*)) handleClient, this)) {
|
||||||
|
printf("Failed to create thread for client\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach the thread so it can run independently
|
||||||
|
pthread_detach(threadId);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void* handleClient(ChatServer* self) {
|
||||||
|
// read shared data - current client id
|
||||||
|
pthread_mutex_lock(&self->mSharedData.mutex);
|
||||||
|
auto clientSocket = self->mSharedData.clients.last();
|
||||||
|
pthread_mutex_unlock(&self->mSharedData.mutex);
|
||||||
|
|
||||||
|
MESSAGE:
|
||||||
|
// wait for a message request
|
||||||
|
auto message = Server::read(clientSocket);
|
||||||
|
|
||||||
|
// Broadcast to all clients
|
||||||
|
for (auto client : self->mSharedData.clients) {
|
||||||
|
Server::write(client.data(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto exit = memCompare(message, "exit", 5) == 0;
|
||||||
|
|
||||||
|
delete[] message;
|
||||||
|
|
||||||
|
if (exit) {
|
||||||
|
// TODO : disconnect
|
||||||
|
for (auto iter : self->mSharedData.clients) {
|
||||||
|
if (clientSocket == iter.data()) {
|
||||||
|
self->mSharedData.clients.removeNode(iter.node());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&self->mSharedData.mutex);
|
||||||
|
|
||||||
|
if (exit) return nullptr;
|
||||||
|
goto MESSAGE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ChatServer server(5555);
|
||||||
|
server.start();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
90
Storage/private/LocalStorage.cpp
Normal file
90
Storage/private/LocalStorage.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include "LocalStorage.hpp"
|
||||||
|
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
|
||||||
|
bool FileLocation::exists() const {
|
||||||
|
FILE* file = fopen(mLocation.read(), "r");
|
||||||
|
if (file) {
|
||||||
|
// File exists, close it and return 1
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::connect(const FileLocation& location, const FileConnectionType& connectionInfo) {
|
||||||
|
DEBUG_ASSERT(!mStatus.isOpened());
|
||||||
|
if (mStatus.isOpened()) return false;
|
||||||
|
|
||||||
|
auto handle = new FileSystemHandle();
|
||||||
|
|
||||||
|
switch (connectionInfo.getType()) {
|
||||||
|
case FileConnectionType::READ:
|
||||||
|
handle->open(location.getLocation().read(), false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FileConnectionType::WRITE:
|
||||||
|
handle->open(location.getLocation().read(), true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!handle->isOpen()) {
|
||||||
|
mStatus.setStatus(FileConnectionStatus::DENIED);
|
||||||
|
delete handle;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatus.setStatus(FileConnectionStatus::OPENED);
|
||||||
|
mHandle = handle;
|
||||||
|
mConnectionType = connectionInfo;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::disconnect() {
|
||||||
|
DEBUG_ASSERT(mStatus.isOpened());
|
||||||
|
if (!mStatus.isOpened() || !mHandle) return false;
|
||||||
|
mHandle->close();
|
||||||
|
delete mHandle;
|
||||||
|
mStatus.setStatus(FileConnectionStatus::CLOSED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::setPointer(BytePointer pointer) {
|
||||||
|
DEBUG_ASSERT(mStatus.isOpened());
|
||||||
|
if (!mStatus.isOpened()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::readBytes(Byte* bytes, SizeBytes size) {
|
||||||
|
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isWrite());
|
||||||
|
if (!mStatus.isOpened() || !mConnectionType.isWrite()) return false;
|
||||||
|
|
||||||
|
mHandle->seekp(mPointer);
|
||||||
|
mHandle->read(bytes, size);
|
||||||
|
mPointer += size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::writeBytes(const Byte* bytes, SizeBytes size) {
|
||||||
|
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isRead());
|
||||||
|
if (!mStatus.isOpened() || !mConnectionType.isRead()) return false;
|
||||||
|
|
||||||
|
mHandle->seekp(mPointer);
|
||||||
|
mHandle->write(bytes, size);
|
||||||
|
mPointer += size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::SizeBytes File::size() {
|
||||||
|
DEBUG_ASSERT(mStatus.isOpened());
|
||||||
|
if (!mStatus.isOpened() || !mHandle) return 0;
|
||||||
|
return mHandle->size();
|
||||||
|
}
|
||||||
0
Storage/private/RemoteStorage.cpp
Normal file
0
Storage/private/RemoteStorage.cpp
Normal file
9
Storage/private/Storage.cpp
Normal file
9
Storage/private/Storage.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#include "Storage.hpp"
|
||||||
|
|
||||||
|
static tp::ModuleManifest* sModuleDependencies[] = {
|
||||||
|
&tp::gModuleStrings,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
tp::ModuleManifest tp::gModuleStorage = ModuleManifest("Storage", nullptr, nullptr, sModuleDependencies);
|
||||||
57
Storage/private/SystemAPIFile.cpp
Normal file
57
Storage/private/SystemAPIFile.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
ualni tp::FileSystemHandle::size() {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
ualni out = 0;
|
||||||
|
strm->seekg(0, std::ios::beg);
|
||||||
|
out = strm->tellg();
|
||||||
|
strm->seekg(0, std::ios::end);
|
||||||
|
out = (ualni) strm->tellg() - out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemHandle::FileSystemHandle() {
|
||||||
|
stream = new std::fstream();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemHandle::~FileSystemHandle() {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
delete strm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystemHandle::isOpen() {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
return strm->is_open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemHandle::close() {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
strm->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemHandle::seekp(ualni in) {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
strm->seekp(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemHandle::read(int1* in, ualni size) {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
strm->read(in, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemHandle::write(const int1* in, ualni size) {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
strm->write(in, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemHandle::open(const char* path, bool read) {
|
||||||
|
auto strm = (std::fstream*) stream;
|
||||||
|
if (read)
|
||||||
|
strm->open(path, std::ios::in | std::ios::binary | std::ios::app);
|
||||||
|
else
|
||||||
|
strm->open(path, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||||
|
}
|
||||||
130
Storage/private/SystemAPINet.cpp
Normal file
130
Storage/private/SystemAPINet.cpp
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
|
||||||
|
#include "asio.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
class tp::ServerContext {
|
||||||
|
friend class Server;
|
||||||
|
|
||||||
|
asio::io_context context;
|
||||||
|
asio::ip::tcp::acceptor socket;
|
||||||
|
typedef asio::ip::tcp::socket Socket;
|
||||||
|
|
||||||
|
ServerContext() : socket(context) {}
|
||||||
|
|
||||||
|
~ServerContext() {
|
||||||
|
context.stop();
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class tp::ClientContext {
|
||||||
|
friend Client;
|
||||||
|
|
||||||
|
asio::io_context context;
|
||||||
|
asio::ip::tcp::socket socket;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClientContext() : socket(context) {}
|
||||||
|
|
||||||
|
~ClientContext() {
|
||||||
|
context.stop();
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
Server::Server() {
|
||||||
|
mContext = new ServerContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::~Server() {
|
||||||
|
delete mContext;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::start(ualni port) {
|
||||||
|
mContext->socket.open(asio::ip::tcp::v4());
|
||||||
|
mContext->socket.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));
|
||||||
|
mContext->socket.listen();
|
||||||
|
std::cout << "Server listening on port " << port << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::Socket Server::accept() {
|
||||||
|
auto clientSocket = new asio::ip::tcp::socket(mContext->context);
|
||||||
|
mContext->socket.accept(*clientSocket);
|
||||||
|
std::cout << "New client accepted "<< std::endl;
|
||||||
|
return clientSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
int1* Server::read(Socket client) {
|
||||||
|
short messageSize;
|
||||||
|
if (asio::read(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) {
|
||||||
|
std::cerr << "Failed to read from socket" << std::endl;
|
||||||
|
((ServerContext::Socket*)client)->close();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto message = new char[messageSize + 1];
|
||||||
|
message[messageSize] = '\0';
|
||||||
|
if (asio::read(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) {
|
||||||
|
std::cerr << "Failed to read from socket" << std::endl;
|
||||||
|
memcpy(message, "Client wanna say something but i cant read", 100);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::write(Socket client, const char* message) {
|
||||||
|
auto messageSize = (short) strlen(message);
|
||||||
|
if (asio::write(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) {
|
||||||
|
std::cerr << "Failed to write to socket" << std::endl;
|
||||||
|
}
|
||||||
|
if (asio::write(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) {
|
||||||
|
std::cerr << "Failed to write to socket" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
Client::Client() {
|
||||||
|
mContext = new ClientContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
Client::~Client() {
|
||||||
|
delete mContext;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::connect(const char* IP, ualni PORT) {
|
||||||
|
asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string(IP), PORT);
|
||||||
|
mContext->socket.connect(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Client::read() {
|
||||||
|
short messageSize;
|
||||||
|
if (asio::read(mContext->socket, asio::buffer(&messageSize, 2)) == -1) {
|
||||||
|
std::cerr << "Failed to read from socket" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto message = new char[messageSize + 1];
|
||||||
|
message[messageSize] = '\0';
|
||||||
|
if (asio::read(mContext->socket, asio::buffer(message, messageSize)) == -1) {
|
||||||
|
std::cerr << "Failed to read from socket" << std::endl;
|
||||||
|
memcpy(message, "Cant wanna say something but i cant read", 100);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::write( const char* message ) {
|
||||||
|
auto messageSize = (short) strlen(message);
|
||||||
|
if (asio::write(mContext->socket, asio::buffer(&messageSize, 2)) == -1) {
|
||||||
|
std::cerr << "Failed to write to socket" << std::endl;
|
||||||
|
}
|
||||||
|
if (asio::write(mContext->socket, asio::buffer(message, messageSize)) == -1) {
|
||||||
|
std::cerr << "Failed to write to socket" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
99
Storage/public/LocalStorage.hpp
Normal file
99
Storage/public/LocalStorage.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Storage.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
class FileSystemHandle;
|
||||||
|
|
||||||
|
class FileLocation {
|
||||||
|
String mLocation;
|
||||||
|
public:
|
||||||
|
FileLocation() : mLocation("tmp") {};
|
||||||
|
explicit FileLocation(const String& location) : mLocation(location) {}
|
||||||
|
void setLocation(const String& location) { mLocation = location; }
|
||||||
|
[[nodiscard]] const String& getLocation() const { return mLocation; }
|
||||||
|
[[nodiscard]] bool exists() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileConnectionType {
|
||||||
|
public:
|
||||||
|
enum HandleType {
|
||||||
|
READ,
|
||||||
|
WRITE,
|
||||||
|
NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
HandleType mHandleType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileConnectionType() : mHandleType(NONE) {}
|
||||||
|
explicit FileConnectionType(bool read) : mHandleType((HandleType) read) {}
|
||||||
|
explicit FileConnectionType(HandleType handleType) : mHandleType(handleType) {}
|
||||||
|
[[nodiscard]] HandleType getType() const { return mHandleType; }
|
||||||
|
[[nodiscard]] bool isRead() const { return mHandleType == READ; }
|
||||||
|
[[nodiscard]] bool isWrite() const { return mHandleType == WRITE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileConnectionStatus {
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
NONE,
|
||||||
|
OPENED,
|
||||||
|
CLOSED,
|
||||||
|
DENIED,
|
||||||
|
INVALID,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Status mStatus = NONE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileConnectionStatus() = default;
|
||||||
|
[[nodiscard]] Status getStatus() const { return mStatus; }
|
||||||
|
void setStatus(Status status) { mStatus = status; }
|
||||||
|
[[nodiscard]] bool isOpened() const { return mStatus == OPENED; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class File {
|
||||||
|
typedef ualni SizeBytes;
|
||||||
|
typedef ualni BytePointer;
|
||||||
|
typedef int1 Byte;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileSystemHandle* mHandle = nullptr;
|
||||||
|
|
||||||
|
FileLocation mLocation;
|
||||||
|
FileConnectionType mConnectionType;
|
||||||
|
FileConnectionStatus mStatus;
|
||||||
|
|
||||||
|
BytePointer mPointer = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
File() {
|
||||||
|
MODULE_SANITY_CHECK(gModuleStorage)
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~File() {
|
||||||
|
if (mStatus.isOpened()) File::disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool connect(const FileLocation& location, const FileConnectionType& connectionInfo);
|
||||||
|
virtual bool disconnect();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual const FileConnectionStatus& getConnectionStatus() { return mStatus; }
|
||||||
|
virtual const FileConnectionType& getConnectionType() { return mConnectionType; }
|
||||||
|
virtual const FileLocation& getLocation() { return mLocation; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool setPointer(BytePointer pointer);
|
||||||
|
virtual bool readBytes(Byte* bytes, SizeBytes size);
|
||||||
|
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual SizeBytes size();
|
||||||
|
};
|
||||||
|
}
|
||||||
17
Storage/public/RemoteStorage.hpp
Normal file
17
Storage/public/RemoteStorage.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SystemAPI.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
/*
|
||||||
|
class Client : public Storage {
|
||||||
|
// same as local storage file but transfers all commands to server
|
||||||
|
};
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
// opens local storage and transfers all client command to it
|
||||||
|
// manages multiple clients
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
}
|
||||||
53
Storage/public/Storage.hpp
Normal file
53
Storage/public/Storage.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Strings.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
|
||||||
|
extern ModuleManifest gModuleStorage;
|
||||||
|
|
||||||
|
class StorageLocation {
|
||||||
|
public:
|
||||||
|
StorageLocation() = default;
|
||||||
|
virtual ~StorageLocation() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectionType {
|
||||||
|
public:
|
||||||
|
ConnectionType() = default;
|
||||||
|
virtual ~ConnectionType() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectionStatus {
|
||||||
|
public:
|
||||||
|
ConnectionStatus() = default;
|
||||||
|
virtual ~ConnectionStatus() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Storage {
|
||||||
|
typedef ualni SizeBytes;
|
||||||
|
typedef ualni BytePointer;
|
||||||
|
typedef int1 Byte;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StorageLocation mLocation;
|
||||||
|
ConnectionType mConnectionType;
|
||||||
|
ConnectionStatus mStatus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Storage() = default;
|
||||||
|
virtual ~Storage() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool connect(const StorageLocation& location, const ConnectionType& connectionInfo) = 0;
|
||||||
|
virtual bool disconnect() = 0;
|
||||||
|
virtual const ConnectionStatus& getConnectionStatus() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool readBytes(BytePointer pointer, Byte* bytes, SizeBytes size) = 0;
|
||||||
|
virtual bool writeBytes(BytePointer pointer, const Byte* bytes, SizeBytes size) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual SizeBytes size() = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
51
Storage/public/SystemAPI.hpp
Normal file
51
Storage/public/SystemAPI.hpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
namespace tp {
|
||||||
|
class FileSystemHandle {
|
||||||
|
void* stream;
|
||||||
|
public:
|
||||||
|
FileSystemHandle();
|
||||||
|
~FileSystemHandle();
|
||||||
|
void open(const char*, bool);
|
||||||
|
bool isOpen();
|
||||||
|
void close();
|
||||||
|
void seekp(ualni);
|
||||||
|
void read(int1*, ualni);
|
||||||
|
void write(const int1*, ualni);
|
||||||
|
ualni size();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ServerContext;
|
||||||
|
class ClientContext;
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
ServerContext* mContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef void* Socket;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Server();
|
||||||
|
~Server();
|
||||||
|
|
||||||
|
void start(ualni port);
|
||||||
|
Socket accept();
|
||||||
|
static int1* read(Socket client);
|
||||||
|
static void write(Socket client, const int1* message);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Client {
|
||||||
|
ClientContext* mContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Client();
|
||||||
|
~Client();
|
||||||
|
|
||||||
|
void connect(const int1* IP, ualni PORT);
|
||||||
|
int1* read();
|
||||||
|
void write(const int1* message);
|
||||||
|
};
|
||||||
|
}
|
||||||
33
Storage/tests/TestLocalStorage.cpp
Normal file
33
Storage/tests/TestLocalStorage.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
#include "Testing.hpp"
|
||||||
|
#include "LocalStorage.hpp"
|
||||||
|
|
||||||
|
using namespace tp;
|
||||||
|
|
||||||
|
TEST_DEF_STATIC(Simple) {
|
||||||
|
|
||||||
|
const int1* data = "abcde\0";
|
||||||
|
int1 dataRead[6]{};
|
||||||
|
|
||||||
|
{
|
||||||
|
File file;
|
||||||
|
file.connect(FileLocation(String("tmp2.txt")), FileConnectionType(false));
|
||||||
|
file.writeBytes(data, 6);
|
||||||
|
file.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
File file;
|
||||||
|
file.connect(FileLocation(String("tmp2.txt")), FileConnectionType(true));
|
||||||
|
file.readBytes(dataRead, 6);
|
||||||
|
file.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = 0; i < 5; i++) {
|
||||||
|
TEST(data[i] == dataRead[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DEF(LocalStorage) {
|
||||||
|
testSimple();
|
||||||
|
}
|
||||||
19
Storage/tests/Tests.cpp
Normal file
19
Storage/tests/Tests.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
#include "Testing.hpp"
|
||||||
|
#include "Storage.hpp"
|
||||||
|
|
||||||
|
void testLocalStorage();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
tp::ModuleManifest* deps[] = { &tp::gModuleStorage, nullptr };
|
||||||
|
tp::ModuleManifest testModule("StorageTest", nullptr, nullptr, deps);
|
||||||
|
|
||||||
|
if (!testModule.initialize()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
testLocalStorage();
|
||||||
|
|
||||||
|
testModule.deinitialize();
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "PoolAllocator.hpp"
|
#include "Allocators.hpp"
|
||||||
#include "StringLogic.hpp"
|
#include "StringLogic.hpp"
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
@ -188,17 +188,20 @@ namespace tp {
|
||||||
|
|
||||||
explicit operator alni() {
|
explicit operator alni() {
|
||||||
alni out;
|
alni out;
|
||||||
return Logic::convertStringToValue(read(), out);
|
Logic::convertStringToValue(read(), out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator alnf() {
|
explicit operator alnf() {
|
||||||
alnf out;
|
alnf out;
|
||||||
return Logic::convertStringToValue(read(), out);
|
Logic::convertStringToValue(read(), out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() {
|
explicit operator bool() {
|
||||||
bool out;
|
bool out;
|
||||||
return Logic::convertStringToValue(read(), out);
|
Logic::convertStringToValue(read(), out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index size() const {
|
Index size() const {
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ namespace tp {
|
||||||
String extractVal() {
|
String extractVal() {
|
||||||
auto crs = getCursorPrev();
|
auto crs = getCursorPrev();
|
||||||
String out;
|
String out;
|
||||||
out.resize(mLastTokLen + 1);
|
out.resize(mLastTokLen);
|
||||||
memCopy(out.write(), crs.str(), mLastTokLen);
|
memCopy(out.write(), crs.str(), mLastTokLen);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue