add pipestream ctor overload for vectors of string
[libi2ncommon] / src / pipestream.hxx
index 734b99c..d13f312 100644 (file)
@@ -33,9 +33,48 @@ on this file might be covered by the GNU General Public License.
 #include <streambuf>
 #include <istream>
 #include <ostream>
-#include <cstdio>
+#include <vector>
 
-#include "exception.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;
+};
+typedef struct ExecResult ExecResult;
+
+std::string capture_exec(const std::string& command, ExecResult &rescode);
+std::string capture_exec(const char *const *command, ExecResult &rescode);
+std::string capture_exec(const std::vector<std::string>& command, ExecResult &rescode);
+
+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
  *
@@ -50,6 +89,7 @@ class inpipebuf : public std::streambuf
 {
 protected:
     char buffer;
+
     FILE *pipe;
 
     // "callback" variables for destructor to store exit status
@@ -57,54 +97,19 @@ protected:
     int *exit_status;
 
 public:
-    inpipebuf(const std::string& command)
-    {
-        status_set = NULL;
-        exit_status = NULL;
-
-        pipe = popen (command.c_str(), "r");
-        if (pipe == NULL)
-            throw EXCEPTION (pipestream_error, "can't open program or permission denied");
+    inpipebuf(const std::string& command);
+    inpipebuf(const char *const *command);
+    inpipebuf(const std::vector<std::string> &command);
 
-        // force underflow
-        setg (&buffer, &buffer, &buffer);
-    }
+    ~inpipebuf();
 
-    ~inpipebuf()
-    {
-        if (pipe != NULL) {
-            int pclose_exit = pclose (pipe);
-
-            if (exit_status && pclose_exit != -1) {
-                *status_set = true;
-                *exit_status = pclose_exit;
-            }
-
-            pipe = NULL;
-        }
-    }
-
-    /** note: exit status only available after destruction */
-    void store_exit_status(bool *_status_set, int *_exit_status)
-    { status_set = _status_set; exit_status = _exit_status; }
+    void store_exit_status(bool *_status_set, int *_exit_status);
 
 protected:
-    virtual int_type underflow()
-    {
-        if (gptr() < egptr())
-            return traits_type::to_int_type(*gptr());
-
-        buffer = fgetc (pipe);
-        if (feof (pipe))
-        {
-            // ERROR or EOF
-            return EOF;
-        }
-
-        setg (&buffer, &buffer, &buffer+sizeof(char));
-
-        return traits_type::to_int_type(*gptr());
-    }
+    virtual int_type underflow();
+
+private:
+    FILE *init_without_shell (const char *const *argv) const;
 };
 
 /** @brief stream around inpipebuf -- see comment there */
@@ -117,48 +122,18 @@ public:
     inpipestream(const std::string& command)
             : std::istream(&buf), buf(command)
     {}
+    inpipestream(const char *const command[])
+            : std::istream(&buf), buf(command)
+    {}
+
+    inpipestream(const std::vector<std::string> &command)
+            : std::istream(&buf), buf(command)
+    {}
 
     void store_exit_status(bool *_status_set, int *_exit_status)
     { buf.store_exit_status(_status_set, _exit_status); }
 };
 
-/** @brief runs command and returns it's output as string
- *  @param command the full command with all parameters
- *  @param exit_status the full exit status, use WEXITSTATUS to get the "regular" return code
- *  @returns the output (stderr) of the called program
- */
-std::string pipe_to_string(const std::string& command, std::string *error=NULL, int *_exit_status=NULL)
-{
-    std::string result;
-    bool exit_set;
-
-    try
-    {
-        inpipestream ips(command);
-
-        ips.store_exit_status(&exit_set, _exit_status);
-
-        char buffer[2048];
-        while (ips.good())
-        {
-            ips.read(buffer, sizeof(buffer));
-            result.append(buffer, ips.gcount());
-        }
-    }
-    catch (pipestream_error &e)
-    {
-        if (error)
-            *error=e.what();
-        return "";
-    }
-    catch(...)
-    {
-        throw;
-    }
-
-    return result;
-}
-
 /** @brief runs command and provides buffered ouptput from it through pipe
  *
  * opens pipe to command using popen; exit status available after destruction
@@ -174,49 +149,17 @@ protected:
     int *exit_status;
 
 public:
-    outpipebuf(const std::string& command)
-    {
-        status_set = NULL;
-        exit_status = NULL;
-
-        pipe = popen (command.c_str(), "w");
-        if (pipe == NULL)
-            throw EXCEPTION (pipestream_error, "can't open program or permission denied");
-    }
-
-    ~outpipebuf()
-    {
-        if (pipe != NULL) {
-            int pclose_exit = pclose (pipe);
-
-            if (exit_status && pclose_exit != -1) {
-                *status_set = true;
-                *exit_status = pclose_exit;
-            }
-
-            pipe = NULL;
-        }
-    }
+    outpipebuf(const std::string& command);
+
+    ~outpipebuf();
 
     /** note: exit status only available after destruction */
-    void store_exit_status(bool *_status_set, int *_exit_status)
-    { status_set = _status_set; exit_status = _exit_status; }
+    void store_exit_status(bool *_status_set, int *_exit_status);
 
 protected:
-    virtual int_type overflow(int_type c)
-    {
-        if (c != EOF)
-        {
-            if (fputc(c,pipe)==EOF)
-                return EOF;
-        }
-        return c;
-    }
-
-    virtual std::streamsize xsputn(const char* s, std::streamsize num)
-    {
-        return fwrite(s,num,1,pipe);
-    }
+    virtual int_type overflow(int_type c);
+
+    virtual std::streamsize xsputn(const char* s, std::streamsize num);
 };