summaryrefslogtreecommitdiff
path: root/lib/python.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python.c')
-rw-r--r--lib/python.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/lib/python.c b/lib/python.c
new file mode 100644
index 0000000..da6f25e
--- /dev/null
+++ b/lib/python.c
@@ -0,0 +1,421 @@
+/*
+ * python.c
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include "python.h"
+
+cDbTable* Python::globalEventsDb = 0;
+int Python::globalNamingMode = 0;
+const char* Python::globalTmplExpression = "";
+
+//***************************************************************************
+// Static Interface Methods (Table events)
+//***************************************************************************
+
+PyObject* Python::eventTitle(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("TITLE"));
+}
+
+PyObject* Python::eventShortText(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("SHORTTEXT"));
+}
+
+PyObject* Python::eventStartTime(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("i", 0);
+
+ return Py_BuildValue("i", globalEventsDb->getIntValue("STARTTIME"));
+}
+
+PyObject* Python::eventYear(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("YEAR"));
+}
+
+PyObject* Python::eventCategory(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("CATEGORY"));
+}
+
+PyObject* Python::episodeName(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODENAME"));
+}
+
+PyObject* Python::episodeShortName(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODESHORTNAME"));
+}
+
+PyObject* Python::episodePartName(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODEPARTNAME"));
+}
+
+PyObject* Python::extracol1(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODEEXTRACOL1"));
+}
+
+PyObject* Python::extracol2(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODEEXTRACOL2"));
+}
+
+PyObject* Python::extracol3(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("s", "");
+
+ return Py_BuildValue("s", globalEventsDb->getStrValue("EPISODEEXTRACOL3"));
+}
+
+PyObject* Python::episodeSeason(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("i", na);
+
+ return Py_BuildValue("i", globalEventsDb->getIntValue("EPISODESEASON"));
+}
+
+PyObject* Python::episodePart(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("i", na);
+
+ return Py_BuildValue("i", globalEventsDb->getIntValue("EPISODEPART"));
+}
+
+PyObject* Python::episodeNumber(PyObject* /*self*/, PyObject* /*args*/)
+{
+ if (!globalEventsDb)
+ return Py_BuildValue("i", na);
+
+ return Py_BuildValue("i", globalEventsDb->getIntValue("EPISODENUMBER"));
+}
+
+PyObject* Python::namingMode(PyObject* /*self*/, PyObject* /*args*/)
+{
+ return Py_BuildValue("i", globalNamingMode);
+}
+
+PyObject* Python::tmplExpression(PyObject* /*self*/, PyObject* /*args*/)
+{
+ return Py_BuildValue("s", globalTmplExpression);
+}
+
+//***************************************************************************
+// The Methods
+//***************************************************************************
+
+PyMethodDef Python::eventMethods[] =
+{
+ { "title", Python::eventTitle, METH_VARARGS, "Return the events ..." },
+ { "shorttext", Python::eventShortText, METH_VARARGS, "Return the events ..." },
+ { "starttime", Python::eventStartTime, METH_VARARGS, "Return the events ..." },
+ { "year", Python::eventYear, METH_VARARGS, "Return the events ..." },
+ { "category", Python::eventCategory, METH_VARARGS, "Return the events ..." },
+
+ { "episodname", Python::episodeName, METH_VARARGS, "Return the events ..." },
+ { "shortname", Python::episodeShortName, METH_VARARGS, "Return the events ..." },
+ { "partname", Python::episodePartName, METH_VARARGS, "Return the events ..." },
+
+ { "season", Python::episodeSeason, METH_VARARGS, "Return the events ..." },
+ { "part", Python::episodePart, METH_VARARGS, "Return the events ..." },
+ { "number", Python::episodeNumber, METH_VARARGS, "Return the events ..." },
+
+ { "extracol1", Python::extracol1, METH_VARARGS, "Return the events ..." },
+ { "extracol2", Python::extracol2, METH_VARARGS, "Return the events ..." },
+ { "extracol3", Python::extracol3, METH_VARARGS, "Return the events ..." },
+
+ { "namingmode", Python::namingMode, METH_VARARGS, "Return the ..." },
+ { "tmplExpression", Python::tmplExpression, METH_VARARGS, "Return the ..." },
+
+ { 0, 0, 0, 0 }
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+PyModuleDef Python::moduledef =
+{
+ PyModuleDef_HEAD_INIT, // m_base
+ "event", // m_name - name of module
+ 0, // m_doc - module documentation, may be NULL
+ -1, // m_size - size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
+ eventMethods, // m_methods
+ 0, // m_slots - array of slot definitions for multi-phase initialization, terminated by a {0, NULL} entry.
+ // when using single-phase initialization, m_slots must be NULL.
+ 0, // traverseproc m_traverse - traversal function to call during GC traversal of the module object, or NULL if not needed.
+ 0, // inquiry m_clear - clear function to call during GC clearing of the module object, or NULL if not needed.
+ 0 // freefunc m_free - function to call during deallocation of the module object or NULL if not needed.
+};
+
+#endif
+
+//***************************************************************************
+// Object
+//***************************************************************************
+
+Python::Python(const char* aFile, const char* aFunction)
+{
+ pFunc = 0;
+ pModule = 0;
+ result = 0;
+ file = strdup(aFile);
+ function = strdup(aFunction);
+}
+
+Python::~Python()
+{
+ exit();
+
+ free(result);
+ free(file);
+ free(function);
+}
+
+//***************************************************************************
+// Init / Exit
+//***************************************************************************
+
+int Python::init(const char* modulePath)
+{
+ PyObject* pName;
+
+ tell(0, "Initialize python script '%s/%s.py'", modulePath, file);
+
+ // register event methods
+
+#if PY_MAJOR_VERSION >= 3
+ PyImport_AppendInittab("event", &PyInitEvent);
+ Py_Initialize(); // initialize the Python interpreter
+ pName = PyUnicode_FromString(file);
+#else
+ Py_Initialize(); // initialize the Python interpreter
+ Py_InitModule("event", eventMethods);
+ pName = PyString_FromString(file);
+#endif
+
+ // add search path for Python modules
+
+ if (modulePath)
+ {
+ char* p;
+ asprintf(&p, "sys.path.append(\"%s\")", modulePath);
+ PyRun_SimpleString("import sys");
+ PyRun_SimpleString(p);
+ free(p);
+ }
+
+ // import the module
+
+ pModule = PyImport_Import(pName);
+ Py_DECREF(pName);
+
+ if (!pModule)
+ {
+ showError();
+ tell(0, "Failed to load '%s.py'", file);
+
+ return fail;
+ }
+
+ pFunc = PyObject_GetAttrString(pModule, function);
+
+ // pFunc is a new reference
+
+ if (!pFunc || !PyCallable_Check(pFunc))
+ {
+ if (PyErr_Occurred())
+ showError();
+
+ tell(0, "Cannot find function '%s'", function);
+
+ return fail;
+ }
+
+ return success;
+}
+
+int Python::exit()
+{
+ if (pFunc)
+ Py_XDECREF(pFunc);
+
+ if (pModule)
+ Py_DECREF(pModule);
+
+ Py_Finalize();
+
+ return success;
+}
+
+//***************************************************************************
+// Execute
+//***************************************************************************
+
+int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpression)
+{
+ PyObject* pValue;
+
+ free(result);
+ result = 0;
+
+ globalEventsDb = eventsDb;
+ globalNamingMode = namingmode;
+ globalTmplExpression = tmplExpression;
+
+ pValue = PyObject_CallObject(pFunc, 0);
+
+ if (!pValue)
+ {
+ showError();
+ tell(0, "Python: Call of function '%s()' failed", function);
+
+ return fail;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ // PyObject* strExc = PyObject_Repr(pValue);
+ // PyObject* pyStr = PyUnicode_AsEncodedString(strExc, "utf-8", "replace");
+ PyObject* pyStr = PyUnicode_AsEncodedString(pValue, "utf-8", "replace");
+ result = strdup(PyBytes_AsString(pyStr));
+ // Py_XDECREF(strExc);
+
+#else
+ result = strdup(PyString_AsString(pValue));
+#endif
+
+ tell(3, "Result of call: %s", result);
+
+ Py_DECREF(pValue);
+
+ return success;
+}
+
+
+//***************************************************************************
+// Dup Py String
+//***************************************************************************
+
+char* dupPyString(PyObject* pyObj)
+{
+ char* s;
+ PyObject* pyString;
+
+ if (!pyObj || !(pyString=PyObject_Str(pyObj)))
+ {
+ s = strdup("unknown error");
+ return s;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ PyObject* pyUni = PyObject_Repr(pyString); // Now a unicode object
+ PyObject* pyStr = PyUnicode_AsEncodedString(pyUni, "utf-8", "Error ~");
+ s = strdup(PyBytes_AsString(pyStr));
+ Py_XDECREF(pyUni);
+ Py_XDECREF(pyStr);
+#else
+ s = strdup(PyString_AsString(pyString));
+#endif
+
+ Py_DECREF(pyString);
+
+ return s;
+}
+
+//***************************************************************************
+// PY String From String
+//***************************************************************************
+
+PyObject* pyStringFromString(const char* s)
+{
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_FromString(s);
+#else
+ return PyString_FromString(s);
+#endif
+}
+
+//***************************************************************************
+// Show Error
+//***************************************************************************
+
+void Python::showError()
+{
+ char* error;
+ PyObject *ptype = 0, *pError = 0, *ptraceback = 0;
+ PyObject *moduleName, *pythModule;
+
+ PyErr_Fetch(&ptype, &pError, &ptraceback);
+
+ error = dupPyString(pError);
+ moduleName = pyStringFromString("traceback");
+
+ tell(0, "Python error was '%s'", error);
+
+ pythModule = PyImport_Import(moduleName);
+ Py_DECREF(moduleName);
+
+ // traceback
+
+ if (pythModule)
+ {
+ PyObject* pyFunc = PyObject_GetAttrString(pythModule, "format_exception");
+
+ if (pyFunc && PyCallable_Check(pyFunc))
+ {
+ PyObject *pythVal, *pystr;
+ char* s;
+
+ pythVal = PyObject_CallFunctionObjArgs(pyFunc, ptype, pError, ptraceback, 0);
+ if (pythVal)
+ {
+ s = dupPyString(pystr = PyObject_Str(pythVal));
+ tell(0, " %s", s);
+
+ free(s);
+ Py_DECREF(pystr);
+ Py_DECREF(pythVal);
+ }
+ }
+ }
+
+ free(error);
+ Py_DECREF(pError);
+ Py_DECREF(ptype);
+ Py_XDECREF(ptraceback);
+}