execute files with #!

This commit is contained in:
vrd
2025-06-06 18:00:38 +03:00
parent 368fc9b100
commit 1dfaa83dbe
5 changed files with 119 additions and 148 deletions
+10 -21
View File
@@ -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 */
+72 -93
View File
@@ -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,81 +127,59 @@ namespace _cppipe
return childproc; return childproc;
} }
}
inline Proc createRedirProcess(const char* const argv[], U32 flags) /* todo rename */ inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
{
fd_t childIn[2];
Proc proc;
if(flags & INPUT)
{ {
pipe(childIn); fd_t childOut[2];
if(flags & OUTPUT) pipe(childOut);
proc = _cppipe::createRedirProc(argv, childIn);
else Proc proc;
proc = _cppipe::createProc(argv, childIn); 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;
} }
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) 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
View File
@@ -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
View File
@@ -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
View File
@@ -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