diff --git a/include/ShellLoop.hpp b/include/ShellLoop.hpp index 1e202e9..ef4775c 100644 --- a/include/ShellLoop.hpp +++ b/include/ShellLoop.hpp @@ -8,6 +8,7 @@ #include #include #include "Circuit.hpp" +#include namespace nts { @@ -17,6 +18,8 @@ class ShellLoop { ~ShellLoop(); void run(); + static bool signalReceived; + static void signalHandler(int signal); private: protected: Circuit &_circuit; @@ -26,6 +29,9 @@ class ShellLoop { void display(Circuit &circuit); void simulate(Circuit &circuit); void loop(Circuit &circuit); + bool getUserInput(std::string &input); + bool executeCommand(const std::string &input); + void handleException(const std::exception &e); bool _running; }; diff --git a/src/ShellLoop.cpp b/src/ShellLoop.cpp index 4965e46..42d0e0f 100644 --- a/src/ShellLoop.cpp +++ b/src/ShellLoop.cpp @@ -7,14 +7,29 @@ #include "ShellLoop.hpp" + +bool nts::ShellLoop::signalReceived = false; + +void nts::ShellLoop::signalHandler(int signal) { + if (signal == SIGINT) { + signalReceived = true; + dup2(0, 0); + } +} + nts::ShellLoop::ShellLoop(Circuit &circuit) : _circuit(circuit) { + struct sigaction sa; + _commands.emplace("exit", &ShellLoop::exit); _commands.emplace("simulate", &ShellLoop::simulate); _commands.emplace("display", &ShellLoop::display); _commands.emplace("loop", &ShellLoop::loop); _running = true; -} + sa.sa_handler = signalHandler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL);} nts::ShellLoop::~ShellLoop() { @@ -38,7 +53,7 @@ void nts::ShellLoop::simulate(Circuit &circuit) void nts::ShellLoop::loop(Circuit &circuit) { - while (_running) { + while (_running && !signalReceived) { circuit.simulate(circuit.getTick() + 1); circuit.display(); } @@ -78,25 +93,60 @@ bool nts::ShellLoop::setComponentValue(const std::string &input, Circuit &circui return false; } +bool nts::ShellLoop::getUserInput(std::string &input) +{ + if (!std::getline(std::cin, input)) { + if (signalReceived || std::cin.eof()) { + std::cout << std::endl; + return false; + } + if (std::cin.fail()) { + std::cin.clear(); + return true; + } + } + return !signalReceived; +} + +bool nts::ShellLoop::executeCommand(const std::string &input) +{ + if (input.empty()) + return true; + if (_commands.find(input) != _commands.end()) { + (this->*_commands[input])(_circuit); + } else if (input == "exit") { + exit(_circuit); + return false; + } else if (!setComponentValue(input, _circuit)) { + std::cerr << "Invalid command: " << input << std::endl; + } + return !signalReceived; +} + +void nts::ShellLoop::handleException(const std::exception &e) +{ + if (!signalReceived) { + std::cerr << "Error: " << e.what() << std::endl; + } +} + void nts::ShellLoop::run() { std::string input; _circuit.simulate(0); - while (_running) { - std::cout << "> "; - if (!std::getline(std::cin, input)) { - std::cout << std::endl; - break; - } - if (input.empty()) - continue; - if (_commands.find(input) != _commands.end()) - (this->*_commands[input])(_circuit); - else if (input == "exit") - exit(_circuit); - else if (!setComponentValue(input, _circuit)) { - std::cerr << "Invalid command: " << input << std::endl; + while (_running && !signalReceived) { + std::cout << "> " << std::flush; + try { + if (!getUserInput(input)) + break; + if (!executeCommand(input)) + break; + } catch (const std::exception &e) { + handleException(e); } + if (signalReceived) + break; } + _running = false; } \ No newline at end of file diff --git a/src/specialComponents/Input.cpp b/src/specialComponents/Input.cpp index 53f97f6..a5aec26 100644 --- a/src/specialComponents/Input.cpp +++ b/src/specialComponents/Input.cpp @@ -21,18 +21,23 @@ nts::InputComponent::~InputComponent() void nts::InputComponent::simulate(std::size_t tick) { - (void)tick; - if (_pins[0].lock() == nullptr) { + if (_lastTick == tick) + return; + _lastTick = tick; + + if (_pins[0].lock() == nullptr) this->setState(nts::UNDEFINED); - } else { - this->setState(_pins[0].lock()->compute(tick)); + auto linkedComponent = _pins[0].lock(); + linkedComponent->simulate(tick); + this->setState(linkedComponent->getState()); } } nts::Tristate nts::InputComponent::compute(std::size_t tick) { - this->simulate(tick); + if (_lastTick != tick) + this->simulate(tick); return this->getState(); } diff --git a/tests/test_elementaryComponents.cpp b/tests/test_elementaryComponents.cpp index fbcd6ef..6a33190 100644 --- a/tests/test_elementaryComponents.cpp +++ b/tests/test_elementaryComponents.cpp @@ -30,7 +30,7 @@ Test(Circuit, link_input_to_output) { circuit.addComponent("output", "Out1"); circuit.linkComponents("In1", "Out1", 1, 1); circuit.setInputState(*dynamic_cast(circuit.getComponent("In1").get()), nts::TRUE); - circuit.simulate(1); + //circuit.simulate(1); nts::Tristate state = circuit.compute("Out1"); cr_assert_eq(state, nts::TRUE, "Output should be TRUE when input is TRUE"); }