16 void memcpy (T* to,
const T* from,
size_t n) {
17 for (
size_t i=0 ; i<n ; ++i)
30 template <
typename T,
typename Container>
31 void split(
const std::basic_string<T>& str, Container& cont, T delim) {
32 std::basic_stringstream<T> ss(str);
33 std::basic_string<T> token;
34 while (std::getline(ss, token, delim)) {
35 cont.push_back(token);
49 std::string
filter (
const std::string in) {
50 auto first = in.find_first_not_of(
' ');
51 std::string nonws = (first != std::string::npos) ?
52 in.substr(first) :
"";
54 char prev {0}, cur, next {0};
60 for (
auto i = nonws.begin(); i != nonws.end() ; ++i) {
63 if (prev !=
' ') out +=
' ';
65 if (next ==
'|' || next ==
' ') {
66 out += cur; cur = next;
69 out += cur; out +=
' ';
90 if (p !=
nullptr)
delete[] p;
102 memcpy (it, item.c_str(), item.length());
103 it[item.length()] = 0;
106 args_.push_back(
nullptr);
117 if (fd[0] != -1) close(fd[0]);
118 if (fd[1] != -1) close(fd[1]);
127 for (
int i=0 ; i<3 ; ++i)
138 if ((files[std_fd] = openat(AT_FDCWD, fn.c_str(), O_RDWR | O_CREAT, 0640)) == -1)
139 throw Error (
"Child: Can not open file");
140 if ((sstd[std_fd] = dup (std_fd)) == -1)
141 throw Error (
"Child: Can not create file descriptor");
142 if ((dup2(files[std_fd], std_fd)) == -1)
143 throw Error (
"Child: Can not redirect file descriptor");
151 if (sstd[std_fd] != -1) {
152 dup2(sstd[std_fd], std_fd);
153 close (sstd[std_fd]);
156 if (files[std_fd] != -1) {
157 close (files[std_fd]);
168 bool in{
false}, out{
false}, err{
false};
169 bool CanRedirectIn = (!pipe_.from) ?
true :
false;
170 bool CanRedirectOut = (!pipe_.to) ?
true :
false;
172 for (
auto& t: command) {
173 if (t ==
"" || t==
" " || t==
"|")
continue;
175 if (t ==
"&&") logic = LogicOp::AND;
176 else if (t ==
"||") logic = LogicOp::OR;
178 else if (CanRedirectIn && !t.compare(0, 1,
"<"))
179 filenames[
STDIN_] = t.substr(1);
180 else if (CanRedirectOut&& !t.compare(0, 1,
">"))
181 filenames[
STDOUT_] = t.substr(1);
182 else if (CanRedirectOut&& !t.compare(0, 2,
"1>"))
183 filenames[
STDOUT_] = t.substr(2);
184 else if (!t.compare(0, 2,
"2>"))
185 filenames[
STDERR_] = t.substr(2);
187 else if (t ==
"<") in =
true;
188 else if (t ==
"1>" || t ==
">") out =
true;
189 else if (t ==
"2>") err =
true;
201 filenames[
STDERR_] = t; err =
false;
204 arguments.push_back(t);
228 Child& previous = (!first) ? *--it : *it;
231 redirect_std_if (filenames[
STDIN_], STDIN_);
232 redirect_std_if (filenames[
STDOUT_], STDOUT_);
233 redirect_std_if (filenames[
STDERR_], STDERR_);
237 if((::pipe (pipe_.fd)) == -1)
238 throw Error(
"Child: Can not create pipe");
242 throw Error(
"Child: Can not create child process");
250 if ((dup2(pipe_.fd[1], STDOUT_)) == -1)
251 throw Error(
"Child pipe[to]: Can not redirect through pipe");
253 else if (!first && pipe_.from) {
254 close (previous.
pipe().fd[1]);
255 if ((dup2(previous.
pipe().fd[0], STDIN_)) == -1)
256 throw Error(
"Child pipe[from]: Can not redirect through pipe");
259 execvp(arguments.front(), arguments.data());
261 std::cout <<
"Can not invoke: " << arguments.front() << std::endl;
262 throw Error(
"Child: Can not run child process");
266 if (pipe_.to) close (pipe_.fd[1]);
267 else if (!first && pipe_.from)
268 close (previous.
pipe().fd[0]);
271 waitpid(pid, &exit_status, 0);
272 restore_std_if (STDIN_);
273 restore_std_if (STDOUT_);
274 restore_std_if (STDERR_);
277 if ( exit_status && logic == LogicOp::AND) stop =
true;
278 if (!exit_status && logic == LogicOp::OR) stop =
true;
300 std::vector<std::string> chains;
301 std::vector<std::string> tokens;
304 split (input, chains,
';');
305 for (
auto& chain : chains) {
308 split (chain, tokens,
' ');
310 seq_.emplace_back(std::vector<Child>{});
313 for (
auto& t: tokens) {
314 command.push_back(t);
315 if (is_seperator(t)) {
317 seq_.back().emplace_back(command);
321 seq_.back().back().pipe().from = from;
326 seq_.back().back().pipe().to =
true;
331 seq_.back().emplace_back(command);
333 seq_.back().back().pipe().from = from;
345 for (
auto& chain : seq_) {
347 for (
auto it = chain.begin() ; it != chain.end(); ++it) {
349 Child& command = *it;
std::string filter(const std::string in)
void restore_std_if(fd_t std_fd)
bool execute(std::vector< Child >::iterator it, bool first)
Execute the child in separate process.
Sequencer & parse(const std::string &input)
constexpr fd_t STDERR_
Constant for stderr file descriptor.
~Pipe()
Destructor to free up all the resources.
std::vector< vtype > args_
underling data for the execvp() arguments
std::vector< std::string > command_t
A command type.
~Child()
Destructor to free up all the resources.
std::runtime_error Error
An error type.
Pipe & pipe()
A pipe_ getter.
void memcpy(T *to, const T *from, size_t n)
A type-safe memcpy.
typename std::string::value_type type
Basic data type (aka char)
A basic sequence interpreter for snel.
int fd_t
file descriptor type
void split(const std::basic_string< T > &str, Container &cont, T delim)
void redirect_std_if(std::string fn, fd_t std_fd)
Tool to redirect std.
ArgList & push_back(const std::string &item)
A vector::push_back wrapper.
Child & make_arguments()
A per child parser before execution.
constexpr fd_t STDIN_
Constant for stdin file descriptor.
constexpr fd_t STDOUT_
Constant for stdout file descriptor.