00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pfstreamBuf.h"
00020 #include <assert.h>
00021
00022 PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) :
00023 _dir(dir)
00024 {
00025 init_pipe();
00026
00027 #ifndef HAVE_IOSTREAM
00028
00029
00030 allocate();
00031 assert((dir == Input) || (dir == Output));
00032 if (dir == Input) {
00033 setg(base(), ebuf(), ebuf());
00034 } else {
00035 setp(base(), ebuf());
00036 }
00037 #endif
00038 }
00039
00040 PipeStreamBuf::
00041 ~PipeStreamBuf(void) {
00042 if (is_open()) {
00043 sync();
00044 flush();
00045 close_pipe();
00046 }
00047 }
00048
00049 void PipeStreamBuf::flush(void) {
00050 assert(is_open());
00051 if (_dir == Output) {
00052 write_chars("", 0, true);
00053 }
00054 }
00055
00056 void PipeStreamBuf::command(const string cmd) {
00057 assert(!is_open());
00058 open_pipe(cmd);
00059 }
00060
00061 int PipeStreamBuf::overflow(int c) {
00062 assert(is_open());
00063 assert(_dir == Output);
00064 streamsize n = pptr() - pbase();
00065 if (n != 0) {
00066 write_chars(pbase(), n, false);
00067 pbump(-n);
00068 }
00069 if (c != EOF) {
00070
00071 char ch = c;
00072 write_chars(&ch, 1, false);
00073 }
00074 return 0;
00075 }
00076
00077 int PipeStreamBuf::sync(void) {
00078 assert(is_open());
00079 if (_dir == Output) {
00080 streamsize n = pptr() - pbase();
00081 write_chars(pbase(), n, false);
00082 pbump(-n);
00083 } else {
00084 streamsize n = egptr() - gptr();
00085 if (n != 0) {
00086 gbump(n);
00087 #ifndef NDEBUG
00088 cerr << "pfstream tossed out " << n << " bytes" << endl;
00089 #endif
00090 }
00091 }
00092 return 0;
00093 }
00094
00095 int PipeStreamBuf::underflow(void) {
00096 assert(_dir == Input);
00097 if ((eback() == (char*)0L) || (gptr() == (char*)0L) ||
00098 (egptr() == (char*)0L)) {
00099
00100 char* buf = new char[4096];
00101 char* ebuf = &(buf[4096]);
00102 setg(buf, ebuf, ebuf);
00103 }
00104 if (gptr() < egptr()) {
00105 char c = *(gptr());
00106 return c;
00107 }
00108 if (eof_pipe()) {
00109 return EOF;
00110 }
00111 #ifdef HAVE_IOSTREAM
00112 size_t len = 4096;
00113 #else
00114 size_t len = ebuf() - base();
00115 #endif
00116 char* buf = new char[len];
00117 size_t n = read_pipe(buf, len);
00118 int ret = buf[0];
00119 if (n == 0)
00120 ret = EOF;
00121 else {
00122 #ifdef HAVE_IOSTREAM
00123 memcpy(eback()+(len-n), buf, n);
00124 #else
00125 memcpy(base()+(len-n), buf, n);
00126 #endif
00127 gbump(-((int)n));
00128 }
00129 delete buf;
00130 return ret;
00131 }
00132
00133 void PipeStreamBuf::write_chars(const char* start, int length, bool flush) {
00134 assert(_dir == Output);
00135 size_t orig = _line_buffer.length();
00136 string latest(start, length);
00137 string line;
00138
00139 if (flush) {
00140
00141
00142 line = _line_buffer + latest;
00143 _line_buffer = "";
00144 } else {
00145
00146 _line_buffer += latest;
00147 size_t eol = _line_buffer.rfind('\n', orig);
00148 if (eol != string::npos) {
00149 line = _line_buffer.substr(0, eol+1);
00150 _line_buffer = _line_buffer.substr(eol+1);
00151 }
00152 }
00153
00154 size_t wrote = write_pipe(line.c_str(), line.length());
00155 #ifndef NDEBUG
00156 if (wrote != line.length())
00157 cerr << "wrote only " << wrote << " of " << line.length()
00158 << " bytes to pipe" << endl;
00159 #endif
00160 }
00161
00162 #ifndef WIN_PIPE_CALLS
00163
00164
00165
00166
00167
00168
00169
00170
00171 void PipeStreamBuf::
00172 init_pipe() {
00173 _pipe = NULL;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182 bool PipeStreamBuf::
00183 is_open() const {
00184 return _pipe != NULL;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 bool PipeStreamBuf::
00194 eof_pipe() const {
00195 return (_pipe == NULL) && feof(_pipe);
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 bool PipeStreamBuf::
00209 open_pipe(const string &cmd) {
00210 const char *typ = (_dir == Output)?"w":"r";
00211 _pipe = popen(cmd.c_str(), typ);
00212 return (_pipe != NULL);
00213 }
00214
00215
00216
00217
00218
00219
00220 void PipeStreamBuf::
00221 close_pipe() {
00222 if (_pipe != NULL) {
00223 fclose(_pipe);
00224 _pipe = NULL;
00225 }
00226 }
00227
00228
00229
00230
00231
00232
00233
00234 size_t PipeStreamBuf::
00235 write_pipe(const char *data, size_t len) {
00236 size_t wrote_count = fwrite(data, 1, len, _pipe);
00237 fflush(_pipe);
00238 return wrote_count;
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248 size_t PipeStreamBuf::
00249 read_pipe(char *data, size_t len) {
00250 return fread(data, 1, len, _pipe);
00251 }
00252
00253 #else // WIN_PIPE_CALLS
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 void PipeStreamBuf::
00270 init_pipe() {
00271 _child_out = 0;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280 bool PipeStreamBuf::
00281 is_open() const {
00282 return (_child_out != 0);
00283 }
00284
00285
00286
00287
00288
00289
00290
00291 bool PipeStreamBuf::
00292 eof_pipe() const {
00293 return (_child_out == 0);
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 bool PipeStreamBuf::
00307 open_pipe(const string &cmd) {
00308 close_pipe();
00309
00310
00311
00312 if (_dir == Output) {
00313 return false;
00314 }
00315
00316
00317
00318 HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00319
00320
00321 HANDLE hChildStdoutRd, hChildStdoutWr;
00322
00323
00324 SECURITY_ATTRIBUTES saAttr;
00325 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
00326 saAttr.bInheritHandle = TRUE;
00327 saAttr.lpSecurityDescriptor = NULL;
00328 if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
00329 #ifndef NDEBUG
00330 cerr << "Unable to create output pipe\n";
00331 #endif
00332 return false;
00333 }
00334
00335
00336 if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) {
00337 #ifndef NDEBUG
00338 cerr << "Unable to redirect stdout\n";
00339 #endif
00340 CloseHandle(hChildStdoutRd);
00341 CloseHandle(hChildStdoutWr);
00342 return false;
00343 }
00344
00345
00346
00347
00348 BOOL fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
00349 GetCurrentProcess(), &_child_out,
00350 0, FALSE, DUPLICATE_SAME_ACCESS);
00351
00352 if (!fSuccess) {
00353 #ifndef NDEBUG
00354 cerr << "DuplicateHandle failed\n";
00355 #endif
00356 CloseHandle(hChildStdoutRd);
00357 CloseHandle(hChildStdoutWr);
00358 return false;
00359 }
00360 CloseHandle(hChildStdoutRd);
00361
00362
00363
00364
00365
00366
00367 char *cmdline = new char[cmd.length() + 1];
00368 strcpy(cmdline, cmd.c_str());
00369
00370
00371
00372
00373 if (!WinExec(cmdline, 0)) {
00374 #ifndef NDEBUG
00375 cerr << "Unable to spawn process.\n";
00376 #endif
00377 close_pipe();
00378
00379 }
00380
00381 delete[] cmdline;
00382
00383
00384 if (!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) {
00385 #ifndef NDEBUG
00386 cerr << "Unable to restore stdout\n";
00387 #endif
00388 }
00389
00390
00391
00392 if (!CloseHandle(hChildStdoutWr)) {
00393 #ifndef NDEBUG
00394 cerr << "Unable to close write end of pipe\n";
00395 #endif
00396 }
00397
00398 return (_child_out != 0);
00399 }
00400
00401
00402
00403
00404
00405
00406 void PipeStreamBuf::
00407 close_pipe() {
00408 if (_child_out != 0) {
00409 CloseHandle(_child_out);
00410 _child_out = 0;
00411 }
00412 }
00413
00414
00415
00416
00417
00418
00419
00420 size_t PipeStreamBuf::
00421 write_pipe(const char *data, size_t len) {
00422 return 0;
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432 size_t PipeStreamBuf::
00433 read_pipe(char *data, size_t len) {
00434 if (_child_out == 0) {
00435 return 0;
00436 }
00437 DWORD dwRead;
00438 if (!ReadFile(_child_out, data, len, &dwRead, NULL)) {
00439 close_pipe();
00440 return 0;
00441 }
00442
00443 return dwRead;
00444 }
00445
00446
00447 #endif // WIN_PIPE_CALLS