#include #include #include #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.. 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.. ass_subscript? * jyon crys hehe is he making anal rape jokes now too? heh py_squirm_ass_insert(PyObject *thingy); ? haha PyDildo *red 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); } }