pipes: ... in progress ...
This commit is contained in:
parent
e284226897
commit
8671686e80
@ -63,6 +63,9 @@ namespace snel {
|
||||
Child::~Child () {
|
||||
for (int i=0 ; i<3 ; ++i)
|
||||
restore_std_if(i);
|
||||
// close any leaked pipes
|
||||
// if (pipe_.fd[0] != -1) close(pipe_.fd[0]);
|
||||
// if (pipe_.fd[1] != -1) close(pipe_.fd[1]);
|
||||
}
|
||||
|
||||
void Child::redirect_std_if(std::string fn, fd_t std_fd) {
|
||||
@ -89,26 +92,36 @@ namespace snel {
|
||||
}
|
||||
Child& Child::make_arguments () {
|
||||
bool in{false}, out{false}, err{false};
|
||||
bool CanRedirectIn = (pipe_.from) ? true : false;
|
||||
bool CanRedirectOut = (!pipe_.to) ? true : false;
|
||||
|
||||
for (auto& t: command) {
|
||||
if (t == "" || t== " ") continue; // skip crap
|
||||
if (t == "" || t== " " || t=="|") continue; // skip crap
|
||||
|
||||
if (t == "&&") logic = LogicOp::AND;
|
||||
else if (t == "||") logic = LogicOp::OR;
|
||||
// one pass redirection parsing
|
||||
else if (!t.compare(0, 1, "<")) filenames[STDIN_] = t.substr(1);
|
||||
else if (!t.compare(0, 1, ">")) filenames[STDOUT_] = t.substr(1);
|
||||
else if (!t.compare(0, 2, "1>")) filenames[STDOUT_] = t.substr(2);
|
||||
else if (!t.compare(0, 2, "2>")) filenames[STDERR_] = t.substr(2);
|
||||
else if (CanRedirectIn && !t.compare(0, 1, "<"))
|
||||
filenames[STDIN_] = t.substr(1);
|
||||
else if (CanRedirectOut&& !t.compare(0, 1, ">"))
|
||||
filenames[STDOUT_] = t.substr(1);
|
||||
else if (CanRedirectOut&& !t.compare(0, 2, "1>"))
|
||||
filenames[STDOUT_] = t.substr(2);
|
||||
else if (!t.compare(0, 2, "2>"))
|
||||
filenames[STDERR_] = t.substr(2);
|
||||
// two pass redirection parsing (if redirection came in 2 arguments)
|
||||
else if (t == "<") in = true;
|
||||
else if (t == "1>" || t == ">") out = true;
|
||||
else if (t == "2>") err = true;
|
||||
else if (in) {
|
||||
filenames[STDIN_] = t; in = false;
|
||||
if (CanRedirectIn)
|
||||
filenames[STDIN_] = t;
|
||||
in = false;
|
||||
}
|
||||
else if (out) {
|
||||
filenames[STDOUT_] = t; out = false;
|
||||
if (CanRedirectOut)
|
||||
filenames[STDOUT_] = t;
|
||||
out = false;
|
||||
}
|
||||
else if (err) {
|
||||
filenames[STDERR_] = t; err = false;
|
||||
@ -119,24 +132,45 @@ namespace snel {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Child::execute() {
|
||||
bool Child::execute(const Child* previous) {
|
||||
bool stop = {false};
|
||||
|
||||
// Check parent redirection
|
||||
redirect_std_if (filenames[STDIN_], STDIN_);
|
||||
redirect_std_if (filenames[STDOUT_], STDOUT_);
|
||||
redirect_std_if (filenames[STDERR_], STDERR_);
|
||||
|
||||
// Check parent pipe control
|
||||
if (pipe_.to) {
|
||||
if((::pipe (pipe_.fd)) == -1)
|
||||
throw Error("Child: Can not create pipe");
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
throw Error("Child::execute(): Can not create child process");
|
||||
throw Error("Child: Can not create child process");
|
||||
}
|
||||
else if (pid == 0) { // child
|
||||
|
||||
// Some extra pipe checking while we still have our data
|
||||
if (pipe_.to) { // transmitting child
|
||||
close(pipe_.fd[0]); // close the read end
|
||||
if ((dup2(pipe_.fd[1], STDOUT_)) == -1) // redirect output
|
||||
throw Error("Child pipe[to]: Can not redirect through pipe");
|
||||
}
|
||||
else if ((previous!= nullptr) && pipe_.from) { // receiveing child
|
||||
std::cout << "from[0]=" << previous->pipe().fd[0] << " from[1]=" << previous->pipe().fd[1]<< std::endl;
|
||||
close (previous->pipe().fd[1]); // close the write end
|
||||
if ((dup2(previous->pipe().fd[0], STDIN_)) == -1) // redirect input
|
||||
throw Error("Child pipe[from]: Can not redirect through pipe");
|
||||
}
|
||||
execvp(arguments.front(), arguments.data());
|
||||
// error if we got here
|
||||
std::cout << "Can not invoke: " << arguments.front() << std::endl;
|
||||
throw Error("Child::execute(): Can not run child process");
|
||||
throw Error("Child: Can not run child process");
|
||||
}
|
||||
else { // parent
|
||||
if (pipe_.to) close (pipe_.fd[1]);
|
||||
else if (pipe_.from) close (previous->pipe().fd[0]);
|
||||
|
||||
int exit_status;
|
||||
waitpid(pid, &exit_status, 0); // wait child process to finish
|
||||
restore_std_if (STDIN_);
|
||||
@ -171,31 +205,42 @@ namespace snel {
|
||||
tokens.clear(); // make a new token vector for command
|
||||
split (s, tokens, ' ');
|
||||
|
||||
seq_.emplace_back(std::vector<Child>{}); // make a new child for command
|
||||
seq_.emplace_back(std::vector<Child>{}); // make a new child for command
|
||||
// check tokens inside command
|
||||
bool from = false;
|
||||
for (auto& t: tokens) {
|
||||
if (is_pipe(t)) {
|
||||
|
||||
}
|
||||
|
||||
command.push_back(t); // get current token
|
||||
if (is_seperator(t)) {
|
||||
// construct a child with what we have so far and clear command
|
||||
seq_.back().emplace_back(command);
|
||||
command.clear();
|
||||
if (from) {
|
||||
seq_.back().back().pipe().from = from;
|
||||
from = false;
|
||||
}
|
||||
|
||||
if (is_pipe(t)) {
|
||||
seq_.back().back().pipe().to = true;
|
||||
from = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
seq_.back().emplace_back(command); // construct the child with tokens
|
||||
if (from)
|
||||
seq_.back().back().pipe().from = from;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Sequencer& Sequencer::execute() {
|
||||
for (auto& batch : seq_)
|
||||
for (auto& command: batch)
|
||||
if (command.make_arguments().execute())
|
||||
for (auto it = batch.begin() ; it != batch.end(); ++it) {
|
||||
Child& command = *it;
|
||||
Child p = (it != batch.begin()) ? std::prev(it) : Child{};
|
||||
if (command.make_arguments().execute(p))
|
||||
break;
|
||||
|
||||
}
|
||||
seq_.clear();
|
||||
return *this;
|
||||
}
|
||||
|
@ -59,6 +59,12 @@ namespace snel {
|
||||
};
|
||||
|
||||
|
||||
struct Pipe {
|
||||
fd_t fd[2] {-1, -1};
|
||||
bool from {false};
|
||||
bool to {false};
|
||||
};
|
||||
|
||||
class Child {
|
||||
public:
|
||||
enum class LogicOp { NONE=0, OR, AND };
|
||||
@ -69,10 +75,11 @@ namespace snel {
|
||||
~Child ();
|
||||
Child () noexcept = default;
|
||||
Child (const command_t& c) : command{c} { }
|
||||
Child (command_t&& c) : command{std::move(c)} { }
|
||||
Child (command_t&& c) : command{std::move(c)} { }
|
||||
|
||||
Child& make_arguments ();
|
||||
bool execute ();
|
||||
bool execute (const Child* previous);
|
||||
Pipe& pipe() { return pipe_; }
|
||||
private:
|
||||
void redirect_std_if(std::string fn, fd_t std_fd);
|
||||
void restore_std_if(fd_t std_fd);
|
||||
@ -84,10 +91,9 @@ namespace snel {
|
||||
fd_t sstd [3] = {-1, -1, -1};
|
||||
std::string filenames[3] = {"", "", ""};
|
||||
LogicOp logic {LogicOp::NONE};
|
||||
bool pipe {false};
|
||||
Pipe pipe_;
|
||||
};
|
||||
|
||||
|
||||
class Sequencer {
|
||||
public:
|
||||
Sequencer& parse (const std::string& input);
|
||||
@ -95,7 +101,7 @@ namespace snel {
|
||||
|
||||
private:
|
||||
bool is_seperator (std::string& s) {
|
||||
return (s == "&&" || s == "||") ? true : false;
|
||||
return (s == "&&" || s == "||" || s == "|") ? true : false;
|
||||
}
|
||||
bool is_pipe (std::string& s) {
|
||||
return (s == "|") ? true : false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user