From a3b3a9b6e803f785e4e092038b1393a9fa77f464 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Apr 2025 17:16:40 -0500 Subject: [PATCH] use strings and forkpty --- ExampleApps.nix | 2 + modules/Terminal/src/Terminal.cpp | 163 +++++++----------------------- modules/Terminal/src/Terminal.h | 2 +- 3 files changed, 40 insertions(+), 127 deletions(-) diff --git a/ExampleApps.nix b/ExampleApps.nix index c2d87ba..123520f 100644 --- a/ExampleApps.nix +++ b/ExampleApps.nix @@ -53,6 +53,7 @@ modules/ImguiModule/src/*.cpp \ $imgui/backends/imgui_impl_glfw.cpp \ $imgui/backends/imgui_impl_opengl3.cpp \ + $imgui/misc/cpp/*.cpp \ $imgui/*.cpp \ -DRENDERER_OPENGL \ -DWINDOW_GLFW \ @@ -94,6 +95,7 @@ modules/ImguiModule/src/*.cpp \ $imgui/backends/imgui_impl_glfw.cpp \ $imgui/backends/imgui_impl_opengl3.cpp \ + $imgui/misc/cpp/*.cpp \ $imgui/*.cpp \ -DRENDERER_OPENGL \ -DWINDOW_GLFW \ diff --git a/modules/Terminal/src/Terminal.cpp b/modules/Terminal/src/Terminal.cpp index 599c664..e2a60e9 100644 --- a/modules/Terminal/src/Terminal.cpp +++ b/modules/Terminal/src/Terminal.cpp @@ -1,14 +1,8 @@ -#define _XOPEN_SOURCE 600 -#include -#include #include + #include -//#include -#define __USE_BSD -#include -#include -#include -#include +#include +#include #include "Terminal.h" #include "modules/ImguiModule/src/ImguiModule.h" @@ -37,140 +31,57 @@ void Terminal::onLoad() { ImGui::SetCurrentContext(im->getContext()); - master = posix_openpt(O_RDWR); - if (master < 0) { - std::cerr << "Error " << errno << " on posix_openpt()\n"; - std::abort(); - } + child_pid = forkpty(&master, nullptr, nullptr, nullptr); - int returnCode = grantpt(master); - if (returnCode != 0) { - std::cerr << "Error " << errno << " on grantpt()\n"; - std::abort(); - } - - returnCode = unlockpt(master); - if (returnCode != 0) { - 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 - { + if(!child_pid) { char* const* args = nullptr; - returnCode = execvp("bash", args); + execvp("bash", args); } - // if Error... - std::abort(); - } - - ///////////////////////////////////////////////////// + //fcntl(master, F_SETFL, fcntl(master, F_GETFL, 0) | O_NONBLOCK); +/* + if (master >= 0) + (void)write(master, "ls\n", 3); +*/ } void Terminal::run() { - static char input[150] = ""; - static std::vector output(150); - static std::string op = ""; - static int returnCode; - static std::future rc; - static fd_set fd_in; + static fd_set fds; + static int rc; + static char opArr[150]; + static std::string input, output; + static timeval to; to = { 0, 0 }; - // Wait for data from standard input and master side of PTY - FD_ZERO(&fd_in); - FD_SET(master, &fd_in); + FD_ZERO(&fds); + FD_SET(master, &fds); - //returnCode = select(master + 1, &fd_in, NULL, NULL, NULL); - rc = std::async(std::launch::async, [this](fd_set* f) -> int { - return select(master + 1, f, NULL, NULL, NULL); - }, &fd_in); - - if(rc.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - switch(rc.get()) { - case -1: fprintf(stderr, "Error %d on select()\n", errno); - exit(1); + rc = select(master + 1, &fds, NULL, NULL, &to); - default: { - // If data on master side of PTY - if(FD_ISSET(master, &fd_in)) { - returnCode = read(master, output.data(), 150); - if (returnCode > 0) { - write(1, output.data(), returnCode); - op += "\n"; - op += output.data(); - op += "\n"; - output.clear(); - } else { - if (returnCode < 0) { - fprintf(stderr, "Error %d on read master PTY\n", errno); - exit(1); - } - } - } - } - } // End switch + switch(rc) { + case -1: + std::cerr << "Error " << errno << " on select()\n"; + exit(1); + default: + if(FD_ISSET(master, &fds)) { + rc = read(master, opArr, 150); + if(rc < 0) { + //error on read + app->stopModule(getName()); + } else { + if(input == "clear") output = ""; + output += opArr; + } + } } - ImGui::Begin("Terminal Module"); - ImGui::TextWrapped("%s", op.c_str()); - ImGui::InputText("input", input, 150); + ImGui::TextWrapped("%s", output.c_str()); + ImGui::InputText("input", &input); if(ImGui::Button("send")) { - static std::string s; s = input; s += "\n"; - write(master, s.c_str(), s.length()); + (void)write(master, (input + "\n").c_str(), input.length() + 1); } diff --git a/modules/Terminal/src/Terminal.h b/modules/Terminal/src/Terminal.h index d7180df..4c46ca3 100644 --- a/modules/Terminal/src/Terminal.h +++ b/modules/Terminal/src/Terminal.h @@ -11,7 +11,7 @@ class Terminal : public Archimedes::Module { void run(); private: - int master; + int child_pid, master; }; #ifdef TERMINAL_DYNAMIC