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