From 2fca3155578753fb33c027abac4141bf25a4c2c1 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Thu, 16 Sep 2021 18:11:47 +0200 Subject: [PATCH] Util: Add support for stdin and | piping In order to accomplish this, the arguments have to be stored in the object. Because () evaluation order is not defined in the spec. Because arguments have to be stored now, char pointers no longer work and std::strings are stored instead. Systems object also cant be returned as a reference anymore because you need to be able to know which is the lhs and which is the rhs in the operator overloads. --- src/util/system.cpp | 128 ++++++++++++++++++++++++++++---------------- src/util/system.h | 25 +++++---- 2 files changed, 97 insertions(+), 56 deletions(-) diff --git a/src/util/system.cpp b/src/util/system.cpp index 839038c..057b6db 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -14,70 +14,101 @@ namespace Util { -void System::operator()(const char* command) +System::System() { - // Split modifies the string, so two copies are needed - char charCommand[strlen(command)]; - strcpy(charCommand, command); - char charCommand2[strlen(command)]; - strcpy(charCommand2, command); - - size_t index = split(charCommand, " "); +} - // Preallocation is roughly ~10% faster even with just a single space. - std::vector arguments(index + 1, 0); +System::System(std::vector arguments) + : m_arguments(arguments) +{ +} - split(charCommand2, " ", [&arguments](int index, char* pointer) { - arguments[index] = pointer; - }); +System System::operator()() +{ + return exec(); +} - operator()(arguments); +System System::operator()(const char* command) +{ + return operator()(std::string { command }); } -void System::operator()(std::string command) +System System::operator()(std::string command) { - operator()(command.c_str()); + std::vector arguments; + + size_t index = 0; + while (index != std::string::npos) { + index = command.find_first_of(" "); + arguments.push_back(command.substr(0, index)); + command = command.substr(index + 1); + } + + return System(arguments); } -void System::operator()(std::string_view command) +System System::operator()(std::string_view command) { - operator()(command.data()); + return operator()(std::string { command }); } -void System::operator()(const std::vector& arguments) +System System::operator()(const std::vector& arguments) { - std::vector nonConstArguments(arguments.size() + 1, 0); + std::vector stringArguments(arguments.size(), ""); for (size_t i = 0; i < arguments.size(); ++i) { - nonConstArguments[i] = const_cast(arguments[i]); + stringArguments[i] = arguments[i]; } - operator()(nonConstArguments); + + return System(stringArguments); } -void System::operator()(const std::vector& arguments) +System System::operator()(const std::vector& arguments) { - std::vector nonConstArguments(arguments.size() + 1, 0); + return System(arguments); +} + +System System::operator()(const std::vector& arguments) +{ + std::vector stringArguments(arguments.size(), ""); for (size_t i = 0; i < arguments.size(); ++i) { - nonConstArguments[i] = const_cast(arguments[i].c_str()); + stringArguments[i] = arguments[i]; } - operator()(nonConstArguments); + return System(stringArguments); +} + +System System::operator|(System rhs) +{ + rhs.exec(exec().output()); + return rhs; } -void System::operator()(const std::vector& arguments) +void System::print(const std::vector& arguments) { - std::vector nonConstArguments(arguments.size() + 1, 0); + if (!arguments.size()) { + return; + } + + printf("----------\n"); + printf("size: %zu\n", arguments.size()); + printf("command: "); for (size_t i = 0; i < arguments.size(); ++i) { - nonConstArguments[i] = const_cast(arguments[i].data()); + printf("%s ", arguments.at(i).c_str()); } - operator()(nonConstArguments); + printf("\n"); + printf("----------\n"); } // ----------------------------------------- -void System::operator()(const std::vector& arguments) +System System::exec(std::string input) { + int stdinFd[2]; int stdoutFd[2]; int stderrFd[2]; + if (pipe(stdinFd) < 0) { + perror("\033[31;1mError\033[0m"); + } if (pipe(stdoutFd) < 0) { perror("\033[31;1mError\033[0m"); } @@ -93,6 +124,10 @@ void System::operator()(const std::vector& arguments) break; // Child case 0: { + close(stdinFd[WriteFileDescriptor]); + dup2(stdinFd[ReadFileDescriptor], fileno(stdin)); + close(stdinFd[ReadFileDescriptor]); + close(stdoutFd[ReadFileDescriptor]); dup2(stdoutFd[WriteFileDescriptor], fileno(stdout)); close(stdoutFd[WriteFileDescriptor]); @@ -101,7 +136,12 @@ void System::operator()(const std::vector& arguments) dup2(stderrFd[WriteFileDescriptor], fileno(stderr)); close(stderrFd[WriteFileDescriptor]); - execvp(arguments[0], &arguments[0]); + std::vector charArguments(m_arguments.size() + 1, 0); + for (size_t i = 0; i < m_arguments.size(); ++i) { + charArguments[i] = const_cast(m_arguments[i].c_str()); + } + + execvp(charArguments[0], &charArguments[0]); exit(0); } // Parent @@ -109,6 +149,12 @@ void System::operator()(const std::vector& arguments) break; } + close(stdinFd[ReadFileDescriptor]); + if (!input.empty()) { + write(stdinFd[WriteFileDescriptor], input.c_str(), input.size()); + } + close(stdinFd[WriteFileDescriptor]); + readFromFileDescriptor(stdoutFd, m_output); readFromFileDescriptor(stderrFd, m_error); @@ -117,11 +163,14 @@ void System::operator()(const std::vector& arguments) result = waitpid(pid, &m_status, 0); } while (result == -1 && errno == EINTR); m_status = WEXITSTATUS(m_status); + + return *this; } void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output) { close(fileDescriptor[WriteFileDescriptor]); + output.clear(); constexpr int bufferSize = 4096; char buffer[bufferSize]; @@ -141,19 +190,4 @@ void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output) close(fileDescriptor[ReadFileDescriptor]); } -size_t System::split(char* split, const char* delimiters, SplitCallback callback) -{ - size_t index = 0; - char* pointer = strtok(split, delimiters); - while (pointer != nullptr) { - if (callback) { - callback(index, pointer); - } - index++; - pointer = strtok(nullptr, delimiters); - } - - return index; -} - } // namespace Util diff --git a/src/util/system.h b/src/util/system.h index 362a4f0..b57990a 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -13,7 +13,8 @@ using SplitCallback = std::function; class System { public: - System() {} + System(); + System(std::vector arguments); virtual ~System() {} enum FileDescriptor { @@ -21,22 +22,28 @@ public: WriteFileDescriptor, }; - void operator()(const char* command); - void operator()(std::string command); - void operator()(std::string_view command); - void operator()(const std::vector& arguments); - void operator()(const std::vector& arguments); - void operator()(const std::vector& arguments); + System operator()(); + System operator()(const char* command); + System operator()(std::string command); + System operator()(std::string_view command); + System operator()(const std::vector& arguments); + System operator()(const std::vector& arguments); + System operator()(const std::vector& arguments); + System operator|(System rhs); + + void print(const std::vector& arguments); + + const std::vector& arguments() const { return m_arguments; } std::string output() const { return m_output; } std::string error() const { return m_error; } int status() const { return m_status; } private: - void operator()(const std::vector& arguments); + System exec(std::string input = ""); void readFromFileDescriptor(int fileDescriptor[2], std::string& output); - size_t split(char* split, const char* delimiters, SplitCallback callback = {}); + std::vector m_arguments; std::string m_output; std::string m_error; int m_status { 0 };