178 lines
5.2 KiB
C++
178 lines
5.2 KiB
C++
/**
|
|
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;
|
|
}
|