diff --git a/dtool/src/dtoolutil/Sources.pp b/dtool/src/dtoolutil/Sources.pp index 0540a716c3..7be0aa6933 100644 --- a/dtool/src/dtoolutil/Sources.pp +++ b/dtool/src/dtoolutil/Sources.pp @@ -7,12 +7,13 @@ executionEnvironment.I executionEnvironment.cxx \ executionEnvironment.h filename.I filename.cxx filename.h \ load_dso.cxx load_dso.h dSearchPath.I dSearchPath.cxx \ - dSearchPath.h pfstream.h vector_string.cxx vector_string.h \ - gnu_getopt.c gnu_getopt.h gnu_getopt1.c + dSearchPath.h pfstream.h vector_string.cxx vector_string.h \ + gnu_getopt.c gnu_getopt.h gnu_getopt1.c pfstreamBuf.h pfstreamBuf.cxx #define INSTALL_HEADERS \ executionEnvironment.I executionEnvironment.h filename.I \ filename.h load_dso.h dSearchPath.I dSearchPath.h \ - pfstream.h vector_string.h gnu_getopt.h + pfstream.h pfstream.I vector_string.h gnu_getopt.h \ + pfstreamBuf.h #end lib_target diff --git a/dtool/src/dtoolutil/pfstream.h b/dtool/src/dtoolutil/pfstream.h index d51a2c10ba..ca08aedbac 100644 --- a/dtool/src/dtoolutil/pfstream.h +++ b/dtool/src/dtoolutil/pfstream.h @@ -6,87 +6,28 @@ #ifndef __PFSTREAM_H__ #define __PFSTREAM_H__ -#include +#include "pfstreambuf.h" -#include -#include +class EXPCL_DTOOL ipfstream : public istream { +PUBLISHED: + INLINE ipfstream(const string); -#ifdef WIN32_VC -#define popen _popen -#define pclose _pclose -#endif + INLINE void flush(void); +private: + PipeStreamBuf _psb; -class EXPCL_DTOOL ipfstream { - private: - ifstream *ifs; - FILE *fd; - bool ok; - - ipfstream() {} - ipfstream(const ipfstream&) {} - public: - ipfstream(std::string cmd, int mode = ios::in, int = 0664) : ok(false) { -#ifndef PENV_PS2 - fd = popen(cmd.c_str(), (mode & ios::in)?"r":"w"); - if (fd != (FILE *)0l) { -// this can't work under windows until this is re-written -#ifdef WIN32_VC - cerr << "ipfstream: this class needs to be rewritten for windows!" - << endl; -#else - ifs = new ifstream(fileno(fd)); -#endif // WIN32_VC - ok = true; - } -#endif // PENV_PS2 - } - - ~ipfstream() { -#ifndef PENV_PS2 - if (ok) { - pclose(fd); - delete ifs; - } -#endif // PENV_PS2 - } - - INLINE operator istream&() { - return *ifs; - } + INLINE ipfstream(void); }; -class EXPCL_DTOOL opfstream { - private: - ofstream *ofs; - FILE *fd; - bool ok; +class EXPCL_DTOOL opfstream : public ostream { +PUBLISHED: + INLINE opfstream(const string); - opfstream() {} - opfstream(const opfstream&) {} - public: - opfstream(std::string cmd, int mode = ios::out, int = 0664) : ok(false) { -#ifndef PENV_PS2 - fd = popen(cmd.c_str(), (mode & ios::out)?"w":"r"); - if (fd != (FILE *)0L) { -#ifndef WIN32_VC - ofs = new ofstream(fileno(fd)); -#endif - ok = true; - } -#endif // PENV_PS2 - } - ~opfstream() { -#ifndef PENV_PS2 - if (ok) { - pclose(fd); - delete ofs; - } -#endif - } + INLINE void flush(void); +private: + PipeStreamBuf _psb; - INLINE operator ostream&() { - return *ofs; - } + INLINE opfstream(void); }; #endif /* __PFSTREAM_H__ */ diff --git a/dtool/src/dtoolutil/pfstreamBuf.cxx b/dtool/src/dtoolutil/pfstreamBuf.cxx index cba92f109d..2756320e01 100644 --- a/dtool/src/dtoolutil/pfstreamBuf.cxx +++ b/dtool/src/dtoolutil/pfstreamBuf.cxx @@ -4,32 +4,55 @@ //////////////////////////////////////////////////////////////////// #include "pfstreamBuf.h" +#include #ifndef HAVE_STREAMSIZE // Some compilers (notably SGI) don't define this for us typedef int streamsize; #endif /* HAVE_STREAMSIZE */ -PipeStreamBuf::PipeStreamBuf(void) { +PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) : _dir(dir), + _pipe((FILE*)0L) { #ifndef WIN32_VC // taken from Dr. Ose. // These lines, which are essential on Irix and Linux, seem to be // unnecessary and not understood on Windows. allocate(); - setp(base(), ebuf()); + assert((dir == Input) || (dir == Output)); + if (dir == Input) { + cerr << "allocated reserve is " << blen() << " bytes long" << endl; + setg(base(), ebuf(), ebuf()); + } else { + setp(base(), ebuf()); + } #endif /* WIN32_VC */ } PipeStreamBuf::~PipeStreamBuf(void) { - sync(); - // any other cleanup needed (pclose, etc) + if (_pipe != (FILE*)0L) { + sync(); + flush(); + // any other cleanup needed (pclose, etc) + pclose(_pipe); + } } void PipeStreamBuf::flush(void) { - // if there's anything to do here + assert(_pipe != (FILE*)0L); + if (_dir == Output) { + write_chars("", 0, true); + } +} + +void PipeStreamBuf::command(const string cmd) { + assert(_pipe == (FILE*)0L); + const char *typ = (_dir == Output)?"w":"r"; + _pipe = popen(cmd.c_str(), typ); } int PipeStreamBuf::overflow(int c) { + assert(_pipe != (FILE*)0L); + assert(_dir == Output); streamsize n = pptr() - pbase(); if (n != 0) { write_chars(pbase(), n, false); @@ -44,11 +67,65 @@ int PipeStreamBuf::overflow(int c) { } int PipeStreamBuf::sync(void) { - streamsize n = pptr() - pbase(); - write_chars(pbase(), n, false); - pbump(-n); + assert(_pipe != (FILE*)0L); + if (_dir == Output) { + streamsize n = pptr() - pbase(); + write_chars(pbase(), n, false); + pbump(-n); + } else { + streamsize n = egptr() - gptr(); + gbump(n); // flush all our stored input away + cerr << "pfstream tossed out " << n << " bytes" << endl; + } return 0; } int PipeStreamBuf::underflow(void) { + assert(_pipe != (FILE*)0L); + assert(_dir == Input); + if (gptr() < egptr()) { + char c = *(gptr()); + return c; + } + if (feof(_pipe) != 0) + return EOF; + char* buf = new char[blen()]; + size_t n = fread(buf, 1, blen(), _pipe); + int ret = buf[0]; + if (n == 0) + ret = EOF; + else { + memcpy(base()+(blen() - n), buf, n); + gbump(-n); + } + delete buf; + return ret; +} + +void PipeStreamBuf::write_chars(const char* start, int length, bool flush) { + assert(_dir == Output); + size_t orig = _line_buffer.length(); + string latest(start, length); + string line; + + if (flush) { + // if we're going to flush the stream now, we dump the whole thing + // reguardless of whether we have reached end-of-line. + line = _line_buffer + latest; + _line_buffer = ""; + } else { + // Otherwise, we check for the end-of-line character. + _line_buffer += latest; + size_t eol = _line_buffer.rfind('\n', orig); + if (eol != string::npos) { + line = _line_buffer.substr(0, eol+1); + _line_buffer = _line_buffer.substr(eol+1); + } + } + // now output 'line' + size_t wrote = fwrite(line.c_str(), 1, line.length(), _pipe); + if (wrote != line.length()) + cerr << "wrote only " << wrote << " of " << line.length() + << " bytes to pipe" << endl; + fflush(_pipe); } diff --git a/dtool/src/dtoolutil/pfstreamBuf.h b/dtool/src/dtoolutil/pfstreamBuf.h index ecb9688f27..8d04469b41 100644 --- a/dtool/src/dtoolutil/pfstreamBuf.h +++ b/dtool/src/dtoolutil/pfstreamBuf.h @@ -8,18 +8,33 @@ #include #include +#include +#include -class EXPCL_PANDA PipeStreamBuf : public streambuf { +#ifdef WIN32_VC +#define popen _popen +#define pclose _pclose +#endif + +class EXPCL_DTOOL PipeStreamBuf : public streambuf { public: - PipeStreamBuf(void); + enum Direction { Input, Output }; + + PipeStreamBuf(Direction); virtual ~PipeStreamBuf(void); void flush(); + void command(const string); protected: virtual int overflow(int c); - virtual int sync(); - virtual int underflow(); + virtual int sync(void); + virtual int underflow(void); private: + Direction _dir; + string _line_buffer; + FILE* _pipe; + + void write_chars(const char*, int, bool); }; #endif /* __PFSTREAMBUF_H__ */