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
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<const char*>);
/* 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&);
+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);
}
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)
{
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<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
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<PendingCmd&>(c)();
}
inline PendingCmd operator,(const PendingCmd& cleft, const Cmd& right)
inline Proc detach(const PendingCmd& ccmd)
{
auto& left = const_cast<PendingCmd&>(cleft);
left();
auto& c = const_cast<PendingCmd&>(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<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);
}
@@ -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<PendingCmd&>(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<PendingCmd&>(ccmd);
assert(cmd.out == 1 && "ERROR: Output is already redirected!");
auto& c = const_cast<PendingCmd&>(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<PendingCmd&>(ccmd);
assert(cmd.err == 2 && "ERROR: Error output is already redirected!");
auto& c = const_cast<PendingCmd&>(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<PendingCmd&>(ccmd);
assert(cmd.in == 0 && "ERROR: Input is already redirected!");
auto& c = const_cast<PendingCmd&>(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<PendingCmd&>(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;
}
+5 -1
View File
@@ -243,7 +243,11 @@ optional<fs::path> 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
{
+2
View File
@@ -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