You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
10 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "PythonInterface.h"
#include "compile.h"
#include "eval.h"
#include "marshal.h"
#include "cStringIO.h"
#include "plFileSystem.h"
static PyObject* stdFile; // python object of the stdout and err file
void PythonInterface::initPython(const plFileName& rootDir)
{
// if haven't been initialized then do it
if ( Py_IsInitialized() == 0 )
{
// initialize the Python stuff
// let Python do some intialization...
Py_SetProgramName(const_cast<char*>("plasma"));
Py_NoSiteFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_Initialize();
// intialize any of our special plasma python modules
// initP2PInterface();
// save object to the Plasma module
// plasmaMod = PyImport_ImportModule("Plasma");
// create the StringIO for the stdout and stderr file
PycStringIO = (struct PycStringIO_CAPI*)PyCObject_Import(const_cast<char*>("cStringIO"), const_cast<char*>("cStringIO_CAPI"));
stdFile = (*PycStringIO->NewOutput)(20000);
// if we need the builtins then find the builtin module
PyObject* sysmod = PyImport_ImportModule("sys");
// then add the builtin dicitionary to our module's dictionary
if (sysmod != NULL )
{
// get the sys's dictionary to find the stdout and stderr
PyObject* sys_dict = PyModule_GetDict(sysmod);
if (stdFile != nil)
{
PyDict_SetItemString(sys_dict, "stdout", stdFile);
PyDict_SetItemString(sys_dict, "stderr", stdFile);
}
// NOTE: we will reset the path to not include paths
// ...that Python may have found in the registery
PyObject* path_list = PyList_New(0);
printf("Setting up include dirs:\n");
printf("%s\n", rootDir.AsString().c_str());
PyObject* more_path = PyString_FromString(rootDir.AsString().c_str());
PyList_Append(path_list, more_path);
// make sure that our plasma libraries are gotten before the system ones
plFileName temp = plFileName::Join(rootDir, "plasma");
printf("%s\n", temp.AsString().c_str());
PyObject* more_path3 = PyString_FromString(temp.AsString().c_str());
PyList_Append(path_list, more_path3);
temp = plFileName::Join(rootDir, "system");
printf("%s\n\n", temp.AsString().c_str());
PyObject* more_path2 = PyString_FromString("system");
PyList_Append(path_list, more_path2);
// set the path to be this one
PyDict_SetItemString(sys_dict, "path", path_list);
Py_DECREF(sysmod);
}
}
// initialized++;
}
void PythonInterface::addPythonPath(const plFileName& path)
{
PyObject* sysmod = PyImport_ImportModule("sys");
if (sysmod != NULL)
{
PyObject* sys_dict = PyModule_GetDict(sysmod);
PyObject* path_list = PyDict_GetItemString(sys_dict, "path");
printf("Adding path %s\n", path.AsString().c_str());
PyObject* more_path = PyString_FromString(path.AsString().c_str());
PyList_Append(path_list, more_path);
Py_DECREF(sysmod);
}
}
void PythonInterface::finiPython()
{
if (Py_IsInitialized() != 0)
{
Py_Finalize();
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : CompileString
// PARAMETERS : command - string of commands to execute in the...
// : filename - filename to say where to code came from
//
// PURPOSE : run a python string in a specific module name
//
PyObject* PythonInterface::CompileString(const char *command, const plFileName& filename)
{
PyObject* pycode = Py_CompileString(command, filename.AsString().c_str(), Py_file_input);
return pycode;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : DumpObject
// PARAMETERS : pyobject - string of commands to execute in the...
//
// PURPOSE : marshals an object into a char string
//
12 years ago
bool PythonInterface::DumpObject(PyObject* pyobj, char** pickle, int32_t* size)
{
PyObject *s; // the python string object where the marsalled object wil go
// convert object to a marshalled string python object
#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 4)
s = PyMarshal_WriteObjectToString(pyobj);
#else
s = PyMarshal_WriteObjectToString(pyobj, Py_MARSHAL_VERSION);
#endif
// did it actually do it?
if ( s != NULL )
{
// yes, then get the size and the string address
*size = PyString_Size(s);
*pickle = PyString_AsString(s);
return true;
}
else // otherwise, there was an error
{
// Yikes! errors!
PyErr_Print(); // FUTURE: we may have to get the string to display in max...later
return false;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : getOutputAndReset
// PARAMETERS : none
//
// PURPOSE : get the Output to the error file to be displayed
//
int PythonInterface::getOutputAndReset(char** line)
{
PyObject* pyStr = (*PycStringIO->cgetvalue)(stdFile);
char *str = PyString_AsString( pyStr );
int size = PyString_Size( pyStr );
// reset the file back to zero
PyObject_CallMethod(stdFile, const_cast<char*>("reset"), const_cast<char*>(""));
/*
// check to see if the debug python module is loaded
if ( dbgOut != nil )
{
// then send it the new text
if ( PyObject_CallFunction(dbgOut,"s",str) == nil )
{
// for some reason this function didn't, remember that and not call it again
dbgOut = nil;
// if there was an error make sure that the stderr gets flushed so it can be seen
PyErr_Print(); // make sure the error is printed
PyErr_Clear(); // clear the error
}
}
*/
if (line)
*line = str;
return size;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : CreateModule
// PARAMETERS : module - module name to create
//
// PURPOSE : create a new module with built-ins
//
PyObject* PythonInterface::CreateModule(const char* module)
{
PyObject *m, *d;
// first we must get rid of any old modules of the same name, we'll replace it
PyObject *modules = PyImport_GetModuleDict();
if ((m = PyDict_GetItemString(modules, module)) != NULL && PyModule_Check(m))
// clear it
_PyModule_Clear(m);
// create the module
m = PyImport_AddModule(module);
if (m == NULL)
return nil;
d = PyModule_GetDict(m);
// add in the built-ins
// first make sure that we don't already have the builtins
if (PyDict_GetItemString(d, "__builtins__") == NULL)
{
// if we need the builtins then find the builtin module
PyObject *bimod = PyImport_ImportModule("__builtin__");
// then add the builtin dicitionary to our module's dictionary
if (bimod == NULL || PyDict_SetItemString(d, "__builtins__", bimod) != 0)
return nil;
Py_DECREF(bimod);
}
return m;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RunPYC
// PARAMETERS : code - compiled code
// : module - module name to run the code in
//
// PURPOSE : run a compiled python code in a specific module name
//
12 years ago
bool PythonInterface::RunPYC(PyObject* code, PyObject* module)
{
PyObject *d, *v;
// make sure that we're given a good module... or at least one with an address
if ( !module )
{
// if no module was given then use just use the main module
module = PyImport_AddModule("__main__");
if (module == NULL)
return false;
}
// get the dictionaries for this module
d = PyModule_GetDict(module);
// run the string
v = PyEval_EvalCode((PyCodeObject*)code, d, d);
// check for errors and print them
if (v == NULL)
{
// Yikes! errors!
PyErr_Print();
return false;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetModuleItem
// PARAMETERS : item - what item in the plasma module to get
//
// PURPOSE : get an item (probably a function) from a specific module
//
PyObject* PythonInterface::GetModuleItem(const char* item, PyObject* module)
{
if ( module )
{
PyObject* d = PyModule_GetDict(module);
return PyDict_GetItemString(d, item);
}
return nil;
}