From 1dfaa83dbe7f6d825b2d90c3f44fba3eeb21a64c Mon Sep 17 00:00:00 2001 From: Venelin Date: Thu, 26 Dec 2024 15:31:21 +0200 Subject: [PATCH] execute files with #! --- src/childProcess.hpp | 31 +++----- src/childProcess.inl | 165 +++++++++++++++++++------------------------ src/commands.hpp | 6 +- src/commands.inl | 38 +++++----- src/cppipe.cpp | 27 ++++--- 5 files changed, 119 insertions(+), 148 deletions(-) diff --git a/src/childProcess.hpp b/src/childProcess.hpp index 4289d11..c1f5202 100644 --- a/src/childProcess.hpp +++ b/src/childProcess.hpp @@ -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 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 */ diff --git a/src/childProcess.inl b/src/childProcess.inl index 9a0186b..970fe78 100644 --- a/src/childProcess.inl +++ b/src/childProcess.inl @@ -53,12 +53,39 @@ inline std::optional 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 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; childproc.in = childIn[1]; childproc.out = STDOUT_FILENO; + childproc.err = STDERR_FILENO; childproc.pid = fork(); if(childproc.pid == 0) /* child */ @@ -72,34 +99,8 @@ namespace _cppipe 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]) + /* 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); @@ -107,9 +108,9 @@ namespace _cppipe Proc childproc; childproc.in = childIn[1]; childproc.out = childOut[0]; + childproc.err = STDERR_FILENO; childproc.pid = fork(); - /* close(STDIN_FILENO); flush?*/ if(childproc.pid != 0) /* parent */ { close(childOut[1]); @@ -126,81 +127,59 @@ namespace _cppipe return childproc; } -} -inline Proc createRedirProcess(const char* const argv[], U32 flags) /* todo rename */ -{ - fd_t childIn[2]; - Proc proc; - - if(flags & INPUT) + inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err) { - pipe(childIn); - if(flags & OUTPUT) - proc = _cppipe::createRedirProc(argv, childIn); - else - proc = _cppipe::createProc(argv, childIn); + 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; } - 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; - proc.err = err; - proc.pid = fork(); - if(proc.pid == 0) /* child */ + if(in == PIPE) { - if(in != STDIN_FILENO) - dup2(in, STDIN_FILENO); + fd_t childIn[2]; + pipe(childIn); - if(out != STDOUT_FILENO) - dup2(out, STDOUT_FILENO); + if(out == PIPE) + proc = _cppipe::createInOutRedirected(argv, childIn); + else + proc = _cppipe::createInRedirected(argv, childIn); - if(err != STDERR_FILENO) - dup2(err, STDERR_FILENO); - - exec_or_die(argv); + 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; } diff --git a/src/commands.hpp b/src/commands.hpp index 18bb92a..049f967 100644 --- a/src/commands.hpp +++ b/src/commands.hpp @@ -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: diff --git a/src/commands.inl b/src/commands.inl index 0c399eb..06efae7 100644 --- a/src/commands.inl +++ b/src/commands.inl @@ -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(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(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(ccmd); + assert(c.in==0 && "Rediredcting redirected input"); + + c.in = PIPE; + + return detachRedirOut(c); } inline PendingCmd operator,(const PendingCmd& left, const Cmd& right) diff --git a/src/cppipe.cpp b/src/cppipe.cpp index 26a2e3a..064eac6 100644 --- a/src/cppipe.cpp +++ b/src/cppipe.cpp @@ -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 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 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