diff --git a/modules/Terminal/src/Terminal.cpp b/modules/Terminal/src/Terminal.cpp new file mode 100644 index 0000000..1c34c5b --- /dev/null +++ b/modules/Terminal/src/Terminal.cpp @@ -0,0 +1,165 @@ +#define _XOPEN_SOURCE 600 +#include +#include +#include +#include +//#include +#define __USE_BSD +#include +#include +#include +#include + +#include "Terminal.h" +#include "modules/ImguiModule/src/ImguiModule.h" + + +Terminal::Terminal(Archimedes::App* a, void* h) : Archimedes::Module(a, h) { + + name = "Terminal"; + + ImguiModule* im = new ImguiModule(a, nullptr); + deps[im->getName()] = im; +} + +Terminal::~Terminal() { + +} + +void Terminal::onLoad() { + + ImguiModule* im = (ImguiModule*) moduleInstances["ImguiModule"]; + + if(!im) { + std::cout << "No ImguiModule for Terminal!\n"; + std::abort(); + } + + ImGui::SetCurrentContext(im->getContext()); + + master = posix_openpt(O_RDWR); + if (master < 0) { + std::cerr << "Error " << errno << " on posix_openpt()\n"; + std::abort(); + } + + int returnCode = grantpt(master); + if (!returnCode) { + std::cerr << "Error " << errno << " on grantpt()\n"; + std::abort(); + } + + returnCode = unlockpt(master); + if (!returnCode) { + std::cerr << "Error " << errno << " on unlockpt()\n"; + std::abort(); + } + + int slave = open(ptsname(master), O_RDWR); + + ///////////////////////////////////////////////////// + // Create the child process + if (fork()) + { + + // FATHER + + // Close the slave side of the PTY + close(slave); + + return; + } else + { + struct termios slave_orig_term_settings; // Saved terminal settings + struct termios new_term_settings; // Current terminal settings + + // CHILD + + // Close the master side of the PTY + close(master); + + // Save the defaults parameters of the slave side of the PTY + returnCode = tcgetattr(slave, &slave_orig_term_settings); + + // Set RAW mode on slave side of PTY + new_term_settings = slave_orig_term_settings; + cfmakeraw (&new_term_settings); + tcsetattr (slave, TCSANOW, &new_term_settings); + + // The slave side of the PTY becomes the standard input and outputs of the child process + close(0); // Close standard input (current terminal) + close(1); // Close standard output (current terminal) + close(2); // Close standard error (current terminal) + + dup(slave); // PTY becomes standard input (0) + dup(slave); // PTY becomes standard output (1) + dup(slave); // PTY becomes standard error (2) + + // Now the original file descriptor is useless + close(slave); + + // Make the current process a new session leader + setsid(); + + // As the child is a session leader, set the controlling terminal to be the slave side of the PTY + // (Mandatory for programs like the shell to make them manage correctly their outputs) + ioctl(0, TIOCSCTTY, 1); + + // Execution of the program + { + char* const* args = nullptr; + returnCode = execvp("bash", args); + } + + // if Error... + std::abort(); + } + + ///////////////////////////////////////////////////// +} + +void Terminal::run() { + + static char input[150]; + static char output[150]; + static int returnCode; + static timeval timeout; timeout = { 0, 0 }; + fd_set fd_in; + // Wait for data from standard input and master side of PTY + FD_ZERO(&fd_in); + FD_SET(master, &fd_in); + + returnCode = select(master + 1, &fd_in, NULL, NULL, &timeout); + switch(returnCode) { + case -1: fprintf(stderr, "Error %d on select()\n", errno); + exit(1); + + default: { + // If data on master side of PTY + if (FD_ISSET(master, &fd_in)) { + returnCode = read(master, output, sizeof(output)); + if (returnCode > 0) { + + } else { + if (returnCode < 0) { + fprintf(stderr, "Error %d on read master PTY\n", errno); + exit(1); + } + } + } + } + } // End switch + + + ImGui::Begin("Terminal Module"); + + ImGui::Text("%s", output); + ImGui::SameLine(); + ImGui::InputText("", input, 150); + + if(ImGui::Button("send")) + write(master, input, returnCode); + + + ImGui::End(); +} diff --git a/modules/Terminal/src/Terminal.h b/modules/Terminal/src/Terminal.h new file mode 100644 index 0000000..a520cd8 --- /dev/null +++ b/modules/Terminal/src/Terminal.h @@ -0,0 +1,20 @@ +#include "Archimedes.h" + +class Terminal : public Archimedes::Module { + + public: + Terminal(Archimedes::App*, void*); + + ~Terminal(); + + void onLoad(); + + void run(); + private: + int master; +}; + +#ifdef MAINGUI_DYNAMIC +#define MODULE_TYPE Terminal +#include "endModule.h" +#endif