f283d87cf1ab2f180871f1eebfbecf452d267f6e
[libi2ncommon] / src / pipestream.hxx
1  /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19 */
20 /***************************************************************************
21               inpipestream.hxx  -  C++ streambuffer wrapper 
22                              -------------------
23     begin                : Thu Dec 27 2001
24     copyright            : (C) 2001 by Intra2net AG
25  ***************************************************************************/
26
27 #ifndef _PIPESTREAM
28 #define _PIPESTREAM
29
30 #include <stdio.h>
31
32 #include <string>
33 #include <streambuf>
34 #include <istream>
35 #include <ostream>
36 #include <vector>
37
38 struct ExecResult
39 {
40     /** if the program exited normally and returned a return code */
41     bool normal_exit;
42
43     /** the real return code of the program, only set when normal_exit true */
44     char return_code;
45
46     /** if the program was terminated by a signal */
47     bool terminated_by_signal;
48
49     /** number of the signal that terminated the program, only valid when terminated_by_signal true */
50     int signal;
51
52     /** errormessage if we have one */
53     std::string error_message;
54 };
55 typedef struct ExecResult ExecResult;
56
57 std::string capture_exec(const std::string& command, ExecResult &rescode);
58 std::string capture_exec(const char *const *command, ExecResult &rescode,
59                          const bool out=true, const bool err=false);
60 std::string capture_exec(const std::vector<std::string>& command, ExecResult &rescode,
61                          const bool out=true, const bool err=false);
62
63 inline std::string capture_exec (const std::string &command)
64 {
65     ExecResult r;
66     return capture_exec(command,r);
67 }
68
69 inline std::string capture_exec(const char *const *command)
70 {
71     ExecResult r;
72     return capture_exec(command,r);
73 }
74
75 inline std::string capture_exec(const std::vector<std::string>& command)
76 {
77     ExecResult r;
78     return capture_exec(command,r);
79 }
80
81 /** @brief runs command and provides buffered input for it through pipe
82  *
83  * opens pipe to command using popen; exit status available after destruction
84  * (use WEXITSTATUS to get the "regular" return code (lowest byte))
85  *
86  * ATTENTION: A lot of mysterious STL bugs occured
87  *            with a "real" buffer (buffer larger than 1 byte and up to 100 bytes)
88  *            -> Keep it slow and working!
89  */
90 class inpipebuf : public std::streambuf
91 {
92 protected:
93     char buffer;
94
95     FILE *pipe;
96     pid_t pid;
97
98     // "callback" variables for destructor to store exit status
99     bool *status_set;
100     int *exit_status;
101
102 public:
103     inpipebuf(const std::string& command,
104               const bool out, const bool err);
105     inpipebuf(const char *const *command,
106               const bool out, const bool err);
107     inpipebuf(const std::vector<std::string> &command,
108               const bool out, const bool err);
109
110     ~inpipebuf();
111
112     void store_exit_status(bool *_status_set, int *_exit_status);
113
114 protected:
115     virtual int_type underflow();
116
117 private:
118     std::pair <pid_t, FILE *>
119     init_without_shell (const char *const *argv,
120                         const bool out, const bool err) const;
121 };
122
123 /** @brief stream around inpipebuf -- see comment there */
124 class inpipestream : public std::istream
125 {
126 protected:
127     inpipebuf buf;
128
129 public:
130     inpipestream(const std::string& command,
131                  const bool out=true, const bool err=false)
132             : std::istream(&buf), buf(command, out, err)
133     {}
134
135     inpipestream(const char *const command[],
136                  const bool out=true, const bool err=false)
137             : std::istream(&buf), buf(command, out, err)
138     {}
139
140     inpipestream(const std::vector<std::string> &command,
141                  const bool out=true, const bool err=false)
142             : std::istream(&buf), buf(command, out, err)
143     {}
144
145     void store_exit_status(bool *_status_set, int *_exit_status)
146     { buf.store_exit_status(_status_set, _exit_status); }
147 };
148
149 /** @brief runs command and provides buffered ouptput from it through pipe
150  *
151  * opens pipe to command using popen; exit status available after destruction
152  * (use WEXITSTATUS to get the "regular" return code (lowest byte))
153  */
154 class outpipebuf : public std::streambuf
155 {
156 protected:
157     FILE *pipe;
158
159     // "callback" variables for destructor to store exit status
160     bool *status_set;
161     int *exit_status;
162
163 public:
164     outpipebuf(const std::string& command);
165
166     ~outpipebuf();
167
168     /** note: exit status only available after destruction */
169     void store_exit_status(bool *_status_set, int *_exit_status);
170
171 protected:
172     virtual int_type overflow(int_type c);
173
174     virtual std::streamsize xsputn(const char* s, std::streamsize num);
175 };
176
177
178 /** @brief stream around outpipebuf -- see comment there */
179 class outpipestream : public std::ostream
180 {
181 protected:
182     outpipebuf buf;
183 public:
184     outpipestream(const std::string& command)
185             : std::ostream(&buf), buf(command)
186     {}
187
188     void store_exit_status(bool *_status_set, int *_exit_status)
189     { buf.store_exit_status(_status_set, _exit_status); }
190 };
191
192 #endif