211ee5d2261ae0758a07a7048f25b860133a368d
[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 <cstdio>
37
38 #include "exception.hxx"
39
40 // ATTENTION: A lot of mysterious STL bugs occured
41 //            with a "real" buffer (buffer larger than 1 byte and up to 100 bytes)
42 //            -> Keep it slow and working!
43
44 class inpipebuf : public std::streambuf
45 {
46 protected:
47     char buffer;
48     FILE *pipe;
49
50     // "callback" variables for destructor to store exit status
51     bool *status_set;
52     int *exit_status;
53
54 public:
55     inpipebuf(const std::string& command)
56     {
57         status_set = NULL;
58         exit_status = NULL;
59
60         pipe = popen (command.c_str(), "r");
61         if (pipe == NULL)
62             throw EXCEPTION (pipestream_error, "can't open program or permission denied");
63
64         // force underflow
65         setg (&buffer, &buffer, &buffer);
66     }
67
68     ~inpipebuf()
69     {
70         if (pipe != NULL) {
71             int pclose_exit = pclose (pipe);
72
73             if (exit_status && pclose_exit != -1) {
74                 *status_set = true;
75                 *exit_status = pclose_exit;
76             }
77
78             pipe = NULL;
79         }
80     }
81
82     void store_exit_status(bool *_status_set, int *_exit_status)
83     { status_set = _status_set; exit_status = _exit_status; }
84
85 protected:
86     virtual int_type underflow()
87     {
88         if (gptr() < egptr())
89             return traits_type::to_int_type(*gptr());
90
91         buffer = fgetc (pipe);
92         if (feof (pipe))
93         {
94             // ERROR or EOF
95             return EOF;
96         }
97
98         setg (&buffer, &buffer, &buffer+sizeof(char));
99
100         return traits_type::to_int_type(*gptr());
101     }
102 };
103
104 class inpipestream : public std::istream
105 {
106 protected:
107     inpipebuf buf;
108
109 public:
110     inpipestream(const std::string& command)
111             : std::istream(&buf), buf(command)
112     {}
113
114     void store_exit_status(bool *_status_set, int *_exit_status)
115     { buf.store_exit_status(_status_set, _exit_status); }
116 };
117
118 class outpipebuf : public std::streambuf
119 {
120 protected:
121     FILE *pipe;
122
123     // "callback" variables for destructor to store exit status
124     bool *status_set;
125     int *exit_status;
126
127 public:
128     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()
139     {
140         if (pipe != NULL) {
141             int pclose_exit = pclose (pipe);
142
143             if (exit_status && pclose_exit != -1) {
144                 *status_set = true;
145                 *exit_status = pclose_exit;
146             }
147
148             pipe = NULL;
149         }
150     }
151
152     void store_exit_status(bool *_status_set, int *_exit_status)
153     { status_set = _status_set; exit_status = _exit_status; }
154
155 protected:
156     virtual int_type overflow(int_type c)
157     {
158         if (c != EOF)
159         {
160             if (fputc(c,pipe)==EOF)
161                 return EOF;
162         }
163         return c;
164     }
165
166     virtual std::streamsize xsputn(const char* s, std::streamsize num)
167     {
168         return fwrite(s,num,1,pipe);
169     }
170 };
171
172 class outpipestream : public std::ostream
173 {
174 protected:
175     outpipebuf buf;
176 public:
177     outpipestream(const std::string& command)
178             : std::ostream(&buf), buf(command)
179     {}
180
181     void store_exit_status(bool *_status_set, int *_exit_status)
182     { buf.store_exit_status(_status_set, _exit_status); }
183 };
184
185 #endif