c475a50bd10ce8f4287cafe1f07afe99bad158bf
[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
29 #include <string>
30 #include <streambuf>
31 #include <istream>
32 #include <ostream>
33 #include <cstdio>
34
35 #include "exception.hxx"
36 #include "pipestream.hxx"
37
38 inpipebuf::inpipebuf(const std::string& command)
39 {
40     status_set = NULL;
41     exit_status = NULL;
42
43     pipe = popen (command.c_str(), "r");
44     if (pipe == NULL)
45         throw EXCEPTION (pipestream_error, "can't open program or permission denied");
46
47     // force underflow
48     setg (&buffer, &buffer, &buffer);
49 }
50
51 inpipebuf::~inpipebuf()
52 {
53     if (pipe != NULL) {
54         int pclose_exit = pclose (pipe);
55
56         if (exit_status && pclose_exit != -1)
57         {
58             if (status_set)
59                 *status_set = true;
60             *exit_status = pclose_exit;
61         }
62
63         pipe = NULL;
64     }
65 }
66
67 /** note: exit status only available after destruction */
68 void inpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
69
70     status_set = _status_set; 
71     exit_status = _exit_status; 
72 }
73
74 inpipebuf::int_type inpipebuf::underflow()
75 {
76     if (gptr() < egptr())
77         return traits_type::to_int_type(*gptr());
78
79     buffer = fgetc (pipe);
80     if (feof (pipe))
81     {
82         // ERROR or EOF
83         return EOF;
84     }
85
86     setg (&buffer, &buffer, &buffer+sizeof(char));
87
88     return traits_type::to_int_type(*gptr());
89 }
90
91 /** @brief runs command and returns it's output as string
92  *  @param command the full command with all parameters
93  *  @param exit_status the full exit status, use WEXITSTATUS to get the "regular" return code
94  *  @returns the output (stderr) of the called program
95  */
96 std::string pipe_to_string(const std::string& command, std::string *error, int *_exit_status)
97 {
98     std::string result;
99     bool exit_set;
100
101     try
102     {
103         inpipestream ips(command);
104
105         ips.store_exit_status(&exit_set, _exit_status);
106
107         char buffer[2048];
108         while (ips.good())
109         {
110             ips.read(buffer, sizeof(buffer));
111             result.append(buffer, ips.gcount());
112         }
113     }
114     catch (pipestream_error &e)
115     {
116         if (error)
117             *error=e.what();
118         return "";
119     }
120     catch(...)
121     {
122         throw;
123     }
124
125     return result;
126 }
127
128 outpipebuf::outpipebuf(const std::string& command)
129 {
130     status_set = NULL;
131     exit_status = NULL;
132
133     pipe = popen (command.c_str(), "w");
134     if (pipe == NULL)
135         throw EXCEPTION (pipestream_error, "can't open program or permission denied");
136 }
137
138 outpipebuf::~outpipebuf()
139 {
140     if (pipe != NULL) {
141         int pclose_exit = pclose (pipe);
142
143         if (exit_status && pclose_exit != -1)
144         {
145             if (status_set)
146                 *status_set = true;
147             *exit_status = pclose_exit;
148         }
149
150         pipe = NULL;
151     }
152 }
153
154 /** note: exit status only available after destruction */
155 void outpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
156
157     status_set = _status_set; 
158     exit_status = _exit_status; 
159 }
160
161 outpipebuf::int_type outpipebuf::overflow(int_type c)
162 {
163     if (c != EOF)
164     {
165         if (fputc(c,pipe)==EOF)
166             return EOF;
167     }
168     return c;
169 }
170
171 std::streamsize outpipebuf::xsputn(const char* s, std::streamsize num)
172 {
173     return fwrite(s,num,1,pipe);
174 }