mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-05 19:34:18 -04:00
bi-directional communication
This commit is contained in:
parent
3f42a08968
commit
ce182cb038
@ -6,6 +6,7 @@ from LoggerGlobal import defaultLogger
|
|||||||
from direct.showbase import PythonUtil
|
from direct.showbase import PythonUtil
|
||||||
import time
|
import time
|
||||||
import types
|
import types
|
||||||
|
import sys
|
||||||
|
|
||||||
class Notifier:
|
class Notifier:
|
||||||
serverDelta = 0
|
serverDelta = 0
|
||||||
@ -237,7 +238,7 @@ class Notifier:
|
|||||||
if self.streamWriter:
|
if self.streamWriter:
|
||||||
self.streamWriter.appendData(string + '\n')
|
self.streamWriter.appendData(string + '\n')
|
||||||
else:
|
else:
|
||||||
print string
|
print >> sys.stderr, string
|
||||||
|
|
||||||
def debugStateCall(self, obj=None, fsmMemberName='fsm',
|
def debugStateCall(self, obj=None, fsmMemberName='fsm',
|
||||||
secondaryFsm='secondaryFSM'):
|
secondaryFsm='secondaryFSM'):
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#define USE_PACKAGES tinyxml python
|
#define USE_PACKAGES tinyxml python
|
||||||
#define TARGET p3dpython
|
#define TARGET p3dpython
|
||||||
|
|
||||||
#define OTHER_LIBS \
|
#define OTHER_LIBS \
|
||||||
dtoolutil:c dtoolbase:c dtool:m \
|
dtoolutil:c dtoolbase:c dtool:m \
|
||||||
interrogatedb:c dconfig:c dtoolconfig:m \
|
interrogatedb:c dconfig:c dtoolconfig:m \
|
||||||
express:c pandaexpress:m \
|
express:c pandaexpress:m \
|
||||||
@ -51,11 +51,19 @@
|
|||||||
#end bin_target
|
#end bin_target
|
||||||
|
|
||||||
#begin bin_target
|
#begin bin_target
|
||||||
|
#define USE_PACKAGES openssl
|
||||||
#define TARGET panda3d
|
#define TARGET panda3d
|
||||||
|
|
||||||
|
#define OTHER_LIBS \
|
||||||
|
prc:c dtoolutil:c dtoolbase:c dtool:m \
|
||||||
|
interrogatedb:c dconfig:c dtoolconfig:m \
|
||||||
|
express:c pandaexpress:m \
|
||||||
|
pstatclient:c pandabase:c linmath:c putil:c \
|
||||||
|
pipeline:c panda:m \
|
||||||
|
pystub
|
||||||
|
|
||||||
#define SOURCES \
|
#define SOURCES \
|
||||||
panda3d.cxx \
|
panda3d.cxx
|
||||||
$[if $[WINDOWS_PLATFORM],wingetopt.h wingetopt.c]
|
|
||||||
|
|
||||||
#define WIN_SYS_LIBS user32.lib gdi32.lib
|
#define WIN_SYS_LIBS user32.lib gdi32.lib
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ write_chars(const char *start, size_t length) {
|
|||||||
BOOL success = WriteFile(_handle, start, length, &bytes_written, NULL);
|
BOOL success = WriteFile(_handle, start, length, &bytes_written, NULL);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
DWORD error = GetLastError();
|
DWORD error = GetLastError();
|
||||||
if (error != ERROR_BROKEN_PIPE) {
|
if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) {
|
||||||
cerr
|
cerr
|
||||||
<< "Error writing " << length
|
<< "Error writing " << length
|
||||||
<< " bytes, windows error code 0x" << hex
|
<< " bytes, windows error code 0x" << hex
|
||||||
|
@ -153,6 +153,7 @@ get_request() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DInstance::
|
void P3DInstance::
|
||||||
add_request(P3D_request *request) {
|
add_request(P3D_request *request) {
|
||||||
|
cerr << "adding a request\n";
|
||||||
assert(request->_instance == this);
|
assert(request->_instance == this);
|
||||||
|
|
||||||
ACQUIRE_LOCK(_request_lock);
|
ACQUIRE_LOCK(_request_lock);
|
||||||
|
@ -23,14 +23,3 @@ INLINE int P3DInstanceManager::
|
|||||||
get_num_instances() const {
|
get_num_instances() const {
|
||||||
return _instances.size();
|
return _instances.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: P3DInstanceManager::get_dll_filename
|
|
||||||
// Access: Public
|
|
||||||
// Description: Returns the DLL filename that was passed to
|
|
||||||
// initialize().
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE const string &P3DInstanceManager::
|
|
||||||
get_dll_filename() const {
|
|
||||||
return _dll_filename;
|
|
||||||
}
|
|
||||||
|
@ -46,15 +46,13 @@ P3DInstanceManager::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DInstanceManager::initialize
|
// Function: P3DInstanceManager::initialize
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Called by the host at application startup, this
|
// Description: Called by the host at application startup. It
|
||||||
// receives the name of the DLL that contains this code
|
// returns true if the DLL is successfully initialized,
|
||||||
// (for patching purposes). It returns true if the DLL
|
// false if it should be immediately shut down and
|
||||||
// is successfully initialized, false if it should be
|
// redownloaded.
|
||||||
// immediately shut down and redownloaded.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool P3DInstanceManager::
|
bool P3DInstanceManager::
|
||||||
initialize(const string &config_xml, const string &dll_filename) {
|
initialize() {
|
||||||
_dll_filename = dll_filename;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ private:
|
|||||||
~P3DInstanceManager();
|
~P3DInstanceManager();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool initialize(const string &config_xml, const string &dll_filename);
|
bool initialize();
|
||||||
|
|
||||||
P3DInstance *
|
P3DInstance *
|
||||||
create_instance(P3D_request_ready_func *func,
|
create_instance(P3D_request_ready_func *func,
|
||||||
@ -53,15 +53,12 @@ public:
|
|||||||
|
|
||||||
INLINE int get_num_instances() const;
|
INLINE int get_num_instances() const;
|
||||||
|
|
||||||
INLINE const string &get_dll_filename() const;
|
|
||||||
|
|
||||||
int get_unique_session_index();
|
int get_unique_session_index();
|
||||||
void signal_request_ready();
|
void signal_request_ready();
|
||||||
|
|
||||||
static P3DInstanceManager *get_global_ptr();
|
static P3DInstanceManager *get_global_ptr();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string _dll_filename;
|
|
||||||
string _p3d_root_directory;
|
string _p3d_root_directory;
|
||||||
|
|
||||||
typedef set<P3DInstance *> Instances;
|
typedef set<P3DInstance *> Instances;
|
||||||
|
@ -103,16 +103,17 @@ run_python() {
|
|||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_exit = PyObject_GetAttrString(appmf, "exit");
|
|
||||||
if (_exit == NULL) {
|
|
||||||
PyErr_Print();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
|
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
|
||||||
if (_setupWindow == NULL) {
|
if (_setupWindow == NULL) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
|
||||||
|
if (_taskMgr == NULL) {
|
||||||
|
PyErr_Print();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Py_DECREF(appmf);
|
Py_DECREF(appmf);
|
||||||
|
|
||||||
// Now add check_comm() as a task.
|
// Now add check_comm() as a task.
|
||||||
@ -121,14 +122,8 @@ run_python() {
|
|||||||
task_mgr->add(_check_comm_task);
|
task_mgr->add(_check_comm_task);
|
||||||
|
|
||||||
// Finally, get lost in taskMgr.run().
|
// Finally, get lost in taskMgr.run().
|
||||||
|
|
||||||
PyObject *taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
|
|
||||||
if (taskMgr == NULL) {
|
|
||||||
PyErr_Print();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cerr << "calling run()\n";
|
cerr << "calling run()\n";
|
||||||
PyObject *done = PyObject_CallMethod(taskMgr, "run", "");
|
PyObject *done = PyObject_CallMethod(_taskMgr, "run", "");
|
||||||
if (done == NULL) {
|
if (done == NULL) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
@ -136,8 +131,6 @@ run_python() {
|
|||||||
Py_DECREF(done);
|
Py_DECREF(done);
|
||||||
cerr << "done calling run()\n";
|
cerr << "done calling run()\n";
|
||||||
|
|
||||||
Py_DECREF(taskMgr);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +158,8 @@ handle_command(TiXmlDocument *doc) {
|
|||||||
if (xcommand->Attribute("id", &id)) {
|
if (xcommand->Attribute("id", &id)) {
|
||||||
terminate_instance(id);
|
terminate_instance(id);
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(cmd, "exit") == 0) {
|
||||||
|
terminate_session();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Unhandled command " << cmd << "\n";
|
cerr << "Unhandled command " << cmd << "\n";
|
||||||
@ -251,6 +246,7 @@ void P3DPythonRun::
|
|||||||
join_read_thread() {
|
join_read_thread() {
|
||||||
cerr << "waiting for thread\n";
|
cerr << "waiting for thread\n";
|
||||||
_read_thread_continue = false;
|
_read_thread_continue = false;
|
||||||
|
_pipe_read.close();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
assert(_read_thread != NULL);
|
assert(_read_thread != NULL);
|
||||||
@ -346,11 +342,14 @@ terminate_session() {
|
|||||||
}
|
}
|
||||||
_instances.clear();
|
_instances.clear();
|
||||||
|
|
||||||
PyObject *result = PyObject_CallFunction(_exit, "");
|
cerr << "calling stop()\n";
|
||||||
|
PyObject *result = PyObject_CallMethod(_taskMgr, "stop", "");
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Py_XDECREF(result);
|
Py_DECREF(result);
|
||||||
|
cerr << "done calling stop()\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -372,7 +371,21 @@ rt_thread_run() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Successfully read an XML document. Feed it to the parent.
|
// Successfully read an XML document.
|
||||||
|
|
||||||
|
// Check for one special case: the "exit" command means we shut
|
||||||
|
// down the read thread along with everything else.
|
||||||
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
|
if (xcommand != NULL) {
|
||||||
|
const char *cmd = xcommand->Attribute("cmd");
|
||||||
|
if (cmd != NULL) {
|
||||||
|
if (strcmp(cmd, "exit") == 0) {
|
||||||
|
_read_thread_continue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed the command up to the parent.
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
_commands.push_back(doc);
|
_commands.push_back(doc);
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
|
@ -90,8 +90,8 @@ private:
|
|||||||
char **_py_argv;
|
char **_py_argv;
|
||||||
|
|
||||||
PyObject *_runPackedApp;
|
PyObject *_runPackedApp;
|
||||||
PyObject *_exit;
|
|
||||||
PyObject *_setupWindow;
|
PyObject *_setupWindow;
|
||||||
|
PyObject *_taskMgr;
|
||||||
|
|
||||||
PT(GenericAsyncTask) _check_comm_task;
|
PT(GenericAsyncTask) _check_comm_task;
|
||||||
|
|
||||||
|
@ -34,6 +34,10 @@ P3DSession(P3DInstance *inst) {
|
|||||||
_python_version = inst->get_python_version();
|
_python_version = inst->get_python_version();
|
||||||
_python_root_dir = "C:/p3drun";
|
_python_root_dir = "C:/p3drun";
|
||||||
|
|
||||||
|
INIT_LOCK(_instances_lock);
|
||||||
|
|
||||||
|
_read_thread_continue = false;
|
||||||
|
|
||||||
string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
|
string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
|
||||||
// string p3dpython = _python_root_dir + "/p3dpython.exe";
|
// string p3dpython = _python_root_dir + "/p3dpython.exe";
|
||||||
|
|
||||||
@ -122,12 +126,15 @@ P3DSession(P3DInstance *inst) {
|
|||||||
_pipe_read.open_read(r_from);
|
_pipe_read.open_read(r_from);
|
||||||
_pipe_write.open_write(w_to);
|
_pipe_write.open_write(w_to);
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
if (!_pipe_read) {
|
if (!_pipe_read) {
|
||||||
cerr << "unable to open read pipe\n";
|
cerr << "unable to open read pipe\n";
|
||||||
}
|
}
|
||||||
if (!_pipe_write) {
|
if (!_pipe_write) {
|
||||||
cerr << "unable to open write pipe\n";
|
cerr << "unable to open write pipe\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spawn_read_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -139,13 +146,34 @@ P3DSession(P3DInstance *inst) {
|
|||||||
P3DSession::
|
P3DSession::
|
||||||
~P3DSession() {
|
~P3DSession() {
|
||||||
if (_started_p3dpython) {
|
if (_started_p3dpython) {
|
||||||
|
// Tell the process we're going away.
|
||||||
|
TiXmlDocument doc;
|
||||||
|
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
|
||||||
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
|
xcommand->SetAttribute("cmd", "exit");
|
||||||
|
doc.LinkEndChild(decl);
|
||||||
|
doc.LinkEndChild(xcommand);
|
||||||
|
_pipe_write << doc << flush;
|
||||||
|
|
||||||
|
// Also close the pipe, to help underscore the point.
|
||||||
|
_pipe_write.close();
|
||||||
|
_pipe_read.close();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Now give the process a chance to terminate itself cleanly.
|
||||||
|
if (WaitForSingleObject(_p3dpython.hProcess, 2000) == WAIT_TIMEOUT) {
|
||||||
|
// It didn't shut down cleanly, so kill it the hard way.
|
||||||
cerr << "Terminating process.\n";
|
cerr << "Terminating process.\n";
|
||||||
// Messy. Shouldn't use TerminateProcess unless necessary.
|
|
||||||
TerminateProcess(_p3dpython.hProcess, 2);
|
TerminateProcess(_p3dpython.hProcess, 2);
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(_p3dpython.hProcess);
|
CloseHandle(_p3dpython.hProcess);
|
||||||
CloseHandle(_p3dpython.hThread);
|
CloseHandle(_p3dpython.hThread);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
join_read_thread();
|
||||||
|
DESTROY_LOCK(_instances_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -164,8 +192,10 @@ start_instance(P3DInstance *inst) {
|
|||||||
assert(inst->get_session_key() == _session_key);
|
assert(inst->get_session_key() == _session_key);
|
||||||
assert(inst->get_python_version() == _python_version);
|
assert(inst->get_python_version() == _python_version);
|
||||||
|
|
||||||
|
ACQUIRE_LOCK(_instances_lock);
|
||||||
inst->_session = this;
|
inst->_session = this;
|
||||||
bool inserted = _instances.insert(inst).second;
|
bool inserted = _instances.insert(Instances::value_type(inst->get_instance_id(), inst)).second;
|
||||||
|
RELEASE_LOCK(_instances_lock);
|
||||||
assert(inserted);
|
assert(inserted);
|
||||||
|
|
||||||
TiXmlDocument doc;
|
TiXmlDocument doc;
|
||||||
@ -201,8 +231,118 @@ terminate_instance(P3DInstance *inst) {
|
|||||||
|
|
||||||
_pipe_write << doc << flush;
|
_pipe_write << doc << flush;
|
||||||
|
|
||||||
|
ACQUIRE_LOCK(_instances_lock);
|
||||||
if (inst->_session == this) {
|
if (inst->_session == this) {
|
||||||
inst->_session = NULL;
|
inst->_session = NULL;
|
||||||
_instances.erase(inst);
|
_instances.erase(inst->get_instance_id());
|
||||||
|
}
|
||||||
|
RELEASE_LOCK(_instances_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::spawn_read_thread
|
||||||
|
// Access: Private
|
||||||
|
// Description: Starts the read thread. This thread is responsible
|
||||||
|
// for reading the standard input socket for XML
|
||||||
|
// requests and storing them in the _requests queue.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSession::
|
||||||
|
spawn_read_thread() {
|
||||||
|
assert(!_read_thread_continue);
|
||||||
|
|
||||||
|
// We have to use direct OS calls to create the thread instead of
|
||||||
|
// Panda constructs, because it has to be an actual thread, not
|
||||||
|
// necessarily a Panda thread (we can't use Panda's simple threads
|
||||||
|
// implementation, because we can't get overlapped I/O on an
|
||||||
|
// anonymous pipe in Windows).
|
||||||
|
|
||||||
|
_read_thread_continue = true;
|
||||||
|
#ifdef _WIN32
|
||||||
|
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::join_read_thread
|
||||||
|
// Access: Private
|
||||||
|
// Description: Waits for the read thread to stop.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSession::
|
||||||
|
join_read_thread() {
|
||||||
|
cerr << "session waiting for thread\n";
|
||||||
|
_read_thread_continue = false;
|
||||||
|
_pipe_read.close();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
assert(_read_thread != NULL);
|
||||||
|
WaitForSingleObject(_read_thread, INFINITE);
|
||||||
|
CloseHandle(_read_thread);
|
||||||
|
_read_thread = NULL;
|
||||||
|
#endif
|
||||||
|
cerr << "session done waiting for thread\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::rt_thread_run
|
||||||
|
// Access: Private
|
||||||
|
// Description: The main function for the read thread.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSession::
|
||||||
|
rt_thread_run() {
|
||||||
|
cerr << "session thread reading.\n";
|
||||||
|
while (_read_thread_continue) {
|
||||||
|
TiXmlDocument *doc = new TiXmlDocument;
|
||||||
|
|
||||||
|
_pipe_read >> *doc;
|
||||||
|
if (!_pipe_read || _pipe_read.eof()) {
|
||||||
|
// Some error on reading. Abort.
|
||||||
|
cerr << "Error on session reading.\n";
|
||||||
|
rt_terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully read an XML document.
|
||||||
|
cerr << "Session got request: " << *doc << "\n";
|
||||||
|
|
||||||
|
// TODO: feed the request up to the parent.
|
||||||
|
delete doc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::rt_terminate
|
||||||
|
// Access: Private
|
||||||
|
// Description: Got a closed pipe from the sub-process. Send a
|
||||||
|
// terminate request for all instances.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSession::
|
||||||
|
rt_terminate() {
|
||||||
|
Instances icopy;
|
||||||
|
ACQUIRE_LOCK(_instances_lock);
|
||||||
|
icopy = _instances;
|
||||||
|
RELEASE_LOCK(_instances_lock);
|
||||||
|
|
||||||
|
// TODO: got a race condition here. What happens if someone deletes
|
||||||
|
// an instance while we're processing this loop?
|
||||||
|
|
||||||
|
for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
|
||||||
|
P3DInstance *inst = (*ii).second;
|
||||||
|
P3D_request *request = new P3D_request;
|
||||||
|
request->_instance = inst;
|
||||||
|
request->_request_type = P3D_RT_stop;
|
||||||
|
inst->add_request(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPython::win_rt_thread_run
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: The Windows flavor of the thread callback function.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
DWORD P3DSession::
|
||||||
|
win_rt_thread_run(LPVOID data) {
|
||||||
|
((P3DSession *)data)->rt_thread_run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -42,22 +42,43 @@ public:
|
|||||||
|
|
||||||
INLINE int get_num_instances() const;
|
INLINE int get_num_instances() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void spawn_read_thread();
|
||||||
|
void join_read_thread();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// These methods run only within the read thread.
|
||||||
|
void rt_thread_run();
|
||||||
|
void rt_terminate();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static DWORD WINAPI win_rt_thread_run(LPVOID data);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string _session_key;
|
string _session_key;
|
||||||
string _python_version;
|
string _python_version;
|
||||||
|
|
||||||
string _python_root_dir;
|
string _python_root_dir;
|
||||||
|
|
||||||
typedef set<P3DInstance *> Instances;
|
typedef map<int, P3DInstance *> Instances;
|
||||||
Instances _instances;
|
Instances _instances;
|
||||||
|
LOCK _instances_lock;
|
||||||
|
|
||||||
// Members for communicating with the p3dpython child process.
|
// Members for communicating with the p3dpython child process.
|
||||||
bool _started_p3dpython;
|
bool _started_p3dpython;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
PROCESS_INFORMATION _p3dpython;
|
PROCESS_INFORMATION _p3dpython;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The remaining members are manipulated by the read thread.
|
||||||
HandleStream _pipe_read;
|
HandleStream _pipe_read;
|
||||||
HandleStream _pipe_write;
|
HandleStream _pipe_write;
|
||||||
|
|
||||||
|
bool _read_thread_continue;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE _read_thread;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "p3dSession.I"
|
#include "p3dSession.I"
|
||||||
|
@ -23,24 +23,14 @@ bool initialized_lock = false;
|
|||||||
LOCK _lock;
|
LOCK _lock;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
P3D_initialize(const char *config_xml, const char *dll_filename) {
|
P3D_initialize() {
|
||||||
string config_xml_str;
|
|
||||||
if (config_xml != NULL) {
|
|
||||||
config_xml_str = config_xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
string dll_filename_str;
|
|
||||||
if (dll_filename != NULL) {
|
|
||||||
dll_filename_str = dll_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!initialized_lock) {
|
if (!initialized_lock) {
|
||||||
INIT_LOCK(_lock);
|
INIT_LOCK(_lock);
|
||||||
initialized_lock = true;
|
initialized_lock = true;
|
||||||
}
|
}
|
||||||
ACQUIRE_LOCK(_lock);
|
ACQUIRE_LOCK(_lock);
|
||||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||||
bool result = inst_mgr->initialize(config_xml_str, dll_filename_str);
|
bool result = inst_mgr->initialize();
|
||||||
RELEASE_LOCK(_lock);
|
RELEASE_LOCK(_lock);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -74,22 +74,14 @@ extern "C" {
|
|||||||
to being specific to a particular instance. */
|
to being specific to a particular instance. */
|
||||||
|
|
||||||
/* This function should be called immediately after the plugin is
|
/* This function should be called immediately after the plugin is
|
||||||
loaded. The config_xml parameter is the plugin configuration data,
|
loaded.
|
||||||
formatted as an XML stream (it contains the XML data itself; it is
|
|
||||||
not a filename). The exact contents of this XML stream are
|
|
||||||
documented elsewhere. This config_xml parameter may be the empty
|
|
||||||
string or NULL; if so, the plugin will use its own internal default
|
|
||||||
configuration.
|
|
||||||
|
|
||||||
The dll_filename parameter is the filename of the plugin's dll
|
|
||||||
itself, which is needed for self-patching.
|
|
||||||
|
|
||||||
This function returns true if the plugin is valid, false otherwise.
|
This function returns true if the plugin is valid, false otherwise.
|
||||||
If it returns false, the host should not call any more functions in
|
If it returns false, the host should not call any more functions in
|
||||||
this API, and should immediately unload the DLL and (if possible)
|
this API, and should immediately unload the DLL and (if possible)
|
||||||
download a new one. */
|
download a new one. */
|
||||||
typedef bool
|
typedef bool
|
||||||
P3D_initialize_func(const char *config_xml, const char *dll_filename);
|
P3D_initialize_func();
|
||||||
|
|
||||||
/* This function frees a pointer returned by
|
/* This function frees a pointer returned by
|
||||||
P3D_instance_get_property(), or another similar function that
|
P3D_instance_get_property(), or another similar function that
|
||||||
@ -266,7 +258,6 @@ P3D_instance_set_property_func(P3D_instance *instance,
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
P3D_RT_stop,
|
P3D_RT_stop,
|
||||||
P3D_RT_new_config_xml,
|
P3D_RT_new_config_xml,
|
||||||
P3D_RT_patch,
|
|
||||||
P3D_RT_get_url,
|
P3D_RT_get_url,
|
||||||
P3D_RT_post_url,
|
P3D_RT_post_url,
|
||||||
} P3D_request_type;
|
} P3D_request_type;
|
||||||
@ -291,16 +282,6 @@ typedef struct {
|
|||||||
const char *_config_xml;
|
const char *_config_xml;
|
||||||
} P3D_request_new_config_xml;
|
} P3D_request_new_config_xml;
|
||||||
|
|
||||||
/* A patch request. The plugin has determined that it is out of date
|
|
||||||
and needs to be patched. It has already applied the patch to
|
|
||||||
itself, and the resulting patched dll is referenced in the request
|
|
||||||
data. The host should respond by finishing all active instances,
|
|
||||||
unloading the DLL, moving the patched dll onto the original DLL,
|
|
||||||
and reloading the DLL and (optionally) restarting the instances. */
|
|
||||||
typedef struct {
|
|
||||||
const char *_patched_filename;
|
|
||||||
} P3D_request_patch;
|
|
||||||
|
|
||||||
/* A get_url request. The plugin would like to retrieve data for a
|
/* A get_url request. The plugin would like to retrieve data for a
|
||||||
particular URL. The plugin is responsible for supplying a valid
|
particular URL. The plugin is responsible for supplying a valid
|
||||||
URL string, and a unique integer ID. The unique ID is needed to
|
URL string, and a unique integer ID. The unique ID is needed to
|
||||||
@ -334,7 +315,6 @@ typedef struct {
|
|||||||
union {
|
union {
|
||||||
P3D_request_stop _stop;
|
P3D_request_stop _stop;
|
||||||
P3D_request_new_config_xml _new_config_xml;
|
P3D_request_new_config_xml _new_config_xml;
|
||||||
P3D_request_patch _patch;
|
|
||||||
P3D_request_get_url _get_url;
|
P3D_request_get_url _get_url;
|
||||||
P3D_request_post_url _post_url;
|
P3D_request_post_url _post_url;
|
||||||
} _request;
|
} _request;
|
||||||
|
@ -12,20 +12,34 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "p3d_plugin.h"
|
// This program must link with Panda for HTTPClient support. This
|
||||||
|
// means it probably should be built with LINK_ALL_STATIC defined, so
|
||||||
|
// we won't have to deal with confusing .dll or .so files that might
|
||||||
|
// compete on the disk with the dynamically-loaded versions. There's
|
||||||
|
// no competition in memory address space, though, because
|
||||||
|
// p3d_plugin--the only file we dynamically link in--doesn't itself
|
||||||
|
// link with Panda.
|
||||||
|
|
||||||
#include <iostream>
|
#include "pandabase.h"
|
||||||
#include <string>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "wingetopt.h"
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
|
||||||
#include <getopt.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
#include "httpClient.h"
|
||||||
|
#include "httpChannel.h"
|
||||||
|
#include "Ramfile.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "p3d_plugin.h"
|
||||||
|
#include "pset.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_GETOPT
|
||||||
|
#include "gnu_getopt.h"
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_GETOPT_H
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static const string default_plugin_filename = "libp3d_plugin";
|
static const string default_plugin_filename = "libp3d_plugin";
|
||||||
|
|
||||||
@ -41,9 +55,88 @@ P3D_check_request_func *P3D_check_request;
|
|||||||
P3D_request_finish_func *P3D_request_finish;
|
P3D_request_finish_func *P3D_request_finish;
|
||||||
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
||||||
|
|
||||||
|
typedef pset<P3D_instance *> Instances;
|
||||||
|
Instances _instances;
|
||||||
|
|
||||||
|
class URLGetterThread : public Thread {
|
||||||
|
public:
|
||||||
|
URLGetterThread(P3D_instance *instance,
|
||||||
|
int unique_id,
|
||||||
|
const URLSpec &url,
|
||||||
|
const string &post_data);
|
||||||
|
protected:
|
||||||
|
virtual void thread_main();
|
||||||
|
|
||||||
|
private:
|
||||||
|
P3D_instance *_instance;
|
||||||
|
int _unique_id;
|
||||||
|
URLSpec _url;
|
||||||
|
string _post_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
URLGetterThread::
|
||||||
|
URLGetterThread(P3D_instance *instance,
|
||||||
|
int unique_id,
|
||||||
|
const URLSpec &url,
|
||||||
|
const string &post_data) :
|
||||||
|
Thread(url, "URLGetter"),
|
||||||
|
_instance(instance),
|
||||||
|
_unique_id(unique_id),
|
||||||
|
_url(url),
|
||||||
|
_post_data(post_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLGetterThread::
|
||||||
|
thread_main() {
|
||||||
|
HTTPClient *http = HTTPClient::get_global_ptr();
|
||||||
|
|
||||||
|
cerr << "Getting URL " << _url << "\n";
|
||||||
|
|
||||||
|
PT(HTTPChannel) channel = http->make_channel(false);
|
||||||
|
if (_post_data.empty()) {
|
||||||
|
channel->begin_get_document(_url);
|
||||||
|
} else {
|
||||||
|
channel->begin_post_form(_url, _post_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ramfile rf;
|
||||||
|
channel->download_to_ram(&rf);
|
||||||
|
|
||||||
|
size_t bytes_sent = 0;
|
||||||
|
while (channel->run()) {
|
||||||
|
if (rf.get_data_size() != 0) {
|
||||||
|
// Got some new data.
|
||||||
|
P3D_instance_feed_url_stream
|
||||||
|
(_instance, _unique_id, P3D_RC_in_progress,
|
||||||
|
channel->get_status_code(),
|
||||||
|
channel->get_file_size(),
|
||||||
|
(const unsigned char *)rf.get_data().data(), rf.get_data_size());
|
||||||
|
bytes_sent += rf.get_data_size();
|
||||||
|
rf.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done.
|
||||||
|
P3D_result_code status = P3D_RC_done;
|
||||||
|
if (!channel->is_valid()) {
|
||||||
|
if (channel->get_status_code() != 0) {
|
||||||
|
status = P3D_RC_http_error;
|
||||||
|
} else {
|
||||||
|
status = P3D_RC_generic_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
P3D_instance_feed_url_stream
|
||||||
|
(_instance, _unique_id, status,
|
||||||
|
channel->get_status_code(),
|
||||||
|
bytes_sent, NULL, 0);
|
||||||
|
|
||||||
|
cerr << "Done getting URL " << _url << ", got " << bytes_sent << " bytes\n";
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
load_plugin(const string &config_xml_filename,
|
load_plugin(const string &p3d_plugin_filename) {
|
||||||
const string &p3d_plugin_filename) {
|
|
||||||
string filename = p3d_plugin_filename;
|
string filename = p3d_plugin_filename;
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
// Look for the plugin along the path.
|
// Look for the plugin along the path.
|
||||||
@ -102,7 +195,7 @@ load_plugin(const string &config_xml_filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Successfully loaded.
|
// Successfully loaded.
|
||||||
if (!P3D_initialize(NULL, filename.c_str())) {
|
if (!P3D_initialize()) {
|
||||||
// Oops, failure to initialize.
|
// Oops, failure to initialize.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -116,12 +209,40 @@ handle_request(P3D_request *request) {
|
|||||||
|
|
||||||
switch (request->_request_type) {
|
switch (request->_request_type) {
|
||||||
case P3D_RT_stop:
|
case P3D_RT_stop:
|
||||||
|
cerr << "Got P3D_RT_stop\n";
|
||||||
P3D_instance_finish(request->_instance);
|
P3D_instance_finish(request->_instance);
|
||||||
|
_instances.erase(request->_instance);
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Post a silly message to spin the event loop.
|
||||||
|
PostMessage(NULL, WM_USER, 0, 0);
|
||||||
|
#endif
|
||||||
handled = true;
|
handled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case P3D_RT_get_url:
|
||||||
|
cerr << "Got P3D_RT_get_url\n";
|
||||||
|
{
|
||||||
|
PT(URLGetterThread) thread = new URLGetterThread
|
||||||
|
(request->_instance, request->_request._get_url._unique_id,
|
||||||
|
URLSpec(request->_request._get_url._url), "");
|
||||||
|
thread->start(TP_normal, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P3D_RT_post_url:
|
||||||
|
cerr << "Got P3D_RT_post_url\n";
|
||||||
|
{
|
||||||
|
PT(URLGetterThread) thread = new URLGetterThread
|
||||||
|
(request->_instance, request->_request._post_url._unique_id,
|
||||||
|
URLSpec(request->_request._post_url._url),
|
||||||
|
string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
|
||||||
|
thread->start(TP_normal, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Some request types are not handled.
|
// Some request types are not handled.
|
||||||
|
cerr << "Unhandled request: " << request->_request_type << "\n";
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,12 +310,6 @@ usage() {
|
|||||||
|
|
||||||
<< "Options:\n\n"
|
<< "Options:\n\n"
|
||||||
|
|
||||||
<< " -c config.xml\n"
|
|
||||||
<< " Specify the name of the config.xml file that informs the Panda\n"
|
|
||||||
<< " plugin where to download patches and such. This is normally\n"
|
|
||||||
<< " not necessary to specify, since it is already stored within\n"
|
|
||||||
<< " the Panda plugin itself.\n\n"
|
|
||||||
|
|
||||||
<< " -p p3d_plugin.dll\n"
|
<< " -p p3d_plugin.dll\n"
|
||||||
<< " Specify the full path to the particular Panda plugin DLL to\n"
|
<< " Specify the full path to the particular Panda plugin DLL to\n"
|
||||||
<< " run. Normally, this will be found by searching in the usual\n"
|
<< " run. Normally, this will be found by searching in the usual\n"
|
||||||
@ -231,9 +346,8 @@ int
|
|||||||
main(int argc, char *argv[]) {
|
main(int argc, char *argv[]) {
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
const char *optstr = "c:p:t:s:o:h";
|
const char *optstr = "p:t:s:o:h";
|
||||||
|
|
||||||
string config_xml_filename;
|
|
||||||
string p3d_plugin_filename;
|
string p3d_plugin_filename;
|
||||||
P3D_window_type window_type = P3D_WT_toplevel;
|
P3D_window_type window_type = P3D_WT_toplevel;
|
||||||
int win_x = 0, win_y = 0;
|
int win_x = 0, win_y = 0;
|
||||||
@ -243,10 +357,6 @@ main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
while (flag != EOF) {
|
while (flag != EOF) {
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
case 'c':
|
|
||||||
config_xml_filename = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
p3d_plugin_filename = optarg;
|
p3d_plugin_filename = optarg;
|
||||||
break;
|
break;
|
||||||
@ -297,7 +407,7 @@ main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!load_plugin(config_xml_filename, p3d_plugin_filename)) {
|
if (!load_plugin(p3d_plugin_filename)) {
|
||||||
cerr << "Unable to load Panda3D plugin.\n";
|
cerr << "Unable to load Panda3D plugin.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -342,30 +452,33 @@ main(int argc, char *argv[]) {
|
|||||||
int inst_x = win_x + xi * inst_width;
|
int inst_x = win_x + xi * inst_width;
|
||||||
int inst_y = win_y + yi * inst_height;
|
int inst_y = win_y + yi * inst_height;
|
||||||
|
|
||||||
P3D_create_instance
|
P3D_instance *inst = P3D_create_instance
|
||||||
(NULL, argv[i + 1],
|
(NULL, argv[i + 1],
|
||||||
P3D_WT_embedded, inst_x, inst_y, inst_width, inst_height, parent_window,
|
P3D_WT_embedded, inst_x, inst_y, inst_width, inst_height, parent_window,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
_instances.insert(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Not an embedded window. Create each window with the same parameters.
|
// Not an embedded window. Create each window with the same parameters.
|
||||||
for (int i = 0; i < num_instances; ++i) {
|
for (int i = 0; i < num_instances; ++i) {
|
||||||
P3D_create_instance
|
P3D_instance *inst = P3D_create_instance
|
||||||
(NULL, argv[i + 1],
|
(NULL, argv[i + 1],
|
||||||
window_type, win_x, win_y, win_width, win_height, parent_window,
|
window_type, win_x, win_y, win_width, win_height, parent_window,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
_instances.insert(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
if (window_type == P3D_WT_embedded) {
|
||||||
// Wait for new messages from Windows, and new requests from the
|
// Wait for new messages from Windows, and new requests from the
|
||||||
// plugin.
|
// plugin.
|
||||||
MSG msg;
|
MSG msg;
|
||||||
int retval;
|
int retval;
|
||||||
retval = GetMessage(&msg, NULL, 0, 0);
|
retval = GetMessage(&msg, NULL, 0, 0);
|
||||||
while (retval != 0) {
|
while (retval != 0 && !_instances.empty()) {
|
||||||
if (retval == -1) {
|
if (retval == -1) {
|
||||||
cerr << "Error processing message queue.\n";
|
cerr << "Error processing message queue.\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -385,7 +498,29 @@ main(int argc, char *argv[]) {
|
|||||||
retval = GetMessage(&msg, NULL, 0, 0);
|
retval = GetMessage(&msg, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
cerr << "WM_QUIT\n";
|
||||||
|
// WM_QUIT has been received. Terminate all instances, and fall
|
||||||
|
// through.
|
||||||
|
Instances::iterator ii;
|
||||||
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||||
|
P3D_instance_finish(*ii);
|
||||||
|
}
|
||||||
|
_instances.clear();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Not an embedded window, so we don't have our own window to
|
||||||
|
// generate Windows events. Instead, just wait for requests.
|
||||||
|
P3D_instance *inst = P3D_check_request(true);
|
||||||
|
while (inst != (P3D_instance *)NULL) {
|
||||||
|
P3D_request *request = P3D_instance_get_request(inst);
|
||||||
|
if (request != (P3D_request *)NULL) {
|
||||||
|
handle_request(request);
|
||||||
|
}
|
||||||
|
inst = P3D_check_request(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// Now wait while we process pending requests.
|
// Now wait while we process pending requests.
|
||||||
P3D_instance *inst = P3D_check_request(true);
|
P3D_instance *inst = P3D_check_request(true);
|
||||||
@ -396,7 +531,6 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
inst = P3D_check_request(true);
|
inst = P3D_check_request(true);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// All instances have finished; we can exit.
|
// All instances have finished; we can exit.
|
||||||
|
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
POSIX getopt for Windows
|
|
||||||
|
|
||||||
AT&T Public License
|
|
||||||
|
|
||||||
Code given out at the 1985 UNIFORUM conference in Dallas.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
|
|
||||||
#include "wingetopt.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
//#define NULL 0
|
|
||||||
#define EOF (-1)
|
|
||||||
#define ERR(s, c) if(opterr){\
|
|
||||||
char errbuf[2];\
|
|
||||||
errbuf[0] = c; errbuf[1] = '\n';\
|
|
||||||
fputs(argv[0], stderr);\
|
|
||||||
fputs(s, stderr);\
|
|
||||||
fputc(c, stderr);}
|
|
||||||
//(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
|
|
||||||
//(void) write(2, s, (unsigned)strlen(s));\
|
|
||||||
//(void) write(2, errbuf, 2);}
|
|
||||||
|
|
||||||
int opterr = 1;
|
|
||||||
int optind = 1;
|
|
||||||
int optopt;
|
|
||||||
char *optarg;
|
|
||||||
|
|
||||||
int
|
|
||||||
getopt(int argc, char **argv, const char *opts)
|
|
||||||
{
|
|
||||||
static int sp = 1;
|
|
||||||
register int c;
|
|
||||||
register char *cp;
|
|
||||||
|
|
||||||
if(sp == 1)
|
|
||||||
if(optind >= argc ||
|
|
||||||
argv[optind][0] != '-' || argv[optind][1] == '\0')
|
|
||||||
return(EOF);
|
|
||||||
else if(strcmp(argv[optind], "--") == NULL) {
|
|
||||||
optind++;
|
|
||||||
return(EOF);
|
|
||||||
}
|
|
||||||
optopt = c = argv[optind][sp];
|
|
||||||
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
|
|
||||||
ERR(": illegal option -- ", c);
|
|
||||||
if(argv[optind][++sp] == '\0') {
|
|
||||||
optind++;
|
|
||||||
sp = 1;
|
|
||||||
}
|
|
||||||
return('?');
|
|
||||||
}
|
|
||||||
if(*++cp == ':') {
|
|
||||||
if(argv[optind][sp+1] != '\0')
|
|
||||||
optarg = &argv[optind++][sp+1];
|
|
||||||
else if(++optind >= argc) {
|
|
||||||
ERR(": option requires an argument -- ", c);
|
|
||||||
sp = 1;
|
|
||||||
return('?');
|
|
||||||
} else
|
|
||||||
optarg = argv[optind++];
|
|
||||||
sp = 1;
|
|
||||||
} else {
|
|
||||||
if(argv[optind][++sp] == '\0') {
|
|
||||||
sp = 1;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
optarg = NULL;
|
|
||||||
}
|
|
||||||
return(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __GNUC__ */
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
POSIX getopt for Windows
|
|
||||||
|
|
||||||
AT&T Public License
|
|
||||||
|
|
||||||
Code given out at the 1985 UNIFORUM conference in Dallas.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#include <getopt.h>
|
|
||||||
#endif
|
|
||||||
#ifndef __GNUC__
|
|
||||||
|
|
||||||
#ifndef _WINGETOPT_H_
|
|
||||||
#define _WINGETOPT_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int opterr;
|
|
||||||
extern int optind;
|
|
||||||
extern int optopt;
|
|
||||||
extern char *optarg;
|
|
||||||
extern int getopt(int argc, char **argv, const char *opts);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _GETOPT_H_ */
|
|
||||||
#endif /* __GNUC__ */
|
|
@ -230,7 +230,7 @@ class AppPacker:
|
|||||||
bamFile = BamFile()
|
bamFile = BamFile()
|
||||||
stream = StringStream()
|
stream = StringStream()
|
||||||
bamFile.openWrite(stream)
|
bamFile.openWrite(stream)
|
||||||
bamFile.getWriter().setFileTextureMode(BTMUnchanged)
|
bamFile.getWriter().setFileTextureMode(bamFile.BTMUnchanged)
|
||||||
bamFile.writeObject(node)
|
bamFile.writeObject(node)
|
||||||
bamFile.close()
|
bamFile.close()
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@ def initPackedAppEnvironment():
|
|||||||
|
|
||||||
__packedAppEnvironmentInitialized = True
|
__packedAppEnvironmentInitialized = True
|
||||||
|
|
||||||
|
# We need to make sure sys.stdout maps to sys.stderr instead, so
|
||||||
|
# if someone makes an unadorned print command within Python code,
|
||||||
|
# it won't muck up the data stream between parent and child.
|
||||||
|
sys.stdout = sys.stderr
|
||||||
|
|
||||||
vfs = VirtualFileSystem.getGlobalPtr()
|
vfs = VirtualFileSystem.getGlobalPtr()
|
||||||
|
|
||||||
# Clear *all* the mount points, including "/", so that we no
|
# Clear *all* the mount points, including "/", so that we no
|
||||||
@ -145,17 +150,6 @@ def setupWindow(windowType, x, y, width, height, parent):
|
|||||||
|
|
||||||
loadPrcFileData("setupWindow", data)
|
loadPrcFileData("setupWindow", data)
|
||||||
|
|
||||||
def add_check_comm(func, this):
|
|
||||||
""" This function is provided just a convenience for
|
|
||||||
p3dPythonRun.cxx. It adds the indicated function to the task
|
|
||||||
manager with the appropriate parameters for the check_comm
|
|
||||||
task. """
|
|
||||||
return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this],
|
|
||||||
appendTask = True)
|
|
||||||
|
|
||||||
def exit():
|
|
||||||
taskMgr.stop()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
runPackedApp(sys.argv[1:])
|
runPackedApp(sys.argv[1:])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user