summaryrefslogtreecommitdiffstats
path: root/c-layman/src/interpreter.c
diff options
context:
space:
mode:
Diffstat (limited to 'c-layman/src/interpreter.c')
-rw-r--r--c-layman/src/interpreter.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/c-layman/src/interpreter.c b/c-layman/src/interpreter.c
new file mode 100644
index 0000000..95d40d9
--- /dev/null
+++ b/c-layman/src/interpreter.c
@@ -0,0 +1,189 @@
+#include <Python.h>
+#include <stdio.h>
+#include <string.h>
+#include "interpreter.h"
+
+/**
+ * \internal
+ * Stores modules in a linked list so that they don't have to be reloaded every time.
+ */
+typedef struct PyObjectListElem
+{
+ PyObject *object;
+ struct PyObjectListElem *next;
+} PyObjectListElem;
+
+typedef struct PyObjectList
+{
+ PyObjectListElem *root;
+ int count;
+} PyObjectList;
+
+PyObjectList *createObjectList()
+{
+ PyObjectList *ret = malloc(sizeof(PyObjectList));
+ ret->count = 0;
+ ret->root = 0;
+ return ret;
+}
+
+void insert(PyObjectList* list, PyObject *object)
+{
+ if (!list || !object)
+ return;
+ PyObjectListElem *node = malloc(sizeof(PyObjectListElem));
+ node->object = object;
+ node->next = list->root;
+ list->root = node;
+ list->count++;
+}
+
+PyObject *moduleNamed(const char *name, PyObjectList *list)
+{
+ PyObjectListElem *node = list->root;
+ while (node)
+ {
+ if (strcmp(PyModule_GetName(node->object), name) == 0)
+ return node->object;
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+int listCount(PyObjectList *list)
+{
+ return (list ? list->count : 0);
+}
+
+void freeList(PyObjectList *list, int deref)
+{
+ if (!list)
+ return;
+
+ PyObjectListElem *node = list->root;
+ while (node)
+ {
+ PyObjectListElem *tmp = node;
+ node = node->next;
+ if (deref)
+ {
+ Py_DECREF(tmp->object);
+ }
+ free(tmp);
+ }
+
+ free(list);
+}
+
+/**
+ * \internal
+ * A Python interpreter object keeps the context like the loaded modules.
+ */
+struct Interpreter
+{
+ PyObjectList *modules;
+} *in = 0;
+
+
+/** \defgroup layman_base Layman base
+ *
+ * \brief Layman Base functions
+ *
+ * These functions are used when you want to begin or end using the library.
+ */
+
+/** \addtogroup layman_base
+ * @{
+ */
+
+/**
+ * This is the first function that must be called before using the library.
+ * It initializes the Python interpreter.
+ */
+void laymanInit()
+{
+ if (in)
+ return;
+
+ if (!Py_IsInitialized())
+ Py_Initialize();
+
+ in = malloc(sizeof(struct Interpreter));
+ in->modules = createObjectList();
+}
+
+/**
+ * Call this function when you're done using the library.
+ * It will free memory.
+ */
+void laymanFinalize()
+{
+ if (!in)
+ return;
+ freeList(in->modules, 1);
+ free(in);
+
+ if (Py_IsInitialized())
+ Py_Finalize();
+}
+
+/** @} */
+
+/**
+ * \internal
+ * printf() like function that executes a python function
+ *
+ * \param module name of the python module in which the function is
+ * \param funcName the function name to call
+ * \param format printf() like list of arguments. See Python documentation
+ * \param ... arguments for the function
+ *
+ * \return the result of the execution. Can be NULL if the call failed.
+ */
+PyObject *executeFunction(const char *module, const char *funcName, const char* format, ...)
+{
+ assert(in);
+
+ // Make argument list
+ PyObject *args;
+ if (format == NULL || strcmp(format, "") == 0)
+ args = PyTuple_New(0);
+ else
+ {
+ va_list listArgs;
+ va_start(listArgs, format);
+
+ args = Py_VaBuildValue(format, listArgs);
+ }
+
+ // Look for the module.
+ PyObject *mod = 0;
+ if (in->modules)
+ {
+ mod = moduleNamed(module, in->modules);
+ }
+ // If module is not loaded yet, do it.
+ if (!mod)
+ {
+ mod = PyImport_ImportModule(module);
+ if (!mod)
+ return NULL;
+ insert(in->modules, mod);
+ }
+
+ // Look for the function
+ PyObject *func = PyObject_GetAttrString(mod, funcName);
+ if (!PyCallable_Check(func))
+ return NULL;
+
+ // Execute it
+ PyObject *val = PyObject_CallObject(func, args);
+
+ if (args != NULL)
+ {
+ Py_DECREF(args);
+ }
+
+ return val;
+}