afa6d568ccfcc55c12e739e4210089e6b9a5b97e
[libi2ncommon] / src / pipestream.cpp
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.cpp  -  C++ streambuffer wrapper 
22                              -------------------
23     begin                : Thu Dec 27 2001
24     copyright            : (C) 2001 by Intra2net AG
25  ***************************************************************************/
26
27 #include <stdio.h>
28 #include <sys/wait.h>
29
30 #include <string>
31 #include <streambuf>
32 #include <istream>
33 #include <ostream>
34 #include <cstdio>
35
36 #include "exception.hxx"
37 #include "pipestream.hxx"
38
39 /** @brief runs command and returns it's output as string
40  *  @param command the full command with all parameters
41  *  @param rescode struct containing the return code, if the program exited normally and so on
42  *  @returns the output (stdout) of the called program
43  */
44 std::string capture_exec(const std::string& command, ExecResult &rescode)
45 {
46     std::string output;
47
48     bool exit_set = false;
49     int exit_status_waitpid;
50
51     // set the results to false until we are sure we have proper values
52     rescode.normal_exit = false;
53     rescode.terminated_by_signal = false;
54
55     try
56     {
57         {
58             inpipestream ips(command);
59
60             ips.store_exit_status(&exit_set, &exit_status_waitpid);
61
62             char buffer[2048];
63             while (ips.good())
64             {
65                 ips.read(buffer, sizeof(buffer));
66                 output.append(buffer, ips.gcount());
67             }
68         }
69
70         // exit_status_waitpid only valid after destruction of the inpipestream
71
72         if (exit_set)
73         {
74             rescode.normal_exit = WIFEXITED(exit_status_waitpid);
75             if (rescode.normal_exit)
76                 rescode.return_code = WEXITSTATUS(exit_status_waitpid);
77
78             rescode.terminated_by_signal = WIFSIGNALED(exit_status_waitpid);
79             if (rescode.terminated_by_signal)
80                 rescode.signal = WTERMSIG(exit_status_waitpid);
81         }
82     }
83     catch (pipestream_error &e)
84     {
85         rescode.error_message = e.what();
86     }
87
88     return output;
89 }
90
91 inpipebuf::inpipebuf(const std::string& command)
92 {
93     status_set = NULL;
94     exit_status = NULL;
95
96     pipe = popen (command.c_str(), "r");
97     if (pipe == NULL)
98         throw EXCEPTION (pipestream_error, "can't open program or permission denied");
99
100     // force underflow
101     setg (&buffer, &buffer, &buffer);
102 }
103
104 inpipebuf::~inpipebuf()
105 {
106     if (pipe != NULL) {
107         int pclose_exit = pclose (pipe);
108
109         if (exit_status && pclose_exit != -1)
110         {
111             if (status_set)
112                 *status_set = true;
113             *exit_status = pclose_exit;
114         }
115
116         pipe = NULL;
117     }
118 }
119
120 /** note: exit status only available after destruction */
121 void inpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
122
123     status_set = _status_set; 
124     exit_status = _exit_status; 
125 }
126
127 inpipebuf::int_type inpipebuf::underflow()
128 {
129     if (gptr() < egptr())
130         return traits_type::to_int_type(*gptr());
131
132     buffer = fgetc (pipe);
133     if (feof (pipe))
134     {
135         // ERROR or EOF
136         return EOF;
137     }
138
139     setg (&buffer, &buffer, &buffer+sizeof(char));
140
141     return traits_type::to_int_type(*gptr());
142 }
143
144 outpipebuf::outpipebuf(const std::string& command)
145 {
146     status_set = NULL;
147     exit_status = NULL;
148
149     pipe = popen (command.c_str(), "w");
150     if (pipe == NULL)
151         throw EXCEPTION (pipestream_error, "can't open program or permission denied");
152 }
153
154 outpipebuf::~outpipebuf()
155 {
156     if (pipe != NULL) {
157         int pclose_exit = pclose (pipe);
158
159         if (exit_status && pclose_exit != -1)
160         {
161             if (status_set)
162                 *status_set = true;
163             *exit_status = pclose_exit;
164         }
165
166         pipe = NULL;
167     }
168 }
169
170 /** note: exit status only available after destruction */
171 void outpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
172
173     status_set = _status_set; 
174     exit_status = _exit_status; 
175 }
176
177 outpipebuf::int_type outpipebuf::overflow(int_type c)
178 {
179     if (c != EOF)
180     {
181         if (fputc(c,pipe)==EOF)
182             return EOF;
183     }
184     return c;
185 }
186
187 std::streamsize outpipebuf::xsputn(const char* s, std::streamsize num)
188 {
189     return fwrite(s,num,1,pipe);
190 }