|
- /*
- * child.cpp
- *
- * Created on: Feb 11, 2019
- * Author: hoo2
- */
-
- #include "sequencer.h"
-
- namespace snel {
-
-
- //! A type-safe memcpy
- template <typename T>
- void memcpy (T* to, const T* from, size_t n) {
- for (size_t i=0 ; i<n ; ++i)
- *to++ = *from++;
- }
-
- /*!
- * Split a string to tokens and store them in a container, using a delimiter
- * character.
- * \note
- * Requires: container with push_back functionality
- * @param str
- * @param cont
- * @param delim
- */
- template <typename T, typename Container>
- void split(const std::basic_string<T>& str, Container& cont, T delim) {
- std::basic_stringstream<T> ss(str);
- std::basic_string<T> token;
- while (std::getline(ss, token, delim)) {
- cont.push_back(token);
- }
- }
-
- /*
- * ========== ArgList ==========
- */
- ArgList::~ArgList() {
- for (vtype p : args_) {
- if (p != nullptr)
- delete[] p;
- }
- }
- ArgList& ArgList::push_back(const std::basic_string<type>& item) {
- vtype it = new type[item.length()+1];
-
- // get data
- memcpy (it, item.c_str(), item.length());
- it[item.length()] = 0;
-
- // update the argument vector
- args_.back() = it;
- args_.push_back(nullptr);
- return *this;
- }
-
- /*
- * ========== Child ==========
- */
- Child::~Child () {
- for (int i=0 ; i<3 ; ++i)
- restore_std_if(i);
- }
-
- void Child::redirect_std_if(std::string fn, fd_t std_fd) {
- if (fn != "") {
- if ((files[std_fd] = openat(AT_FDCWD, fn.c_str(), O_RDWR | O_CREAT, 0640)) == -1)
- throw Error ("Child: Can not open file");
- if ((sstd[std_fd] = dup (std_fd)) == -1) // save STDxxx
- throw Error ("Child: Can not create file descriptor");
- if ((dup2(files[std_fd], std_fd)) == -1) // use input as STDIN_
- throw Error ("Child: Can not redirect file descriptor");
- }
- }
- void Child::restore_std_if(fd_t std_fd) {
- if (sstd[std_fd] != -1) {
- dup2(sstd[std_fd], std_fd);
- close (sstd[std_fd]);
- sstd[std_fd] = -1;
- }
- if (files[std_fd] != -1) {
- close (files[std_fd]);
- files[std_fd] = -1;
- }
-
- }
- Child& Child::make_arguments () {
- bool in{false}, out{false}, err{false};
-
- for (auto& t: command) {
- if (t == "" || t== " ")
- continue;
- if (t == "&&") logic = LogicOp::AND;
- else if (t == "||") logic = LogicOp::OR;
- 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;
- }
- else if (out) {
- filenames[STDOUT_] = t; out = false;
- }
- else if (err) {
- filenames[STDERR_] = t; err = false;
- }
- else
- arguments.push_back(t);
- }
- return *this;
- }
-
- bool Child::execute() {
- bool stop = {false};
-
- redirect_std_if (filenames[STDIN_], STDIN_);
- redirect_std_if (filenames[STDOUT_], STDOUT_);
- redirect_std_if (filenames[STDERR_], STDERR_);
- pid_t pid = fork();
- if (pid < 0) {
- throw Error("Child::execute(): Can not create child process");
- }
- else if (pid == 0) { // child
-
- 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");
- }
- else { // parent
- int exit_status;
- waitpid(pid, &exit_status, 0); // wait child process to finish
- restore_std_if (STDIN_);
- restore_std_if (STDOUT_);
- restore_std_if (STDERR_);
-
- switch (logic) {
- case LogicOp::AND:
- if (exit_status) stop = true;
- break;
- case LogicOp::OR:
- if (!exit_status) stop = true;
- break;
- default: break;
- }
- }
-
- return stop;
- }
-
- /*
- * ======== Sequencer ===========
- */
- Sequencer& Sequencer::parse (const std::string& input) {
- std::vector<std::string> commands;
- std::vector<std::string> tokens;
- Child::command_t command;
-
- split (input, commands, ';'); // split all commands
- for (auto& s : commands) {
- command.clear(); //clear child tokens
- tokens.clear(); // make a new token vector for command
- split (s, tokens, ' ');
-
- seq_.emplace_back(std::vector<Child>{}); // make a new child for command
- // check tokens inside command
- 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();
- }
- }
- seq_.back().emplace_back(command); // construct the child with tokens
- }
-
- return *this;
- }
-
- Sequencer& Sequencer::execute() {
- for (auto& batch : seq_)
- for (auto& command: batch)
- if (command.make_arguments().execute())
- break;
- seq_.clear();
- return *this;
- }
-
- }
|