| /** | |
| python-console | |
| Copyright (C) 2014 Alex Tsui | |
| Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| this software and associated documentation files (the "Software"), to deal in | |
| the Software without restriction, including without limitation the rights to | |
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
| of the Software, and to permit persons to whom the Software is furnished to do | |
| so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in all | |
| copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| SOFTWARE. | |
| */ | |
| #include "pyinterpreter.h" | |
| #include <Python.h> | |
| #include <iostream> | |
| #include <map> | |
| #include <memory> | |
| #include "pyredirector.h" | |
| static PyThreadState *MainThreadState = NULL; | |
| static PyThreadState *m_threadState = NULL; | |
| static PyObject *glb = NULL; | |
| static PyObject *loc = NULL; | |
| static std::list<std::string> m_suggestions; | |
| template <typename... Args> std::string string_format(const std::string &format, Args... args) | |
| { | |
| size_t size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' | |
| std::unique_ptr<char[]> buf(new char[size]); | |
| snprintf(buf.get(), size, format.c_str(), args...); | |
| return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside | |
| } | |
| std::string pyinterpreter_execute(const std::string &command, int *errorCode) | |
| { | |
| PyEval_AcquireThread(m_threadState); | |
| *errorCode = 0; | |
| PyObject *py_result; | |
| PyObject *dum; | |
| std::string res; | |
| py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input); | |
| if (py_result == 0) { | |
| if (PyErr_Occurred()) { | |
| *errorCode = 1; | |
| PyErr_Print(); | |
| res = redirector_take_output(m_threadState); | |
| } | |
| PyEval_ReleaseThread(m_threadState); | |
| return res; | |
| } | |
| dum = PyEval_EvalCode(py_result, glb, loc); | |
| Py_XDECREF(dum); | |
| Py_XDECREF(py_result); | |
| if (PyErr_Occurred()) { | |
| *errorCode = 1; | |
| PyErr_Print(); | |
| } | |
| res = redirector_take_output(m_threadState); | |
| PyEval_ReleaseThread(m_threadState); | |
| return res; | |
| } | |
| const std::list<std::string> &pyinterpreter_suggest(const std::string &hint) | |
| { | |
| PyEval_AcquireThread(m_threadState); | |
| m_suggestions.clear(); | |
| int i = 0; | |
| std::string command = string_format("sys.completer.complete('%s', %d)\n", hint.c_str(), i); | |
| std::string res; | |
| do { | |
| PyObject *py_result; | |
| PyObject *dum; | |
| py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input); | |
| dum = PyEval_EvalCode(py_result, glb, loc); | |
| Py_XDECREF(dum); | |
| Py_XDECREF(py_result); | |
| res = redirector_take_output(m_threadState); | |
| ++i; | |
| command = string_format("sys.completer.complete('%s', %d)\n", hint.c_str(), i); | |
| if (res.size()) { | |
| // throw away the newline | |
| res = res.substr(1, res.size() - 3); | |
| m_suggestions.push_back(res); | |
| } | |
| } while (res.size()); | |
| PyEval_ReleaseThread(m_threadState); | |
| return m_suggestions; | |
| } | |
| void pyinterpreter_preinit() | |
| { | |
| m_suggestions.clear(); | |
| inittab_redirector(); | |
| } | |
| void pyinterpreter_initialize() | |
| { | |
| PyEval_InitThreads(); | |
| MainThreadState = PyEval_SaveThread(); | |
| PyEval_AcquireThread(MainThreadState); | |
| m_threadState = Py_NewInterpreter(); | |
| PyObject *module = PyImport_ImportModule("__main__"); | |
| loc = glb = PyModule_GetDict(module); | |
| PyRun_SimpleString("import sys\n" | |
| "import redirector\n" | |
| "sys.path.insert(0, \".\")\n" // add current path | |
| "sys.stdout = redirector.redirector()\n" | |
| "sys.stderr = sys.stdout\n" | |
| "import rlcompleter\n" | |
| "sys.completer = rlcompleter.Completer()\n"); | |
| PyEval_ReleaseThread(m_threadState); | |
| } | |
| void pyinterpreter_finalize() | |
| { | |
| m_suggestions.clear(); | |
| PyEval_AcquireThread(m_threadState); | |
| Py_EndInterpreter(m_threadState); | |
| PyEval_ReleaseLock(); | |
| PyEval_RestoreThread(MainThreadState); | |
| } | |
| void pyinterpreter_aquire() | |
| { | |
| PyEval_AcquireThread(m_threadState); | |
| } | |
| void pyinterpreter_release() | |
| { | |
| PyEval_ReleaseThread(m_threadState); | |
| } | |
| std::string pyinterpreter_execute_file(const char *python_file, int *errorCode) | |
| { | |
| PyEval_AcquireThread(m_threadState); | |
| *errorCode = 0; | |
| std::string res; | |
| FILE *fp = fopen(python_file, "r"); | |
| if (fp == NULL) { | |
| *errorCode = 1; | |
| res = "Fatal error: file not found " + std::string(python_file) + "\n"; | |
| return res; | |
| } | |
| if (PyRun_SimpleFile(fp, python_file)==-1) { | |
| *errorCode = 1; | |
| PyErr_Print(); | |
| } | |
| res = redirector_take_output(m_threadState); | |
| PyEval_ReleaseThread(m_threadState); | |
| return res; | |
| } |