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 };