Massive reformating and cleanup

This commit is contained in:
2024-12-06 21:07:54 +01:00
parent 79390b94b7
commit d2cbdc2910
33 changed files with 1030 additions and 1100 deletions

66
.clang-format Normal file
View File

@ -0,0 +1,66 @@
---
Language: Cpp
BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: AfterColon
ColumnLimit: 120
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentWidth: 4
PointerAlignment: Left
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 4
UseTab: Never
AllowShortEnumsOnASingleLine: false
BraceWrapping:
AfterEnum: false
AlignConsecutiveDeclarations:
Enabled: true
NamespaceIndentation: All

View File

@ -1,18 +1,18 @@
/* /*
* Fsh Grammar * Fsh Grammar
* *
* Command_Line ::= Command EOF * Command_Line ::= Command EOF
* | Command Pipeline_Command * | Command Pipeline_Command
* *
* Pipeline_Command ::= "|" Command EOF * Pipeline_Command ::= "|" Command EOF
* | "|" Command "|" Pipeline_Command * | "|" Command "|" Pipeline_Command
* *
* Command ::= Command_Name [Flag_Opt] {Command_Argument} [Redirect] * Command ::= Command_Name [Flag_Opt] {Command_Argument} [Redirect]
* *
* Redirects ::= [LRedirect Word] RRedirect Word | [RRedirect Word] LRedirect Word * Redirects ::= [LRedirect Word] RRedirect Word | [RRedirect Word] LRedirect Word
* *
* Command_Argument ::= Word | String_Literal * Command_Argument ::= Word | String_Literal
* *
* Command_Name ::= Word * Command_Name ::= Word
*/ */
#pragma once #pragma once
@ -21,26 +21,24 @@
#include "util/text.hpp" #include "util/text.hpp"
#include "ast/ast_base.hpp" #include "ast/ast_base.hpp"
#include "ast/ast_token.hpp"
#include "ast/ast_component.hpp" #include "ast/ast_component.hpp"
#include "ast/ast_executable.hpp" #include "ast/ast_executable.hpp"
#include "ast/ast_token.hpp"
namespace fsh { namespace fsh {
class AstFactory { class AstFactory {
public: public:
// Generates an abstract syntax tree
static std::shared_ptr<ExecutableNode> generate_ast(std::list<Token>& list) {
auto it = list.begin();
return CommandLineNode::build(it);
}
// Generates an abstract syntax tree private:
static std::shared_ptr<ExecutableNode> generate_ast(std::list<Token>& list) { static AstFactory& get_factory();
auto it = list.begin(); AstFactory() {}
return CommandLineNode::build(it); AstFactory(const AstFactory&) = default;
} };
private: } // namespace fsh
static AstFactory& get_factory();
AstFactory() {}
AstFactory(const AstFactory&) = default;
};
}

View File

@ -1,67 +1,73 @@
#pragma once #pragma once
#include <string>
#include <memory> #include <memory>
#include <stdexcept>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string>
#include "lexer.hpp" #include "lexer.hpp"
#include "util/text.hpp" #include "util/text.hpp"
namespace fsh { namespace fsh {
enum NodeType { enum NodeType {
COMMAND_LINE, COMMAND_LINE,
COMMAND, COMMAND,
PIPELINE_COMMAND, PIPELINE_COMMAND,
LREDIRECTS, LREDIRECTS,
RREDIRECTS, RREDIRECTS,
REDIRECTS, REDIRECTS,
STRING_LITERAL, STRING_LITERAL,
COMMAND_ARGUMENT, COMMAND_ARGUMENT,
TOKEN TOKEN
}; };
class AstNode { class AstNode {
friend class std::shared_ptr<AstNode>; friend class std::shared_ptr<AstNode>;
public:
NodeType gtype() {return type;}
const std::string& gname() {return name;};
protected: public:
using TokenType = Lexer::TokenType; NodeType gtype() { return type; }
AstNode(NodeType type, std::string name) : type(type), name(name) {} const std::string& gname() { return name; };
protected:
using TokenType = Lexer::TokenType;
AstNode(NodeType type, std::string name) : type(type), name(name) {}
template <class T> template <class T>
static std::shared_ptr<T> Optional(std::list<Token>::iterator& it, std::shared_ptr<T>& node_ptr); static std::shared_ptr<T> Optional(std::list<Token>::iterator& it, std::shared_ptr<T>& node_ptr);
template <class T>
static std::shared_ptr<T> Optional(std::list<Token>::iterator& it) {
std::shared_ptr<T> node_ptr;
return Optional<T>(it, node_ptr);
}
template <class T>
static std::shared_ptr<T> Mandatory(std::list<Token>::iterator& it) {return T::build(it);}
private: template <class T>
AstNode(); static std::shared_ptr<T> Optional(std::list<Token>::iterator& it) {
AstNode(const AstNode&); std::shared_ptr<T> node_ptr;
NodeType type; return Optional<T>(it, node_ptr);
const std::string name; }
};
class ExecutableNode : public AstNode { template <class T>
public: static std::shared_ptr<T> Mandatory(std::list<Token>::iterator& it) {
virtual void print(int indent) {}; return T::build(it);
virtual void execute(std::istream &in, std::ostream &out) {} }
protected:
ExecutableNode(NodeType type, std::string Name) : AstNode(type, Name) {}
private:
};
class AstBuildError : public std::runtime_error { private:
public: AstNode();
AstBuildError(std::string err) : std::runtime_error(err) {} AstNode(const AstNode&);
}; NodeType type;
const std::string name;
};
} class ExecutableNode : public AstNode {
public:
virtual void print(int indent) {};
virtual void execute(std::istream& in, std::ostream& out) {}
protected:
ExecutableNode(NodeType type, std::string Name) : AstNode(type, Name) {}
private:
};
class AstBuildError : public std::runtime_error {
public:
AstBuildError(std::string err) : std::runtime_error(err) {}
};
} // namespace fsh

View File

@ -11,80 +11,73 @@
namespace fsh { namespace fsh {
class CommandArgumentNode : public AstNode { class CommandArgumentNode : public AstNode {
public: public:
static std::shared_ptr<CommandArgumentNode> build(std::list<Token>::iterator& it); static std::shared_ptr<CommandArgumentNode> build(std::list<Token>::iterator& it);
Lexer::TokenType gtoken_type() {return type;} Lexer::TokenType gtoken_type() { return type; }
std::string& gvalue() {return value;} std::string& gvalue() { return value; }
protected: protected:
CommandArgumentNode(TokenNode<TokenType::WORD>::shared word) CommandArgumentNode(TokenNode<TokenType::WORD>::shared word) :
: AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"), AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"), type(word->gtoken_type()), value(word->gvalue()) {}
type(word->gtoken_type()),
value(word->gvalue()) {}
CommandArgumentNode(TokenNode<TokenType::STRING_LITERAL>::shared word)
: AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"),
type(word->gtoken_type()),
value(word->gvalue()) {}
private: CommandArgumentNode(TokenNode<TokenType::STRING_LITERAL>::shared word) :
Lexer::TokenType type; AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"), type(word->gtoken_type()), value(word->gvalue()) {}
std::string value;
};
class LRedirectNode : public AstNode { private:
public: Lexer::TokenType type;
static std::shared_ptr<LRedirectNode> build(std::list<Token>::iterator& it); std::string value;
};
std::string gvalue() {return input;} class LRedirectNode : public AstNode {
public:
static std::shared_ptr<LRedirectNode> build(std::list<Token>::iterator& it);
protected: std::string gvalue() { return input; }
LRedirectNode(TokenNode<TokenType::LREDIRECTION>::shared, TokenNode<TokenType::WORD>::shared in)
: AstNode(NodeType::LREDIRECTS, "LRedirectNode"),
input(in->gvalue()) {}
private: protected:
std::string input; LRedirectNode(TokenNode<TokenType::LREDIRECTION>::shared, TokenNode<TokenType::WORD>::shared in) :
}; AstNode(NodeType::LREDIRECTS, "LRedirectNode"), input(in->gvalue()) {}
private:
std::string input;
};
class RRedirectNode : public AstNode { class RRedirectNode : public AstNode {
public: public:
static std::shared_ptr<RRedirectNode> build(std::list<Token>::iterator& it); static std::shared_ptr<RRedirectNode> build(std::list<Token>::iterator& it);
std::string gvalue() {return output;} std::string gvalue() { return output; }
bool gappend() {return append;} bool gappend() { return append; }
protected: protected:
RRedirectNode(TokenNode<TokenType::RREDIRECTION>::shared rr, TokenNode<TokenType::WORD>::shared out) RRedirectNode(TokenNode<TokenType::RREDIRECTION>::shared rr, TokenNode<TokenType::WORD>::shared out) :
: AstNode(NodeType::RREDIRECTS, "LRedirectNode"), AstNode(NodeType::RREDIRECTS, "LRedirectNode"), output(out->gvalue()), append(rr->gvalue().size() > 1) {}
output(out->gvalue()),
append(rr->gvalue().size()>1) {}
private: private:
std::string output; std::string output;
bool append; bool append;
}; };
class RedirectsNode : public AstNode { class RedirectsNode : public AstNode {
public: public:
static std::shared_ptr<RedirectsNode> build(std::list<Token>::iterator& it); static std::shared_ptr<RedirectsNode> build(std::list<Token>::iterator& it);
std::optional<std::string> ginput() {return input;} std::optional<std::string> ginput() { return input; }
std::optional<std::string> goutput() {return output;} std::optional<std::string> goutput() { return output; }
bool gappend() {return append;} bool gappend() { return append; }
protected: protected:
RedirectsNode(std::shared_ptr<LRedirectNode> in, std::shared_ptr<RRedirectNode> out) RedirectsNode(std::shared_ptr<LRedirectNode> in, std::shared_ptr<RRedirectNode> out) :
: AstNode(NodeType::REDIRECTS, "RedirectNode"), AstNode(NodeType::REDIRECTS, "RedirectNode"), input(util::mk_optional(in)), output(util::mk_optional(out)) {
input(util::mk_optional(in)), if (out) append = out->gappend();
output(util::mk_optional(out)) {if(out) append = out->gappend();} }
private: private:
std::optional<std::string> input; std::optional<std::string> input;
std::optional<std::string> output; std::optional<std::string> output;
bool append = false; bool append = false;
}; };
} } // namespace fsh

View File

@ -1,78 +1,69 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <stdexcept>
#include <optional> #include <optional>
#include <stdexcept>
#include "ast/ast_base.hpp" #include "ast/ast_base.hpp"
#include "ast/ast_token.hpp"
#include "ast/ast_component.hpp" #include "ast/ast_component.hpp"
#include "ast/ast_token.hpp"
#include "lexer.hpp" #include "lexer.hpp"
#include "util/text.hpp" #include "util/text.hpp"
namespace fsh { namespace fsh {
class CommandNode : public ExecutableNode { class CommandNode : public ExecutableNode {
using ArgumentVec = std::vector<std::shared_ptr<CommandArgumentNode> >; using ArgumentVec = std::vector<std::shared_ptr<CommandArgumentNode> >;
public:
static std::shared_ptr<CommandNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream &in, std::ostream &out) override;
protected: public:
CommandNode( static std::shared_ptr<CommandNode> build(std::list<Token>::iterator& it);
TokenNode<TokenType::WORD>::shared cmd_name, virtual void print(int indent) override;
TokenNode<TokenType::FLAG>::shared flag, virtual void execute(std::istream& in, std::ostream& out) override;
ArgumentVec args,
std::shared_ptr<RedirectsNode> redirects
) : ExecutableNode(NodeType::COMMAND, "CommandNode"),
cmd_name(cmd_name->gvalue()),
flag(util::mk_optional(flag)),
redirects(redirects),
args(args) {}
private:
std::string cmd_name;
std::optional<std::string> flag;
std::shared_ptr<RedirectsNode> redirects;
ArgumentVec args;
};
class PipeLineNode : public ExecutableNode { protected:
public: CommandNode(TokenNode<TokenType::WORD>::shared cmd_name,
static std::shared_ptr<PipeLineNode> build(std::list<Token>::iterator& it); TokenNode<TokenType::FLAG>::shared flag,
virtual void print(int indent) override; ArgumentVec args,
virtual void execute(std::istream &in, std::ostream &out) override; std::shared_ptr<RedirectsNode> redirects) :
ExecutableNode(NodeType::COMMAND, "CommandNode"), cmd_name(cmd_name->gvalue()), flag(util::mk_optional(flag)),
redirects(redirects), args(args) {}
protected: private:
PipeLineNode(std::shared_ptr<CommandNode> l, std::shared_ptr<ExecutableNode> r) std::string cmd_name;
: ExecutableNode(NodeType::PIPELINE_COMMAND, "PipeLine"), std::optional<std::string> flag;
l_command(l), std::shared_ptr<RedirectsNode> redirects;
r_command(r) {} ArgumentVec args;
};
private:
std::shared_ptr<ExecutableNode> l_command;
std::shared_ptr<ExecutableNode> r_command;
};
class PipeLineNode : public ExecutableNode {
public:
static std::shared_ptr<PipeLineNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream& in, std::ostream& out) override;
class CommandLineNode : public ExecutableNode { protected:
public: PipeLineNode(std::shared_ptr<CommandNode> l, std::shared_ptr<ExecutableNode> r) :
static std::shared_ptr<CommandLineNode> build(std::list<Token>::iterator& it); ExecutableNode(NodeType::PIPELINE_COMMAND, "PipeLine"), l_command(l), r_command(r) {}
virtual void print(int indent) override;
virtual void execute(std::istream &in, std::ostream &out) override;
protected: private:
CommandLineNode(std::shared_ptr<ExecutableNode> command, std::shared_ptr<ExecutableNode> pipe = nullptr) std::shared_ptr<ExecutableNode> l_command;
: ExecutableNode(NodeType::COMMAND_LINE, "CommandLine"), std::shared_ptr<ExecutableNode> r_command;
command(command), };
pipe(pipe) {}
private:
std::shared_ptr<ExecutableNode> command;
std::shared_ptr<ExecutableNode> pipe;
};
} class CommandLineNode : public ExecutableNode {
public:
static std::shared_ptr<CommandLineNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream& in, std::ostream& out) override;
protected:
CommandLineNode(std::shared_ptr<ExecutableNode> command, std::shared_ptr<ExecutableNode> pipe = nullptr) :
ExecutableNode(NodeType::COMMAND_LINE, "CommandLine"), command(command), pipe(pipe) {}
private:
std::shared_ptr<ExecutableNode> command;
std::shared_ptr<ExecutableNode> pipe;
};
} // namespace fsh

View File

@ -4,23 +4,21 @@
#include "ast/ast_base.hpp" #include "ast/ast_base.hpp"
#include "util/text.hpp" #include "util/text.hpp"
namespace fsh { namespace fsh {
template<Lexer::TokenType T> template <Lexer::TokenType T>
class TokenNode : public AstNode { class TokenNode : public AstNode {
public: public:
using shared = std::shared_ptr<TokenNode>; using shared = std::shared_ptr<TokenNode>;
Lexer::TokenType gtoken_type() {return T;} Lexer::TokenType gtoken_type() { return T; }
std::string& gvalue() {return value;}; std::string& gvalue() { return value; };
static std::shared_ptr<TokenNode> build(std::list<Token>::iterator& it); static std::shared_ptr<TokenNode> build(std::list<Token>::iterator& it);
protected: protected:
TokenNode(std::string value) TokenNode(std::string value) : AstNode(NodeType::TOKEN, util::tokens[T]), value(value) {}
: AstNode(NodeType::TOKEN, util::tokens[T]), value(value) {}
private: private:
std::string value; std::string value;
}; };
} }

View File

@ -13,55 +13,53 @@
#include "cmd/args/arg_input.hpp" #include "cmd/args/arg_input.hpp"
#include "cmd/args/arg_manager.hpp" #include "cmd/args/arg_manager.hpp"
namespace fsh{ namespace fsh {
class ArgFactory { class ArgFactory {
public: public:
using FlagNode = std::optional<std::string>&; using FlagNode = std::optional<std::string>&;
using ArgNodes = std::vector<std::shared_ptr<CommandArgumentNode > >; using ArgNodes = std::vector<std::shared_ptr<CommandArgumentNode> >;
using BuildFunc = std::shared_ptr<_Argument> (*) (void); using BuildFunc = std::shared_ptr<_Argument> (*)(void);
struct ArgRule struct ArgRule {
{ BuildFunc build;
BuildFunc build; bool mandatory;
bool mandatory; bool extends;
bool extends; };
struct FlagRule {
BuildFunc build;
bool specialinput; //Not implemented
bool capturing;
bool extends; //Not implemented
};
void add_input_rule() {
has_input = true;
pos_arg_rules.push_back({ &_Argument::create<ArgInput>, false, false });
}
template <typename T>
void add_rule(bool mandatory, bool extends = false) {
pos_arg_rules.push_back({ &_Argument::create<Argument<T> >, mandatory, extends });
}
template <typename T = bool>
void add_rule(const std::string name, bool capturing = false) {
flag_rules[name] = { _Argument::create<Argument<T> >, false, capturing, false };
}
void parse(ArgManager& manager, ArgNodes& vec, FlagNode flag);
bool ghas_input() { return has_input; }
private:
std::vector<ArgRule> pos_arg_rules;
std::unordered_map<std::string, FlagRule> flag_rules;
bool has_input = false;
void parse_flag(ArgManager& manager, FlagNode flag);
std::shared_ptr<_Argument> build_arg(BuildFunc build_func, const std::string& str);
std::shared_ptr<_Argument> build_arg(BuildFunc build_func, std::shared_ptr<CommandArgumentNode> cmd_arg);
}; };
struct FlagRule
{
BuildFunc build;
bool specialinput; //Not implemented
bool capturing;
bool extends; //Not implemented
};
void add_input_rule() {
has_input = true;
pos_arg_rules.push_back({&_Argument::create<ArgInput>, false, false});
}
template<typename T>
void add_rule(bool mandatory, bool extends = false) {
pos_arg_rules.push_back({&_Argument::create<Argument<T> >, mandatory, extends});
}
template<typename T = bool >
void add_rule(const std::string name, bool capturing = false) {
flag_rules[name] = {_Argument::create<Argument<T> >, false, capturing, false};
}
void parse(ArgManager& manager, ArgNodes& vec, FlagNode flag);
bool ghas_input() {return has_input;}
private:
std::vector<ArgRule> pos_arg_rules;
std::unordered_map<std::string, FlagRule> flag_rules;
bool has_input = false;
void parse_flag(ArgManager& manager, FlagNode flag);
std::shared_ptr<_Argument> build_arg(BuildFunc build_func, const std::string& str);
std::shared_ptr<_Argument> build_arg(BuildFunc build_func, std::shared_ptr<CommandArgumentNode> cmd_arg);
};
} }

View File

@ -4,19 +4,20 @@
#include "ast/ast_component.hpp" #include "ast/ast_component.hpp"
namespace fsh{ namespace fsh {
class _Argument { class _Argument {
public: public:
virtual void svalue(const std::string& can, const Lexer::TokenType& type = Lexer::TokenType::FLAG) {} virtual void svalue(const std::string& can, const Lexer::TokenType& type = Lexer::TokenType::FLAG) {}
virtual void svalue(std::shared_ptr<CommandArgumentNode> can) { virtual void svalue(std::shared_ptr<CommandArgumentNode> can) { svalue(can->gvalue(), can->gtoken_type()); }
svalue(can->gvalue(), can->gtoken_type());
}
template<typename T> template <typename T>
static std::shared_ptr<_Argument> create() {return std::make_shared<T>();} static std::shared_ptr<_Argument> create() {
protected: return std::make_shared<T>();
_Argument(){} }
};
protected:
_Argument() {}
};
} }

View File

@ -5,35 +5,32 @@
#include "cmd/args/arg_base.hpp" #include "cmd/args/arg_base.hpp"
#include "ast/ast_component.hpp" #include "ast/ast_component.hpp"
namespace fsh{ namespace fsh {
template<typename T> template <typename T>
class Argument : public _Argument { class Argument : public _Argument {
public: public:
static T& get(std::shared_ptr<_Argument> a) { static T& get(std::shared_ptr<_Argument> a) { return std::dynamic_pointer_cast<Argument<T> >(a)->gvalue(); }
return std::dynamic_pointer_cast<Argument<T> >(a)->gvalue();
}
Argument() {} Argument() {}
virtual void svalue(const std::string& val, const Lexer::TokenType& type) override; virtual void svalue(const std::string& val, const Lexer::TokenType& type) override;
virtual T& gvalue() {return value;} virtual T& gvalue() { return value; }
private:
bool is_string_literal; // Currently no getter
T value;
};
template<class T> private:
void Argument<T>::svalue(const std::string& val, const Lexer::TokenType& type) { bool is_string_literal; // Currently no getter
if constexpr (std::is_same_v<T, std::string>) { T value;
value = val; };
} else {
std::stringstream ss_val(val); template <class T>
if(!(ss_val >> value)) { void Argument<T>::svalue(const std::string& val, const Lexer::TokenType& type) {
throw std::invalid_argument("Incorrect type"); if constexpr (std::is_same_v<T, std::string>) {
value = val;
} else {
std::stringstream ss_val(val);
if (!(ss_val >> value)) { throw std::invalid_argument("Incorrect type"); }
} }
is_string_literal = type == Lexer::TokenType::STRING_LITERAL;
} }
is_string_literal = type == Lexer::TokenType::STRING_LITERAL;
}
} }

View File

@ -5,22 +5,22 @@
#include "cmd/args/arg_base.hpp" #include "cmd/args/arg_base.hpp"
namespace fsh{ namespace fsh {
class ArgInput : public _Argument { class ArgInput : public _Argument {
public: public:
static std::istream& get(std::shared_ptr<_Argument> a) { static std::istream& get(std::shared_ptr<_Argument> a) {
return std::dynamic_pointer_cast<ArgInput>(a)->gvalue(); return std::dynamic_pointer_cast<ArgInput>(a)->gvalue();
} }
ArgInput() {} ArgInput() {}
virtual void svalue(const std::string& val, const Lexer::TokenType& type) override; virtual void svalue(const std::string& val, const Lexer::TokenType& type) override;
virtual std::istream& gvalue(); virtual std::istream& gvalue();
private: private:
std::optional<std::stringstream> str; std::optional<std::stringstream> str;
std::optional<std::ifstream> file; std::optional<std::ifstream> file;
}; };
} }

View File

@ -3,46 +3,40 @@
#include "cmd/args/arg_input.hpp" #include "cmd/args/arg_input.hpp"
#include "util/input.hpp" #include "util/input.hpp"
namespace fsh{ namespace fsh {
class ArgManager { class ArgManager {
friend class ArgFactory; friend class ArgFactory;
using PosArgs = std::vector<std::shared_ptr<_Argument> >; using PosArgs = std::vector<std::shared_ptr<_Argument> >;
using FlagOpts = std::unordered_map< std::string ,std::shared_ptr<_Argument> >; using FlagOpts = std::unordered_map<std::string, std::shared_ptr<_Argument> >;
public: public:
ArgManager() {} ArgManager() {}
std::istream& get_input(const unsigned int id) {
if (id < pos_argument.size()) return ArgInput::get(pos_argument[id]);
return util::cin;
}
std::istream& get_input(const unsigned int id) { template <typename T>
if(id < pos_argument.size()) return ArgInput::get(pos_argument[id]); std::optional<T> get(const unsigned int id) {
return util::cin; if ((unsigned int)id < pos_argument.size()) return Argument<T>::get(pos_argument[id]);
} return std::make_optional<T>();
}
template<typename T> template <typename T>
std::optional<T> get(const unsigned int id) { std::optional<T> get(const std::string& id) {
if((unsigned int) id < pos_argument.size()) return Argument<T>::get(pos_argument[id]); if (flags.find(id) != flags.end()) return Argument<T>::get(flags[id]);
return std::make_optional<T>(); return std::make_optional<T>();
} }
template<typename T> bool get(const std::string& id) { return flags.find(id) != flags.end(); }
std::optional<T> get(const std::string& id) {
if(flags.find(id) != flags.end()) return Argument<T>::get(flags[id]);
return std::make_optional<T>();
}
bool get(const std::string& id) {
return flags.find(id) != flags.end();
}
void push_arg(std::shared_ptr<_Argument> arg) { void push_arg(std::shared_ptr<_Argument> arg) { pos_argument.push_back(arg); }
pos_argument.push_back(arg); void push_flag(const std::string& id, std::shared_ptr<_Argument> arg = nullptr) { flags[id] = arg; }
}
void push_flag(const std::string &id,std::shared_ptr<_Argument> arg = nullptr) { private:
flags[id] = arg; PosArgs pos_argument;
} FlagOpts flags;
};
private:
PosArgs pos_argument;
FlagOpts flags;
};
} }

View File

@ -3,51 +3,41 @@
#include <unordered_map> #include <unordered_map>
#include "cmd/cmd_base.hpp" #include "cmd/cmd_base.hpp"
#include "cmd/cmd_wc.hpp"
#include "cmd/cmd_time.hpp"
#include "cmd/cmd_date.hpp" #include "cmd/cmd_date.hpp"
#include "cmd/cmd_echo.hpp" #include "cmd/cmd_echo.hpp"
#include "cmd/cmd_touch.hpp"
#include "cmd/cmd_misc.hpp" #include "cmd/cmd_misc.hpp"
#include "cmd/cmd_time.hpp"
#include "cmd/cmd_touch.hpp"
#include "cmd/cmd_wc.hpp"
namespace fsh namespace fsh {
{
class CommandRegistry { class CommandRegistry {
public:
public: static CommandRegistry& instance() {
static CommandRegistry cmd_registry;
static CommandRegistry& instance() { return cmd_registry;
static CommandRegistry cmd_registry;
return cmd_registry;
}
Command& get(const std::string n) {
if(cmds.find(n) == cmds.end()) {
throw std::runtime_error("Command not found");
} }
return *(cmds[n]);
}
Command& operator[](const std::string n) { Command& get(const std::string n) {
return get(n); if (cmds.find(n) == cmds.end()) { throw std::runtime_error("Command not found"); }
} return *(cmds[n]);
}
Command& operator[](const std::string n) { return get(n); }
private: private:
CommandRegistry() { CommandRegistry() {
cmds["wc" ] = Command::register_cmd<CmdWc>(); cmds["wc"] = Command::register_cmd<CmdWc>();
cmds["date" ] = Command::register_cmd<CmdDate>(); cmds["date"] = Command::register_cmd<CmdDate>();
cmds["time" ] = Command::register_cmd<CmdTime>(); cmds["time"] = Command::register_cmd<CmdTime>();
cmds["echo" ] = Command::register_cmd<CmdEcho>(); cmds["echo"] = Command::register_cmd<CmdEcho>();
cmds["exit" ] = Command::register_cmd<CmdExit>(); cmds["exit"] = Command::register_cmd<CmdExit>();
cmds["touch"] = Command::register_cmd<CmdTouch>(); cmds["touch"] = Command::register_cmd<CmdTouch>();
cmds["debug"] = Command::register_cmd<CmdPrintTree>(); cmds["debug"] = Command::register_cmd<CmdPrintTree>();
} }
std::unordered_map<std::string, std::unique_ptr<Command> > cmds; std::unordered_map<std::string, std::unique_ptr<Command> > cmds;
};
}; } // namespace fsh
}

View File

@ -9,33 +9,30 @@
#include "ast/ast.hpp" #include "ast/ast.hpp"
#include "cmd/args/arg.hpp" #include "cmd/args/arg.hpp"
namespace fsh{ namespace fsh {
class Command { class Command {
using FlagNode = std::optional<std::string>&; using FlagNode = std::optional<std::string>&;
using ArgNodes = std::vector<std::shared_ptr<CommandArgumentNode > >; using ArgNodes = std::vector<std::shared_ptr<CommandArgumentNode> >;
public: public:
void execute(FlagNode flag, ArgNodes& vec, std::istream& in, std::ostream& out); void execute(FlagNode flag, ArgNodes& vec, std::istream& in, std::ostream& out);
template <typename T> template <typename T>
static std::unique_ptr<Command> register_cmd() { static std::unique_ptr<Command> register_cmd() {
std::unique_ptr<Command> cmd = std::make_unique<T>(); std::unique_ptr<Command> cmd = std::make_unique<T>();
cmd->register_flags(); cmd->register_flags();
return cmd; return cmd;
} }
protected: protected:
virtual void register_flags() {};
virtual void register_flags() {}; virtual void run(std::istream& in, std::ostream& out, ArgManager& args) {};
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) {}; ArgFactory& get_factory() { return arg_factory; }
ArgFactory& get_factory() {return arg_factory;}
private:
ArgFactory arg_factory;
};
private:
ArgFactory arg_factory;
};
} }

View File

@ -5,17 +5,15 @@
#include "cmd/cmd_base.hpp" #include "cmd/cmd_base.hpp"
namespace fsh { namespace fsh {
class CmdDate : public Command { class CmdDate : public Command {
protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::time_t time = std::time(nullptr);
out << std::asctime(std::localtime(&time));
}
}; protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::time_t time = std::time(nullptr);
out << std::asctime(std::localtime(&time));
}
};
} }

View File

@ -4,23 +4,20 @@
namespace fsh { namespace fsh {
class CmdEcho : public Command { class CmdEcho : public Command {
protected:
virtual void register_flags() override {
ArgFactory& factory = get_factory();
factory.add_input_rule();
}
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { protected:
std::string s; virtual void register_flags() override {
std::string o; ArgFactory& factory = get_factory();
while(getline(in, s)) { factory.add_input_rule();
o += s + "\n"; }
}
out << o;
}
}; virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::string s;
std::string o;
while (getline(in, s)) { o += s + "\n"; }
out << o;
}
};
} }

View File

@ -6,38 +6,33 @@
#include "fsh.hpp" #include "fsh.hpp"
#include "ast/ast.hpp" #include "ast/ast.hpp"
namespace fsh { namespace fsh {
class CmdExit : public Command { class CmdExit : public Command {
protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
fsh::instance().environment["EXITING"] = "1";
}
}; protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
fsh::instance().environment["EXITING"] = "1";
}
};
class CmdPrintTree : public Command { class CmdPrintTree : public Command {
protected:
virtual void register_flags() override { protected:
auto& factory = get_factory(); virtual void register_flags() override {
factory.add_input_rule(); auto& factory = get_factory();
} factory.add_input_rule();
}
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::string line;
std::getline(in, line);
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { auto tokens = Lexer::process(line);
std::string line; auto ast = AstFactory::generate_ast(tokens);
std::getline(in, line);
auto tokens = Lexer::process(line); ast->print(0);
auto ast = AstFactory::generate_ast(tokens); }
};
ast->print(0);
}
};
} }

View File

@ -7,14 +7,13 @@
namespace fsh { namespace fsh {
class CmdTime : public Command { class CmdTime : public Command {
protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::time_t time = std::time(nullptr);
out << std::put_time(std::localtime(&time), "%T%n");
}
}; protected:
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
std::time_t time = std::time(nullptr);
out << std::put_time(std::localtime(&time), "%T%n");
}
};
} }

View File

@ -4,21 +4,20 @@
namespace fsh { namespace fsh {
class CmdTouch : public Command { class CmdTouch : public Command {
protected:
virtual void register_flags() override {
ArgFactory& factory = get_factory();
factory.add_rule<std::string>(true);
}
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { protected:
auto name = *(args.get<std::string>(0)); virtual void register_flags() override {
if(std::ifstream(name, std::ios::in).good() || !std::ofstream(name, std::ios::out).is_open()) { ArgFactory& factory = get_factory();
throw std::runtime_error("File exists"); factory.add_rule<std::string>(true);
} }
}
}; virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
auto name = *(args.get<std::string>(0));
if (std::ifstream(name, std::ios::in).good() || !std::ofstream(name, std::ios::out).is_open()) {
throw std::runtime_error("File exists");
}
}
};
} }

View File

@ -4,45 +4,43 @@
namespace fsh { namespace fsh {
class CmdWc : public Command { class CmdWc : public Command {
protected:
virtual void register_flags() override {
ArgFactory& factory = get_factory();
factory.add_input_rule();
factory.add_rule("-c");
factory.add_rule("-w");
}
int count_chars(std::istream& in) { protected:
int i = 0; virtual void register_flags() override {
char c; ArgFactory& factory = get_factory();
while(in.get(c)) i++; factory.add_input_rule();
return i; factory.add_rule("-c");
} factory.add_rule("-w");
int count_words(std::istream& in) {
int i = 0;
char c;
bool prev_space = true;
while(in.get(c)) {
i+= prev_space & !std::isspace(c);
prev_space = std::isspace(c);
} }
return i;
}
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { int count_chars(std::istream& in) {
bool prev_space = true; int i = 0;
if(args.get("-c")) { char c;
out << count_chars(in) << "\n"; while (in.get(c)) i++;
} else if (args.get("-w")) { return i;
out << count_words(in) << "\n";
} else {
throw std::invalid_argument("Didn't provide flag");
} }
}
}; int count_words(std::istream& in) {
int i = 0;
char c;
bool prev_space = true;
while (in.get(c)) {
i += prev_space & !std::isspace(c);
prev_space = std::isspace(c);
}
return i;
}
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
if (args.get("-c")) {
out << count_chars(in) << "\n";
} else if (args.get("-w")) {
out << count_words(in) << "\n";
} else {
throw std::invalid_argument("Didn't provide flag");
}
}
};
} }

View File

@ -6,28 +6,25 @@
#include "ast/ast.hpp" #include "ast/ast.hpp"
#include "util/input.hpp" #include "util/input.hpp"
namespace fsh namespace fsh {
{
class fsh {
public:
std::unordered_map<std::string, std::string> environment;
static fsh& instance() { class fsh {
static fsh f; public:
return f; std::unordered_map<std::string, std::string> environment;
}
void run_line(std::string &line, std::istream &in = util::cin, std::ostream &out = std::cout); static fsh& instance() {
void run(); static fsh f;
return f;
}
private: void run_line(std::string& line, std::istream& in = util::cin, std::ostream& out = std::cout);
fsh(){ void run();
environment["PROMPT"] = "$";
environment["QUIT"] = "";
}
};
private:
fsh() {
environment["PROMPT"] = "$";
environment["QUIT"] = "";
}
};
} }

View File

@ -1,92 +1,90 @@
#pragma once #pragma once
#include <list>
#include <functional> #include <functional>
#include <list>
#include <string> #include <string>
namespace fsh { namespace fsh {
class Lexer { class Lexer {
public: public:
enum TokenType { enum TokenType {
WHITESPACE, WHITESPACE,
WORD, WORD,
STRING_LITERAL, STRING_LITERAL,
OPT, OPT,
FLAG, FLAG,
LREDIRECTION, LREDIRECTION,
RREDIRECTION, RREDIRECTION,
PIPE, PIPE,
END_OF_STREAM
END_OF_STREAM
};
using Token = std::pair<Lexer::TokenType, std::string>;
int peek();
int consume();
Token next_token();
static std::list<Token> process(std::string line);
private:
std::string workspace;
unsigned int idx;
Lexer(std::string str) : workspace(str), idx(0) {}
};
using Token = Lexer::Token;
class LexerStateMachine {
friend class Lexer;
private:
enum State {
START,
REDIRECT,
FLAG_OPT,
POTENTIAL_WORD,
STRING_LITERAL,
STATE_COUNT,
END
};
using StateHandler = std::function<State(void)>;
Lexer& parser;
std::string token;
Lexer::TokenType type;
std::vector<StateHandler> state_handlers;
LexerStateMachine(Lexer& parser) :
parser(parser), token(""), type(Lexer::TokenType::WHITESPACE), state_handlers(STATE_COUNT) {
state_handlers[State::START] = std::bind(&LexerStateMachine::handle_start, this);
state_handlers[State::REDIRECT] = std::bind(&LexerStateMachine::handle_redirect, this);
state_handlers[State::FLAG_OPT] = std::bind(&LexerStateMachine::handle_flag_opt, this);
state_handlers[State::POTENTIAL_WORD] = std::bind(&LexerStateMachine::handle_potential_word, this);
state_handlers[State::STRING_LITERAL] = std::bind(&LexerStateMachine::handle_string_literal, this);
}
State set_type(Lexer::TokenType type, State state);
Token run();
State handle_start();
State handle_redirect();
State handle_flag_opt();
State handle_potential_word();
State handle_string_literal();
State word_like_handler(Lexer::TokenType type, State state);
}; };
using Token = std::pair<Lexer::TokenType, std::string>; inline LexerStateMachine::State LexerStateMachine::set_type(Lexer::TokenType type = Lexer::TokenType::WHITESPACE,
State state = State::END) {
int peek();
int consume();
Token next_token();
static std::list<Token> process(std::string line);
private:
std::string workspace;
unsigned int idx;
Lexer(std::string str) : workspace(str), idx(0) {}
};
using Token = Lexer::Token;
class LexerStateMachine {
friend class Lexer;
private:
enum State {
START,
REDIRECT,
FLAG_OPT,
POTENTIAL_WORD,
STRING_LITERAL,
STATE_COUNT,
END
};
using StateHandler = std::function<State(void)>;
Lexer& parser;
std::string token;
Lexer::TokenType type;
std::vector<StateHandler> state_handlers;
LexerStateMachine(Lexer& parser) : parser(parser), token(""), type(Lexer::TokenType::WHITESPACE), state_handlers(STATE_COUNT) {
state_handlers[State::START] = std::bind(&LexerStateMachine::handle_start , this);
state_handlers[State::REDIRECT ] = std::bind(&LexerStateMachine::handle_redirect , this);
state_handlers[State::FLAG_OPT ] = std::bind(&LexerStateMachine::handle_flag_opt , this);
state_handlers[State::POTENTIAL_WORD] = std::bind(&LexerStateMachine::handle_potential_word, this);
state_handlers[State::STRING_LITERAL] = std::bind(&LexerStateMachine::handle_string_literal, this);
}
State set_type(Lexer::TokenType type, State state);
Token run();
State handle_start();
State handle_redirect();
State handle_flag_opt();
State handle_potential_word();
State handle_string_literal();
State word_like_handler(Lexer::TokenType type, State state);
};
inline LexerStateMachine::State LexerStateMachine::set_type(
Lexer::TokenType type = Lexer::TokenType::WHITESPACE,
State state = State::END
){
this->type = type; this->type = type;
return state; return state;
} }
} } // namespace fsh

View File

@ -7,63 +7,59 @@
#include <iostream> #include <iostream>
#endif #endif
namespace fsh::util {
namespace fsh::util /**
{
/**
* Applies some settings to terminals to fix some inconsistencies between * Applies some settings to terminals to fix some inconsistencies between
* windows and linux terminals * windows and linux terminals
* *
* * **Windows** : it enables using ansii characters * * **Windows** : it enables using ansii characters
* * **Linux** : it enables [Noncanonical Mode](https://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html) * * **Linux** : it enables [Noncanonical Mode](https://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html)
*/ */
void prepTerminal(); void prepTerminal();
#ifndef _WIN32 #ifndef _WIN32
class CursorIStreamBuffer : public std::streambuf { class CursorIStreamBuffer : public std::streambuf {
public: public:
enum EscapeSequence { enum EscapeSequence {
FAILED, FAILED,
POSSIBLE, POSSIBLE,
LEFT_ARROW, LEFT_ARROW,
RIGHT_ARROW RIGHT_ARROW
};
CursorIStreamBuffer() : valid(0), read_chars(0), cursor_pos(0), buffer() { setg(buffer, buffer, buffer); }
protected:
int underflow() override;
// int uflow() override;
// std::streamsize xsgetn(char* s, std::streamsize n) override;
private:
int valid;
EscapeSequence testForEscapeCodes(char chr);
int readInputToNewLine();
std::string input;
int read_chars;
int cursor_pos;
char buffer[32];
}; };
CursorIStreamBuffer() : valid(0), read_chars(0), cursor_pos(0), buffer() { class CursorIStream : public std::istream {
setg(buffer,buffer,buffer); public:
} CursorIStream() : std::istream(&buffer) {}
protected:
int underflow() override;
// int uflow() override;
// std::streamsize xsgetn(char* s, std::streamsize n) override;
private: private:
int valid; CursorIStreamBuffer buffer;
EscapeSequence testForEscapeCodes(char chr); };
extern CursorIStream cin;
int readInputToNewLine();
std::string input;
int read_chars;
int cursor_pos;
char buffer[32];
};
class CursorIStream : public std::istream {
public:
CursorIStream() : std::istream(&buffer) {}
private:
CursorIStreamBuffer buffer;
};
extern CursorIStream cin;
#else #else
extern std::istream& cin; extern std::istream& cin;
#endif
#endif
} }

View File

@ -7,49 +7,37 @@
namespace fsh::util { namespace fsh::util {
extern const char* tokens[];
extern const char* tokens[]; template <class T>
static inline std::optional<std::string> mk_optional(T t) {
template <class T> if (t) { return t->gvalue(); }
static inline std::optional<std::string> mk_optional(T t){ return std::optional<std::string>();
if(t){
return t->gvalue();
} }
return std::optional<std::string>();
}
static inline bool contains(char x, std::string text) { static inline bool contains(char x, std::string text) {
for (const auto& chr : text){ for (const auto& chr : text) {
if(chr == x) return 1; if (chr == x) return 1;
}
return 0;
};
static inline std::ifstream input(const std::string& x) {
std::ifstream in(x, std::ios::in);
if (!in) { throw std::runtime_error("Can't open file"); }
return in;
} }
return 0;
};
static inline std::ofstream output(const std::string& x) {
static inline std::ifstream input(const std::string& x) { std::ofstream out(x, std::ios::out);
std::ifstream in(x, std::ios::in); if (!out.is_open()) { throw std::runtime_error("Can't open file"); }
if(!in) { return out;
throw std::runtime_error("Can't open file");
} }
return in;
}
static inline std::ofstream output_append(const std::string& x) {
static inline std::ofstream output(const std::string& x) { std::ofstream out(x, std::ios::app | std::ios::out);
std::ofstream out(x, std::ios::out); if (!out.is_open()) { throw std::runtime_error("Can't open file"); }
if(!out.is_open()) { return out;
throw std::runtime_error("Can't open file");
} }
return out;
}
static inline std::ofstream output_append(const std::string& x) {
std::ofstream out(x, std::ios::app | std::ios::out);
if(!out.is_open()) {
throw std::runtime_error("Can't open file");
}
return out;
}
} }

View File

@ -2,91 +2,95 @@
namespace fsh { namespace fsh {
template <class T> template <class T>
std::shared_ptr<T> AstNode::Optional(std::list<Token>::iterator& it, std::shared_ptr<T>& node_ptr) { std::shared_ptr<T> AstNode::Optional(std::list<Token>::iterator& it, std::shared_ptr<T>& node_ptr) {
auto it_ = it; auto it_ = it;
try{ try {
node_ptr = T::build(it); node_ptr = T::build(it);
return node_ptr; return node_ptr;
} catch(AstBuildError &e){ } catch (AstBuildError& e) {
it = it_; it = it_;
return nullptr;
}
}
template <Lexer::TokenType T>
typename TokenNode<T>::shared TokenNode<T>::build(std::list<Token>::iterator& it) {
auto& [token_type, value] = *it;
if (T == token_type) {
it++;
return std::shared_ptr<TokenNode<T>>(new TokenNode<T>(value));
} else {
throw AstBuildError(std::string("Got unexcpected: ") + util::tokens[token_type]);
}
return nullptr; return nullptr;
} }
}
template<Lexer::TokenType T> std::shared_ptr<CommandArgumentNode> CommandArgumentNode::build(std::list<Token>::iterator& it) {
typename TokenNode<T>::shared TokenNode<T>::build(std::list<Token>::iterator& it){ auto word = Optional<TokenNode<TokenType::WORD>>(it);
auto& [token_type,value] = *it;
if(T == token_type) { if (word) return std::shared_ptr<CommandArgumentNode>(new CommandArgumentNode(word));
it++;
return std::shared_ptr<TokenNode<T>>(new TokenNode<T>(value)); auto sl = Mandatory<TokenNode<TokenType::STRING_LITERAL>>(it);
} else { return std::shared_ptr<CommandArgumentNode>(new CommandArgumentNode(sl));
throw AstBuildError(std::string("Got unexcpected: ") + util::tokens[token_type]);
} }
return nullptr;
}
std::shared_ptr<CommandArgumentNode> CommandArgumentNode::build(std::list<Token>::iterator& it) { std::shared_ptr<RRedirectNode> RRedirectNode::build(std::list<Token>::iterator& it) {
auto word = Optional<TokenNode<TokenType::WORD> >(it); auto Rr = Mandatory<TokenNode<TokenType::RREDIRECTION>>(it);
if(word) { auto output = Mandatory<TokenNode<TokenType::WORD>>(it);
return std::shared_ptr<CommandArgumentNode>(new CommandArgumentNode(word));
return std::shared_ptr<RRedirectNode>(new RRedirectNode(Rr, output));
} }
auto sl = Mandatory<TokenNode<TokenType::STRING_LITERAL> >(it);
return std::shared_ptr<CommandArgumentNode>(new CommandArgumentNode(sl));
}
std::shared_ptr<RRedirectNode> RRedirectNode::build(std::list<Token>::iterator& it) { std::shared_ptr<LRedirectNode> LRedirectNode::build(std::list<Token>::iterator& it) {
auto Rr = Mandatory <TokenNode<TokenType::RREDIRECTION> >(it); auto Lr = Mandatory<TokenNode<TokenType::LREDIRECTION>>(it);
auto output = Mandatory<TokenNode<TokenType::WORD> >(it); auto output = Mandatory<TokenNode<TokenType::WORD>>(it);
return std::shared_ptr<RRedirectNode>(new RRedirectNode(Rr, output));
}
std::shared_ptr<LRedirectNode> LRedirectNode::build(std::list<Token>::iterator& it) { return std::shared_ptr<LRedirectNode>(new LRedirectNode(Lr, output));
auto Lr = Mandatory <TokenNode<TokenType::LREDIRECTION> >(it);
auto output = Mandatory<TokenNode<TokenType::WORD> >(it);
return std::shared_ptr<LRedirectNode>(new LRedirectNode(Lr, output));
}
std::shared_ptr<RedirectsNode> RedirectsNode::build(std::list<Token>::iterator& it) {
TokenNode<TokenType::WORD>::shared input,output;
auto Lr = Optional<LRedirectNode>(it);
auto Rr = Optional<RRedirectNode>(it);
if(!Lr) Lr = Optional<LRedirectNode>(it);
if(!Lr && !Rr) throw AstBuildError("No redirects where provided");
return std::shared_ptr<RedirectsNode>(new RedirectsNode(Lr,Rr));
}
std::shared_ptr<CommandNode> CommandNode::build(std::list<Token>::iterator& it) {
auto cmd_name = Mandatory<TokenNode<TokenType::WORD> >(it);
auto cmd_opts = Optional<TokenNode<TokenType::FLAG> >(it);
ArgumentVec argv;
auto cmd_argument = Optional<CommandArgumentNode>(it);
while(cmd_argument){
argv.push_back(cmd_argument);
cmd_argument = Optional<CommandArgumentNode>(it);
} }
auto cmd_redr = Optional<RedirectsNode>(it);
return std::shared_ptr<CommandNode>(new CommandNode(cmd_name,cmd_opts, argv, cmd_redr));
}
std::shared_ptr<RedirectsNode> RedirectsNode::build(std::list<Token>::iterator& it) {
TokenNode<TokenType::WORD>::shared input, output;
std::shared_ptr<PipeLineNode> PipeLineNode::build(std::list<Token>::iterator& it) { auto Lr = Optional<LRedirectNode>(it);
Mandatory<TokenNode<TokenType::PIPE> >(it); auto Rr = Optional<RRedirectNode>(it);
auto l_cmd = Mandatory<CommandNode>(it);
if(Optional <TokenNode<TokenType::END_OF_STREAM>>(it)) { if (!Lr) Lr = Optional<LRedirectNode>(it);
return std::shared_ptr<PipeLineNode>(new PipeLineNode(l_cmd, nullptr)); if (!Lr && !Rr) throw AstBuildError("No redirects where provided");
return std::shared_ptr<RedirectsNode>(new RedirectsNode(Lr, Rr));
} }
auto r_cmd = Mandatory<PipeLineNode>(it);
return std::shared_ptr<PipeLineNode>(new PipeLineNode(l_cmd, r_cmd));
}
std::shared_ptr<CommandLineNode> CommandLineNode::build(std::list<Token>::iterator& it) { std::shared_ptr<CommandNode> CommandNode::build(std::list<Token>::iterator& it) {
auto cmd = Mandatory<CommandNode>(it); auto cmd_name = Mandatory<TokenNode<TokenType::WORD>>(it);
if(Optional<TokenNode<TokenType::END_OF_STREAM> >(it)){ auto cmd_opts = Optional<TokenNode<TokenType::FLAG>>(it);
return std::shared_ptr<CommandLineNode>(new CommandLineNode(cmd)); auto cmd_argument = Optional<CommandArgumentNode>(it);
ArgumentVec argv;
while (cmd_argument) {
argv.push_back(cmd_argument);
cmd_argument = Optional<CommandArgumentNode>(it);
}
auto cmd_redr = Optional<RedirectsNode>(it);
return std::shared_ptr<CommandNode>(new CommandNode(cmd_name, cmd_opts, argv, cmd_redr));
}
std::shared_ptr<PipeLineNode> PipeLineNode::build(std::list<Token>::iterator& it) {
Mandatory<TokenNode<TokenType::PIPE>>(it);
auto l_cmd = Mandatory<CommandNode>(it);
if (Optional<TokenNode<TokenType::END_OF_STREAM>>(it)) {
return std::shared_ptr<PipeLineNode>(new PipeLineNode(l_cmd, nullptr));
}
auto r_cmd = Mandatory<PipeLineNode>(it);
return std::shared_ptr<PipeLineNode>(new PipeLineNode(l_cmd, r_cmd));
}
std::shared_ptr<CommandLineNode> CommandLineNode::build(std::list<Token>::iterator& it) {
auto cmd = Mandatory<CommandNode>(it);
if (Optional<TokenNode<TokenType::END_OF_STREAM>>(it)) {
return std::shared_ptr<CommandLineNode>(new CommandLineNode(cmd));
}
auto pipe = Mandatory<PipeLineNode>(it);
return std::shared_ptr<CommandLineNode>(new CommandLineNode(cmd, pipe));
} }
auto pipe = Mandatory<PipeLineNode>(it);
return std::shared_ptr<CommandLineNode>(new CommandLineNode(cmd, pipe));
}
} }

View File

@ -5,51 +5,48 @@
namespace fsh { namespace fsh {
void CommandNode::execute(std::istream& in, std::ostream& out) { void CommandNode::execute(std::istream& in, std::ostream& out) {
std::istream* i = &in; std::istream* i = &in;
std::ostream* o = &out; std::ostream* o = &out;
std::ifstream f_i; std::ifstream f_i;
std::ofstream f_o; std::ofstream f_o;
if(redirects){ if (redirects) {
if(redirects->goutput()) { if (redirects->goutput()) {
if(redirects->gappend()) if (redirects->gappend()) f_o = util::output_append(*(redirects->goutput()));
f_o = util::output_append(*(redirects->goutput())); else
else f_o = util::output(*(redirects->goutput()));
f_o = util::output(*(redirects->goutput())); o = &f_o;
o = &f_o; }
if (redirects->ginput()) {
f_i = util::input(*(redirects->ginput()));
i = &f_i;
}
} }
if(redirects->ginput()) {
f_i = util::input(*(redirects->ginput())); /// TODO: Error when input/output was overwritten and in and out weren't cin/cout
i = &f_i;
auto& cmd_registry = CommandRegistry::instance();
cmd_registry[cmd_name].execute(flag, args, *i, *o);
}
void PipeLineNode::execute(std::istream& in, std::ostream& out) {
std::stringstream buffer;
if (r_command) {
l_command->execute(in, buffer);
r_command->execute(buffer, out);
} else {
l_command->execute(in, out);
} }
} }
void CommandLineNode::execute(std::istream& in, std::ostream& out) {
/// TODO: Error when input/output was overwritten and in and out weren't cin/cout std::stringstream buffer;
if (pipe) {
auto& cmd_registry = CommandRegistry::instance(); command->execute(in, buffer);
cmd_registry[cmd_name].execute(flag, args, *i, *o); pipe->execute(buffer, out);
} } else {
command->execute(in, out);
}
void PipeLineNode::execute(std::istream& in, std::ostream& out) {
std::stringstream buffer;
if(r_command){
l_command->execute(in, buffer);
r_command->execute(buffer, out);
} else {
l_command->execute(in,out);
} }
}
void CommandLineNode::execute(std::istream& in, std::ostream& out) {
std::stringstream buffer;
if(pipe){
command->execute(in, buffer);
pipe->execute(buffer, out);
} else {
command->execute(in,out);
}
}
} }

View File

@ -3,44 +3,38 @@
namespace fsh { namespace fsh {
void CommandNode::print(int indent) { void CommandNode::print(int indent) {
std::string t = ""; std::string t = "";
for(int i=0; i<indent;i++) { for (int i = 0; i < indent; i++) { t += "\t"; }
t+="\t"; std::cout << t << gname() << "\n";
std::cout << t << "\tCommand_Name = " << cmd_name << "\n";
if (flag) std::cout << t << "\tFlagOpt = " << *flag << "\n";
for (const auto& x : args)
std::cout << t << "\tArgs: " << x->gvalue() << " " << util::tokens[x->gtoken_type()] << "\n";
if (redirects) {
auto out = redirects->goutput();
auto in = redirects->ginput();
if (in) std::cout << t << "\tinput = " << *in << "\n";
if (out) std::cout << t << "\toutput = " << *out << " " << redirects->gappend() << "\n";
}
} }
std::cout<<t<< gname() << "\n";
std::cout<<t<<"\tCommand_Name = " << cmd_name << "\n";
if(flag) std::cout<<t<<"\tFlagOpt = " << *flag << "\n";
for(const auto& x : args)
std::cout<<t<<"\tArgs: " << x->gvalue() <<" "<< util::tokens[x->gtoken_type()]<< "\n";
if(redirects) {
auto out = redirects->goutput();
auto in = redirects->ginput();
if(in) std::cout<<t<<"\tinput = " << *in << "\n";
if(out) std::cout<<t<<"\toutput = " << *out << " " << redirects->gappend() << "\n";
}
}
void PipeLineNode::print(int indent) { void PipeLineNode::print(int indent) {
std::string t = ""; std::string t = "";
for(int i=0; i<indent;i++) { for (int i = 0; i < indent; i++) { t += "\t"; }
t+="\t"; std::cout << t << gname() << "\n";
std::cout << "left_cmd:\n";
if (l_command) l_command->print(indent + 1);
std::cout << "right_cmd:\n";
if (r_command) r_command->print(indent + 1);
} }
std::cout<<t<< gname() << "\n";
std::cout<<"left_cmd:\n";
if(l_command) l_command->print(indent + 1);
std::cout<<"right_cmd:\n";
if(r_command) r_command->print(indent + 1);
}
void CommandLineNode::print(int indent) { void CommandLineNode::print(int indent) {
std::string t = ""; std::string t = "";
for(int i=0; i<indent;i++) { for (int i = 0; i < indent; i++) { t += "\t"; }
t+="\t"; std::cout << t << gname() << "\n";
if (command) command->print(indent + 1);
if (pipe) pipe->print(indent + 1);
} }
std::cout<<t<< gname() << "\n";
if(command) command->print(indent + 1);
if(pipe) pipe->print(indent + 1);
}
} }

View File

@ -2,71 +2,62 @@
namespace fsh { namespace fsh {
void ArgInput::svalue(const std::string& val, const Lexer::TokenType& type) { void ArgInput::svalue(const std::string& val, const Lexer::TokenType& type) {
const std::string& txt = val; const std::string& txt = val;
if(type == Lexer::TokenType::STRING_LITERAL) { if (type == Lexer::TokenType::STRING_LITERAL) {
str = std::stringstream(txt); str = std::stringstream(txt);
} else { } else {
file = std::ifstream(txt, std::ios::in); file = std::ifstream(txt, std::ios::in);
if(!*file) { if (!*file) { throw std::runtime_error("Failed to open file"); }
throw std::runtime_error("Failed to open file");
} }
} }
}
std::istream& ArgInput::gvalue() {
std::istream& ArgInput::gvalue(){ if (str) return *str;
if(str) return *file;
return *str;
return *file;
}
void ArgFactory::parse(ArgManager& manager, ArgNodes& vec, FlagNode flag) {
if(flag) {
parse_flag(manager, flag);
} }
unsigned int i = 0;
for(const auto& arg : vec) {
std::shared_ptr<_Argument> a;
if(i >= pos_arg_rules.size()) throw std::invalid_argument("More arguments then excpected");
manager.push_arg(build_arg(pos_arg_rules[i].build, arg));
if(!pos_arg_rules[i].extends) i++;
}
}
void ArgFactory::parse(ArgManager& manager, ArgNodes& vec, FlagNode flag) {
void ArgFactory::parse_flag(ArgManager& manager, FlagNode flag) { if (flag) { parse_flag(manager, flag); }
const std::string f = *flag; unsigned int i = 0;
int f_sz = f.size(); for (const auto& arg : vec) {
for(const auto& [key, rule] : flag_rules) { std::shared_ptr<_Argument> a;
const std::string_view k(key); if (i >= pos_arg_rules.size()) throw std::invalid_argument("More arguments then excpected");
if(k == f) { manager.push_arg(build_arg(pos_arg_rules[i].build, arg));
manager.push_flag(f); if (!pos_arg_rules[i].extends) i++;
return;
}
if(rule.capturing && f == k.substr(0, f_sz)) {
auto arg = build_arg(rule.build, (std::string) k.substr(f_sz));
manager.push_flag(f, arg);
return;
} }
} }
throw std::invalid_argument("Invalid flag");
}
void ArgFactory::parse_flag(ArgManager& manager, FlagNode flag) {
const std::string f = *flag;
int f_sz = f.size();
for (const auto& [key, rule] : flag_rules) {
const std::string_view k(key);
if (k == f) {
manager.push_flag(f);
return;
}
std::shared_ptr<_Argument> ArgFactory::build_arg(BuildFunc build_func, const std::string& str) { if (rule.capturing && f == k.substr(0, f_sz)) {
auto arg = build_func(); auto arg = build_arg(rule.build, (std::string)k.substr(f_sz));
arg->svalue(str); manager.push_flag(f, arg);
return arg; return;
} }
}
throw std::invalid_argument("Invalid flag");
}
std::shared_ptr<_Argument> ArgFactory::build_arg(BuildFunc build_func, std::shared_ptr<CommandArgumentNode> cmd_arg) { std::shared_ptr<_Argument> ArgFactory::build_arg(BuildFunc build_func, const std::string& str) {
auto arg = build_func(); auto arg = build_func();
arg->svalue(cmd_arg); arg->svalue(str);
return arg; return arg;
} }
std::shared_ptr<_Argument> ArgFactory::build_arg(BuildFunc build_func,
std::shared_ptr<CommandArgumentNode> cmd_arg) {
auto arg = build_func();
arg->svalue(cmd_arg);
return arg;
}
} }

View File

@ -6,20 +6,17 @@ namespace fsh {
void Command::execute(FlagNode flag, ArgNodes& vec, std::istream& in, std::ostream& out) { void Command::execute(FlagNode flag, ArgNodes& vec, std::istream& in, std::ostream& out) {
ArgManager args; ArgManager args;
arg_factory.parse(args, vec, flag); arg_factory.parse(args, vec, flag);
if(arg_factory.ghas_input()) { if (arg_factory.ghas_input()) {
if (&args.get_input(0) != &util::cin && &in != &util::cin) {
if(&args.get_input(0) != &util::cin && &in!= &util::cin) {
throw std::runtime_error("Tried to set input to command twice"); throw std::runtime_error("Tried to set input to command twice");
} }
if(&args.get_input(0) != &util::cin) if (&args.get_input(0) != &util::cin) run(args.get_input(0), out, args);
run(args.get_input(0), out, args);
else else
run(in, out, args); run(in, out, args);
} } else {
else {
run(in, out, args); run(in, out, args);
} }
in.clear(); in.clear();
} }
} } // namespace fsh

View File

@ -12,20 +12,18 @@
namespace fsh { namespace fsh {
void fsh::run_line(std::string& line, std::istream& in, std::ostream& out) { void fsh::run_line(std::string& line, std::istream& in, std::ostream& out) {
auto tokens = Lexer::process(line); auto tokens = Lexer::process(line);
auto ast = AstFactory::generate_ast(tokens); auto ast = AstFactory::generate_ast(tokens);
ast->execute(in, out); ast->execute(in, out);
} }
void fsh::run() { void fsh::run() {
while(environment["EXITING"] == "") { while (environment["EXITING"] == "") {
try { try {
std::cout << environment["PROMPT"] << " "; std::cout << environment["PROMPT"] << " ";
std::string line; std::string line;
std::getline(util::cin, line); std::getline(util::cin, line);
run_line(line, util::cin, std::cout); run_line(line, util::cin, std::cout);
} catch(const std::exception& e) { } catch (const std::exception& e) { std::cerr << e.what() << "\n"; }
std::cerr << e.what() << "\n";
}
} }
} }
} }

View File

@ -7,112 +7,98 @@
namespace fsh { namespace fsh {
Token LexerStateMachine::run() { Token LexerStateMachine::run() {
State state = State::START; State state = State::START;
while (state != State::END) { while (state != State::END) { state = state_handlers[state](); }
state = state_handlers[state](); return { type, token };
}
return {type, token};
}
LexerStateMachine::State LexerStateMachine::handle_start() {
const int c = parser.peek();
if(c == std::char_traits<char>::eof()) {
return set_type(Lexer::TokenType::END_OF_STREAM);
} else if(util::contains(c, " \t")) {
parser.consume();
return State::START;
} else if(c == '\"') {
parser.consume();
return set_type(Lexer::TokenType::STRING_LITERAL, State::STRING_LITERAL);
} }
token = parser.consume(); LexerStateMachine::State LexerStateMachine::handle_start() {
if(c == '|') { const int c = parser.peek();
return set_type(Lexer::TokenType::PIPE);
} else if(c == '<') { if (c == std::char_traits<char>::eof()) {
return set_type(Lexer::TokenType::LREDIRECTION); return set_type(Lexer::TokenType::END_OF_STREAM);
} else if(c == '>') { } else if (util::contains(c, " \t")) {
return set_type(Lexer::TokenType::RREDIRECTION, State::REDIRECT ); parser.consume();
} else if(c == '-') { return State::START;
return set_type(Lexer::TokenType::FLAG , State::FLAG_OPT ); } else if (c == '\"') {
} else { parser.consume();
return set_type(Lexer::TokenType::WORD , State::POTENTIAL_WORD ); return set_type(Lexer::TokenType::STRING_LITERAL, State::STRING_LITERAL);
}
token = parser.consume();
if (c == '|') {
return set_type(Lexer::TokenType::PIPE);
} else if (c == '<') {
return set_type(Lexer::TokenType::LREDIRECTION);
} else if (c == '>') {
return set_type(Lexer::TokenType::RREDIRECTION, State::REDIRECT);
} else if (c == '-') {
return set_type(Lexer::TokenType::FLAG, State::FLAG_OPT);
} else {
return set_type(Lexer::TokenType::WORD, State::POTENTIAL_WORD);
}
} }
}
LexerStateMachine::State LexerStateMachine::handle_flag_opt() { LexerStateMachine::State LexerStateMachine::handle_flag_opt() {
return word_like_handler(Lexer::TokenType::FLAG, State::FLAG_OPT); return word_like_handler(Lexer::TokenType::FLAG, State::FLAG_OPT);
}
LexerStateMachine::State LexerStateMachine::handle_redirect() {
const int c = parser.peek();
if(c == '>') {
token += parser.consume();
} }
return set_type(Lexer::TokenType::RREDIRECTION);
}
LexerStateMachine::State LexerStateMachine::handle_potential_word() { LexerStateMachine::State LexerStateMachine::handle_redirect() {
return word_like_handler(Lexer::TokenType::WORD, State::POTENTIAL_WORD); const int c = parser.peek();
} if (c == '>') { token += parser.consume(); }
return set_type(Lexer::TokenType::RREDIRECTION);
LexerStateMachine::State LexerStateMachine::handle_string_literal() {
const int c = parser.peek();
if( c == std::char_traits<char>::eof() ) {
throw std::runtime_error("Excpected \" before \\n");
} else if(c == '\"') {
parser.consume();
return set_type(Lexer::TokenType::STRING_LITERAL);
} else {
token += parser.consume();
return State::STRING_LITERAL;
} }
}
LexerStateMachine::State LexerStateMachine::handle_potential_word() {
return word_like_handler(Lexer::TokenType::WORD, State::POTENTIAL_WORD);
}
LexerStateMachine::State LexerStateMachine::word_like_handler(Lexer::TokenType type, State state) { LexerStateMachine::State LexerStateMachine::handle_string_literal() {
const int c = parser.peek(); const int c = parser.peek();
if(util::contains(c, "\t><| ") || c == std::char_traits<char>::eof()) { if (c == std::char_traits<char>::eof()) {
return set_type(type); throw std::runtime_error("Excpected \" before \\n");
} else if(c == '\"') { } else if (c == '\"') {
throw std::runtime_error("Invalid \""); parser.consume();
} else { return set_type(Lexer::TokenType::STRING_LITERAL);
token += parser.consume(); } else {
return state; token += parser.consume();
} return State::STRING_LITERAL;
} }
}
std::list<Token> Lexer::process(std::string line) { LexerStateMachine::State LexerStateMachine::word_like_handler(Lexer::TokenType type, State state) {
Lexer parser(line); const int c = parser.peek();
std::list<Token> tokens; if (util::contains(c, "\t><| ") || c == std::char_traits<char>::eof()) {
tokens.push_back(parser.next_token()); return set_type(type);
while(tokens.back().first != TokenType::END_OF_STREAM) { } else if (c == '\"') {
throw std::runtime_error("Invalid \"");
} else {
token += parser.consume();
return state;
}
}
std::list<Token> Lexer::process(std::string line) {
Lexer parser(line);
std::list<Token> tokens;
tokens.push_back(parser.next_token()); tokens.push_back(parser.next_token());
} while (tokens.back().first != TokenType::END_OF_STREAM) { tokens.push_back(parser.next_token()); }
return tokens; return tokens;
} }
int Lexer::peek() { int Lexer::peek() {
if(idx < workspace.size()) if (idx < workspace.size()) return workspace[idx];
return workspace[idx]; return std::char_traits<char>::eof();
return std::char_traits<char>::eof(); }
} int Lexer::consume() {
int Lexer::consume() { if (idx < workspace.size()) return workspace[idx++];
if(idx < workspace.size()) return std::char_traits<char>::eof();
return workspace[idx++]; }
return std::char_traits<char>::eof();
}
Token Lexer::next_token() { Token Lexer::next_token() {
LexerStateMachine psm(*this); LexerStateMachine psm(*this);
return psm.run(); return psm.run();
} }
} }

View File

@ -5,8 +5,7 @@
#include "fsh.hpp" #include "fsh.hpp"
#include "util/input.hpp" #include "util/input.hpp"
int main() {
int main(){
fsh::util::prepTerminal(); fsh::util::prepTerminal();
fsh::fsh::instance().run(); fsh::fsh::instance().run();
return 0; return 0;

View File

@ -11,139 +11,118 @@
#endif #endif
#include <iostream> #include <iostream>
#include "util/input.hpp" #include "util/input.hpp"
namespace fsh::util {
namespace fsh::util
{
#ifndef _WIN32 #ifndef _WIN32
struct termios prev_attr; struct termios prev_attr;
void resetTerminal() { void resetTerminal() { tcsetattr(STDIN_FILENO, TCSANOW, &prev_attr); }
tcsetattr(STDIN_FILENO, TCSANOW, &prev_attr);
}
#endif #endif
void prepTerminal() {
void prepTerminal() {
#ifdef _WIN32 #ifdef _WIN32
/* Ovaj deo koda je namenjen da omoguci koriscenje neke ansi-escape sekvence na windows platformi */ /* Ovaj deo koda je namenjen da omoguci koriscenje neke ansi-escape sekvence na windows platformi */
#else #else
/* Ova porcija koda je preuzata sa https://www.gnu.org/software/libc/manual/html_node/Noncanon-Example.html /* Ova porcija koda je preuzata sa https://www.gnu.org/software/libc/manual/html_node/Noncanon-Example.html
Omogucava da karaktere primim kako su unjeti, sto kasnije koristim da omogucim pomeranje kursora pomocu Omogucava da karaktere primim kako su unjeti, sto kasnije koristim da omogucim pomeranje kursora pomocu
strelica pod UNIX sistemima */ strelica pod UNIX sistemima */
struct termios tattr; struct termios tattr;
if(!isatty(STDIN_FILENO)) { if (!isatty(STDIN_FILENO)) { return; }
return;
}
tcgetattr(STDIN_FILENO, &prev_attr); tcgetattr(STDIN_FILENO, &prev_attr);
atexit(resetTerminal); atexit(resetTerminal);
tcgetattr(STDIN_FILENO, &tattr); tcgetattr(STDIN_FILENO, &tattr);
tattr.c_lflag &= ~(ICANON|ECHO); tattr.c_lflag &= ~(ICANON | ECHO);
tattr.c_cc[VMIN] = 1; tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0; tattr.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSAFLUSH ,&tattr); tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
std::cout << "\e[?25h"; std::cout << "\e[?25h";
#endif #endif
}
}
#ifndef _WIN32 #ifndef _WIN32
int CursorIStreamBuffer::underflow() { int CursorIStreamBuffer::underflow() {
if(gptr() < egptr()) return traits_type::to_int_type(*gptr()); if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
if(read_chars >= input.size()) { if (read_chars >= input.size()) { readInputToNewLine(); }
readInputToNewLine();
int n = input.copy(buffer, sizeof(buffer) - 1, read_chars);
read_chars += n;
setg(buffer, buffer, buffer + n);
return traits_type::to_int_type(*gptr());
} }
int n = input.copy(buffer, sizeof(buffer)-1, read_chars); CursorIStreamBuffer::EscapeSequence CursorIStreamBuffer::testForEscapeCodes(char chr) {
read_chars+=n; if (valid == 2) {
valid = 0;
setg(buffer,buffer,buffer+n); switch (chr) {
return traits_type::to_int_type(*gptr()); case 'C': return RIGHT_ARROW;
} case 'D': return LEFT_ARROW;
}
CursorIStreamBuffer::EscapeSequence CursorIStreamBuffer::testForEscapeCodes(char chr) { }
if(valid==2) { if (chr == '\033') {
valid = 1;
return POSSIBLE;
}
if (valid == 1 && chr == '[') {
valid = 2;
return POSSIBLE;
}
valid = 0; valid = 0;
switch (chr) return FAILED;
{
case 'C':
return RIGHT_ARROW;
case 'D':
return LEFT_ARROW;
}
} }
if(chr == '\033') {
valid=1;
return POSSIBLE;
}
if(valid==1 && chr == '[') {
valid=2;
return POSSIBLE;
}
valid = 0;
return FAILED;
}
int CursorIStreamBuffer::readInputToNewLine() {
int CursorIStreamBuffer::readInputToNewLine(){ read_chars = 0;
read_chars = 0; cursor_pos = 0;
cursor_pos = 0; input = "";
input = ""; char c;
char c; while (std::cin.get(c)) {
while(std::cin.get(c)) { //std::cout << (int)c;
//std::cout << (int)c; EscapeSequence e = testForEscapeCodes(c);
EscapeSequence e = testForEscapeCodes(c); if (c == '\r') continue; // Skip CR to keep sanity
if(c == '\r') continue; // Skip CR to keep sanity else if (c == 127 || c == 8) {
else if(c == 127 || c == 8) { if (cursor_pos > 0) {
if(cursor_pos > 0) { std::cout << "\e[D\e[P";
std::cout<<"\e[D\e[P"; input.erase(--cursor_pos, 1);
input.erase(--cursor_pos,1);
}
}
else if(e>0) {
if(e==RIGHT_ARROW) {
if(cursor_pos<input.size()) {
cursor_pos++;
std::cout << "\e[C";
} }
} } else if (e > 0) {
else if(e==LEFT_ARROW) { if (e == RIGHT_ARROW) {
if(cursor_pos>0) { if (cursor_pos < input.size()) {
cursor_pos--; cursor_pos++;
std::cout << "\e[D"; std::cout << "\e[C";
}
} else if (e == LEFT_ARROW) {
if (cursor_pos > 0) {
cursor_pos--;
std::cout << "\e[D";
}
} }
continue;
} else if (c == '\n') {
std::cout << '\n';
input.push_back(c);
return 0;
} else {
input.insert(cursor_pos++, 1, c);
std::cout << "\033[@" << c;
} }
continue;
} }
else if(c == '\n') { input.push_back(0);
std::cout<<'\n'; return 0;
input.push_back(c);
return 0;
}
else{
input.insert(cursor_pos++,1,c);
std::cout<<"\033[@"<<c;
}
} }
input.push_back(0);
return 0;
}
CursorIStream cin; CursorIStream cin;
#else #else
std::istream& cin = std::cin; std::istream& cin = std::cin;
#endif #endif
} }

View File

@ -2,16 +2,7 @@
namespace fsh::util { namespace fsh::util {
const char* tokens[] = { const char* tokens[] = { "WHITESPACE", "WORD", "STRING_LITERAL", "OPT", "FLAG",
"WHITESPACE", "LREDIRECTION", "RREDIRECTION", "PIPE", "END_OF_STREAM" };
"WORD",
"STRING_LITERAL",
"OPT",
"FLAG",
"LREDIRECTION",
"RREDIRECTION",
"PIPE",
"END_OF_STREAM"
};
} }