Cary Sandvig 25 سال پیش
والد
کامیت
e7660fd47c
4فایلهای تغییر یافته به همراه123 افزوده شده و 89 حذف شده
  1. 4 3
      dtool/src/dtoolutil/Sources.pp
  2. 15 74
      dtool/src/dtoolutil/pfstream.h
  3. 85 8
      dtool/src/dtoolutil/pfstreamBuf.cxx
  4. 19 4
      dtool/src/dtoolutil/pfstreamBuf.h

+ 4 - 3
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

+ 15 - 74
dtool/src/dtoolutil/pfstream.h

@@ -6,87 +6,28 @@
 #ifndef __PFSTREAM_H__
 #define __PFSTREAM_H__
 
-#include <dtoolbase.h>
+#include "pfstreambuf.h"
 
-#include <string>
-#include <stdio.h>
+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__ */

+ 85 - 8
dtool/src/dtoolutil/pfstreamBuf.cxx

@@ -4,32 +4,55 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "pfstreamBuf.h"
+#include <assert.h>
 
 #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);
 }

+ 19 - 4
dtool/src/dtoolutil/pfstreamBuf.h

@@ -8,18 +8,33 @@
 
 #include <dtoolbase.h>
 #include <iostream>
+#include <string>
+#include <stdio.h>
 
-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__ */