diff --git a/src/commands.hpp b/src/commands.hpp index b2599ad..18bb92a 100644 --- a/src/commands.hpp +++ b/src/commands.hpp @@ -7,9 +7,10 @@ /* All CONST references are used and cast away to allow for taking both l and r values without using templates or making copies - implicitly convert to it but not to const char* and we want the - implicit conversion for quick scripting - arg pointers are kept and used not copied */ + char* arg pointers are kept and used NOT COPIED + + Anything that takes a PendingCmd takes a Cmd as well +*/ /* A shell command */ class Cmd @@ -28,9 +29,6 @@ public: to redirect err to out by giving err=1 like in shell */ DeadProc operator()(fd_t in=0, fd_t out=1, fd_t err=2) const; - /* Run the command, don't wait to return like shell's & */ - Proc detach(fd_t in=0, fd_t out=1, fd_t err=2) const; - /* Append arguments */ void append_args(std::initializer_list); /* Append an argument and return the new command */ @@ -52,37 +50,40 @@ public: /* Execute the command on destruction */ ~PendingCmd(); - /* No copy we use unnamed return value optimization to return PendingCmd without destruction */ + /* No copy - we use unnamed return value optimization to return PendingCmd without destruction */ PendingCmd(const PendingCmd&) = delete; PendingCmd& operator=(const PendingCmd&) = delete; /* Run the command */ DeadProc operator()(); - /* Run the command async - shell: cmd & - becomes: cmd.detach() */ - Proc detach(); - /* Detach but redirect output to a pipe */ - Proc detachRedirOut(); - /* Prevent a pending command from being executed on destruction */ void cancel(); - Cmd cmd; + const Cmd& cmd; fd_t in, out, err; private: bool execed_; + + friend Proc detach(const PendingCmd&); + friend Proc detachRedirOut(const PendingCmd&); }; -/* Anything that takes PendingCmd can take Cmd aswell */ - /* Like shell's exec */ void exec(const Cmd&); /* todo: take Pending? */ /* Execute the command, like the operator() */ -DeadProc run(const Cmd&); +DeadProc run(const PendingCmd&); + +/* Run the command async + shell: cmd & + becomes: cmd.detach() */ +Proc detach(const PendingCmd&); + +/* Detach but redirect output to a pipe */ +Proc detachRedirOut(const PendingCmd&); + /* Run commands in sequence shell: @@ -164,6 +165,10 @@ PendingCmd operator&(const PendingCmd&, const Cmd&); */ std::string $(const PendingCmd&); +/* Read from a file descriptor until it closes + can be used on proccess out/err */ +std::string read_to_end(fd_t); + /* Operator<< for printing */ std::ostream& operator<<(std::ostream&, const Cmd&); diff --git a/src/commands.inl b/src/commands.inl index adbc705..0c399eb 100644 --- a/src/commands.inl +++ b/src/commands.inl @@ -43,11 +43,6 @@ inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const return wait(p); } -inline Proc Cmd::detach(fd_t in, fd_t out, fd_t err) const -{ - return createProcess(argv.data(), in, out, err); -} - inline void Cmd::append_args(std::initializer_list args) { argv.reserve(argv.size() + args.size()); @@ -100,31 +95,30 @@ inline DeadProc PendingCmd::operator()() return cmd(in, out, err); } -inline Proc PendingCmd::detach() -{ - assert(!execed_ && "Executed command twice"); - execed_ = true; - return cmd.detach(in, out, err); -} - -inline Proc PendingCmd::detachRedirOut() -{ - assert(!execed_ && "Executed command twice"); - assert(out==1 && "Capturing redirected proccess"); - - execed_ = true; - return createCapProcess(cmd.argv.data(), in, err); -} - inline void PendingCmd::cancel() { execed_ = true; } -inline std::string $(const PendingCmd& cmd) +inline std::string $(const PendingCmd& c) { - Proc p = const_cast(cmd).detachRedirOut(); + Proc p = detachRedirOut(c); + std::string output = read_to_end(p.out); + + // Remove trailing newlines + int i = output.size() - 1; + while(i > 0 && output[i] == '\n') + --i; + + // erase the newlines + output.erase(i+1, -1); // till the end + + return output; +} + +std::string read_to_end(fd_t fd) +{ // write to the string directly, todo: find a better way std::string output; @@ -134,44 +128,53 @@ inline std::string $(const PendingCmd& cmd) { output.resize(output.size() + PIPE_BUF); // todo: check if we are overallocating - read_count = read(p.out, &output[i], PIPE_BUF); // todo: check errno + read_count = read(fd, &output[i], PIPE_BUF); // todo: check errno if(read_count > 0) i += read_count; } while(read_count > 0); - // p finished? - // Remove trailing newlines - // i is on the past the end element, go back to end - int j = i - 1; - - while(j > 0 && output[j] == '\n') - --j; - - i = j + 1; + close(fd); // erase the extra elements output.erase(i, -1); // till the end - close(p.out); - return output; } -inline void exec(const Cmd& cmd) +inline void exec(const Cmd& c) { - exec_or_die(cmd.argv.data()); + exec_or_die(c.argv.data()); } -inline DeadProc run(const Cmd& cmd) +inline DeadProc run(const PendingCmd& c) { - return cmd(); + return const_cast(c)(); } -inline PendingCmd operator,(const PendingCmd& cleft, const Cmd& right) +inline Proc detach(const PendingCmd& ccmd) { - auto& left = const_cast(cleft); - left(); + auto& c = const_cast(ccmd); + + assert(!c.execed_ && "Executed command twice"); + c.execed_ = true; + return createProcess(c.cmd.argv.data(), c.in, c.out, c.err); +} + +Proc detachRedirOut(const PendingCmd& ccmd) +{ + auto& c = const_cast(ccmd); + + assert(!c.execed_ && "Executed command twice"); + assert(c.out==1 && "Capturing redirected proccess"); + + c.execed_ = true; + return createCapProcess(c.cmd.argv.data(), c.in, c.err); +} + +inline PendingCmd operator,(const PendingCmd& left, const Cmd& right) +{ + run(left); return PendingCmd(right); } @@ -180,10 +183,9 @@ inline PendingCmd operator,(DeadProc, const Cmd& right) return PendingCmd(right); } -inline PendingCmd operator|(const PendingCmd& cleft, const Cmd& right) +inline PendingCmd operator|(const PendingCmd& left, const Cmd& right) { - auto& left = const_cast(cleft); - fd_t leftOut = left.detachRedirOut().out; + fd_t leftOut = detachRedirOut(left).out; return PendingCmd(right, leftOut); } @@ -230,77 +232,77 @@ inline DeadProc operator||(DeadProc p, const Cmd& ccmd) return p; } -inline PendingCmd& operator>(const PendingCmd& cmd, const char* file) +inline PendingCmd& operator>(const PendingCmd& c, const char* file) { fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT); - return cmd > fd; + return c > fd; } inline PendingCmd& operator>(const PendingCmd& ccmd, fd_t fd) { - auto& cmd = const_cast(ccmd); - assert(cmd.out == 1 && "ERROR: Output is already redirected!"); + auto& c = const_cast(ccmd); + assert(c.out == 1 && "ERROR: Output is already redirected!"); - cmd.out = fd; - return cmd; + c.out = fd; + return c; } -inline PendingCmd& operator>>(const PendingCmd& cmd, const char* file) +inline PendingCmd& operator>>(const PendingCmd& c, const char* file) { fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND); - return cmd > fd; + return c > fd; } -inline PendingCmd& operator>>(const PendingCmd& cmd, fd_t fd) +inline PendingCmd& operator>>(const PendingCmd& c, fd_t fd) { - return cmd > fd; + return c > fd; } -inline PendingCmd& operator>=(const PendingCmd& cmd, const char* file) +inline PendingCmd& operator>=(const PendingCmd& c, const char* file) { fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT); - return cmd >= fd; + return c >= fd; } inline PendingCmd& operator>=(const PendingCmd& ccmd, fd_t fd) { - auto& cmd = const_cast(ccmd); - assert(cmd.err == 2 && "ERROR: Error output is already redirected!"); + auto& c = const_cast(ccmd); + assert(c.err == 2 && "ERROR: Error output is already redirected!"); - cmd.err = fd; - return cmd; + c.err = fd; + return c; } -inline PendingCmd& operator>>=(const PendingCmd& cmd, const char* file) +inline PendingCmd& operator>>=(const PendingCmd& c, const char* file) { fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND); - return cmd >= fd; + return c >= fd; } -inline PendingCmd& operator>>=(const PendingCmd& cmd, fd_t fd) +inline PendingCmd& operator>>=(const PendingCmd& c, fd_t fd) { - return cmd >= fd; + return c >= fd; } -inline PendingCmd& operator<(const PendingCmd& cmd, const char* file) +inline PendingCmd& operator<(const PendingCmd& c, const char* file) { fd_t fd = _cppipe::open_or_die(file, O_RDONLY); - return cmd < fd; + return c < fd; } inline PendingCmd& operator<(const PendingCmd& ccmd, fd_t fd) { - auto& cmd = const_cast(ccmd); - assert(cmd.in == 0 && "ERROR: Input is already redirected!"); + auto& c = const_cast(ccmd); + assert(c.in == 0 && "ERROR: Input is already redirected!"); - cmd.in = fd; - return cmd; + c.in = fd; + return c; } -inline PendingCmd operator&(const PendingCmd& cleft, const Cmd& right) +inline PendingCmd operator&(const PendingCmd& left, const Cmd& right) { - const_cast(cleft).detach(); + detach(left); return PendingCmd(right); } -inline std::ostream& operator<<(std::ostream& s, const Cmd& cmd) +inline std::ostream& operator<<(std::ostream& s, const Cmd& c) { - for(size_t i = 0; i < cmd.argv.size() - 1; ++i) - s << '"' << cmd.argv[i] << '"' << ' '; + for(size_t i = 0; i < c.argv.size() - 1; ++i) + s << '"' << c.argv[i] << '"' << ' '; return s; } diff --git a/src/cppipe.cpp b/src/cppipe.cpp index 3786371..99e659f 100644 --- a/src/cppipe.cpp +++ b/src/cppipe.cpp @@ -243,7 +243,11 @@ optional preprocess_and_compare() += (src_type == SrcType::C ? ".i" : ".ii"); // Result of preprocessing as string - string new_pp = $(preprocess); + Proc preprocessing = detachRedirOut(preprocess); + string new_pp = read_to_end(preprocessing.out); + + if( !wait(preprocessing) ) // preprocessing failed + exit(1); if( fs::exists(old_pp_path) ) // todo: clean up if else blocks { diff --git a/todo.txt b/todo.txt index 6218faf..23046e3 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,7 @@ +-q only check timestamps man tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL) + - redirected processes block if their output is not read make sure file descriptors are closed when no longer used cppipe compile options from tft respect CXXFLAGS LDFLAGS