mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
WIN_PIPE_CALLS
This commit is contained in:
parent
8cf2629af5
commit
9f36acf15b
@ -24,8 +24,11 @@
|
||||
typedef int streamsize;
|
||||
#endif /* HAVE_STREAMSIZE */
|
||||
|
||||
PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) : _dir(dir),
|
||||
_pipe((FILE*)0L) {
|
||||
PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) :
|
||||
_dir(dir)
|
||||
{
|
||||
init_pipe();
|
||||
|
||||
#ifndef WIN32_VC
|
||||
// taken from Dr. Ose.
|
||||
// These lines, which are essential on Irix and Linux, seem to be
|
||||
@ -33,7 +36,6 @@ PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) : _dir(dir),
|
||||
allocate();
|
||||
assert((dir == Input) || (dir == Output));
|
||||
if (dir == Input) {
|
||||
// cerr << "allocated reserve is " << blen() << " bytes long" << endl;
|
||||
setg(base(), ebuf(), ebuf());
|
||||
} else {
|
||||
setp(base(), ebuf());
|
||||
@ -41,30 +43,29 @@ PipeStreamBuf::PipeStreamBuf(PipeStreamBuf::Direction dir) : _dir(dir),
|
||||
#endif /* WIN32_VC */
|
||||
}
|
||||
|
||||
PipeStreamBuf::~PipeStreamBuf(void) {
|
||||
if (_pipe != (FILE*)0L) {
|
||||
PipeStreamBuf::
|
||||
~PipeStreamBuf(void) {
|
||||
if (is_open()) {
|
||||
sync();
|
||||
flush();
|
||||
// any other cleanup needed (pclose, etc)
|
||||
pclose(_pipe);
|
||||
close_pipe();
|
||||
}
|
||||
}
|
||||
|
||||
void PipeStreamBuf::flush(void) {
|
||||
assert(_pipe != (FILE*)0L);
|
||||
assert(is_open());
|
||||
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);
|
||||
assert(!is_open());
|
||||
open_pipe(cmd);
|
||||
}
|
||||
|
||||
int PipeStreamBuf::overflow(int c) {
|
||||
assert(_pipe != (FILE*)0L);
|
||||
assert(is_open());
|
||||
assert(_dir == Output);
|
||||
streamsize n = pptr() - pbase();
|
||||
if (n != 0) {
|
||||
@ -80,7 +81,7 @@ int PipeStreamBuf::overflow(int c) {
|
||||
}
|
||||
|
||||
int PipeStreamBuf::sync(void) {
|
||||
assert(_pipe != (FILE*)0L);
|
||||
assert(is_open());
|
||||
if (_dir == Output) {
|
||||
streamsize n = pptr() - pbase();
|
||||
write_chars(pbase(), n, false);
|
||||
@ -89,14 +90,15 @@ int PipeStreamBuf::sync(void) {
|
||||
streamsize n = egptr() - gptr();
|
||||
if (n != 0) {
|
||||
gbump(n); // flush all our stored input away
|
||||
#ifndef NDEBUG
|
||||
cerr << "pfstream tossed out " << n << " bytes" << endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PipeStreamBuf::underflow(void) {
|
||||
assert(_pipe != (FILE*)0L);
|
||||
assert(_dir == Input);
|
||||
if ((eback() == (char*)0L) || (gptr() == (char*)0L) ||
|
||||
(egptr() == (char*)0L)) {
|
||||
@ -109,15 +111,16 @@ int PipeStreamBuf::underflow(void) {
|
||||
char c = *(gptr());
|
||||
return c;
|
||||
}
|
||||
if (feof(_pipe) != 0)
|
||||
if (eof_pipe()) {
|
||||
return EOF;
|
||||
}
|
||||
#ifdef WIN32_VC
|
||||
size_t len = 4096;
|
||||
#else /* WIN32_VC */
|
||||
size_t len = ebuf() - base();
|
||||
#endif /* WIN32_VC */
|
||||
char* buf = new char[len];
|
||||
size_t n = fread(buf, 1, len, _pipe);
|
||||
size_t n = read_pipe(buf, len);
|
||||
int ret = buf[0];
|
||||
if (n == 0)
|
||||
ret = EOF;
|
||||
@ -154,9 +157,303 @@ void PipeStreamBuf::write_chars(const char* start, int length, bool flush) {
|
||||
}
|
||||
}
|
||||
// now output 'line'
|
||||
size_t wrote = fwrite(line.c_str(), 1, line.length(), _pipe);
|
||||
size_t wrote = write_pipe(line.c_str(), line.length());
|
||||
#ifndef NDEBUG
|
||||
if (wrote != line.length())
|
||||
cerr << "wrote only " << wrote << " of " << line.length()
|
||||
<< " bytes to pipe" << endl;
|
||||
fflush(_pipe);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN_PIPE_CALLS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::init_pipe
|
||||
// Access: Private
|
||||
// Description: Initializes whatever data structures store the child
|
||||
// process information. This function is only called
|
||||
// once at startup, by the constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PipeStreamBuf::
|
||||
init_pipe() {
|
||||
_pipe = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::is_open
|
||||
// Access: Private
|
||||
// Description: Returns true if the pipe has been opened, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
is_open() const {
|
||||
return _pipe != NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::eof_pipe
|
||||
// Access: Private
|
||||
// Description: Returns true if there is an end-of-file condition on
|
||||
// the input, or if the pipe was never opened.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
eof_pipe() const {
|
||||
return (_pipe == NULL) && feof(_pipe);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::open_pipe
|
||||
// Access: Private
|
||||
// Description: Forks a child to run the indicated command, and
|
||||
// according to the setting of _dir, binds either its
|
||||
// input or output to this process for writing or
|
||||
// reading.
|
||||
//
|
||||
// Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
open_pipe(const string &cmd) {
|
||||
const char *typ = (_dir == Output)?"w":"r";
|
||||
_pipe = popen(cmd.c_str(), typ);
|
||||
return (_pipe != NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::close_pipe
|
||||
// Access: Private
|
||||
// Description: Closes the pipe opened previously.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PipeStreamBuf::
|
||||
close_pipe() {
|
||||
if (_pipe != NULL) {
|
||||
fclose(_pipe);
|
||||
_pipe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::write_pipe
|
||||
// Access: Private
|
||||
// Description: Writes the indicated data out to the child process
|
||||
// opened previously. Returns the number of bytes read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t PipeStreamBuf::
|
||||
write_pipe(const char *data, size_t len) {
|
||||
size_t wrote_count = fwrite(data, 1, len, _pipe);
|
||||
fflush(_pipe);
|
||||
return wrote_count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::read_pipe
|
||||
// Access: Private
|
||||
// Description: Reads the indicated amount of data from the child
|
||||
// process opened previously. Returns the number of
|
||||
// bytes read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t PipeStreamBuf::
|
||||
read_pipe(char *data, size_t len) {
|
||||
return fread(data, 1, len, _pipe);
|
||||
}
|
||||
|
||||
#else // WIN_PIPE_CALLS
|
||||
|
||||
// The official Windows way of reading from a child process, without
|
||||
// using a Unix-style convenience function like popen(), is similar in
|
||||
// principle to the Unix pipe() method. We have to first redirect our
|
||||
// own stdout to an anonymous pipe, then we spawn a child, who
|
||||
// inherits this new stdout. Then we can restore our own stdout, and
|
||||
// read from the other end of the pipe.
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::init_pipe
|
||||
// Access: Private
|
||||
// Description: Initializes whatever data structures store the child
|
||||
// process information. This function is only called
|
||||
// once at startup, by the constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PipeStreamBuf::
|
||||
init_pipe() {
|
||||
_child_out = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::is_open
|
||||
// Access: Private
|
||||
// Description: Returns true if the pipe has been opened, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
is_open() const {
|
||||
return (_child_out != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::eof_pipe
|
||||
// Access: Private
|
||||
// Description: Returns true if there is an end-of-file condition on
|
||||
// the input, or if the pipe was never opened.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
eof_pipe() const {
|
||||
return (_child_out == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::open_pipe
|
||||
// Access: Private
|
||||
// Description: Forks a child to run the indicated command, and
|
||||
// according to the setting of _dir, binds either its
|
||||
// input or output to this process for writing or
|
||||
// reading.
|
||||
//
|
||||
// Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PipeStreamBuf::
|
||||
open_pipe(const string &cmd) {
|
||||
close_pipe();
|
||||
|
||||
// At the present, this only works for input pipes. We can add code
|
||||
// to support output pipes later if anyone cares.
|
||||
if (_dir == Output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, save our current stdout, so we can restore it after all of
|
||||
// this nonsense.
|
||||
HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// Now create a pipe to accept the child processes' output.
|
||||
HANDLE hChildStdoutRd, hChildStdoutWr;
|
||||
|
||||
// Set the bInheritHandle flag so pipe handles are inherited.
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "Unable to create output pipe\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remap stdout to the "write" end of this pipe.
|
||||
if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "Unable to redirect stdout\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create noninheritable read handle and close the inheritable read
|
||||
// handle.
|
||||
|
||||
BOOL fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
|
||||
GetCurrentProcess(), &_child_out,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
if (!fSuccess) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "DuplicateHandle failed\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
CloseHandle(hChildStdoutRd);
|
||||
|
||||
// Now spawn the child process.
|
||||
|
||||
PROCESS_INFORMATION piProcInfo;
|
||||
STARTUPINFO siStartInfo;
|
||||
|
||||
// Set up members of the PROCESS_INFORMATION structure.
|
||||
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
// Set up members of the STARTUPINFO structure.
|
||||
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
||||
siStartInfo.cb = sizeof(STARTUPINFO);
|
||||
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
siStartInfo.hStdError = hChildStdoutWr;
|
||||
siStartInfo.hStdInput = (HANDLE)STD_INPUT_HANDLE;
|
||||
siStartInfo.hStdOutput = hChildStdoutWr;
|
||||
|
||||
if (!CreateProcess(NULL,
|
||||
(LPSTR)cmd.c_str(), // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo)) {// receives PROCESS_INFORMATION
|
||||
#ifndef NDEBUG
|
||||
cerr << "Unable to spawn process.\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now restore our own stdout, up here in the parent process.
|
||||
if (!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "Unable to restore stdout\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close the write end of the pipe before reading from the
|
||||
// read end of the pipe.
|
||||
if (!CloseHandle(hChildStdoutWr)) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "Unable to close write end of pipe\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::close_pipe
|
||||
// Access: Private
|
||||
// Description: Closes the pipe opened previously.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PipeStreamBuf::
|
||||
close_pipe() {
|
||||
if (_child_out != 0) {
|
||||
CloseHandle(_child_out);
|
||||
_child_out = 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::write_pipe
|
||||
// Access: Private
|
||||
// Description: Writes the indicated data out to the child process
|
||||
// opened previously. Returns the number of bytes read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t PipeStreamBuf::
|
||||
write_pipe(const char *data, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PipeStreamBuf::read_pipe
|
||||
// Access: Private
|
||||
// Description: Reads the indicated amount of data from the child
|
||||
// process opened previously. Returns the number of
|
||||
// bytes read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t PipeStreamBuf::
|
||||
read_pipe(char *data, size_t len) {
|
||||
DWORD dwRead;
|
||||
if (!ReadFile(_child_out, data, len, &dwRead, NULL)) {
|
||||
close_pipe();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dwRead;
|
||||
}
|
||||
|
||||
|
||||
#endif // WIN_PIPE_CALLS
|
||||
|
@ -23,11 +23,26 @@
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
|
||||
// By default, we'll use the Windows flavor of pipe functions if we're
|
||||
// compiling under Windows. Turn this off to use popen(), even on
|
||||
// Windows. (popen() doesn't seem to work on Win9x, although it does
|
||||
// work on NT-based variants.)
|
||||
#ifdef WIN32_VC
|
||||
#define WIN_PIPE_CALLS 1
|
||||
#endif
|
||||
|
||||
#ifdef WIN_PIPE_CALLS
|
||||
#include <windows.h>
|
||||
|
||||
#else // WIN_PIPE_CALLS
|
||||
|
||||
#ifdef WIN32_VC
|
||||
#define popen _popen
|
||||
#define pclose _pclose
|
||||
#endif
|
||||
|
||||
#endif // WIN_PIPE_CALLS
|
||||
|
||||
class EXPCL_DTOOL PipeStreamBuf : public streambuf {
|
||||
public:
|
||||
enum Direction { Input, Output };
|
||||
@ -37,14 +52,29 @@ public:
|
||||
|
||||
void flush();
|
||||
void command(const string);
|
||||
|
||||
protected:
|
||||
virtual int overflow(int c);
|
||||
virtual int sync(void);
|
||||
virtual int underflow(void);
|
||||
private:
|
||||
void init_pipe();
|
||||
bool is_open() const;
|
||||
bool eof_pipe() const;
|
||||
bool open_pipe(const string &cmd);
|
||||
void close_pipe();
|
||||
size_t write_pipe(const char *data, size_t len);
|
||||
size_t read_pipe(char *data, size_t len);
|
||||
|
||||
Direction _dir;
|
||||
string _line_buffer;
|
||||
FILE* _pipe;
|
||||
|
||||
#ifndef WIN_PIPE_CALLS
|
||||
FILE *_pipe;
|
||||
|
||||
#else // WIN_PIPE_CALLS
|
||||
HANDLE _child_out;
|
||||
#endif // WIN_PIPE_CALLS
|
||||
|
||||
void write_chars(const char*, int, bool);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user