command-line arguments

This commit is contained in:
David Rose 2009-08-17 16:03:49 +00:00
parent 8f96fa71f5
commit 1dda2cfb99
16 changed files with 135 additions and 46 deletions

View File

@ -82,6 +82,25 @@ set_tokens(const P3D_token tokens[], size_t num_tokens) {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::set_args
// Access: Public
// Description: Specifies the command-line arguments associated with
// the instance.
////////////////////////////////////////////////////////////////////
void P3DFileParams::
set_args(int argc, const char *argv[]) {
_args.clear();
for (int i = 0; i < argc; ++i) {
const char *arg = argv[i];
if (arg == NULL) {
arg = "";
}
_args.push_back(arg);
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::lookup_token // Function: P3DFileParams::lookup_token
// Access: Public // Access: Public
@ -136,10 +155,17 @@ make_xml() {
for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
const Token &token = (*ti); const Token &token = (*ti);
TiXmlElement *xtoken = new TiXmlElement("token"); TiXmlElement *xtoken = new TiXmlElement("token");
xtoken->SetAttribute("keyword", token._keyword.c_str()); xtoken->SetAttribute("keyword", token._keyword);
xtoken->SetAttribute("value", token._value.c_str()); xtoken->SetAttribute("value", token._value);
xfparams->LinkEndChild(xtoken); xfparams->LinkEndChild(xtoken);
} }
Args::const_iterator ai;
for (ai = _args.begin(); ai != _args.end(); ++ai) {
TiXmlElement *xarg = new TiXmlElement("arg");
xarg->SetAttribute("value", (*ai));
xfparams->LinkEndChild(xarg);
}
return xfparams; return xfparams;
} }

View File

@ -32,6 +32,7 @@ public:
void set_p3d_filename(const string &p3d_filename); void set_p3d_filename(const string &p3d_filename);
void set_tokens(const P3D_token tokens[], size_t num_tokens); void set_tokens(const P3D_token tokens[], size_t num_tokens);
void set_args(int argc, const char *argv[]);
inline const string &get_p3d_filename() const; inline const string &get_p3d_filename() const;
string lookup_token(const string &keyword) const; string lookup_token(const string &keyword) const;
@ -46,9 +47,11 @@ private:
string _value; string _value;
}; };
typedef vector<Token> Tokens; typedef vector<Token> Tokens;
typedef vector<string> Args;
string _p3d_filename; string _p3d_filename;
Tokens _tokens; Tokens _tokens;
Args _args;
}; };
#include "p3dFileParams.I" #include "p3dFileParams.I"

View File

@ -51,7 +51,8 @@ typedef P3DSplashWindow SplashWindowType;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3DInstance:: P3DInstance::
P3DInstance(P3D_request_ready_func *func, P3DInstance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, void *user_data) : const P3D_token tokens[], size_t num_tokens,
int argc, const char *argv[], void *user_data) :
_func(func) _func(func)
{ {
_browser_script_object = NULL; _browser_script_object = NULL;

View File

@ -49,7 +49,8 @@ class P3DToplevelObject;
class P3DInstance : public P3D_instance, public P3DReferenceCount { class P3DInstance : public P3D_instance, public P3DReferenceCount {
public: public:
P3DInstance(P3D_request_ready_func *func, P3DInstance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, void *user_data); const P3D_token tokens[], size_t num_tokens,
int argc, const char *argv[], void *user_data);
~P3DInstance(); ~P3DInstance();
void set_p3d_url(const string &p3d_url); void set_p3d_url(const string &p3d_url);

View File

@ -207,8 +207,9 @@ read_contents_file(const string &contents_filename) {
P3DInstance *P3DInstanceManager:: P3DInstance *P3DInstanceManager::
create_instance(P3D_request_ready_func *func, create_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, const P3D_token tokens[], size_t num_tokens,
void *user_data) { int argc, const char *argv[], void *user_data) {
P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, user_data); P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, argc, argv,
user_data);
inst->ref(); inst->ref();
_instances.insert(inst); _instances.insert(inst);

View File

@ -55,7 +55,7 @@ public:
P3DInstance * P3DInstance *
create_instance(P3D_request_ready_func *func, create_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, const P3D_token tokens[], size_t num_tokens,
void *user_data); int argc, const char *argv[], void *user_data);
bool set_p3d_filename(P3DInstance *inst, bool is_local, bool set_p3d_filename(P3DInstance *inst, bool is_local,
const string &p3d_filename); const string &p3d_filename);

View File

@ -942,7 +942,6 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
} }
PyObject *token_list = PyList_New(0); PyObject *token_list = PyList_New(0);
TiXmlElement *xtoken = xfparams->FirstChildElement("token"); TiXmlElement *xtoken = xfparams->FirstChildElement("token");
while (xtoken != NULL) { while (xtoken != NULL) {
string keyword, value; string keyword, value;
@ -963,11 +962,28 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
xtoken = xtoken->NextSiblingElement("token"); xtoken = xtoken->NextSiblingElement("token");
} }
PyObject *arg_list = PyList_New(0);
TiXmlElement *xarg = xfparams->FirstChildElement("arg");
while (xarg != NULL) {
string value;
const char *value_c = xarg->Attribute("value");
if (value_c != NULL) {
value = value_c;
}
PyObject *str = Py_BuildValue("s", value.c_str());
PyList_Append(arg_list, str);
Py_DECREF(str);
xarg = xarg->NextSiblingElement("arg");
}
PyObject *result = PyObject_CallMethod PyObject *result = PyObject_CallMethod
(_runner, (char *)"setP3DFilename", (char *)"sOi", p3d_filename.c_str(), (_runner, (char *)"setP3DFilename", (char *)"sOOi", p3d_filename.c_str(),
token_list, inst->get_instance_id()); token_list, arg_list, inst->get_instance_id());
Py_DECREF(token_list); Py_DECREF(token_list);
Py_DECREF(arg_list);
if (result == NULL) { if (result == NULL) {
PyErr_Print(); PyErr_Print();

View File

@ -105,12 +105,13 @@ P3D_finalize() {
P3D_instance * P3D_instance *
P3D_new_instance(P3D_request_ready_func *func, P3D_new_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, const P3D_token tokens[], size_t num_tokens,
void *user_data) { int argc, const char *argv[], void *user_data) {
nout << "new_instance\n"; nout << "new_instance\n";
assert(P3DInstanceManager::get_global_ptr()->is_initialized()); assert(P3DInstanceManager::get_global_ptr()->is_initialized());
ACQUIRE_LOCK(_api_lock); ACQUIRE_LOCK(_api_lock);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
P3DInstance *result = inst_mgr->create_instance(func, tokens, num_tokens, user_data); P3DInstance *result = inst_mgr->create_instance(func, tokens, num_tokens,
argc, argv, user_data);
RELEASE_LOCK(_api_lock); RELEASE_LOCK(_api_lock);
return result; return result;
} }

View File

@ -224,6 +224,14 @@ typedef struct {
passed to the application, who is free to decide how to interpret passed to the application, who is free to decide how to interpret
them; they have no meaning at the system level. them; they have no meaning at the system level.
The argc/argv parameters are intended for when the plugin is
invoked from the command line; they should be filled a standard
C-style argc/argv parameter list, corresponding to the command-line
parameters passed to the application. They may be 0 and NULL when
the plugin is invoked from the web. As above, this array and its
string data will be copied into the core API's own internal
storage, and need not persist after this call.
The user_data pointer is any arbitrary pointer value; it will be The user_data pointer is any arbitrary pointer value; it will be
copied into the _user_data member of the new P3D_instance object. copied into the _user_data member of the new P3D_instance object.
This pointer is intended for the host to use to store private data This pointer is intended for the host to use to store private data
@ -234,6 +242,7 @@ typedef struct {
typedef P3D_instance * typedef P3D_instance *
P3D_new_instance_func(P3D_request_ready_func *func, P3D_new_instance_func(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens, const P3D_token tokens[], size_t num_tokens,
int argc, const char *argv[],
void *user_data); void *user_data);
/* This function should be called at some point after /* This function should be called at some point after

View File

@ -957,7 +957,8 @@ create_instance() {
if (!_tokens.empty()) { if (!_tokens.empty()) {
tokens = &_tokens[0]; tokens = &_tokens[0];
} }
_p3d_inst = P3D_new_instance(request_ready, tokens, _tokens.size(), this); _p3d_inst = P3D_new_instance(request_ready, tokens, _tokens.size(),
0, NULL, this);
if (_p3d_inst != NULL) { if (_p3d_inst != NULL) {
// Now get the browser's window object, to pass to the plugin. // Now get the browser's window object, to pass to the plugin.

View File

@ -609,30 +609,35 @@ make_parent_window(P3D_window_handle &parent_window,
// play a particular .p3d file. // play a particular .p3d file.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3D_instance *Panda3D:: P3D_instance *Panda3D::
create_instance(const string &arg, P3D_window_type window_type, create_instance(const string &p3d, P3D_window_type window_type,
int win_x, int win_y, int win_width, int win_height, int win_x, int win_y, int win_width, int win_height,
P3D_window_handle parent_window, char **args, int num_args) { P3D_window_handle parent_window, char **args, int num_args) {
P3D_token tokens[] = {
{ "src", arg.c_str() },
};
int num_tokens = sizeof(tokens) / sizeof(P3D_token);
// If the supplied parameter name is a real file, pass it in on the // If the supplied parameter name is a real file, pass it in on the
// parameter list. Otherwise, assume it's a URL and let the plugin // parameter list. Otherwise, assume it's a URL and let the plugin
// download it. // download it.
Filename p3d_filename = Filename::from_os_specific(arg); Filename p3d_filename = Filename::from_os_specific(p3d);
string os_p3d_filename; string os_p3d_filename = p3d;
bool is_local = false;
if (p3d_filename.exists()) { if (p3d_filename.exists()) {
p3d_filename.make_absolute(); p3d_filename.make_absolute();
os_p3d_filename = p3d_filename.to_os_specific(); os_p3d_filename = p3d_filename.to_os_specific();
is_local = true;
} }
P3D_instance *inst = P3D_new_instance(NULL, tokens, num_tokens, NULL); // Build up the argument list, beginning with the p3d_filename.
pvector<const char *> argv;
argv.push_back(os_p3d_filename.c_str());
for (int i = 0; i < num_args; ++i) {
argv.push_back(args[i]);
}
P3D_instance *inst = P3D_new_instance(NULL, NULL, 0,
argv.size(), &argv[0], NULL);
if (inst != NULL) { if (inst != NULL) {
P3D_instance_setup_window P3D_instance_setup_window
(inst, window_type, win_x, win_y, win_width, win_height, parent_window); (inst, window_type, win_x, win_y, win_width, win_height, parent_window);
P3D_instance_start(inst, true, os_p3d_filename.c_str()); P3D_instance_start(inst, is_local, os_p3d_filename.c_str());
} }
return inst; return inst;

View File

@ -55,11 +55,11 @@ private:
void make_parent_window(P3D_window_handle &parent_window, void make_parent_window(P3D_window_handle &parent_window,
int win_width, int win_height); int win_width, int win_height);
P3D_instance *create_instance(const string &arg, P3D_window_type window_type, P3D_instance *
int win_x, int win_y, int win_width, create_instance(const string &p3d, P3D_window_type window_type,
int win_height, int win_x, int win_y, int win_width, int win_height,
P3D_window_handle parent_window, P3D_window_handle parent_window,
char **args, int num_args); char **args, int num_args);
void delete_instance(P3D_instance *instance); void delete_instance(P3D_instance *instance);
void usage(); void usage();

View File

@ -371,6 +371,9 @@ class Freezer:
self.moduleName = moduleName self.moduleName = moduleName
self.filename = filename self.filename = filename
def __repr__(self):
return 'ModuleDef(%s, %s, %s)' % (repr(self.token), repr(self.moduleName), repr(self.filename))
def __init__(self, previous = None, debugLevel = 0): def __init__(self, previous = None, debugLevel = 0):
# Normally, we are freezing for our own platform. Change this # Normally, we are freezing for our own platform. Change this
# if untrue. # if untrue.
@ -646,7 +649,6 @@ class Freezer:
parentName, baseName = newName.rsplit('.', 1) parentName, baseName = newName.rsplit('.', 1)
if parentName in excludeDict: if parentName in excludeDict:
token = excludeDict[parentName] token = excludeDict[parentName]
if token == self.MTInclude: if token == self.MTInclude:
includes.append(mdef) includes.append(mdef)
elif token == self.MTAuto or token == self.MTGuess: elif token == self.MTAuto or token == self.MTGuess:
@ -772,10 +774,12 @@ class Freezer:
# Previously exported. # Previously exported.
pass pass
else: else:
if newName in self.mf.modules or \ if mdef.moduleName in self.mf.modules or \
newName in startupModules or \ mdef.moduleName in startupModules or \
mdef.filename: mdef.filename:
moduleDefs.append((newName, mdef)) moduleDefs.append((newName, mdef))
else:
print "Unknown module %s" % (mdef.moduleName)
elif token == self.MTForbid: elif token == self.MTForbid:
if not prev or prev.token != self.MTForbid: if not prev or prev.token != self.MTForbid:
moduleDefs.append((newName, mdef)) moduleDefs.append((newName, mdef))

View File

@ -194,8 +194,9 @@ class Packager:
message = 'No main_module specified for application %s' % (self.packageName) message = 'No main_module specified for application %s' % (self.packageName)
raise PackagerError, message raise PackagerError, message
if self.mainModule: if self.mainModule:
if self.mainModule not in self.freezer.modules: moduleName, newName = self.mainModule
self.freezer.addModule(self.mainModule) if newName not in self.freezer.modules:
self.freezer.addModule(moduleName, newName = newName)
# Pick up any unfrozen Python files. # Pick up any unfrozen Python files.
self.freezer.done() self.freezer.done()
@ -601,7 +602,7 @@ class Packager:
if self.version: if self.version:
xpackage.SetAttribute('version', self.version) xpackage.SetAttribute('version', self.version)
xpackage.SetAttribute('main_module', self.mainModule) xpackage.SetAttribute('main_module', self.mainModule[1])
for variable, value in self.configs.items(): for variable, value in self.configs.items():
if isinstance(value, types.UnicodeType): if isinstance(value, types.UnicodeType):
@ -1463,15 +1464,19 @@ class Packager:
def parse_main_module(self, words): def parse_main_module(self, words):
""" """
main_module moduleName main_module moduleName [newName]
""" """
newName = None
try: try:
command, moduleName = words if len(words) == 2:
command, moduleName = words
else:
command, moduleName, newName = words
except ValueError: except ValueError:
raise ArgumentError raise ArgumentError
self.mainModule(moduleName) self.mainModule(moduleName, newName = newName)
def parse_freeze_exe(self, words): def parse_freeze_exe(self, words):
""" """
@ -1879,11 +1884,13 @@ class Packager:
if not self.currentPackage: if not self.currentPackage:
raise OutsideOfPackageError raise OutsideOfPackageError
if self.currentPackage.mainModule and self.currentPackage.mainModule != moduleName: if self.currentPackage.mainModule and self.currentPackage.mainModule[0] != moduleName:
self.notify.warning("Replacing main_module %s with %s" % ( self.notify.warning("Replacing main_module %s with %s" % (
self.currentPackage.mainModule, moduleName)) self.currentPackage.mainModule[0], moduleName))
self.currentPackage.mainModule = moduleName if not newName:
newName = moduleName
self.currentPackage.mainModule = (moduleName, newName)
def freeze(self, filename, compileToExe = False): def freeze(self, filename, compileToExe = False):
""" Freezes all of the current Python code into either an """ Freezes all of the current Python code into either an
@ -1906,10 +1913,17 @@ class Packager:
raise PackagerError, message raise PackagerError, message
if package.mainModule: if package.mainModule:
if package.mainModule not in freezer.modules: moduleName, newName = package.mainModule
freezer.addModule(package.mainModule, newName = '__main__') if compileToExe:
# If we're producing an exe, the main module must
# be called "__main__".
newName = '__main__'
package.mainModule = (moduleName, newName)
if newName not in freezer.modules:
freezer.addModule(moduleName, newName = newName)
else: else:
freezer.modules['__main__'] = freezer.modules[package.mainModule] freezer.modules[newName] = freezer.modules[moduleName]
freezer.done(compileToExe = compileToExe) freezer.done(compileToExe = compileToExe)
if not package.dryRun: if not package.dryRun:

View File

@ -128,6 +128,12 @@ def makePackedApp(args):
packager.endPackage(appBase, p3dApplication = True) packager.endPackage(appBase, p3dApplication = True)
def main(appRunner):
""" This function is called when this module is invoked as
packp3d.p3d. """
makePackedApp(appRunner.argv[1:])
if __name__ == '__main__': if __name__ == '__main__':
try: try:
makePackedApp(sys.argv[1:]) makePackedApp(sys.argv[1:])

View File

@ -223,12 +223,12 @@ class AppRunner(DirectObject):
v = VFSImporter.VFSImporter(MultifileRoot) v = VFSImporter.VFSImporter(MultifileRoot)
loader = v.find_module(moduleName) loader = v.find_module(moduleName)
if not loader: if not loader:
message = "No %s.py found in application." % (mainName) message = "No %s found in application." % (moduleName)
raise StandardError, message raise StandardError, message
main = loader.load_module(moduleName) main = loader.load_module(moduleName)
if hasattr(main, 'main') and callable(main.main): if hasattr(main, 'main') and callable(main.main):
main.main() main.main(self)
def getPandaScriptObject(self): def getPandaScriptObject(self):
""" Called by the browser to query the Panda instance's """ Called by the browser to query the Panda instance's
@ -251,7 +251,7 @@ class AppRunner(DirectObject):
needsResponse = False) needsResponse = False)
self.deferredEvals = [] self.deferredEvals = []
def setP3DFilename(self, p3dFilename, tokens = [], def setP3DFilename(self, p3dFilename, tokens = [], argv = [],
instanceId = None): instanceId = None):
# One day we will have support for multiple instances within a # One day we will have support for multiple instances within a
# Python session. Against that day, we save the instance ID # Python session. Against that day, we save the instance ID
@ -260,6 +260,7 @@ class AppRunner(DirectObject):
self.tokens = tokens self.tokens = tokens
self.tokenDict = dict(tokens) self.tokenDict = dict(tokens)
self.argv = argv
# Tell the browser that Python is up and running, and ready to # Tell the browser that Python is up and running, and ready to
# respond to queries. # respond to queries.