Browse Source

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.
master
Riyyi 3 years ago
parent
commit
2fca315557
  1. 128
      src/util/system.cpp
  2. 25
      src/util/system.h

128
src/util/system.cpp

@ -14,70 +14,101 @@
namespace Util { 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. System::System(std::vector<std::string> arguments)
std::vector<char*> arguments(index + 1, 0); : m_arguments(arguments)
{
}
split(charCommand2, " ", [&arguments](int index, char* pointer) { System System::operator()()
arguments[index] = pointer; {
}); 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<std::string> 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);
} }
void System::operator()(std::string_view command) return System(arguments);
}
System System::operator()(std::string_view command)
{ {
operator()(command.data()); return operator()(std::string { command });
} }
void System::operator()(const std::vector<const char*>& arguments) System System::operator()(const std::vector<const char*>& arguments)
{ {
std::vector<char*> nonConstArguments(arguments.size() + 1, 0); std::vector<std::string> stringArguments(arguments.size(), "");
for (size_t i = 0; i < arguments.size(); ++i) { for (size_t i = 0; i < arguments.size(); ++i) {
nonConstArguments[i] = const_cast<char*>(arguments[i]); stringArguments[i] = arguments[i];
} }
operator()(nonConstArguments);
return System(stringArguments);
} }
void System::operator()(const std::vector<std::string>& arguments) System System::operator()(const std::vector<std::string>& arguments)
{ {
std::vector<char*> nonConstArguments(arguments.size() + 1, 0); return System(arguments);
}
System System::operator()(const std::vector<std::string_view>& arguments)
{
std::vector<std::string> stringArguments(arguments.size(), "");
for (size_t i = 0; i < arguments.size(); ++i) { for (size_t i = 0; i < arguments.size(); ++i) {
nonConstArguments[i] = const_cast<char*>(arguments[i].c_str()); stringArguments[i] = arguments[i];
}
return System(stringArguments);
} }
operator()(nonConstArguments); System System::operator|(System rhs)
{
rhs.exec(exec().output());
return rhs;
} }
void System::operator()(const std::vector<std::string_view>& arguments) void System::print(const std::vector<std::string>& arguments)
{ {
std::vector<char*> 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) { for (size_t i = 0; i < arguments.size(); ++i) {
nonConstArguments[i] = const_cast<char*>(arguments[i].data()); printf("%s ", arguments.at(i).c_str());
} }
operator()(nonConstArguments); printf("\n");
printf("----------\n");
} }
// ----------------------------------------- // -----------------------------------------
void System::operator()(const std::vector<char*>& arguments) System System::exec(std::string input)
{ {
int stdinFd[2];
int stdoutFd[2]; int stdoutFd[2];
int stderrFd[2]; int stderrFd[2];
if (pipe(stdinFd) < 0) {
perror("\033[31;1mError\033[0m");
}
if (pipe(stdoutFd) < 0) { if (pipe(stdoutFd) < 0) {
perror("\033[31;1mError\033[0m"); perror("\033[31;1mError\033[0m");
} }
@ -93,6 +124,10 @@ void System::operator()(const std::vector<char*>& arguments)
break; break;
// Child // Child
case 0: { case 0: {
close(stdinFd[WriteFileDescriptor]);
dup2(stdinFd[ReadFileDescriptor], fileno(stdin));
close(stdinFd[ReadFileDescriptor]);
close(stdoutFd[ReadFileDescriptor]); close(stdoutFd[ReadFileDescriptor]);
dup2(stdoutFd[WriteFileDescriptor], fileno(stdout)); dup2(stdoutFd[WriteFileDescriptor], fileno(stdout));
close(stdoutFd[WriteFileDescriptor]); close(stdoutFd[WriteFileDescriptor]);
@ -101,7 +136,12 @@ void System::operator()(const std::vector<char*>& arguments)
dup2(stderrFd[WriteFileDescriptor], fileno(stderr)); dup2(stderrFd[WriteFileDescriptor], fileno(stderr));
close(stderrFd[WriteFileDescriptor]); close(stderrFd[WriteFileDescriptor]);
execvp(arguments[0], &arguments[0]); std::vector<char*> charArguments(m_arguments.size() + 1, 0);
for (size_t i = 0; i < m_arguments.size(); ++i) {
charArguments[i] = const_cast<char*>(m_arguments[i].c_str());
}
execvp(charArguments[0], &charArguments[0]);
exit(0); exit(0);
} }
// Parent // Parent
@ -109,6 +149,12 @@ void System::operator()(const std::vector<char*>& arguments)
break; break;
} }
close(stdinFd[ReadFileDescriptor]);
if (!input.empty()) {
write(stdinFd[WriteFileDescriptor], input.c_str(), input.size());
}
close(stdinFd[WriteFileDescriptor]);
readFromFileDescriptor(stdoutFd, m_output); readFromFileDescriptor(stdoutFd, m_output);
readFromFileDescriptor(stderrFd, m_error); readFromFileDescriptor(stderrFd, m_error);
@ -117,11 +163,14 @@ void System::operator()(const std::vector<char*>& arguments)
result = waitpid(pid, &m_status, 0); result = waitpid(pid, &m_status, 0);
} while (result == -1 && errno == EINTR); } while (result == -1 && errno == EINTR);
m_status = WEXITSTATUS(m_status); m_status = WEXITSTATUS(m_status);
return *this;
} }
void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output) void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output)
{ {
close(fileDescriptor[WriteFileDescriptor]); close(fileDescriptor[WriteFileDescriptor]);
output.clear();
constexpr int bufferSize = 4096; constexpr int bufferSize = 4096;
char buffer[bufferSize]; char buffer[bufferSize];
@ -141,19 +190,4 @@ void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output)
close(fileDescriptor[ReadFileDescriptor]); 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 } // namespace Util

25
src/util/system.h

@ -13,7 +13,8 @@ using SplitCallback = std::function<void(size_t, char*)>;
class System { class System {
public: public:
System() {} System();
System(std::vector<std::string> arguments);
virtual ~System() {} virtual ~System() {}
enum FileDescriptor { enum FileDescriptor {
@ -21,22 +22,28 @@ public:
WriteFileDescriptor, WriteFileDescriptor,
}; };
void operator()(const char* command); System operator()();
void operator()(std::string command); System operator()(const char* command);
void operator()(std::string_view command); System operator()(std::string command);
void operator()(const std::vector<const char*>& arguments); System operator()(std::string_view command);
void operator()(const std::vector<std::string>& arguments); System operator()(const std::vector<const char*>& arguments);
void operator()(const std::vector<std::string_view>& arguments); System operator()(const std::vector<std::string>& arguments);
System operator()(const std::vector<std::string_view>& arguments);
System operator|(System rhs);
void print(const std::vector<std::string>& arguments);
const std::vector<std::string>& arguments() const { return m_arguments; }
std::string output() const { return m_output; } std::string output() const { return m_output; }
std::string error() const { return m_error; } std::string error() const { return m_error; }
int status() const { return m_status; } int status() const { return m_status; }
private: private:
void operator()(const std::vector<char*>& arguments); System exec(std::string input = "");
void readFromFileDescriptor(int fileDescriptor[2], std::string& output); void readFromFileDescriptor(int fileDescriptor[2], std::string& output);
size_t split(char* split, const char* delimiters, SplitCallback callback = {});
std::vector<std::string> m_arguments;
std::string m_output; std::string m_output;
std::string m_error; std::string m_error;
int m_status { 0 }; int m_status { 0 };

Loading…
Cancel
Save