execute files with #!
This commit is contained in:
+10
-21
@@ -15,7 +15,7 @@ struct Proc
|
||||
struct DeadProc: public Proc
|
||||
{
|
||||
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 */
|
||||
|
||||
/* 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 */
|
||||
std::optional<DeadProc> check_exited(Proc);
|
||||
|
||||
enum Redirect: U32
|
||||
{
|
||||
NOTHING =0,
|
||||
INPUT = 1 << 0,
|
||||
OUTPUT = 1 << 1,
|
||||
ERR = 1 << 2 /* todo */
|
||||
};
|
||||
enum { PIPE = -1 };
|
||||
|
||||
|
||||
/* For all funcions argv is an array of command parameters
|
||||
/* Create a proccess
|
||||
* argv is an array of command parameters
|
||||
* argv[0] is the command itself, argv needs to end with nullptr
|
||||
* non of the functions wait for the proccess to finish */
|
||||
|
||||
/* Create a proccess and redirect anyting flaged to a new pipe
|
||||
flags - INPUT, OUTPUT, ERR
|
||||
return pipe file descriptors*/
|
||||
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 */
|
||||
* we don't wait for the proccess to finish
|
||||
*
|
||||
* Can take FDs as arguments which will be used instead of std
|
||||
* If PIPE is given for any FD, a pipe is created and input/output/error is redirected there
|
||||
* The pipe can then be read (out, err) or written to (in)
|
||||
*/
|
||||
Proc createProcess(const char* const argv[], fd_t in=0, fd_t out=1, fd_t err=2);
|
||||
|
||||
/* execvp the command or exit */
|
||||
|
||||
+107
-128
@@ -53,135 +53,9 @@ inline std::optional<DeadProc> check_exited(Proc p)
|
||||
|
||||
namespace _cppipe
|
||||
{
|
||||
/* create a process taking input from pipe childIn */
|
||||
inline Proc createProc(const char* const argv[], const fd_t childIn[2])
|
||||
/* Create a proccess */
|
||||
inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||
{
|
||||
Proc childproc;
|
||||
childproc.in = childIn[1];
|
||||
childproc.out = STDOUT_FILENO;
|
||||
|
||||
childproc.pid = fork();
|
||||
if(childproc.pid == 0) /* child */
|
||||
{
|
||||
close(childIn[1]);
|
||||
dup2(childIn[0], STDIN_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
|
||||
return childproc;
|
||||
}
|
||||
|
||||
/* create a process and redirect it's output to a pipe */
|
||||
inline Proc createRedirProc(const char* const argv[])
|
||||
{
|
||||
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"*/
|
||||
pipe(childOut);
|
||||
|
||||
Proc childproc;
|
||||
childproc.in = childIn[1];
|
||||
childproc.out = childOut[0];
|
||||
|
||||
childproc.pid = fork();
|
||||
/* close(STDIN_FILENO); flush?*/
|
||||
if(childproc.pid != 0) /* parent */
|
||||
{
|
||||
close(childOut[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(childIn[1]);
|
||||
dup2(childIn[0], STDIN_FILENO);
|
||||
|
||||
dup2(childOut[1], STDOUT_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fd_t childOut[2];
|
||||
pipe(childOut);
|
||||
|
||||
Proc proc;
|
||||
proc.in = in;
|
||||
proc.out = childOut[0];
|
||||
proc.err = err;
|
||||
|
||||
proc.pid = fork();
|
||||
if(proc.pid == 0) /* child */
|
||||
{
|
||||
if(in != STDIN_FILENO)
|
||||
dup2(in, STDIN_FILENO);
|
||||
|
||||
dup2(childOut[1], STDOUT_FILENO);
|
||||
|
||||
if(err != STDERR_FILENO)
|
||||
dup2(err, STDERR_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(childOut[1]);
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||
{
|
||||
Proc proc;
|
||||
proc.in = in;
|
||||
proc.out = out;
|
||||
@@ -202,6 +76,111 @@ inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||
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;
|
||||
childproc.in = childIn[1];
|
||||
childproc.out = STDOUT_FILENO;
|
||||
childproc.err = STDERR_FILENO;
|
||||
|
||||
childproc.pid = fork();
|
||||
if(childproc.pid == 0) /* child */
|
||||
{
|
||||
close(childIn[1]);
|
||||
dup2(childIn[0], STDIN_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
|
||||
return childproc;
|
||||
}
|
||||
|
||||
/* Like createInRedirected but redirect output to a new pipe */
|
||||
inline Proc createInOutRedirected(const char* const argv[], const fd_t childIn[2])
|
||||
{
|
||||
fd_t childOut[2]; /* todo: add error #include "processTypes.hpp"*/
|
||||
pipe(childOut);
|
||||
|
||||
Proc childproc;
|
||||
childproc.in = childIn[1];
|
||||
childproc.out = childOut[0];
|
||||
childproc.err = STDERR_FILENO;
|
||||
|
||||
childproc.pid = fork();
|
||||
if(childproc.pid != 0) /* parent */
|
||||
{
|
||||
close(childOut[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(childIn[1]);
|
||||
dup2(childIn[0], STDIN_FILENO);
|
||||
|
||||
dup2(childOut[1], STDOUT_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
|
||||
return childproc;
|
||||
}
|
||||
|
||||
inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
|
||||
{
|
||||
fd_t childOut[2];
|
||||
pipe(childOut);
|
||||
|
||||
Proc proc;
|
||||
proc.in = in;
|
||||
proc.out = childOut[0];
|
||||
proc.err = err;
|
||||
|
||||
proc.pid = fork();
|
||||
if(proc.pid == 0) /* child */
|
||||
{
|
||||
if(in != STDIN_FILENO)
|
||||
dup2(in, STDIN_FILENO);
|
||||
|
||||
dup2(childOut[1], STDOUT_FILENO);
|
||||
|
||||
if(err != STDERR_FILENO)
|
||||
dup2(err, STDERR_FILENO);
|
||||
|
||||
exec_or_die(argv);
|
||||
}
|
||||
else /* parent */
|
||||
{
|
||||
close(childOut[1]); /* close write side */
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
}
|
||||
|
||||
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
||||
{
|
||||
Proc proc;
|
||||
|
||||
if(in == PIPE)
|
||||
{
|
||||
fd_t childIn[2];
|
||||
pipe(childIn);
|
||||
|
||||
if(out == PIPE)
|
||||
proc = _cppipe::createInOutRedirected(argv, childIn);
|
||||
else
|
||||
proc = _cppipe::createInRedirected(argv, childIn);
|
||||
|
||||
close(childIn[0]); // parent closes read side
|
||||
}
|
||||
else if(out == PIPE)
|
||||
proc = _cppipe::createCapProcess(argv, in, err);
|
||||
else /* todo: err == PIPE */
|
||||
proc = _cppipe::create(argv, in, out, err);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -67,6 +67,7 @@ private:
|
||||
|
||||
friend Proc detach(const PendingCmd&);
|
||||
friend Proc detachRedirOut(const PendingCmd&);
|
||||
friend Proc detachRedirInOut(const PendingCmd&);
|
||||
};
|
||||
|
||||
|
||||
@@ -81,9 +82,10 @@ DeadProc run(const PendingCmd&);
|
||||
becomes: cmd.detach() */
|
||||
Proc detach(const PendingCmd&);
|
||||
|
||||
/* Detach but redirect output to a pipe */
|
||||
/* Detach but redirect output to a new pipe */
|
||||
Proc detachRedirOut(const PendingCmd&);
|
||||
|
||||
/* Also rediredct input */
|
||||
Proc detachRedirInOut(const PendingCmd&);
|
||||
|
||||
/* Run commands in sequence
|
||||
shell:
|
||||
|
||||
+16
-22
@@ -31,15 +31,6 @@ namespace _cppipe
|
||||
inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -79,13 +70,7 @@ inline PendingCmd::PendingCmd(const Cmd& origin, fd_t in, fd_t out, fd_t err)
|
||||
inline PendingCmd::~PendingCmd()
|
||||
{
|
||||
if(!execed_)
|
||||
operator()();
|
||||
/* if(in != 0) */
|
||||
/* close(in); */
|
||||
/* if(out != 1) */
|
||||
/* close(out); */
|
||||
/* if(err != 2) */
|
||||
/* close(err); */
|
||||
cmd(in, out, err);
|
||||
}
|
||||
|
||||
inline DeadProc PendingCmd::operator()()
|
||||
@@ -155,21 +140,30 @@ inline DeadProc run(const PendingCmd& c)
|
||||
inline Proc detach(const PendingCmd& ccmd)
|
||||
{
|
||||
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)
|
||||
inline Proc detachRedirOut(const PendingCmd& ccmd)
|
||||
{
|
||||
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||
assert(c.out==1 && "Capturing redirected output");
|
||||
|
||||
assert(!c.execed_ && "Executed command twice");
|
||||
assert(c.out==1 && "Capturing redirected proccess");
|
||||
c.out = PIPE;
|
||||
|
||||
c.execed_ = true;
|
||||
return createCapProcess(c.cmd.argv.data(), c.in, c.err);
|
||||
return detach(c);
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
+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
|
||||
cerr << "File: " << src_file << " doesn't exist\n";
|
||||
exit(1);
|
||||
@@ -236,11 +230,11 @@ optional<fs::path> preprocess_and_compare()
|
||||
else
|
||||
{
|
||||
preprocess.append_args({ CXXFLAGS });
|
||||
preprocess += "-xc++"; // treat the file as a cpp
|
||||
preprocess += "-xc++"; // treat the file as a .cpp
|
||||
}
|
||||
|
||||
// File to be preprocessed
|
||||
preprocess += src_file.c_str();
|
||||
// Read source from stdin
|
||||
preprocess += "-";
|
||||
|
||||
|
||||
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()
|
||||
+= (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
|
||||
Proc preprocessing = detachRedirOut(preprocess);
|
||||
string new_pp = read_to_end(preprocessing.out);
|
||||
|
||||
if( !wait(preprocessing) ) // preprocessing failed
|
||||
|
||||
Reference in New Issue
Block a user