ソースを参照

pipes: ... in progress ...

master
Christos Houtouridis 5年前
コミット
8671686e80
2個のファイルの変更75行の追加24行の削除
  1. +64
    -19
      src/sequencer.cpp
  2. +11
    -5
      src/sequencer.h

+ 64
- 19
src/sequencer.cpp ファイルの表示

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


+ 11
- 5
src/sequencer.h ファイルの表示

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


読み込み中…
キャンセル
保存