add option to forward environment to pipestream
[libi2ncommon] / src / pipestream.hxx
index f0cf87b..8668df3 100644 (file)
@@ -29,8 +29,70 @@ on this file might be covered by the GNU General Public License.
 
 #include <stdio.h>
 
+#include <cstring>
 #include <string>
 #include <streambuf>
+#include <istream>
+#include <ostream>
+#include <vector>
+
+#include <stringfunc.hxx>
+
+struct ExecResult
+{
+    /** if the program exited normally and returned a return code */
+    bool normal_exit;
+
+    /** the real return code of the program, only set when normal_exit true */
+    char return_code;
+
+    /** if the program was terminated by a signal */
+    bool terminated_by_signal;
+
+    /** number of the signal that terminated the program, only valid when terminated_by_signal true */
+    int signal;
+
+    /** errormessage if we have one */
+    std::string error_message;
+
+    inline std::string format (void) const
+    {
+        return std::string ("(")
+            + "(normal_exit " + (this->normal_exit ? "T" : "F") + ") "
+              "(return_code '" + I2n::to_string ((int)this->return_code) + "') "
+              "(signal " + (this->terminated_by_signal
+                            ? strsignal (this->signal)
+                            : "<nil>") + "))"
+            ;
+    };
+};
+typedef struct ExecResult ExecResult;
+
+std::string capture_exec(const std::string& command, ExecResult &rescode);
+std::string capture_exec(const char *const *command, ExecResult &rescode,
+                         const bool out=true, const bool err=false,
+                         const bool path=false, const bool env=false);
+std::string capture_exec(const std::vector<std::string>& command, ExecResult &rescode,
+                         const bool out=true, const bool err=false,
+                         const bool path=false, const bool env=false);
+
+inline std::string capture_exec (const std::string &command)
+{
+    ExecResult r;
+    return capture_exec(command,r);
+}
+
+inline std::string capture_exec(const char *const *command)
+{
+    ExecResult r;
+    return capture_exec(command,r);
+}
+
+inline std::string capture_exec(const std::vector<std::string>& command)
+{
+    ExecResult r;
+    return capture_exec(command,r);
+}
 
 /** @brief runs command and provides buffered input for it through pipe
  *
@@ -45,14 +107,21 @@ class inpipebuf : public std::streambuf
 {
 protected:
     char buffer;
+
     FILE *pipe;
+    pid_t pid;
 
     // "callback" variables for destructor to store exit status
     bool *status_set;
     int *exit_status;
 
 public:
-    inpipebuf(const std::string& command);
+    inpipebuf(const std::string& command,
+              const bool out, const bool err, const bool path, const bool env);
+    inpipebuf(const char *const *command,
+              const bool out, const bool err, const bool path, const bool env);
+    inpipebuf(const std::vector<std::string> &command,
+              const bool out, const bool err, const bool path, const bool env);
 
     ~inpipebuf();
 
@@ -60,6 +129,12 @@ public:
 
 protected:
     virtual int_type underflow();
+
+private:
+    std::pair <pid_t, FILE *>
+    init_without_shell (const char *const *argv,
+                        const bool out, const bool err,
+                        const bool path, const bool env) const;
 };
 
 /** @brief stream around inpipebuf -- see comment there */
@@ -69,16 +144,28 @@ protected:
     inpipebuf buf;
 
 public:
-    inpipestream(const std::string& command)
-            : std::istream(&buf), buf(command)
+    inpipestream(const std::string& command,
+                 const bool out=true, const bool err=false,
+                 const bool path=false, const bool env=false)
+            : std::istream(&buf), buf(command, out, err, path, env)
+    {}
+
+    inpipestream(const char *const command[],
+                 const bool out=true, const bool err=false,
+                 const bool path=false, const bool env=false)
+            : std::istream(&buf), buf(command, out, err, path, env)
+    {}
+
+    inpipestream(const std::vector<std::string> &command,
+                 const bool out=true, const bool err=false,
+                 const bool path=false, const bool env=false)
+            : std::istream(&buf), buf(command, out, err, path, env)
     {}
 
     void store_exit_status(bool *_status_set, int *_exit_status)
     { buf.store_exit_status(_status_set, _exit_status); }
 };
 
-std::string pipe_to_string(const std::string& command, std::string *error=NULL, int *_exit_status=NULL);
-
 /** @brief runs command and provides buffered ouptput from it through pipe
  *
  * opens pipe to command using popen; exit status available after destruction