|
|
| Line 1: |
Line 1: |
| <pre>
| | see the [Python/Code code] |
| // CPython.cpp
| |
| | |
| #include "kVersion.h"
| |
| | |
| #if kUsePython
| |
| #if __WIN32__
| |
| #include "python.h"
| |
| #else
| |
| #include <Python/Python.h>
| |
| #endif
| |
| #endif
| |
| | |
| #include "stdafx.h"
| |
| #include "CApp.h"
| |
| #include "CPython.h"
| |
| | |
| bool CPython_UsePython()
| |
| {
| |
| return kUsePython;
| |
| }
| |
| | |
| #if kUsePython
| |
| | |
| #include "CTaskMgr.h"
| |
| | |
| #define kEmbeddedModuleName "kjams"
| |
| | |
| #define kCustomPrint "custom_print"
| |
| #define kCustomErr "custom_err"
| |
| #define kCommand "do_command"
| |
| #define kStringCommand "do_command_str"
| |
| #define kDoMenuCommand "do_menu_command"
| |
| #define kDoMenuName "do_menu_name"
| |
| | |
| #define kStartupScriptName "startup.py"
| |
| #define kUserAbortStr "User Abort"
| |
| | |
| /**********************************************/
| |
| class ScEnsureGIL {
| |
| PyGILState_STATE i_state;
| |
|
| |
| public:
| |
| ScEnsureGIL() :
| |
| i_state(PyGILState_Ensure())
| |
| { }
| |
|
| |
| ~ScEnsureGIL() {
| |
| PyGILState_Release(i_state);
| |
| }
| |
| };
| |
| | |
| class ScReleaseGIL {
| |
|
| |
| public:
| |
| PyThreadState *i_stateP;
| |
| | |
| ScReleaseGIL() :
| |
| i_stateP(PyEval_SaveThread())
| |
| { }
| |
|
| |
| ~ScReleaseGIL() {
| |
| PyEval_RestoreThread(i_stateP);
| |
| }
| |
| };
| |
| | |
| class ScPyObject {
| |
| PyObject *i_objP;
| |
|
| |
| public:
| |
| ScPyObject(PyObject *objP) : i_objP(objP) {}
| |
| ~ScPyObject() {
| |
| Py_DECREF(i_objP);
| |
| }
| |
|
| |
| operator PyObject*() {
| |
| return i_objP;
| |
| }
| |
| };
| |
| | |
| /**********************************************/
| |
| class CPython;
| |
| class CT_RunScript;
| |
| | |
| typedef std::vector<CT_RunScript *> ScriptVec;
| |
| | |
| /*
| |
| this thread runs in the background, serving as the
| |
| "main event loop" for all python scripts
| |
| it runs an "idle" on each script every 1/4 second
| |
| to look for user-aborted threads, and if found,
| |
| causes an exception to be thrown within that thread
| |
| */
| |
| class CPython_RunLoop : public CT_Preemptive {
| |
| public:
| |
| CPython *thiz;
| |
| CMutex_bool i_abortB;
| |
| CMutexT<ScriptVec *> i_scriptVecP;
| |
| bool i_continueB;
| |
|
| |
| CPython_RunLoop(CPython *in_thiz);
| |
| ~CPython_RunLoop();
| |
|
| |
| virtual OSStatus operator()(OSStatus err);
| |
| void RunScript(const char *unf8NameZ, const char *utf8ScriptZ);
| |
|
| |
| void AddScript(CT_RunScript *scriptP);
| |
| void RemoveScript(CT_RunScript *scriptP);
| |
| void IdleScripts();
| |
| void AllowPendingCalls();
| |
| size_t CountScripts();
| |
| };
| |
| | |
| /*
| |
| this is the main Python object the app uses to
| |
| communicate with the python runloop above
| |
| */
| |
| class CPython {
| |
| friend class CPython_RunLoop;
| |
| static CPython *s_pythonP;
| |
| CMutexT<bool> i_inittedB;
| |
| std::string i_appName;
| |
| CMutexT<CPython_RunLoop*> i_runLoopP;
| |
| | |
| public:
| |
| CPython(const char *appNameZ);
| |
| ~CPython();
| |
|
| |
| static CPython* Get(const char *appNameZ = NULL);
| |
|
| |
| /****************************************************/
| |
| void Startup();
| |
| void Test();
| |
| };
| |
| | |
| //static
| |
| CPython* CPython::s_pythonP = NULL;
| |
| | |
| /*********************************************************************/
| |
| struct ThisRec {
| |
| CT_RunScript *i_scriptP;
| |
| ThisRec(CT_RunScript *scriptP) : i_scriptP(scriptP) {}
| |
| };
| |
| | |
| boost::thread_specific_ptr<ThisRec> g_threadP;
| |
| | |
| /*
| |
| this is a script-running thread
| |
| if any "error" statements are "printed", they are gathered up into
| |
| a single string and presented to the user as a dialog
| |
| */
| |
| class CT_RunScript : public CT_Preemptive {
| |
| public:
| |
| SuperString i_name;
| |
| SuperString i_script;
| |
| CPython_RunLoop *i_runLoopP;
| |
| long i_thread_id;
| |
| | |
| class CShowErrorTimer;
| |
| CMutexT<CShowErrorTimer *> i_errTimerP;
| |
|
| |
| /*****************************
| |
| this gathers all errors printed out:
| |
| if it gets some error text, it waits a half second.
| |
| if more error prints come in within that time, they are appended
| |
| when the timer expires, all the error messages gathered are
| |
| shown to the user in a dialog
| |
| */
| |
| class CShowErrorTimer : public CT_Timer {
| |
| friend class CT_RunScript;
| |
| SuperString i_errStr;
| |
| CMutex_bool i_abortB;
| |
| CT_RunScript *i_scriptP;
| |
| bool i_doneB;
| |
|
| |
| public:
| |
| CShowErrorTimer(CT_RunScript *scriptP) :
| |
| i_doneB(false),
| |
| i_scriptP(scriptP),
| |
| CT_Timer(NO_KILL "CShowErrorTimer", kEventDurationSecond / 2)
| |
| {
| |
| call();
| |
| }
| |
|
| |
| ~CShowErrorTimer() {
| |
| i_scriptP->i_errTimerP.Set(NULL);
| |
| }
| |
|
| |
| virtual OSStatus operator()()
| |
| {
| |
| CCritical sc(&i_scriptP->i_errTimerP);
| |
| | |
| if (!i_doneB) {
| |
| i_doneB = true;
| |
| if (!i_errStr.Contains(kUserAbortStr)) {
| |
| | |
| if (i_errStr.GetIndCharR() == '\r') {
| |
| i_errStr.pop_back();
| |
| }
| |
| | |
| i_errStr.Replace("<string>", i_scriptP->i_name);
| |
| PostAlert("Python Error:", i_errStr.utf8Z());
| |
| }
| |
| }
| |
|
| |
| return threadTimerTerminate;
| |
| }
| |
|
| |
| void append(const char *utf8Z) {
| |
|
| |
| if (!i_doneB) {
| |
| i_errStr.append(utf8Z);
| |
| prime(); // tickle the timer
| |
| }
| |
| }
| |
| };
| |
| /*****************************/
| |
|
| |
| CPW_TaskRec *i_taskRecP;
| |
| CPW_ProgData i_progData;
| |
|
| |
| CT_RunScript(
| |
| CPython_RunLoop *runLoopP,
| |
| const SuperString& name,
| |
| const SuperString& script
| |
| ) :
| |
| i_runLoopP(runLoopP),
| |
| i_name(name),
| |
| i_script(script)
| |
| {
| |
| SuperString verb1("Python: ");
| |
| | |
| verb1.append(name);
| |
| i_taskRecP = gApp->NewTask(verb1.ref(), NULL);
| |
| i_runLoopP->AddScript(this);
| |
| call(NO_KILL "CPython::CT_RunScript");
| |
| }
| |
|
| |
| ~CT_RunScript()
| |
| {
| |
| CF_ASSERT(i_errTimerP.Get() == NULL);
| |
| i_taskRecP->Delete();
| |
| i_runLoopP->RemoveScript(this);
| |
| }
| |
|
| |
| // called from CPython_RunLoop thread, NOT from "this" thread
| |
| void Idle()
| |
| {
| |
| OSStatus err = noErr;
| |
|
| |
| ERR(i_runLoopP->i_abortB.Get());
| |
| ERR(i_taskRecP->MT_UpdateData(&i_progData));
| |
|
| |
| // an error here means the user has aborted the script
| |
| if (err) {
| |
| err = noErr;
| |
|
| |
| ERR_XTE_START {
| |
| ScEnsureGIL sc;
| |
| ScPyObject exceptionP(PyString_FromString(kUserAbortStr));
| |
| int countI(PyThreadState_SetAsyncExc(i_thread_id, exceptionP));
| |
|
| |
| // during shut down it is reasonable that countI may be 0
| |
| // but it should never be greater than 1
| |
| CF_ASSERT(countI == 0 || countI == 1);
| |
| } ERR_XTE_END;
| |
|
| |
| if (err) {
| |
| ReportErr("Python: Exception when attempting to kill thread", err);
| |
| }
| |
| }
| |
| }
| |
|
| |
| virtual OSStatus operator()(OSStatus err)
| |
| {
| |
| SetThis(this);
| |
|
| |
| {
| |
| ScEnsureGIL sc;
| |
|
| |
| // gather my thread ID so i can be killed later if
| |
| // the user hits cancel on my thread
| |
| i_thread_id = PyThreadState_Get()->thread_id;
| |
| ERR(PyRun_SimpleString(i_script.utf8Z()));
| |
| }
| |
| | |
| // now wait until errors have already been shown, if any
| |
| while (i_errTimerP.Get()) {
| |
| IdleDuration(0.1f, kDurationForever_Idle);
| |
| }
| |
|
| |
| return err;
| |
| }
| |
|
| |
| /***************************/
| |
| // extensions to python for use within scripts
| |
| static CT_RunScript* GetThis() {
| |
| CT_RunScript *thiz = NULL;
| |
| ThisRec *thisRecP = g_threadP.get();
| |
|
| |
| if (thisRecP) {
| |
| thiz = thisRecP->i_scriptP;
| |
| }
| |
|
| |
| return thiz;
| |
| }
| |
|
| |
| static void SetThis(CT_RunScript *scriptP) {
| |
| g_threadP.reset(new ThisRec(scriptP));
| |
| }
| |
|
| |
| static PyObject* emb_print_err(PyObject *self, PyObject *args) {
| |
| return GetThis()->print_err(args);
| |
| }
| |
| | |
| PyObject* print_err(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| const char *utf8_strZ = NULL;
| |
|
| |
| if (PyArg_ParseTuple(args, "s", &utf8_strZ)) {
| |
| CCritical sc(&i_errTimerP);
| |
| CShowErrorTimer *errTimerP(i_errTimerP.Get());
| |
|
| |
| if (errTimerP == NULL) {
| |
| errTimerP = new CShowErrorTimer(this);
| |
| i_errTimerP.Set(errTimerP);
| |
| }
| |
|
| |
| errTimerP->append(utf8_strZ);
| |
|
| |
| resultObjP = Py_None;
| |
| Py_INCREF(resultObjP);
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| | |
| /***************************/
| |
| static PyObject* emb_print(PyObject *self, PyObject *args) {
| |
| return GetThis()->print(args);
| |
| }
| |
| | |
| PyObject* print(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| const char *utf8_strZ = NULL;
| |
|
| |
| if (PyArg_ParseTuple(args, "s", &utf8_strZ)) {
| |
| Log(utf8_strZ, false);
| |
| | |
| resultObjP = Py_None;
| |
| Py_INCREF(resultObjP);
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| | |
| /***************************/
| |
| static PyObject* emb_do_command(PyObject *self, PyObject *args) {
| |
| return GetThis()->do_command(args);
| |
| }
| |
| | |
| PyObject* do_command(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| int commandID = kScriptCommand_NONE;
| |
|
| |
| if (PyArg_ParseTuple(args, "i", &commandID)) {
| |
| double resultF = Scripting_Command((SInt32)commandID);
| |
| | |
| resultObjP = PyFloat_FromDouble(resultF);
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| | |
| /***************************/
| |
| static PyObject* emb_do_command_str(PyObject *self, PyObject *args) {
| |
| return GetThis()->do_command_str(args);
| |
| }
| |
| | |
| PyObject* do_command_str(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| int commandID = kScriptCommand_NONE;
| |
|
| |
| if (PyArg_ParseTuple(args, "i", &commandID)) {
| |
| SuperString resultStr(Scripting_CommandStr((SInt32)commandID), true);
| |
| | |
| resultObjP = PyString_FromString(resultStr.utf8Z());
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| | |
| /***************************/
| |
| static PyObject* emb_do_menu_command(PyObject *self, PyObject *args) {
| |
| return GetThis()->do_menu_command(args);
| |
| }
| |
| | |
| PyObject* do_menu_command(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| short menuI = 0;
| |
| short menu_itemI = 0;
| |
| short sub_menu_itemI = 0;
| |
|
| |
| if (PyArg_ParseTuple(args, "hh|h", &menuI, &menu_itemI, &sub_menu_itemI)) {
| |
| SInt16Vec intVec;
| |
|
| |
| intVec.push_back(menuI);
| |
| intVec.push_back(menu_itemI);
| |
|
| |
| if (sub_menu_itemI) {
| |
| intVec.push_back(sub_menu_itemI);
| |
| }
| |
|
| |
| DoMenuCommand(intVec);
| |
|
| |
| resultObjP = Py_None;
| |
| Py_INCREF(resultObjP);
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| | |
| /***************************/
| |
| static PyObject* emb_do_menu_name(PyObject *self, PyObject *args) {
| |
| return GetThis()->do_menu_name(args);
| |
| }
| |
| | |
| PyObject* do_menu_name(PyObject *args)
| |
| {
| |
| PyObject *resultObjP = NULL;
| |
| const char *menuZ = NULL;
| |
| const char *menu_itemZ = NULL;
| |
| const char *sub_menu_itemZ = NULL;
| |
|
| |
| if (PyArg_ParseTuple(args, "ss|s", &menuZ, &menu_itemZ, &sub_menu_itemZ)) {
| |
| SStringVec stringVec;
| |
|
| |
| stringVec.push_back(menuZ);
| |
| stringVec.push_back(menu_itemZ);
| |
|
| |
| if (sub_menu_itemZ) {
| |
| stringVec.push_back(sub_menu_itemZ);
| |
| }
| |
|
| |
| DoMenuCommand(stringVec);
| |
| | |
| resultObjP = Py_None;
| |
| Py_INCREF(resultObjP);
| |
| }
| |
|
| |
| return resultObjP;
| |
| }
| |
| };
| |
| | |
| /*****************************************************/
| |
| | |
| static const PyMethodDef EmbMethods[] = {
| |
| {kCustomPrint, CT_RunScript::emb_print, METH_VARARGS, "Calls custom print function."},
| |
| {kCustomErr, CT_RunScript::emb_print_err, METH_VARARGS, "Calls custom error function."},
| |
| {kCommand, CT_RunScript::emb_do_command, METH_VARARGS, "calls scripting command (float result)."},
| |
| {kStringCommand, CT_RunScript::emb_do_command_str, METH_VARARGS, "calls scripting command (string result)."},
| |
| {kDoMenuCommand, CT_RunScript::emb_do_menu_command, METH_VARARGS, "calls menu command by index"},
| |
| {kDoMenuName, CT_RunScript::emb_do_menu_name, METH_VARARGS, "calls menu command by name"},
| |
| {NULL, NULL, 0, NULL}
| |
| };
| |
| | |
| static const char *s_RedirectPrint =
| |
| "import " kEmbeddedModuleName "\n"
| |
| "import sys\n"
| |
| "\n"
| |
| "class CustomPrintClass:\n"
| |
| " def write(self, stuff):\n"
| |
| " " kEmbeddedModuleName "." kCustomPrint "(stuff)\n"
| |
| "class CustomErrClass:\n"
| |
| " def write(self, stuff):\n"
| |
| " " kEmbeddedModuleName "." kCustomErr "(stuff)\n"
| |
| "sys.stdout = CustomPrintClass()\n"
| |
| "sys.stderr = CustomErrClass()\n";
| |
| | |
| static const char *s_PrintTime =
| |
| "import time\n"
| |
| "print 'Today is', time.ctime(time.time())\n";
| |
| | |
| static const char *s_AllowPendingCalls =
| |
| "pass\n";
| |
| | |
| /*****************************************************************
| |
| on Windows, if you bundle python27.dll with your app, it will launch but
| |
| crash on systems that do NOT have python actually installed.
| |
| so get around that here, and bail gracefully. at that point you could
| |
| instruct the user to go install ActivePython 2.7 for x86 (32bit) from here:
| |
| http://www.activestate.com/activepython/downloads
| |
| */
| |
| static bool PythonExists()
| |
| {
| |
| bool existsB = true;
| |
| | |
| #if OPT_WINOS
| |
| {
| |
| CFileRef system32(CFileRef::kFolder_SYSTEM); // CSIDL_SYSTEMX86
| |
| | |
| existsB = system32.Descend("python27.dll") == noErr;
| |
| }
| |
| #endif
| |
|
| |
| return existsB;
| |
| }
| |
| | |
| CPython_RunLoop::CPython_RunLoop(CPython *in_thiz) :
| |
| thiz(in_thiz),
| |
| i_continueB(PythonExists())
| |
| {
| |
| i_scriptVecP.Set(new ScriptVec());
| |
| call(NO_KILL "CPython_RunLoop");
| |
| }
| |
| | |
| CPython_RunLoop::~CPython_RunLoop()
| |
| {
| |
| CCritical sc(&i_scriptVecP);
| |
| ScriptVec *vecP(i_scriptVecP.Get());
| |
| | |
| CF_ASSERT(vecP);
| |
| CF_ASSERT(vecP->empty());
| |
| delete vecP;
| |
| i_scriptVecP.Set(NULL);
| |
| }
| |
| | |
| OSStatus CPython_RunLoop::operator()(OSStatus err)
| |
| {
| |
| XTE_START {
| |
| if (i_continueB) {
| |
| Log("Python: about to set program name");
| |
| Py_SetProgramName(const_cast<char *>(thiz->i_appName.c_str()));
| |
| | |
| Log("Python: about to init");
| |
| Py_Initialize();
| |
| | |
| {
| |
| Log("Python: about to create " kEmbeddedModuleName " module");
| |
|
| |
| PyObject *myModuleP = Py_InitModule(
| |
| kEmbeddedModuleName, const_cast<PyMethodDef*>(EmbMethods));
| |
| ETX(myModuleP == NULL);
| |
|
| |
| // the owner of myModuleP is now the python interpreter
| |
| // it will auto-decref during Py_Finalize()
| |
| }
| |
|
| |
| // redirect stdout and stderr to my own logging functions
| |
| Log("Python: about to run log redirect script");
| |
| ETX(PyRun_SimpleString(s_RedirectPrint));
| |
| PyEval_InitThreads();
| |
| thiz->i_inittedB.Set(true);
| |
| }
| |
| } XTE_END;
| |
| | |
| LogYesOrNo("Python Initted", thiz->i_inittedB.Get());
| |
|
| |
| if (thiz->i_inittedB.Get()) {
| |
| bool abortB = false;
| |
| bool doneB = false;
| |
| | |
| {
| |
| ScReleaseGIL sc;
| |
|
| |
| /*
| |
| run the "loop" that will handle killing of
| |
| any scripts canceled by the user
| |
| */
| |
|
| |
| do {
| |
| // IdleScripts will kill any scripts that the user has hit cancel on
| |
| IdleScripts();
| |
|
| |
| // if you want to use Py_AddPendingCall() to send a message to THIS
| |
| // thread, then you'd need to uncomment this line:
| |
| // AllowPendingCalls();
| |
| | |
| if (!abortB) {
| |
| // this gets set when quitting the app
| |
| abortB = i_abortB.Get();
| |
| }
| |
|
| |
| if (abortB) {
| |
| doneB = CountScripts() == 0;
| |
| }
| |
|
| |
| if (!doneB) {
| |
| IdleDuration(kQuarterSecond);
| |
| }
| |
| } while (!doneB);
| |
| }
| |
| | |
| Py_Finalize();
| |
| thiz->i_inittedB.Set(false);
| |
| }
| |
|
| |
| thiz->i_runLoopP.Set(NULL);
| |
| return err;
| |
| }
| |
| | |
| void CPython_RunLoop::AllowPendingCalls()
| |
| {
| |
| ScEnsureGIL sc;
| |
| | |
| if (PyRun_SimpleString(s_AllowPendingCalls) != 0) {
| |
| PostAlert("Python: s_AllowPendingCalls failed");
| |
| i_abortB.Set(true);
| |
| }
| |
| }
| |
| | |
| void CPython_RunLoop::RunScript(const char *unf8NameZ, const char *utf8ScriptZ)
| |
| {
| |
| new CT_RunScript(this, unf8NameZ, utf8ScriptZ);
| |
| }
| |
| | |
| void CPython_RunLoop::AddScript(CT_RunScript *scriptP)
| |
| {
| |
| CCritical sc(&i_scriptVecP); CF_ASSERT(i_scriptVecP.Get());
| |
| i_scriptVecP.Get()->push_back(scriptP);
| |
| }
| |
| | |
| void CPython_RunLoop::RemoveScript(CT_RunScript *scriptP)
| |
| {
| |
| CCritical sc(&i_scriptVecP); CF_ASSERT(i_scriptVecP.Get());
| |
| ScriptVec& scriptVec(*i_scriptVecP.Get());
| |
| ScriptVec::iterator it(std::find(scriptVec.begin(), scriptVec.end(), scriptP));
| |
|
| |
| CF_ASSERT(it != scriptVec.end());
| |
| if (it != scriptVec.end()) {
| |
| scriptVec.erase(it);
| |
| }
| |
| }
| |
| | |
| void CPython_RunLoop::IdleScripts()
| |
| {
| |
| ScriptVec iter_scriptVec;
| |
| | |
| {
| |
| CCritical sc(&i_scriptVecP); CF_ASSERT(i_scriptVecP.Get());
| |
| ScriptVec& orig_scriptVec(*i_scriptVecP.Get());
| |
|
| |
| // make a copy to iterate over, cuz during the iterate
| |
| // we may actually delete the current script
| |
| iter_scriptVec = orig_scriptVec;
| |
| }
| |
|
| |
| BOOST_FOREACH(CT_RunScript *scriptP, iter_scriptVec) {
| |
| {
| |
| CCritical sc(&i_scriptVecP); CF_ASSERT(i_scriptVecP.Get());
| |
| ScriptVec& scriptVec(*i_scriptVecP.Get());
| |
| ScriptVec::iterator it(std::find(scriptVec.begin(), scriptVec.end(), scriptP));
| |
|
| |
| // we still have to check to see if this script still exists before calling it
| |
| if (it != scriptVec.end()) {
| |
| scriptP->Idle();
| |
| }
| |
| }
| |
| }
| |
| }
| |
| | |
| size_t CPython_RunLoop::CountScripts()
| |
| {
| |
| CCritical sc(&i_scriptVecP); CF_ASSERT(i_scriptVecP.Get());
| |
| | |
| return i_scriptVecP.Get()->size();
| |
| }
| |
| | |
| /**************************************************************/
| |
| CPython::CPython(const char *appNameZ) :
| |
| i_appName(appNameZ)
| |
| {
| |
| i_runLoopP.Set(new CPython_RunLoop(this));
| |
| }
| |
| | |
| CPython::~CPython()
| |
| {
| |
| s_pythonP = NULL;
| |
|
| |
| {
| |
| CCritical sc(&i_runLoopP);
| |
| CPython_RunLoop *runLoopP(i_runLoopP.Get());
| |
|
| |
| if (runLoopP) {
| |
| runLoopP->i_abortB.Set(true);
| |
| }
| |
| }
| |
|
| |
| while (i_runLoopP.Get()) {
| |
| IdleDuration(0.1f, kDurationForever_Idle);
| |
| }
| |
| }
| |
| | |
| // static
| |
| CPython* CPython::Get(const char *appNameZ)
| |
| {
| |
| if (s_pythonP == NULL) {
| |
| CF_ASSERT(appNameZ);
| |
| s_pythonP = new CPython(appNameZ);
| |
| }
| |
|
| |
| return s_pythonP;
| |
| }
| |
| | |
| /****************************************************/
| |
| void CPython::Startup()
| |
| {
| |
| if (i_inittedB.Get()) XTE_START {
| |
| CharVec charVec;
| |
| CFileRef pythonRef(kFolder_KJAMS);
| |
|
| |
| ETX(pythonRef.Descend("Python/" kStartupScriptName));
| |
| pythonRef.Load(&charVec);
| |
| charVec.push_back(0);
| |
| i_runLoopP.Get()->RunScript(kStartupScriptName, &charVec[0]);
| |
| } XTE_END;
| |
| }
| |
| | |
| void CPython::Test()
| |
| {
| |
| if (i_inittedB.Get()) {
| |
| i_runLoopP.Get()->RunScript("print_time.py", s_PrintTime);
| |
| }
| |
| }
| |
| /*****************************************************************/
| |
| | |
| #endif // kUsePython
| |
| | |
| // the entire public interface is here
| |
| // called on startup to init
| |
| OSStatus CPython_PreAlloc(const char *utf8Z)
| |
| {
| |
| OSStatus err = noErr;
| |
|
| |
| #if kUsePython
| |
| if (CPython::Get(utf8Z) == NULL) {
| |
| ERR(tsmUnsupScriptLanguageErr);
| |
| }
| |
| #endif
| |
|
| |
| return err;
| |
| }
| |
| | |
| // called on shutdown
| |
| void CPython_PostDispose()
| |
| {
| |
| #if kUsePython
| |
| CPython *pyP(CPython::Get());
| |
|
| |
| if (pyP) {
| |
| delete pyP;
| |
| }
| |
| #endif
| |
| }
| |
| | |
| // very simple unit test
| |
| void CPython_Test()
| |
| {
| |
| #if kUsePython
| |
| CPython *pyP(CPython::Get());
| |
|
| |
| if (pyP) {
| |
| pyP->Test();
| |
| }
| |
| #endif
| |
| }
| |
| | |
| // called when startup is complete
| |
| void CPython_Startup()
| |
| {
| |
| #if kUsePython
| |
| CPython *pyP(CPython::Get());
| |
|
| |
| if (pyP) {
| |
| pyP->Startup();
| |
| }
| |
| #endif
| |
| }
| |
| </pre>
| |