#include <signal.h>
#include <Python.h>
#include <entity.h>
#define PY_DEBUG 1
typedef struct {
PyObject_HEAD ENode * enode;
} PyEnodeObject;
static void
py_enode_dealloc (PyEnodeObject * self)
{
ECHECK_RET (self->enode != NULL);
enode_unref (self->enode);
PyMem_DEL (self);
}
static int
py_enode_print (PyEnodeObject * self, FILE * fp, int flags)
{
EBuf *path;
ECHECK_RETVAL (self->enode != NULL, -1);
path = enode_path (self->enode);
if (path) {
fprintf (fp, "%s", path->str);
ebuf_free (path);
}
return 0;
}
/* forward decl 'cause we need it here */
static struct PyMethodDef py_enode_methods[];
static PyObject *
py_enode_getattr (PyEnodeObject * self, char *name)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
return Py_FindMethod (py_enode_methods, (PyObject *) self, name);
}
static int
py_enode_compare (PyEnodeObject * self, PyEnodeObject * other)
{
EBuf *s; /* Self. */
EBuf *o; /* Other node. */
int result;
ECHECK_RETVAL (self->enode != NULL, -1);
/* equality means that their paths are the same. */
s = enode_path (self->enode);
o = enode_path (other->enode);
result = strcmp ((const gchar *) s->str, (const gchar *) o->str);
ebuf_free (s);
ebuf_free (o);
return result;
}
static int
py_enode_mapping_length (PyEnodeObject * self)
{
int result;
ECHECK_RETVAL (self->enode != NULL, 0);
/* count # of set items?? */
result = g_slist_length (self->enode->attribs) / 2;
EDEBUG (("python-embed", "mapping_length: returning %i", result));
return result;
}
static PyObject *
py_enode_mapping_subscript (PyEnodeObject * self, PyObject * key)
{
gchar *key_str;
EBuf *result;
PyObject *result_py;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyString_Check (key)) {
PyErr_SetString (PyExc_TypeError,
"Only string objects may be attribute keys.");
return NULL;
}
key_str = PyString_AsString (key);
EDEBUG (("python-embed", "py_enode_mapping_subscript: key is %s", key_str));
result = enode_attrib (self->enode, key_str, NULL);
if (result == NULL) {
PyErr_SetString (PyExc_SystemError,
"py_enode_mapping_subscript: Internal error in enode_attrib");
return NULL;
}
EDEBUG (("python-embed", "mapping_subscript: result->str is %s; len is %i",
result->str, result->len));
result_py = PyString_FromStringAndSize (result->str, result->len);
EDEBUG (
("python-embed",
"mapping_subscript: returning py_string of refcnt %i",
result_py->ob_refcnt));
EDEBUG (
("python-embed", "mapping_subscript: who's string is ->%s",
((PyStringObject *) result_py)->ob_sval));
return result_py;
}
/* Some classic #gimp humour for you..
<Slow> py_enode_mapping_ass_subscript(PyEnodeObject *self, PyObject *key, PyObject *val)
* jyon smacks linux & nfs
* tc tickles jyons navel
* Slow wonders if fatjim meant that as a joke or..
<yosh> ass_subscript?
* jyon crys
<Slow> hehe
<yosh> is he making anal rape jokes now too?
<CyBeR> heh
<tc> py_squirm_ass_insert(PyObject *thingy); ?
<Slow> haha
<yosh> PyDildo *red
<tc> add that function and see what he says ;)
*/
static int
py_enode_mapping_ass_subscript (PyEnodeObject * self, PyObject * key,
PyObject * val)
{
gchar *key_str;
gchar *val_str;
ECHECK_RETVAL (self->enode != NULL, 0);
if (!(PyString_Check (key) && (PyString_Check (val)))) {
PyErr_SetString (PyExc_TypeError,
"Only string objects may be attribute keys or values.");
return 0;
}
key_str = PyString_AsString (key);
val_str = PyString_AsString (val);
EDEBUG (("python-embed", "mapping_ass_subs: key is %s", key_str));
EDEBUG (("python-embed", "mapping_ass_subs: val is %s", val_str));
if (val == NULL) {
enode_attrib (self->enode, key_str, ebuf_new_with_str (""));
} else {
/* set the key to val */
EDEBUG (
("python-embed", "mapping_ass_subs: setting attrib %s to %s.",
key_str, val_str));
enode_attrib (self->enode, key_str, ebuf_new_with_str (val_str));
}
return 0;
}
static char py_enode__doc__[] =
"ENode class. See the entity documentation for more information.";
static PyMappingMethods py_enode_as_mapping = {
(inquiry) py_enode_mapping_length, /* mp_length */
(binaryfunc) py_enode_mapping_subscript, /* mp_subscript */
(objobjargproc) py_enode_mapping_ass_subscript, /* mp_ass_subscript */
};
static PyTypeObject py_enode_type = {
PyObject_HEAD_INIT (NULL)
0, /* ob_size */
"ENode", /* tp_name */
sizeof (PyEnodeObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor) py_enode_dealloc, /* tp_dealloc */
(printfunc) py_enode_print, /* tp_print */
(getattrfunc) py_enode_getattr, /* tp_getattr */
(setattrfunc) 0, /* tp_setattr */
(cmpfunc) py_enode_compare, /* tp_compare */
(reprfunc) 0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
&py_enode_as_mapping, /* tp_as_mapping */
(hashfunc) 0, /* tp_hash */
(ternaryfunc) 0, /* tp_call */
(reprfunc) 0, /* tp_str */
/* Space for future expansion */
0L, 0L, 0L, 0L,
py_enode__doc__ /* Documentation string */
};
static PyObject *
py_enode_new_from_enode (ENode * node)
{
PyEnodeObject *self;
/* The previous behavior was to spew and error and return NULL if
* node == NULL, I think this is far too pedantic, and should be handled
* by the application. There are several places where a None return
* (eg, in searches) is perfectly normal. - Ian */
if (node == NULL) {
Py_INCREF (Py_None);
return Py_None;
}
self = PyObject_NEW (PyEnodeObject, &py_enode_type);
if (self == NULL) {
EDEBUG (
("python-embed",
"in py_enode_new_from_enode() couldn't construct pyobject!"));
return NULL;
}
enode_ref (node);
self->enode = node;
return (PyObject *) self;
}
PyObject *
py_enode_glist_to_pylist (GSList * gslist)
{
PyObject *pylist;
GSList *p;
int len;
int i;
if (gslist == NULL)
EDEBUG (
("python-embed",
"py_enode_glist_to_pylist: result of enode_children was NULL."));
len = g_slist_length (gslist);
EDEBUG (
("python-embed", "py_enode_glist_to_pylist: the list is %d long.",
len));
pylist = PyList_New (len);
for (p = gslist, i = 0; p; p = p->next, i++) {
PyList_SetItem (pylist, i,
py_enode_new_from_enode ((ENode *) (p->data)));
}
EDEBUG (
("python-embed",
"py_enode_new_from_enode: done adding to the list."));
return pylist;
}
gchar *
get_python_namespace (void)
{
return (enode_call_get_namespace ("python"));
}
PyObject *
py_new_child (PyEnodeObject * self, PyObject * args)
{
int nattribs;
int i;
gchar *basename;
gchar *keychar;
gchar *valchar;
PyObject *attribs_dict = NULL;
PyObject *items;
PyObject *item;
PyObject *key;
PyObject *val;
ENode *new_node;
GSList *attribs = NULL;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple
(args, "s|O!", &basename, &PyDict_Type, &attribs_dict)) return NULL;
if (attribs_dict != NULL) {
EDEBUG (("python-embed", "py_new_child: got an attribs dict."));
items = PyMapping_Items (attribs_dict);
nattribs = PyList_Size (items);
for (i = 0; i < nattribs; i++) {
item = PyList_GetItem (items, i);
key = PyTuple_GetItem (item, 0);
val = PyTuple_GetItem (item, 1);
keychar = PyString_AsString (PyObject_Str (key));
valchar = PyString_AsString (PyObject_Str (val));
EDEBUG (("python-embed", "py_new_child: adding attrib %s, val %s",
keychar, valchar));
attribs = g_slist_prepend (attribs, ebuf_new_with_str (valchar));
attribs = g_slist_prepend (attribs, ebuf_new_with_str (keychar));
}
Py_XDECREF (items);
EDEBUG (("python-embed", "py_new_child: done adding attribs to list."));
}
new_node = enode_new_child (self->enode, basename, attribs);
if (new_node == NULL) {
PyErr_SetString (PyExc_SystemError, "Could not create new child.");
return NULL;
}
return py_enode_new_from_enode (new_node);
}
PyObject *
py_type (PyEnodeObject * self, PyObject * args)
{
PyObject *result;
EBuf *type;
ECHECK_RETVAL (self->enode != NULL, NULL);
EDEBUG (("python-embed", "py_type: self refcnt is %i", (self->ob_refcnt)));
type = enode_type (self->enode);
EDEBUG (("python-embed", "py_type: type str is %s", type->str));
result = PyString_FromString (type->str);
EDEBUG (("python-embed", "py_type: returning a pystr refcnt %i val %s",
(PyStringObject *) result->ob_refcnt,
((PyStringObject *) result)->ob_sval));
return result;
}
PyObject *
py_path (PyEnodeObject * self, PyObject * args)
{
EBuf *path;
PyObject *result;
ECHECK_RETVAL (self->enode != NULL, NULL);
EDEBUG (("python-embed", "py_path: self refcnt is %i", (self->ob_refcnt)));
path = enode_path (self->enode);
if (path == NULL) {
PyErr_SetString (PyExc_SystemError, "enode_path returned NULL!");
return NULL;
}
EDEBUG (("python-embed", "py_path: got path str, %s", path->str));
result = PyString_FromString (path->str);
EDEBUG (("python-embed", "py_path: got pystring for the path"));
ebuf_free (path);
EDEBUG (("python-embed", "py_path: have freed path enode"));
return result;
}
PyObject *
py_basename (PyEnodeObject * self, PyObject * args)
{
EBuf *basename;
PyObject *result;
ECHECK_RETVAL (self->enode != NULL, NULL);
basename = enode_basename (self->enode);
result = PyString_FromString (basename->str);
ebuf_free (basename);
return result;
}
PyObject *
py_description (PyEnodeObject * self, PyObject * args)
{
gchar *desc;
ECHECK_RETVAL (self->enode != NULL, NULL);
desc = enode_description (self->enode);
if (desc == NULL)
desc = "";
return PyString_FromString (desc);
}
PyObject *
py_parent (PyEnodeObject * self, PyObject * args)
{
char *search = NULL;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "|s", &search))
return NULL;
return py_enode_new_from_enode (enode_parent (self->enode, search));
}
PyObject *
py_child (PyEnodeObject * self, PyObject * args)
{
char *search;
ENode *node;
PyObject *py_node;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", &search))
return NULL;
node = enode_child (self->enode, search);
if (node == NULL) {
PyErr_SetString (PyExc_SystemError,
"py_child: enode_child returned null.");
return NULL;
}
py_node = py_enode_new_from_enode (node);
return py_node;
}
PyObject *
py_child_rx (PyEnodeObject * self, PyObject * args)
{
char *regex;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", ®ex))
return NULL;
return py_enode_new_from_enode (enode_child_rx (self->enode, regex));
}
PyObject *
py_children (PyEnodeObject * self, PyObject * args)
{
char *search = NULL;
GSList *result;
PyObject *py_result;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "|s", &search))
return NULL;
result = enode_children (self->enode, search);
py_result = py_enode_glist_to_pylist (result);
g_slist_free (result);
return py_result;
}
PyObject *
py_children_rx (PyEnodeObject * self, PyObject * args)
{
char *regex;
GSList *result;
PyObject *py_result;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", ®ex))
return NULL;
result = enode_children_rx (self->enode, regex);
py_result = py_enode_glist_to_pylist (result);
g_slist_free (result);
return py_result;
}
PyObject *
py_children_attrib (PyEnodeObject * self, PyObject * args)
{
gchar *attr;
gchar *val;
EBuf *val_ebuf;
GSList *result;
PyObject *py_result;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "ss", &attr, &val))
return NULL;
val_ebuf = ebuf_new_with_str (val);
result = enode_children_attrib (self->enode, attr, val_ebuf);
ebuf_free (val_ebuf);
py_result = py_enode_glist_to_pylist (result);
return py_result;
}
PyObject *
py_children_attrib_rx (PyEnodeObject * self, PyObject * args)
{
gchar *attr;
gchar *val;
GSList *result;
PyObject *py_result;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "ss", &attr, &val))
return NULL;
result = enode_children_attrib_rx (self->enode, attr, val);
py_result = py_enode_glist_to_pylist (result);
return py_result;
}
PyObject *
py_call (PyEnodeObject * self, PyObject * args)
{
int n_args;
int n_pyargs;
int i;
gchar *function;
gchar *fmt;
EBuf *retval;
GSList *call_args = NULL;
PyObject *py_function;
PyObject *py_fmt;
PyObject *py_retr;
PyObject *tmp;
ECHECK_RETVAL (self->enode != NULL, NULL);
/* WARNING: VERY UGLY CODE AHEAD. it's 4:15 am. */
n_pyargs = PyTuple_Size (args);
EDEBUG (
("python-embed-call", "py_call: got args tuple of size %i",
n_pyargs));
if (n_pyargs < 1) {
PyErr_SetString (PyExc_TypeError, "require at least a function name");
return NULL;
}
py_function = PyTuple_GetItem (args, 0);
if (!PyString_Check (py_function)) {
PyErr_SetString (PyExc_TypeError, "expected a string");
return NULL;
}
function = PyString_AsString (py_function);
EDEBUG (
("python-embed-call", "py_call: got the function name %s",
function));
/* in perl enode_call() we allow a NULL argument list to mean the same as
* an empty one, should probably do the same here. */
if (n_pyargs > 1) {
EDEBUG (
("python-embed-call", "py_call: we have args. checking.",
function));
py_fmt = PyTuple_GetItem (args, 1);
if (!PyString_Check (py_fmt)) {
PyErr_SetString (PyExc_TypeError, "bad arguments.");
return NULL;
}
fmt = PyString_AsString (py_fmt);
n_args = strlen (fmt);
EDEBUG (
("python-embed-call", "py_call: fmt %s has %i elements", fmt,
n_args));
/* note that this check BREAKS if we're using the binary stuff, i
* think.. */
if (n_args != (n_pyargs - 2)) {
PyErr_SetString (PyExc_TypeError,
"argument list and actual arguments don't jive");
return NULL;
}
for (i = 0; i < n_args; i++) {
PyObject *item = PyTuple_GetItem (args, i + 2);
EDEBUG (
("python-embed-call", "py_call: processing argument no. %i",
i));
tmp = PyObject_Str (item);
EDEBUG (("python-embed-call", "py_call: processing item is %s",
PyString_AsString (tmp)));
Py_XDECREF (tmp);
switch (fmt[i]) {
case 'n':
{
ENode *node;
EDEBUG (
("python-embed-call",
"py_call: processing got an enode"));
if (item->ob_type != &py_enode_type) {
PyErr_SetString (PyExc_TypeError, "expected an enode");
return NULL;
}
node = ((PyEnodeObject *) item)->enode;
call_args = enode_call_push_node (call_args, node);
}
break;
case 'e':
case 'b': /* since python strings are capable of
* holding binary data (ie, with embedded
* NULLs etc), we can just use strings. */
EDEBUG (
("python-embed-call",
"py_call: processing got an ebufor a binary"));
if (!PyString_Check (item)) {
PyErr_SetString (PyExc_TypeError,
"expected a string for an ebuf or binary argument.");
return NULL;
}
call_args =
enode_call_push_data (call_args, PyString_AsString (item),
PyString_Size (item));
break;
case 's':
EDEBUG (
("python-embed-call",
"py_call: processing got a string"));
if (!PyString_Check (item)) {
PyErr_SetString (PyExc_TypeError,
"expected a string for a string argument.");
return NULL;
}
call_args =
enode_call_push_str (call_args, PyString_AsString (item));
break;
case 'i':
EDEBUG (
("python-embed-call",
"py_call: processing got an int"));
if (!PyInt_Check (item)) {
PyErr_SetString (PyExc_TypeError, "bad arguments.");
return NULL;
}
call_args =
enode_call_push_int (call_args, PyInt_AS_LONG (item));
break;
default:
/* bad args string */
enode_call_free_arg_list_items (call_args);
PyErr_SetString (PyExc_TypeError, "Bad argument string");
return NULL;
}
}
}
EDEBUG (("python-embed-call", "py_call: done args processing"));
retval = enode_call_with_list (self->enode, function, call_args);
if (!retval) {
EDEBUG (
("python-embed-call",
"py_call: retval was NULL. returning None"));
Py_INCREF (Py_None);
return Py_None;
} else {
EDEBUG (("python-embed-call", "py_call: retval was %s", retval->str));
py_retr = PyString_FromStringAndSize (retval->str, retval->len);
ebuf_free (retval);
return py_retr;
}
}
typedef EBuf *(*enode_attr_func) (ENode *, gchar *, EBuf *);
/* Helper function for py_attrib_common */
static void
py_attrib_set_with_func (ENode * node, GSList * attrs, GSList * vals,
enode_attr_func func)
{
GSList *my_attrs;
GSList *my_vals;
for (my_attrs = attrs, my_vals = vals;
my_attrs && my_vals;
my_attrs = my_attrs->next, my_vals = my_vals->next) {
gchar *attrib = my_attrs->data;
gchar *value = my_vals->data;
EDEBUG (("python-embed", "foo!"));
EDEBUG (("python-embed", "py_attrib_set_with_func, setting %s to %s",
attrib, value));
func (node, attrib, ebuf_new_with_str (value));
g_free (attrib);
g_free (value);
}
}
PyObject *
py_attrib_common (PyEnodeObject * self, PyObject * args, enode_attr_func func)
{
PyObject *this;
EDEBUG (("python-embed", "py_attrib_common: entering."));
this = PyTuple_GetItem (args, 0);
EDEBUG (("python-embed", "py_attrib_common: got argument."));
if (PyString_Check (this)) {
/* return the value of the attribute whose name specified by 'this' */
gchar *val = NULL;
EBuf *ret;
EDEBUG (("python-embed", "in py_attrib_common, arg is a string"));
ret = enode_attrib (self->enode, PyString_AsString (this), NULL);
if (ret) {
val = strdup (ret->str);
EDEBUG (
("python-embed",
"in py_attrib_common, returning a pystring of %s", val));
return PyString_FromString (val);
} else {
return Py_None;
}
}
else if (PyMapping_Check (this)) {
/* take the mapping and apply attribute changes using stringified
* keys as attribute names and the values as the attribute values */
int j;
int len;
GSList *attrs = NULL;
GSList *vals = NULL;
gchar *attr;
gchar *val;
PyObject *a_pair;
PyObject *conv1;
PyObject *conv2;
PyObject *pairs;
pairs = PyMapping_Items (this);
EDEBUG (("python-embed", "in py_attrib_common, arg is a dictionary"));
len = PyMapping_Length (this);
for (j = 0; j < len; j++) {
a_pair = PyList_GetItem (pairs, j);
conv1 = PyObject_Str (PyTuple_GetItem (a_pair, 0));
attr = strdup (PyString_AsString (conv1));
conv2 = PyObject_Str (PyTuple_GetItem (a_pair, 1));
val = strdup (PyString_AsString (conv2));
EDEBUG (("python-embed", "in py_attrib_common, addding %s -> %s",
attr, val));
attrs = g_slist_append (attrs, attr);
vals = g_slist_append (vals, val);
Py_XDECREF (conv1);
Py_XDECREF (conv2);
}
/* This also frees the individual items as it sets them */
py_attrib_set_with_func (self->enode, attrs, vals, func);
g_slist_free (vals);
g_slist_free (attrs);
EDEBUG (
("python-embed",
"py_attrib_set_with_func, cleaing up and returning 'None'"));
Py_XDECREF (pairs);
Py_INCREF (Py_None);
return Py_None;
}
EDEBUG (("python-embed", "py_attrib_set_with_func, incorrect arguments."));
PyErr_SetString (PyExc_TypeError,
"Function takes one argument of string or dictionary type.");
/* clean up here. */
return NULL;
}
PyObject *
py_attrib (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
return py_attrib_common (self, args, enode_attrib);
}
PyObject *
py_attrib_quiet (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
return py_attrib_common (self, args, enode_attrib_quiet);
}
PyObject *
py_attrib_is_true (PyEnodeObject * self, PyObject * args)
{
gchar *attr;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", &attr))
return NULL;
return PyInt_FromLong (enode_attrib_is_true (self->enode, attr));
}
PyObject *
py_list_set_attribs (PyEnodeObject * self, PyObject * args)
{
int num_attrs;
int i;
GSList *attrs;
GSList *p;
PyObject *py_attrs; /* The attribs after pyob conversion. */
EBuf *value; /* The value for the curent attrib. */
ECHECK_RETVAL (self->enode != NULL, NULL);
attrs = enode_list_set_attribs (self->enode);
num_attrs = g_slist_length (attrs);
py_attrs = PyTuple_New (num_attrs);
for (i = 0, p = attrs; p; p = p->next, i++) {
value = (EBuf *) p->data;
PyTuple_SetItem (py_attrs, i, PyString_FromString (value->str));
}
g_slist_free (attrs);
return py_attrs;
}
PyObject *
py_supported_attribs (PyEnodeObject * self, PyObject * args)
{
int num_attrs;
int i;
GSList *attrs;
GSList *p;
PyObject *py_attrs;
ECHECK_RETVAL (self->enode != NULL, NULL);
attrs = enode_supported_attribs (self->enode);
num_attrs = g_slist_length (attrs);
py_attrs = PyTuple_New (num_attrs);
for (i = 0, p = attrs; p; p = p->next, i++)
PyTuple_SetItem (py_attrs, i, PyString_FromString ((gchar *) p->data));
g_slist_free (attrs);
return py_attrs;
}
PyObject *
py_attrib_description (PyEnodeObject * self, PyObject * args)
{
gchar *desc;
gchar *attr;
ECHECK_RETVAL (self->enode != NULL, NULL);
PyArg_ParseTuple (args, "s", &attr);
desc = enode_attrib_description (self->enode, attr);
if (desc == NULL)
desc = ""; /* FIXME: is this the right thing to do? */
return PyString_FromString (desc);
}
PyObject *
py_attrib_value_type (PyEnodeObject * self, PyObject * args)
{
gchar *attr;
gchar *valtype;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", &attr))
return NULL;
valtype = enode_attrib_value_type (self->enode, attr);
if (valtype == NULL) {
PyErr_SetString (PyExc_TypeError,
"No such attribute or No values types listed.");
return NULL;
}
return PyString_FromString (valtype);
}
PyObject *
py_attrib_possible_values (PyEnodeObject * self, PyObject * args)
{
gchar *attr;
gchar *valopts;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s", &attr))
return NULL;
valopts = enode_attrib_possible_values (self->enode, attr);
if (valopts == NULL) {
PyErr_SetString (PyExc_TypeError,
"No such attribute or No value options listed.");
return NULL;
}
return PyString_FromString (valopts);
}
PyObject *
py_attribs_sync (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
enode_attribs_sync (self->enode);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_get_kv (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
PyErr_SetString (PyExc_TypeError, "Not Implemented.");
return NULL;
}
PyObject *
py_set_kv (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
PyErr_SetString (PyExc_TypeError, "Not Implemented.");
return NULL;
}
PyObject *
py_destroy (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
enode_destroy (self->enode);
/* I don't think this is correct, it should be handled by the reference
* counting, and any further access to this node should access the
* 'dangler' enode */
/* self->enode = NULL; */
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_destroy_children (PyEnodeObject * self, PyObject * args)
{
ECHECK_RETVAL (self->enode != NULL, NULL);
enode_destroy_children (self->enode);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_get_xml (PyEnodeObject * self, PyObject * args)
{
EBuf *xml;
PyObject *result;
ECHECK_RETVAL (self->enode != NULL, NULL);
xml = enode_get_xml (self->enode);
result = PyString_FromStringAndSize (xml->str, xml->len);
ebuf_free (xml);
return result;
}
PyObject *
py_get_child_xml (PyEnodeObject * self, PyObject * args)
{
EBuf *xml;
PyObject *result;
ECHECK_RETVAL (self->enode != NULL, NULL);
xml = enode_get_child_xml (self->enode);
result = PyString_FromStringAndSize (xml->str, xml->len);
ebuf_free (xml);
return result;
}
PyObject *
py_append_xml (PyEnodeObject * self, PyObject * args)
{
gchar *xml_str;
EBuf *xml_ebuf;
int len;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s#", &xml_str, &len))
return NULL;
xml_ebuf = ebuf_new_with_data (xml_str, len);
enode_append_xml (self->enode, xml_ebuf);
ebuf_free (xml_ebuf);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_set_data (PyEnodeObject * self, PyObject * args)
{
gchar *data;
int data_len;
EBuf *data_ebuf;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s#", &data, &data_len))
return NULL;
data_ebuf = ebuf_new_with_data (data, data_len);
enode_set_data (self->enode, data_ebuf);
ebuf_free (data_ebuf);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_get_data (PyEnodeObject * self, PyObject * args)
{
PyObject *data_py;
EBuf *data;
ECHECK_RETVAL (self->enode != NULL, NULL);
data = enode_get_data (self->enode);
if (data == NULL) {
PyErr_SetString (PyExc_TypeError, "enode_get_data returned NULL.");
return NULL;
}
data_py = PyString_FromStringAndSize (data->str, data->len);
return data_py;
}
PyObject *
py_append_data (PyEnodeObject * self, PyObject * args)
{
gchar *data;
int data_len;
EBuf *data_ebuf;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s#", &data, &data_len))
return NULL;
data_ebuf = ebuf_new_with_data (data, data_len);
enode_append_data (self->enode, data_ebuf);
ebuf_free (data_ebuf);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_insert_data (PyEnodeObject * self, PyObject * args)
{
gchar *data;
int data_len;
int offset;
EBuf *data_ebuf;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "s#i", &data, &data_len, &offset))
return NULL;
data_ebuf = ebuf_new_with_data (data, data_len);
enode_insert_data (self->enode, offset, data_ebuf);
ebuf_free (data_ebuf);
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
py_delete_data (PyEnodeObject * self, PyObject * args)
{
int len;
int offset;
ECHECK_RETVAL (self->enode != NULL, NULL);
if (!PyArg_ParseTuple (args, "ii", &offset, &len))
return NULL;
enode_delete_data (self->enode, offset, len);
Py_INCREF (Py_None);
return Py_None;
}
static struct PyMethodDef py_enode_methods[] = {
/* Base Interface */
{"new_child", (PyCFunction) py_new_child, METH_VARARGS},
{"type", (PyCFunction) py_type, 0},
{"path", (PyCFunction) py_path, 0},
{"basename", (PyCFunction) py_basename, 0},
{"description", (PyCFunction) py_description, 0},
/* Node Search Functions */
{"parent", (PyCFunction) py_parent, 1},
{"child", (PyCFunction) py_child, 1},
{"child_rx", (PyCFunction) py_child_rx, 1},
{"children", (PyCFunction) py_children, METH_VARARGS},
{"children_rx", (PyCFunction) py_children_rx, 1},
{"children_attrib", (PyCFunction) py_children_attrib, 2},
{"children_attrib_rx", (PyCFunction) py_children_attrib_rx, 2},
/* Object Based Utils */
{"call", (PyCFunction) py_call, METH_VARARGS},
/* Attribute Properties and Attribute Support Queries */
{"attrib", (PyCFunction) py_attrib, 1},
{"attrib_quiet", (PyCFunction) py_attrib_quiet, 1},
{"attrib_is_true", (PyCFunction) py_attrib_is_true, 1},
{"list_set_attribs", (PyCFunction) py_list_set_attribs, 0},
{"supported_attribs", (PyCFunction) py_supported_attribs, 0},
{"attrib_description", (PyCFunction) py_attrib_description, 1},
{"attrib_value_type", (PyCFunction) py_attrib_value_type, METH_VARARGS},
{"attrib_possible_values", (PyCFunction) py_attrib_possible_values,
METH_VARARGS},
{"attribs_sync", (PyCFunction) py_attribs_sync, METH_VARARGS},
/* Arbitrary key/value Attachment */
{"set_kv", (PyCFunction) py_set_kv, METH_VARARGS},
{"get_kv", (PyCFunction) py_get_kv, METH_VARARGS},
/* Node destruction */
{"destroy", (PyCFunction) py_destroy, METH_VARARGS},
{"destroy_children", (PyCFunction) py_destroy_children, METH_VARARGS},
/* Raw XML Interfaces */
{"get_xml", (PyCFunction) py_get_xml, 0},
{"get_child_xml", (PyCFunction) py_get_child_xml, 0},
{"append_xml", (PyCFunction) py_append_xml, 1},
/* Node Data interface */
{"set_data", (PyCFunction) py_set_data, METH_VARARGS},
{"get_data", (PyCFunction) py_get_data, METH_VARARGS},
{"append_data", (PyCFunction) py_append_data, METH_VARARGS},
{"insert_data", (PyCFunction) py_insert_data, METH_VARARGS},
{"delete_data", (PyCFunction) py_delete_data, METH_VARARGS},
{NULL, NULL}
};
/* This function can be called globally
*/
PyObject *
py_enode_rx (PyObject * self, PyObject * args)
{
char *regex = NULL; /* The second or only string. */
ENode *result; /* The found node. */
PyObject *py_result; /* Python result to return out. */
if (!PyArg_ParseTuple (args, "|s", ®ex))
return NULL;
if (!regex) /* We have no arg. */
regex = ""; /* Not NULL. */
result = enode_rx (regex);
py_result = py_enode_new_from_enode (result);
return py_result;
}
PyObject *
py_elist (PyObject * self, PyObject * args)
{
char *search = NULL; /* The string we're searching for */
GSList *result;
PyObject *py_result;
if (!PyArg_ParseTuple (args, "|s", &search))
return NULL;
/* We can't search for a null pointer but we can search for "" */
if (search)
result = elist (search);
else
result = elist ("");
py_result = py_enode_glist_to_pylist (result);
g_slist_free (result);
return py_result;
}
PyObject *
py_elist_rx (PyObject * self, PyObject * args)
{
char *search = NULL; /* The string we're searching for */
GSList *result;
PyObject *py_result;
if (!PyArg_ParseTuple (args, "|s", &search))
return NULL;
/* We can't search for a null pointer but we can search for "" */
if (search)
result = elist_rx (search);
else
result = elist_rx ("");
py_result = py_enode_glist_to_pylist (result);
g_slist_free (result);
return py_result;
}
PyObject *
py_enode_constructor (PyObject * self, PyObject * args)
{
char *path;
ENode *node;
PyObject *py_node;
if (!PyArg_ParseTuple (args, "s", &path)) {
EDEBUG (("python-embed", "enode could not parse its arguments."));
return NULL;
}
EDEBUG (("python-embed", "in enode() parsed args, got path='%s'", path));
node = enode (path);
/* Again, dumbing it down again, and returning Py_None when the node is *
* not found. */
if (node == NULL) {
/*
* PyErr_SetString(PyExc_TypeError, "No such node found.");
* return NULL;
*/
EDEBUG (("python-embed", "in enode() node retrieved was NULL!"));
Py_INCREF (Py_None);
return Py_None;
}
py_node = py_enode_new_from_enode (node);
return py_node;
}
static struct PyMethodDef py_entity_module_methods[] = {
{"enode", py_enode_constructor, 1},
{"enode_rx", py_enode_rx, 1},
{"elist", py_elist, 1},
{"elist_rx", py_elist_rx, 1},
{NULL, NULL}
};
/* Start up the interpreter. */
void
python_start (void)
{
int argc;
gchar **argv;
static struct sigaction siga;
siga.sa_handler = SIG_DFL;
siga.sa_flags = 0;
Py_Initialize ();
argc = entity_get_argc ();
argv = entity_get_argv ();
PySys_SetArgv (argc, argv);
EDEBUG (("python-embed", "python started"));
Py_InitModule ("Entity", py_entity_module_methods);
PyRun_SimpleString ("from Entity import *");
sigaction (SIGINT, &siga, NULL);
}
static EBuf *
python_function_execute (ENode * calling_node, gchar * function, GSList * args)
{
PyObject *args_obj;
PyObject *func = NULL;
PyObject *item = NULL;
PyObject *result;
PyObject *string_rep;
PyObject *modules;
PyObject *module;
PyObject *attribs;
GSList *tmp;
GSList *objlist = NULL; /* Keep track of objects which need freeing
* so we can free them when done */
EBuf *return_val;
gchar *namespace;
LangArg *arg;
gint i = 0;
ECHECK_RETVAL (calling_node != NULL, NULL);
ECHECK_RETVAL (function != NULL, NULL);
EDEBUG (("python-embed", "Trying to call %s", function));
/*
* Find the function (todo: the module dict should be cached, n'estpas?) */
namespace = get_python_namespace ();
modules = PyImport_GetModuleDict (); /* can't fail */
module = PyDict_GetItemString (modules, namespace);
if (!module) {
g_warning ("module %s not found trying to execute %s", namespace,
function);
PyErr_Print ();
return NULL;
}
attribs = PyModule_GetDict (module); /* can't fail */
func = PyDict_GetItemString (attribs, function);
if (!func) {
g_warning ("function (%s) doesn't exist in %s", function, namespace);
return NULL;
}
/* Munge function arguments into a Python arguments tuple.
* Check the value types and make an appropriate python value. */
EDEBUG (("python-embed", "Munging Arguments:"));
args_obj = PyTuple_New (g_slist_length (args));
objlist = g_slist_append (objlist, args_obj);
for (tmp = args; tmp; tmp = tmp->next) {
arg = (LangArg *) tmp->data;
if (arg->type == LANG_NODE) {
item = py_enode_new_from_enode (arg->data);
PyTuple_SetItem (args_obj, i, item);
} else if (arg->type == LANG_STRING) {
item = Py_BuildValue ("s", (char *) arg->data);
PyTuple_SetItem (args_obj, i, item);
} else if (arg->type == LANG_INT) {
item = Py_BuildValue ("i", arg->intdata);
PyTuple_SetItem (args_obj, i, item);
} else if (arg->type == LANG_BINSTRING) {
item = Py_BuildValue ("s#", (char *) arg->data, arg->size);
PyTuple_SetItem (args_obj, i, item);
} else if (arg->type == LANG_DOUBLE) {
item = Py_BuildValue ("d", arg->doubledata);
PyTuple_SetItem (args_obj, i, item);
}
i++;
enode_call_free_arg (arg);
}
EDEBUG (("python-embed", "Done munging arguments, calling function"));
result = PyEval_CallObject (func, args_obj);
/* Do cleanup stuff now */
for (tmp = objlist; tmp; tmp = tmp->next) {
PyObject *obj = tmp->data;
EDEBUG (("python-embed", "XDECREFfing a %s, refcount %i",
obj->ob_type->tp_name, obj->ob_refcnt));
Py_XDECREF (obj);
}
g_slist_free (objlist);
if (!result) {
g_warning ("function (%s) didn't execute correctly", function);
PyErr_Print ();
return NULL;
}
if (result != Py_None) {
string_rep = PyObject_Str (result);
return_val = ebuf_new_with_str (PyString_AsString (string_rep));
EDEBUG (("python-embed", "returning value '%s'", return_val->str));
/* Hopefully this is correct.. */
Py_XDECREF (string_rep);
} else {
return_val = NULL;
}
return return_val;
}
/* Render the python node */
void
python_render (ENode * node)
{
static gint initialized = FALSE;
static EBuf *py_cmd = NULL;
gchar *namespace;
PyObject *code_pyobj;
ECHECK_RET (node != NULL);
ECHECK_RET (node->data != NULL);
if (!initialized) {
python_start ();
initialized = TRUE;
}
if (!py_cmd)
py_cmd = ebuf_new_sized (1024);
ebuf_truncate (py_cmd, 0);
ebuf_append_str (py_cmd, "\nfrom Entity import *\n");
ebuf_append_ebuf (py_cmd, node->data);
enode_call_reference_push (node);
namespace = get_python_namespace ();
code_pyobj = Py_CompileString (py_cmd->str, namespace, Py_file_input);
if (code_pyobj == NULL) {
g_warning
("Could not compile a python data section"
" .. Here, have some traceback:");
if (PyErr_Occurred () != NULL)
PyErr_Print ();
return;
}
/* actually build the new module */
PyImport_ExecCodeModule (namespace, code_pyobj);
ebuf_truncate (py_cmd, 0);
ebuf_append_str (py_cmd, "import ");
ebuf_append_str (py_cmd, namespace);
ebuf_append_str (py_cmd, "\n");
PyRun_SimpleString (py_cmd->str); /* this happens in main */
enode_call_reference_pop ();
}
#ifdef STATIC_PYTHON
void
python_init (RendererFlags flags)
#else
void
renderer_init (RendererFlags flags)
#endif
{
Element *element;
if (flags & RENDERER_REGISTER) {
element = g_new0 (Element, 1);
element->render_func = python_render;
element->tag = "python";
element_register (element);
/* Set both python and py so we can use either name. */
language_register ("python", python_function_execute);
language_register ("py", python_function_execute);
}
}
syntax highlighted by Code2HTML, v. 0.9.1