+ /*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
/***************************************************************************
inpipestream.hxx - C++ streambuffer wrapper
-------------------
begin : Thu Dec 27 2001
copyright : (C) 2001 by Intra2net AG
- email : intranator@intra2net.com
***************************************************************************/
#ifndef _PIPESTREAM
#define _PIPESTREAM
+#include <stdio.h>
+
#include <string>
#include <streambuf>
-#include <cstdio>
+#include <istream>
+#include <ostream>
+#include <vector>
+
+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;
-#include "exception.hxx"
+ /** if the program was terminated by a signal */
+ bool terminated_by_signal;
-// ATTENTION: A lot of mysterious STL bugs occured
-// with a "real" buffer (buffer larger than 1 byte and up to 100 bytes)
-// -> Keep it slow and working!
+ /** 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
+ *
+ * opens pipe to command using popen; exit status available after destruction
+ * (use WEXITSTATUS to get the "regular" return code (lowest byte))
+ *
+ * ATTENTION: A lot of mysterious STL bugs occured
+ * with a "real" buffer (buffer larger than 1 byte and up to 100 bytes)
+ * -> Keep it slow and working!
+ */
class inpipebuf : public std::streambuf
{
- protected:
- char buffer;
- FILE *pipe;
-
- // "callback" variables for destructor to store exit status
- bool *status_set;
- 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");
-
- // force underflow
- setg (&buffer, &buffer, &buffer);
- }
-
- ~inpipebuf()
- {
- if (pipe != NULL) {
- int pclose_exit = pclose (pipe);
-
- if (exit_status && pclose_exit != -1) {
- *status_set = true;
- *exit_status = pclose_exit;
- }
-
- pipe = NULL;
- }
- }
-
- void store_exit_status(bool *_status_set, int *_exit_status)
- { status_set = _status_set; exit_status = _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());
- }
-};
+protected:
+ char buffer;
+ FILE *pipe;
+
+ // "callback" variables for destructor to store exit status
+ bool *status_set;
+ int *exit_status;
+
+public:
+ inpipebuf(const std::string& command);
+ inpipebuf(const char *const *command);
+ inpipebuf(const std::vector<std::string> &command);
+
+ ~inpipebuf();
+
+ void store_exit_status(bool *_status_set, int *_exit_status);
+
+protected:
+ virtual int_type underflow();
+
+private:
+ FILE *init_without_shell (const char *const *argv) const;
+};
+
+/** @brief stream around inpipebuf -- see comment there */
class inpipestream : public std::istream
{
- protected:
- inpipebuf buf;
-
- public:
- inpipestream(const std::string& command)
- : buf(command), std::istream(&buf)
- {}
-
- void store_exit_status(bool *_status_set, int *_exit_status)
- { buf.store_exit_status(_status_set, _exit_status); }
+protected:
+ inpipebuf buf;
+
+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 provides buffered ouptput from it through pipe
+ *
+ * opens pipe to command using popen; exit status available after destruction
+ * (use WEXITSTATUS to get the "regular" return code (lowest byte))
+ */
class outpipebuf : public std::streambuf
{
- protected:
- FILE *pipe;
-
- // "callback" variables for destructor to store exit status
- bool *status_set;
- 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;
- }
- }
-
- void store_exit_status(bool *_status_set, int *_exit_status)
- { status_set = _status_set; exit_status = _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);
- }
+protected:
+ FILE *pipe;
+
+ // "callback" variables for destructor to store exit status
+ bool *status_set;
+ int *exit_status;
+
+public:
+ outpipebuf(const std::string& command);
+
+ ~outpipebuf();
+
+ /** note: exit status only available after destruction */
+ void store_exit_status(bool *_status_set, int *_exit_status);
+
+protected:
+ virtual int_type overflow(int_type c);
+
+ virtual std::streamsize xsputn(const char* s, std::streamsize num);
};
+
+/** @brief stream around outpipebuf -- see comment there */
class outpipestream : public std::ostream
{
- protected:
- outpipebuf buf;
- public:
- outpipestream(const std::string& command)
- : buf(command), std::ostream(&buf)
- {}
-
- void store_exit_status(bool *_status_set, int *_exit_status)
- { buf.store_exit_status(_status_set, _exit_status); }
+protected:
+ outpipebuf buf;
+public:
+ outpipestream(const std::string& command)
+ : std::ostream(&buf), buf(command)
+ {}
+
+ void store_exit_status(bool *_status_set, int *_exit_status)
+ { buf.store_exit_status(_status_set, _exit_status); }
};
#endif