This commit is contained in:
IlyaShurupov 2024-03-27 17:06:46 +03:00
parent 2053bf474b
commit 31fa6e96bb
9 changed files with 166 additions and 58 deletions

View file

@ -4,11 +4,14 @@ project(FileSystemEmulator)
set(CMAKE_CXX_STANDARD 20)
file(GLOB SOURCES "./src/*.cpp")
file(GLOB HEADERS "./inc/*.hpp")
file(GLOB SOURCES "src/*.cpp")
file(GLOB HEADERS "inc/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./inc/)
target_include_directories(${PROJECT_NAME} PUBLIC inc/)
add_executable(fse "app/main.cpp")
target_link_libraries(fse ${PROJECT_NAME})
file(GLOB TEST_SOURCES "./test/*.cpp")
add_executable(Test${PROJECT_NAME} ${TEST_SOURCES})

26
app/main.cpp Normal file
View file

@ -0,0 +1,26 @@
#include "Interpreter.hpp"
#include <iostream>
#include <string>
int main() {
Interpreter interpreter;
std::string line;
std::cout << "File System emulator.\n";
while (true) {
std::cout << ">> ";
std::getline(std::cin, line);
if (line == "stop") {
break;
}
// Process the line here
//
interpreter.interpret(line);
}
return 0;
}

View file

@ -40,7 +40,7 @@ struct Directory : public Node {
Directory();
bool attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode);
Node* findNode(const std::vector<Key>& path, ui32 currentDepth);
Node* findNode(const std::vector<Key>& path, ui32 currentDepth = 0);
void detachNode(Node* node);
template<typename tFunctor>
@ -79,10 +79,12 @@ public:
FileSystem();
~FileSystem();
void makeDirectory(const Path& path);
void changeCurrent(const Path& path);
bool makeDirectory(const Path& path);
bool changeCurrent(const Path& path);
void log() const;
const std::string& getLastError();
private:
void logNode(std::stringstream& ss, const Node* node, int depth, std::vector<bool>& indents) const;
void indent(std::stringstream & ss, int depth, std::vector<bool>& indents) const;

24
inc/Interpreter.hpp Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "FileSystem.hpp"
#include <map>
class Interpreter {
struct Command {
ui32 numArguments = 0;
bool(*callback)(FileSystem&, const std::vector<std::string>&) = nullptr;
};
public:
Interpreter();
void interpret(const std::string& command);
private:
static void reportError(const std::string& string);
private:
std::map<std::string, Command> mCommands;
FileSystem mFileSystem;
std::string mError;
};

View file

@ -9,7 +9,7 @@ void initializeTransitions();
class Path {
public:
Path() = default;
Path(const char* path);
Path(const std::string& path);
void set(const std::string& path);
const std::string& operator[](int idx) const;

View file

@ -1,5 +1,8 @@
#include "FileSystem.hpp"
#include <iostream>
#include <cassert>
static std::string gError;
void Node::updateTreeCache() {
// TODO update cache
@ -20,12 +23,12 @@ Directory::Directory() {
bool Directory::attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode) {
Node* node = findNode(directoryPath, 0);
if (!node) {
// TODO : update error status - invalid path
gError = "Invalid path";
return false;
}
if (node->type != DIRECTORY) {
// TODO : update error status - given path is not a directory
gError = "given path is not a directory";
return false;
}
@ -34,7 +37,7 @@ bool Directory::attachNode(const std::vector<Key>& directoryPath, const Key& new
Node* existingNode = directory->treeSearch(newKey);
if (existingNode) {
if (existingNode->type == newNode->type) return false; // exit silently
// TODO : report error cant add node
gError = "Cant add node";
return false;
}
@ -233,7 +236,7 @@ void Directory::getMaxDepthUtil(ui32 depth, ui32& maxDepth) const {
ui32 Directory::getMaxDepth() const {
ui32 maxDepth = 0;
getMaxDepthUtil(0, maxDepth);
getMaxDepthUtil(1, maxDepth);
return maxDepth;
}
@ -249,31 +252,41 @@ FileSystem::~FileSystem() {
delete root;
}
void FileSystem::makeDirectory(const Path& path) {
bool FileSystem::makeDirectory(const Path& path) {
if (path.getDepth() < 1 || path.isInvalid()) {
// TODO : update error - invalid path
return;
gError = "Invalid path";
return false;
}
Directory* parentDirectory = path.isAbsolute() ? root : currentDirectory;
auto newDirectory = new Directory();
if (!parentDirectory->attachNode(path.getParentChain(), path.getFilename(), newDirectory)) {
delete newDirectory;
auto existingNode = parentDirectory->findNode(path.getChain());
if (existingNode) {
if (existingNode->type == Node::DIRECTORY) return true;
gError = "Cant create directory, such node exists";
return false;
}
auto newDirectory = new Directory();
assert(parentDirectory->attachNode(path.getParentChain(), path.getFilename(), newDirectory));
return true;
}
void FileSystem::changeCurrent(const Path& path) {
bool FileSystem::changeCurrent(const Path& path) {
if (path.isInvalid()) {
// TODO : update error - invalid path
return;
gError = "Invalid path";
return false;
}
auto node = path.isAbsolute() ? root->findNode(path.getChain(), 0) : currentDirectory->findNode(path.getChain(), 0);
if (node->type != Node::DIRECTORY) {
// TODO : update error status - no such directory
return;
gError = "No such directory";
return false;
}
currentDirectory = (Directory*) node;
return true;
}
void FileSystem::log() const {
@ -281,7 +294,7 @@ void FileSystem::log() const {
std::vector<bool> indents;
indents.resize(root->getMaxDepth());
logNode(ss, root, 0, indents);
std::cout << ss.str();
std::cout << ss.str() << "\n";
}
@ -305,6 +318,7 @@ void FileSystem::indent(std::stringstream & ss, int depth, std::vector<bool>& in
}
void FileSystem::logDirectory(std::stringstream & ss, const Directory* node, int depth, std::vector<bool>& indents) const {
ss << (node == currentDirectory ? "* " : " ");
indent(ss, depth, indents);
ss << node->key << "\n";
indents[depth] = true;
@ -325,3 +339,7 @@ void FileSystem::logLink(std::stringstream & ss, const Link* node, int depth, st
indent(ss, depth, indents);
ss << "link [" << node->key << "] \n";
}
const std::string& FileSystem::getLastError() {
return gError;
}

60
src/Interpreter.cpp Normal file
View file

@ -0,0 +1,60 @@
#include "Interpreter.hpp"
#include <iostream>
#include <sstream>
#include <algorithm>
void getWords(const std::string& in, std::vector<std::string>& out) {
std::stringstream ss(in);
std::string word;
while (ss >> word) out.push_back(word);
}
Interpreter::Interpreter() {
mCommands["cd"] = { 1, [](FileSystem& filesystem, const std::vector<std::string>& args){
return filesystem.changeCurrent(args[1]);
}};
mCommands["md"] = { 1, [](FileSystem& filesystem, const std::vector<std::string>& args){
return filesystem.makeDirectory(args[1]);
}};
}
void Interpreter::reportError(const std::string& description) {
std::cout << "ERROR : " << description << std::endl;
}
void Interpreter::interpret(const std::string& command) {
std::cout << "\"" << command << "\"\n";
std::vector<std::string> words;
getWords(command, words);
if (words.empty()) {
reportError("Empty command");
return;
}
std::string& commandName = words.front();
std::transform(commandName.begin(), commandName.end(), commandName.begin(), [](unsigned char c) { return std::tolower(c); });
auto iter = mCommands.find(commandName);
if (iter == mCommands.end()) {
reportError("Command not found");
return;
}
if (iter->second.numArguments != words.size() - 1) {
reportError("invalid number of arguments given");
return;
}
bool success = iter->second.callback(mFileSystem, words);
if (!success) {
reportError(mFileSystem.getLastError());
return;
}
mFileSystem.log();
}

View file

@ -13,7 +13,7 @@ void initializeTransitions() {
transitions['.'] = '.';
}
Path::Path(const char* path) {
Path::Path(const std::string& path) {
set(path);
}

View file

@ -1,42 +1,17 @@
#include "FileSystem.hpp"
#include "Interpreter.hpp"
int main() {
FileSystem fse;
Interpreter interpreter;
fse.makeDirectory("/a");
fse.makeDirectory("/a/b");
fse.makeDirectory("/a/b/k");
fse.makeDirectory("/a/c");
fse.makeDirectory("/a/c/k");
interpreter.interpret("");
interpreter.interpret("m");
interpreter.interpret("mD a");
interpreter.interpret("mD /");
interpreter.interpret("MD /A123");
interpreter.interpret("cd /A123");
interpreter.interpret("md asd");
fse.makeDirectory("/d");
fse.makeDirectory("/d/b");
fse.makeDirectory("/d/b/k");
fse.makeDirectory("/d/c");
fse.makeDirectory("/d/c/k");
fse.makeDirectory("d");
fse.changeCurrent("/d/c/k");
fse.makeDirectory("/a");
fse.makeDirectory("/a/b");
fse.makeDirectory("/a/b/k");
fse.makeDirectory("/a/c");
fse.makeDirectory("/a/c/k");
fse.makeDirectory("ggad");
fse.makeDirectory("gad");
fse.makeDirectory("rwed");
fse.makeDirectory("e");
fse.makeDirectory("d");
fse.makeDirectory("d/b");
fse.makeDirectory("d/b/k");
fse.makeDirectory("d/c");
fse.makeDirectory("d/c/k");
fse.log();
return 0;
}