detachRedirOut for Cmd

This commit is contained in:
vrd
2025-06-06 18:00:38 +03:00
parent 010b8bc699
commit 0d330bd3da
4 changed files with 108 additions and 95 deletions
+23 -18
View File
@@ -7,9 +7,10 @@
/* All CONST references are used and cast away to allow for taking /* All CONST references are used and cast away to allow for taking
both l and r values without using templates or making copies both l and r values without using templates or making copies
implicitly convert to it but not to const char* and we want the char* arg pointers are kept and used NOT COPIED
implicit conversion for quick scripting
arg pointers are kept and used not copied */ Anything that takes a PendingCmd takes a Cmd as well
*/
/* A shell command */ /* A shell command */
class Cmd class Cmd
@@ -28,9 +29,6 @@ public:
to redirect err to out by giving err=1 like in shell */ 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; 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 */ /* Append arguments */
void append_args(std::initializer_list<const char*>); void append_args(std::initializer_list<const char*>);
/* Append an argument and return the new command */ /* Append an argument and return the new command */
@@ -52,37 +50,40 @@ public:
/* Execute the command on destruction */ /* Execute the command on destruction */
~PendingCmd(); ~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(const PendingCmd&) = delete;
PendingCmd& operator=(const PendingCmd&) = delete; PendingCmd& operator=(const PendingCmd&) = delete;
/* Run the command */ /* Run the command */
DeadProc operator()(); 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 */ /* Prevent a pending command from being executed on destruction */
void cancel(); void cancel();
Cmd cmd; const Cmd& cmd;
fd_t in, out, err; fd_t in, out, err;
private: private:
bool execed_; bool execed_;
friend Proc detach(const PendingCmd&);
friend Proc detachRedirOut(const PendingCmd&);
}; };
/* Anything that takes PendingCmd can take Cmd aswell */
/* Like shell's exec */ /* Like shell's exec */
void exec(const Cmd&); /* todo: take Pending? */ void exec(const Cmd&); /* todo: take Pending? */
/* Execute the command, like the operator() */ /* 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 /* Run commands in sequence
shell: shell:
@@ -164,6 +165,10 @@ PendingCmd operator&(const PendingCmd&, const Cmd&);
*/ */
std::string $(const PendingCmd&); 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 */ /* Operator<< for printing */
std::ostream& operator<<(std::ostream&, const Cmd&); std::ostream& operator<<(std::ostream&, const Cmd&);
+78 -76
View File
@@ -43,11 +43,6 @@ inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
return wait(p); 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<const char*> args) inline void Cmd::append_args(std::initializer_list<const char*> args)
{ {
argv.reserve(argv.size() + args.size()); argv.reserve(argv.size() + args.size());
@@ -100,31 +95,30 @@ inline DeadProc PendingCmd::operator()()
return cmd(in, out, err); 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() inline void PendingCmd::cancel()
{ {
execed_ = true; execed_ = true;
} }
inline std::string $(const PendingCmd& cmd) inline std::string $(const PendingCmd& c)
{ {
Proc p = const_cast<PendingCmd&>(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 // write to the string directly, todo: find a better way
std::string output; 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 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) if(read_count > 0)
i += read_count; i += read_count;
} }
while(read_count > 0); while(read_count > 0);
// p finished?
// Remove trailing newlines close(fd);
// 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;
// erase the extra elements // erase the extra elements
output.erase(i, -1); // till the end output.erase(i, -1); // till the end
close(p.out);
return output; 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<PendingCmd&>(c)();
} }
inline PendingCmd operator,(const PendingCmd& cleft, const Cmd& right) inline Proc detach(const PendingCmd& ccmd)
{ {
auto& left = const_cast<PendingCmd&>(cleft); auto& c = const_cast<PendingCmd&>(ccmd);
left();
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<PendingCmd&>(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); return PendingCmd(right);
} }
@@ -180,10 +183,9 @@ inline PendingCmd operator,(DeadProc, const Cmd& right)
return PendingCmd(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<PendingCmd&>(cleft); fd_t leftOut = detachRedirOut(left).out;
fd_t leftOut = left.detachRedirOut().out;
return PendingCmd(right, leftOut); return PendingCmd(right, leftOut);
} }
@@ -230,77 +232,77 @@ inline DeadProc operator||(DeadProc p, const Cmd& ccmd)
return p; 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); 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) inline PendingCmd& operator>(const PendingCmd& ccmd, fd_t fd)
{ {
auto& cmd = const_cast<PendingCmd&>(ccmd); auto& c = const_cast<PendingCmd&>(ccmd);
assert(cmd.out == 1 && "ERROR: Output is already redirected!"); assert(c.out == 1 && "ERROR: Output is already redirected!");
cmd.out = fd; c.out = fd;
return cmd; 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); 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); 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) inline PendingCmd& operator>=(const PendingCmd& ccmd, fd_t fd)
{ {
auto& cmd = const_cast<PendingCmd&>(ccmd); auto& c = const_cast<PendingCmd&>(ccmd);
assert(cmd.err == 2 && "ERROR: Error output is already redirected!"); assert(c.err == 2 && "ERROR: Error output is already redirected!");
cmd.err = fd; c.err = fd;
return cmd; 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); 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); 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) inline PendingCmd& operator<(const PendingCmd& ccmd, fd_t fd)
{ {
auto& cmd = const_cast<PendingCmd&>(ccmd); auto& c = const_cast<PendingCmd&>(ccmd);
assert(cmd.in == 0 && "ERROR: Input is already redirected!"); assert(c.in == 0 && "ERROR: Input is already redirected!");
cmd.in = fd; c.in = fd;
return cmd; return c;
} }
inline PendingCmd operator&(const PendingCmd& cleft, const Cmd& right) inline PendingCmd operator&(const PendingCmd& left, const Cmd& right)
{ {
const_cast<PendingCmd&>(cleft).detach(); detach(left);
return PendingCmd(right); 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) for(size_t i = 0; i < c.argv.size() - 1; ++i)
s << '"' << cmd.argv[i] << '"' << ' '; s << '"' << c.argv[i] << '"' << ' ';
return s; return s;
} }
+5 -1
View File
@@ -243,7 +243,11 @@ optional<fs::path> preprocess_and_compare()
+= (src_type == SrcType::C ? ".i" : ".ii"); += (src_type == SrcType::C ? ".i" : ".ii");
// Result of preprocessing as string // 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 if( fs::exists(old_pp_path) ) // todo: clean up if else blocks
{ {
+2
View File
@@ -1,5 +1,7 @@
-q only check timestamps
man man
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL) 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 make sure file descriptors are closed when no longer used
cppipe compile options from tft cppipe compile options from tft
respect CXXFLAGS LDFLAGS respect CXXFLAGS LDFLAGS