Commit | Line | Data |
---|---|---|
e93545dd GE |
1 | /*************************************************************************** |
2 | inpipestream.hxx - C++ streambuffer wrapper | |
3 | ------------------- | |
4 | begin : Thu Dec 27 2001 | |
5 | copyright : (C) 2001 by Intra2net AG | |
6 | email : intranator@intra2net.com | |
7 | ***************************************************************************/ | |
8 | ||
9 | #ifndef _PIPESTREAM | |
10 | #define _PIPESTREAM | |
11 | ||
be3dbe32 TJ |
12 | #include <stdio.h> |
13 | ||
e93545dd GE |
14 | #include <string> |
15 | #include <streambuf> | |
be3dbe32 TJ |
16 | #include <istream> |
17 | #include <ostream> | |
e93545dd GE |
18 | #include <cstdio> |
19 | ||
20 | #include "exception.hxx" | |
21 | ||
22 | // ATTENTION: A lot of mysterious STL bugs occured | |
23 | // with a "real" buffer (buffer larger than 1 byte and up to 100 bytes) | |
24 | // -> Keep it slow and working! | |
25 | ||
26 | class inpipebuf : public std::streambuf | |
27 | { | |
20a79471 TJ |
28 | protected: |
29 | char buffer; | |
30 | FILE *pipe; | |
31 | ||
32 | // "callback" variables for destructor to store exit status | |
33 | bool *status_set; | |
34 | int *exit_status; | |
35 | ||
36 | public: | |
37 | inpipebuf(const std::string& command) | |
38 | { | |
39 | status_set = NULL; | |
40 | exit_status = NULL; | |
41 | ||
42 | pipe = popen (command.c_str(), "r"); | |
43 | if (pipe == NULL) | |
44 | throw EXCEPTION (pipestream_error, "can't open program or permission denied"); | |
45 | ||
46 | // force underflow | |
47 | setg (&buffer, &buffer, &buffer); | |
48 | } | |
49 | ||
50 | ~inpipebuf() | |
51 | { | |
52 | if (pipe != NULL) { | |
53 | int pclose_exit = pclose (pipe); | |
54 | ||
55 | if (exit_status && pclose_exit != -1) { | |
56 | *status_set = true; | |
57 | *exit_status = pclose_exit; | |
58 | } | |
59 | ||
60 | pipe = NULL; | |
61 | } | |
62 | } | |
63 | ||
64 | void store_exit_status(bool *_status_set, int *_exit_status) | |
65 | { status_set = _status_set; exit_status = _exit_status; } | |
66 | ||
67 | protected: | |
68 | virtual int_type underflow() | |
69 | { | |
70 | if (gptr() < egptr()) | |
71 | return traits_type::to_int_type(*gptr()); | |
72 | ||
73 | buffer = fgetc (pipe); | |
74 | if (feof (pipe)) | |
75 | { | |
76 | // ERROR or EOF | |
77 | return EOF; | |
78 | } | |
79 | ||
80 | setg (&buffer, &buffer, &buffer+sizeof(char)); | |
81 | ||
82 | return traits_type::to_int_type(*gptr()); | |
83 | } | |
84 | }; | |
e93545dd GE |
85 | |
86 | class inpipestream : public std::istream | |
87 | { | |
20a79471 TJ |
88 | protected: |
89 | inpipebuf buf; | |
90 | ||
91 | public: | |
92 | inpipestream(const std::string& command) | |
93 | : buf(command), std::istream(&buf) | |
94 | {} | |
95 | ||
96 | void store_exit_status(bool *_status_set, int *_exit_status) | |
97 | { buf.store_exit_status(_status_set, _exit_status); } | |
e93545dd GE |
98 | }; |
99 | ||
100 | class outpipebuf : public std::streambuf | |
101 | { | |
20a79471 TJ |
102 | protected: |
103 | FILE *pipe; | |
104 | ||
105 | // "callback" variables for destructor to store exit status | |
106 | bool *status_set; | |
107 | int *exit_status; | |
108 | ||
109 | public: | |
110 | outpipebuf(const std::string& command) | |
111 | { | |
112 | status_set = NULL; | |
113 | exit_status = NULL; | |
114 | ||
115 | pipe = popen (command.c_str(), "w"); | |
116 | if (pipe == NULL) | |
117 | throw EXCEPTION (pipestream_error, "can't open program or permission denied"); | |
118 | } | |
119 | ||
120 | ~outpipebuf() | |
121 | { | |
122 | if (pipe != NULL) { | |
123 | int pclose_exit = pclose (pipe); | |
124 | ||
125 | if (exit_status && pclose_exit != -1) { | |
126 | *status_set = true; | |
127 | *exit_status = pclose_exit; | |
128 | } | |
129 | ||
130 | pipe = NULL; | |
131 | } | |
132 | } | |
133 | ||
134 | void store_exit_status(bool *_status_set, int *_exit_status) | |
135 | { status_set = _status_set; exit_status = _exit_status; } | |
136 | ||
137 | protected: | |
138 | virtual int_type overflow(int_type c) | |
139 | { | |
140 | if (c != EOF) | |
141 | { | |
142 | if (fputc(c,pipe)==EOF) | |
143 | return EOF; | |
144 | } | |
145 | return c; | |
146 | } | |
147 | ||
148 | virtual std::streamsize xsputn(const char* s, std::streamsize num) | |
149 | { | |
150 | return fwrite(s,num,1,pipe); | |
151 | } | |
e93545dd GE |
152 | }; |
153 | ||
154 | class outpipestream : public std::ostream | |
155 | { | |
20a79471 TJ |
156 | protected: |
157 | outpipebuf buf; | |
158 | public: | |
159 | outpipestream(const std::string& command) | |
160 | : buf(command), std::ostream(&buf) | |
161 | {} | |
162 | ||
163 | void store_exit_status(bool *_status_set, int *_exit_status) | |
164 | { buf.store_exit_status(_status_set, _exit_status); } | |
e93545dd GE |
165 | }; |
166 | ||
167 | #endif |