execute files with #!
This commit is contained in:
+10
-21
@@ -15,7 +15,7 @@ struct Proc
|
|||||||
struct DeadProc: public Proc
|
struct DeadProc: public Proc
|
||||||
{
|
{
|
||||||
DeadProc(Proc, int status); /* status as returned by waitpid */
|
DeadProc(Proc, int status); /* status as returned by waitpid */
|
||||||
bool normal_exit;
|
bool normal_exit; /* todo: std::optional? */
|
||||||
U8 exit_status; /* only use if normal_exit */
|
U8 exit_status; /* only use if normal_exit */
|
||||||
|
|
||||||
/* A returned process evaluates to true if it exited normaly and
|
/* A returned process evaluates to true if it exited normaly and
|
||||||
@@ -29,28 +29,17 @@ DeadProc wait(Proc);
|
|||||||
/* Check if the Proc has exited and return it's DeadProc if it has */
|
/* Check if the Proc has exited and return it's DeadProc if it has */
|
||||||
std::optional<DeadProc> check_exited(Proc);
|
std::optional<DeadProc> check_exited(Proc);
|
||||||
|
|
||||||
enum Redirect: U32
|
enum { PIPE = -1 };
|
||||||
{
|
|
||||||
NOTHING =0,
|
|
||||||
INPUT = 1 << 0,
|
|
||||||
OUTPUT = 1 << 1,
|
|
||||||
ERR = 1 << 2 /* todo */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/* Create a proccess
|
||||||
/* For all funcions argv is an array of command parameters
|
* argv is an array of command parameters
|
||||||
* argv[0] is the command itself, argv needs to end with nullptr
|
* argv[0] is the command itself, argv needs to end with nullptr
|
||||||
* non of the functions wait for the proccess to finish */
|
* we don't wait for the proccess to finish
|
||||||
|
*
|
||||||
/* Create a proccess and redirect anyting flaged to a new pipe
|
* Can take FDs as arguments which will be used instead of std
|
||||||
flags - INPUT, OUTPUT, ERR
|
* If PIPE is given for any FD, a pipe is created and input/output/error is redirected there
|
||||||
return pipe file descriptors*/
|
* The pipe can then be read (out, err) or written to (in)
|
||||||
Proc createRedirProcess(const char* const argv[], U32 flags);
|
*/
|
||||||
|
|
||||||
/* Capture ouput to a pipe, can take alternative input and err FDs */
|
|
||||||
Proc createCapProcess(const char* const argv[], fd_t in=0, fd_t err=2);
|
|
||||||
|
|
||||||
/* Can take FDs as arguments which will be used instead of std */
|
|
||||||
Proc createProcess(const char* const argv[], fd_t in=0, fd_t out=1, fd_t err=2);
|
Proc createProcess(const char* const argv[], fd_t in=0, fd_t out=1, fd_t err=2);
|
||||||
|
|
||||||
/* execvp the command or exit */
|
/* execvp the command or exit */
|
||||||
|
|||||||
+47
-68
@@ -53,12 +53,39 @@ inline std::optional<DeadProc> check_exited(Proc p)
|
|||||||
|
|
||||||
namespace _cppipe
|
namespace _cppipe
|
||||||
{
|
{
|
||||||
/* create a process taking input from pipe childIn */
|
/* Create a proccess */
|
||||||
inline Proc createProc(const char* const argv[], const fd_t childIn[2])
|
inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||||
|
{
|
||||||
|
Proc proc;
|
||||||
|
proc.in = in;
|
||||||
|
proc.out = out;
|
||||||
|
proc.err = err;
|
||||||
|
|
||||||
|
proc.pid = fork();
|
||||||
|
if(proc.pid == 0) /* child */
|
||||||
|
{
|
||||||
|
if(in != STDIN_FILENO)
|
||||||
|
dup2(in, STDIN_FILENO);
|
||||||
|
|
||||||
|
if(out != STDOUT_FILENO)
|
||||||
|
dup2(out, STDOUT_FILENO);
|
||||||
|
|
||||||
|
if(err != STDERR_FILENO)
|
||||||
|
dup2(err, STDERR_FILENO);
|
||||||
|
|
||||||
|
exec_or_die(argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a process taking input from pipe childIn */
|
||||||
|
inline Proc createInRedirected(const char* const argv[], const fd_t childIn[2])
|
||||||
{
|
{
|
||||||
Proc childproc;
|
Proc childproc;
|
||||||
childproc.in = childIn[1];
|
childproc.in = childIn[1];
|
||||||
childproc.out = STDOUT_FILENO;
|
childproc.out = STDOUT_FILENO;
|
||||||
|
childproc.err = STDERR_FILENO;
|
||||||
|
|
||||||
childproc.pid = fork();
|
childproc.pid = fork();
|
||||||
if(childproc.pid == 0) /* child */
|
if(childproc.pid == 0) /* child */
|
||||||
@@ -72,34 +99,8 @@ namespace _cppipe
|
|||||||
return childproc;
|
return childproc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a process and redirect it's output to a pipe */
|
/* Like createInRedirected but redirect output to a new pipe */
|
||||||
inline Proc createRedirProc(const char* const argv[])
|
inline Proc createInOutRedirected(const char* const argv[], const fd_t childIn[2])
|
||||||
{
|
|
||||||
fd_t childOut[2];
|
|
||||||
pipe(childOut);
|
|
||||||
|
|
||||||
Proc childproc;
|
|
||||||
childproc.in = STDIN_FILENO;
|
|
||||||
childproc.out = childOut[0];
|
|
||||||
|
|
||||||
childproc.pid = fork();
|
|
||||||
/* close(STDIN_FILENO); flush?*/
|
|
||||||
if(childproc.pid != 0) /* parent */
|
|
||||||
{
|
|
||||||
close(childOut[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dup2(childOut[1], STDOUT_FILENO);
|
|
||||||
|
|
||||||
exec_or_die(argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
return childproc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a process redirecting both in and out */
|
|
||||||
inline Proc createRedirProc(const char* const argv[], const fd_t childIn[2])
|
|
||||||
{
|
{
|
||||||
fd_t childOut[2]; /* todo: add error #include "processTypes.hpp"*/
|
fd_t childOut[2]; /* todo: add error #include "processTypes.hpp"*/
|
||||||
pipe(childOut);
|
pipe(childOut);
|
||||||
@@ -107,9 +108,9 @@ namespace _cppipe
|
|||||||
Proc childproc;
|
Proc childproc;
|
||||||
childproc.in = childIn[1];
|
childproc.in = childIn[1];
|
||||||
childproc.out = childOut[0];
|
childproc.out = childOut[0];
|
||||||
|
childproc.err = STDERR_FILENO;
|
||||||
|
|
||||||
childproc.pid = fork();
|
childproc.pid = fork();
|
||||||
/* close(STDIN_FILENO); flush?*/
|
|
||||||
if(childproc.pid != 0) /* parent */
|
if(childproc.pid != 0) /* parent */
|
||||||
{
|
{
|
||||||
close(childOut[1]);
|
close(childOut[1]);
|
||||||
@@ -126,28 +127,6 @@ namespace _cppipe
|
|||||||
|
|
||||||
return childproc;
|
return childproc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inline Proc createRedirProcess(const char* const argv[], U32 flags) /* todo rename */
|
|
||||||
{
|
|
||||||
fd_t childIn[2];
|
|
||||||
Proc proc;
|
|
||||||
|
|
||||||
if(flags & INPUT)
|
|
||||||
{
|
|
||||||
pipe(childIn);
|
|
||||||
if(flags & OUTPUT)
|
|
||||||
proc = _cppipe::createRedirProc(argv, childIn);
|
|
||||||
else
|
|
||||||
proc = _cppipe::createProc(argv, childIn);
|
|
||||||
}
|
|
||||||
else if(flags & OUTPUT)
|
|
||||||
proc = _cppipe::createRedirProc(argv);
|
|
||||||
else
|
|
||||||
proc = createProcess(argv);
|
|
||||||
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
|
inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
|
||||||
{
|
{
|
||||||
@@ -172,35 +151,35 @@ inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
|
|||||||
|
|
||||||
exec_or_die(argv);
|
exec_or_die(argv);
|
||||||
}
|
}
|
||||||
else
|
else /* parent */
|
||||||
{
|
{
|
||||||
close(childOut[1]);
|
close(childOut[1]); /* close write side */
|
||||||
}
|
}
|
||||||
|
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||||
{
|
{
|
||||||
Proc proc;
|
Proc proc;
|
||||||
proc.in = in;
|
|
||||||
proc.out = out;
|
|
||||||
proc.err = err;
|
|
||||||
|
|
||||||
proc.pid = fork();
|
if(in == PIPE)
|
||||||
if(proc.pid == 0) /* child */
|
|
||||||
{
|
{
|
||||||
if(in != STDIN_FILENO)
|
fd_t childIn[2];
|
||||||
dup2(in, STDIN_FILENO);
|
pipe(childIn);
|
||||||
|
|
||||||
if(out != STDOUT_FILENO)
|
if(out == PIPE)
|
||||||
dup2(out, STDOUT_FILENO);
|
proc = _cppipe::createInOutRedirected(argv, childIn);
|
||||||
|
else
|
||||||
|
proc = _cppipe::createInRedirected(argv, childIn);
|
||||||
|
|
||||||
if(err != STDERR_FILENO)
|
close(childIn[0]); // parent closes read side
|
||||||
dup2(err, STDERR_FILENO);
|
|
||||||
|
|
||||||
exec_or_die(argv);
|
|
||||||
}
|
}
|
||||||
|
else if(out == PIPE)
|
||||||
|
proc = _cppipe::createCapProcess(argv, in, err);
|
||||||
|
else /* todo: err == PIPE */
|
||||||
|
proc = _cppipe::create(argv, in, out, err);
|
||||||
|
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -67,6 +67,7 @@ private:
|
|||||||
|
|
||||||
friend Proc detach(const PendingCmd&);
|
friend Proc detach(const PendingCmd&);
|
||||||
friend Proc detachRedirOut(const PendingCmd&);
|
friend Proc detachRedirOut(const PendingCmd&);
|
||||||
|
friend Proc detachRedirInOut(const PendingCmd&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -81,9 +82,10 @@ DeadProc run(const PendingCmd&);
|
|||||||
becomes: cmd.detach() */
|
becomes: cmd.detach() */
|
||||||
Proc detach(const PendingCmd&);
|
Proc detach(const PendingCmd&);
|
||||||
|
|
||||||
/* Detach but redirect output to a pipe */
|
/* Detach but redirect output to a new pipe */
|
||||||
Proc detachRedirOut(const PendingCmd&);
|
Proc detachRedirOut(const PendingCmd&);
|
||||||
|
/* Also rediredct input */
|
||||||
|
Proc detachRedirInOut(const PendingCmd&);
|
||||||
|
|
||||||
/* Run commands in sequence
|
/* Run commands in sequence
|
||||||
shell:
|
shell:
|
||||||
|
|||||||
+16
-22
@@ -31,15 +31,6 @@ namespace _cppipe
|
|||||||
inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
|
inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
|
||||||
{
|
{
|
||||||
Proc p = createProcess(argv.data(), in, out, err);
|
Proc p = createProcess(argv.data(), in, out, err);
|
||||||
|
|
||||||
// Close files if such were used
|
|
||||||
// if(in > 2)
|
|
||||||
// close(in);
|
|
||||||
// if(out > 2)
|
|
||||||
// close(out);
|
|
||||||
// if(err > 2)
|
|
||||||
// close(err);
|
|
||||||
|
|
||||||
return wait(p);
|
return wait(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,13 +70,7 @@ inline PendingCmd::PendingCmd(const Cmd& origin, fd_t in, fd_t out, fd_t err)
|
|||||||
inline PendingCmd::~PendingCmd()
|
inline PendingCmd::~PendingCmd()
|
||||||
{
|
{
|
||||||
if(!execed_)
|
if(!execed_)
|
||||||
operator()();
|
cmd(in, out, err);
|
||||||
/* if(in != 0) */
|
|
||||||
/* close(in); */
|
|
||||||
/* if(out != 1) */
|
|
||||||
/* close(out); */
|
|
||||||
/* if(err != 2) */
|
|
||||||
/* close(err); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DeadProc PendingCmd::operator()()
|
inline DeadProc PendingCmd::operator()()
|
||||||
@@ -155,21 +140,30 @@ inline DeadProc run(const PendingCmd& c)
|
|||||||
inline Proc detach(const PendingCmd& ccmd)
|
inline Proc detach(const PendingCmd& ccmd)
|
||||||
{
|
{
|
||||||
auto& c = const_cast<PendingCmd&>(ccmd);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
|
|
||||||
assert(!c.execed_ && "Executed command twice");
|
assert(!c.execed_ && "Executed command twice");
|
||||||
|
|
||||||
c.execed_ = true;
|
c.execed_ = true;
|
||||||
return createProcess(c.cmd.argv.data(), c.in, c.out, c.err);
|
return createProcess(c.cmd.argv.data(), c.in, c.out, c.err);
|
||||||
}
|
}
|
||||||
|
|
||||||
Proc detachRedirOut(const PendingCmd& ccmd)
|
inline Proc detachRedirOut(const PendingCmd& ccmd)
|
||||||
{
|
{
|
||||||
auto& c = const_cast<PendingCmd&>(ccmd);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
|
assert(c.out==1 && "Capturing redirected output");
|
||||||
|
|
||||||
assert(!c.execed_ && "Executed command twice");
|
c.out = PIPE;
|
||||||
assert(c.out==1 && "Capturing redirected proccess");
|
|
||||||
|
|
||||||
c.execed_ = true;
|
return detach(c);
|
||||||
return createCapProcess(c.cmd.argv.data(), c.in, c.err);
|
}
|
||||||
|
|
||||||
|
inline Proc detachRedirInOut(const PendingCmd& ccmd)
|
||||||
|
{
|
||||||
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
|
assert(c.in==0 && "Rediredcting redirected input");
|
||||||
|
|
||||||
|
c.in = PIPE;
|
||||||
|
|
||||||
|
return detachRedirOut(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd operator,(const PendingCmd& left, const Cmd& right)
|
inline PendingCmd operator,(const PendingCmd& left, const Cmd& right)
|
||||||
|
|||||||
+17
-10
@@ -178,12 +178,6 @@ fs::path find_path_to_src(string_view src_file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search in ~/cppipe
|
|
||||||
if(fs::path p = HOME / "cppipe" / src_file; fs::exists(p)) // todo: what if ~/cppipe/../... matches
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Couln't find the src
|
// Couln't find the src
|
||||||
cerr << "File: " << src_file << " doesn't exist\n";
|
cerr << "File: " << src_file << " doesn't exist\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -236,11 +230,11 @@ optional<fs::path> preprocess_and_compare()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
preprocess.append_args({ CXXFLAGS });
|
preprocess.append_args({ CXXFLAGS });
|
||||||
preprocess += "-xc++"; // treat the file as a cpp
|
preprocess += "-xc++"; // treat the file as a .cpp
|
||||||
}
|
}
|
||||||
|
|
||||||
// File to be preprocessed
|
// Read source from stdin
|
||||||
preprocess += src_file.c_str();
|
preprocess += "-";
|
||||||
|
|
||||||
|
|
||||||
if(!debug)
|
if(!debug)
|
||||||
@@ -250,8 +244,21 @@ optional<fs::path> preprocess_and_compare()
|
|||||||
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem()
|
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem()
|
||||||
+= (src_type == SrcType::C ? ".i" : ".ii");
|
+= (src_type == SrcType::C ? ".i" : ".ii");
|
||||||
|
|
||||||
|
Proc preprocessing = detachRedirInOut(preprocess);
|
||||||
|
|
||||||
|
// File to preprocess
|
||||||
|
MappedFile src = mapfile_for_writing(src_file);
|
||||||
|
|
||||||
|
// If it begins with #! skip the first line
|
||||||
|
const char* p = src.data;
|
||||||
|
if(src.len > 1 && p[0] == '#' && p[1] == '!')
|
||||||
|
while(*p != '\n')
|
||||||
|
++p;
|
||||||
|
|
||||||
|
write(preprocessing.in, p, src.len - (p - src.data));
|
||||||
|
close(preprocessing.in);
|
||||||
|
|
||||||
// Result of preprocessing as string
|
// Result of preprocessing as string
|
||||||
Proc preprocessing = detachRedirOut(preprocess);
|
|
||||||
string new_pp = read_to_end(preprocessing.out);
|
string new_pp = read_to_end(preprocessing.out);
|
||||||
|
|
||||||
if( !wait(preprocessing) ) // preprocessing failed
|
if( !wait(preprocessing) ) // preprocessing failed
|
||||||
|
|||||||
Reference in New Issue
Block a user