rename pipe_to_string() to capture_exec() and improve it's interface
authorGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 17 Dec 2015 09:56:27 +0000 (10:56 +0100)
committerGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 17 Dec 2015 09:56:27 +0000 (10:56 +0100)
src/pipestream.cpp
src/pipestream.hxx
test/test_filefunc.cpp

index c475a50..b29ec70 100644 (file)
@@ -25,6 +25,7 @@ on this file might be covered by the GNU General Public License.
  ***************************************************************************/
 
 #include <stdio.h>
+#include <sys/wait.h>
 
 #include <string>
 #include <streambuf>
@@ -35,6 +36,58 @@ on this file might be covered by the GNU General Public License.
 #include "exception.hxx"
 #include "pipestream.hxx"
 
+/** @brief runs command and returns it's output as string
+ *  @param command the full command with all parameters
+ *  @param rescode struct containing the return code, if the program exited normally and so on
+ *  @returns the output (stdout) of the called program
+ */
+std::string capture_exec(const std::string& command, ExecResult &rescode)
+{
+    std::string output;
+
+    bool exit_set;
+    int exit_status_waitpid;
+
+    // set the results to false until we are sure we have proper values
+    rescode.normal_exit = false;
+    rescode.terminated_by_signal = false;
+
+    try
+    {
+        {
+            inpipestream ips(command);
+
+            ips.store_exit_status(&exit_set, &exit_status_waitpid);
+
+            char buffer[2048];
+            while (ips.good())
+            {
+                ips.read(buffer, sizeof(buffer));
+                output.append(buffer, ips.gcount());
+            }
+        }
+
+        // exit_status_waitpid only valid after destruction of the inpipestream
+
+        if (exit_set)
+        {
+            rescode.normal_exit = WIFEXITED(exit_status_waitpid);
+            if (rescode.normal_exit)
+                rescode.return_code = WEXITSTATUS(exit_status_waitpid);
+
+            rescode.terminated_by_signal = WIFSIGNALED(exit_status_waitpid);
+            if (rescode.terminated_by_signal)
+                rescode.signal = WTERMSIG(exit_status_waitpid);
+        }
+    }
+    catch (pipestream_error &e)
+    {
+        rescode.error_message = e.what();
+    }
+
+    return output;
+}
+
 inpipebuf::inpipebuf(const std::string& command)
 {
     status_set = NULL;
@@ -88,43 +141,6 @@ inpipebuf::int_type inpipebuf::underflow()
     return traits_type::to_int_type(*gptr());
 }
 
-/** @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, int *_exit_status)
-{
-    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;
-}
-
 outpipebuf::outpipebuf(const std::string& command)
 {
     status_set = NULL;
index f0cf87b..83244ed 100644 (file)
@@ -32,6 +32,33 @@ on this file might be covered by the GNU General Public License.
 #include <string>
 #include <streambuf>
 
+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 std::string& command)
+{
+    ExecResult r;
+    return capture_exec(command,r);
+}
+
 /** @brief runs command and provides buffered input for it through pipe
  *
  * opens pipe to command using popen; exit status available after destruction
@@ -77,8 +104,6 @@ public:
     { 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
index d982b5a..3d74a9d 100644 (file)
@@ -592,7 +592,7 @@ BOOST_AUTO_TEST_CASE(FileContentDiffersEqualSize)
 
 BOOST_AUTO_TEST_CASE(FreeDiskSpace1)
 {
-    string dfstr=pipe_to_string("df -B 1 --output=avail /tmp | tail -n 1");
+    string dfstr=capture_exec("df -B 1 --output=avail /tmp | tail -n 1");
 
     long long dfout=-1;
     string_to<long long>(dfstr,dfout);
@@ -620,7 +620,7 @@ BOOST_AUTO_TEST_CASE(TestDu)
     BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
     BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar and some more data, even more that Tom would like to see in one line without linebreak but I still want to have it all here"));
 
-    string dustr=pipe_to_string(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
+    string dustr=capture_exec(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
     long long duout=-1;
     string_to<long long>(dustr,duout);