1 #include <Python.h>
2 #include <structmember.h>
3 #include <lasso/lasso.h>
4 #include <config.h>
5 #include "../ghashtable.h"
6 #include "../../lasso/debug.h"
7 #include "../../lasso/utils.h"
8 #include "../utils.c"
9
10 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
11 typedef int Py_ssize_t;
12 #define PY_SSIZE_T_MAX INT_MAX
13 #define PY_SSIZE_T_MIN INT_MIN
14 #endif
15
16 /** @todo Remove Python 3 defines and update the code when Python 2 is out of the picture. */
17
18 // Python 3 has unified int & long types.
19 #if PY_MAJOR_VERSION >= 3
20 #define PyInt_AS_LONG PyLong_AS_LONG
21 #define PyInt_Check PyLong_Check
22 #define PyInt_FromLong PyLong_FromLong
23 #endif
24
25 // Python 3 has removed PyString and related functions, in favor of PyBytes & PyUnicode.
26 #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 3)
27 #define PyString_Check PyUnicode_Check
28 #define PyString_FromFormat PyUnicode_FromFormat
29 #define PyString_FromString PyUnicode_FromString
30 #define PyString_AsString PyUnicode_AsUTF8
31 #define get_pystring PyUnicode_AsUTF8AndSize
32 #define PyStringFree(string) ;
33 #elif PY_MAJOR_VERSION >= 3
34 #define PyString_Check PyUnicode_Check
35 #define PyString_FromFormat PyUnicode_FromFormat
36 #define PyString_FromString PyUnicode_FromString
PyString_AsString(PyObject * string)37 static char *PyString_AsString(PyObject *string) {
38 PyObject *bytes = PyUnicode_AsUTF8String(string);
39 char *ret = NULL;
40 if (! bytes)
41 return NULL;
42 ret = g_strdup(PyBytes_AsString(bytes));
43 Py_DECREF(bytes);
44 return ret;
45 }
get_pystring(PyObject * string,Py_ssize_t * size)46 static char *get_pystring(PyObject *string, Py_ssize_t *size) {
47 char *ret = NULL;
48
49 ret = PyString_AsString(string);
50 *size = strlen(ret);
51 return ret;
52 }
53 #define PyStringFree(string) g_free(string)
54 #elif PY_MAJOR_VERSION >= 3
55 #else
get_pystring(PyObject * string,Py_ssize_t * size)56 static char *get_pystring(PyObject *string, Py_ssize_t *size) {
57 char *ret = NULL;
58
59 PyString_AsStringAndSize(string, &ret, size);
60
61 return ret;
62 }
63 #define PyStringFree(string) ;
PyErr_WarnFormat(PyObject * category,int stacklevel,const char * format,...)64 void PyErr_WarnFormat(PyObject *category, int stacklevel, const char *format, ...) {
65
66 va_list ap;
67 char s[1024];
68
69 va_start(ap, format);
70 g_vsnprintf(s, 1024, format, ap);
71 va_end(ap);
72 PyErr_WarnEx(category, s, stacklevel);
73 }
74 #endif
75
76 #define RETURN_IF_FAIL(op) do { if (! (op)) { return NULL; } } while(0)
77 #define EXIT_IF_FAIL(op) do { if (! (op)) { ok = 0; goto failure; } } while(0)
78
79 GQuark lasso_wrapper_key;
80
81
82 #if PY_MAJOR_VERSION > 3
83 PyMODINIT_FUNC PyInit_lasso(void);
84 #else
85 PyMODINIT_FUNC init_lasso(void);
86 #endif
87 G_GNUC_UNUSED static PyObject* get_pystring_from_xml_node(xmlNode *xmlnode);
88 G_GNUC_UNUSED static xmlNode* get_xml_node_from_pystring(PyObject *string);
89 G_GNUC_UNUSED static PyObject* get_dict_from_hashtable_of_objects(GHashTable *value);
90 G_GNUC_UNUSED static PyObject* get_dict_from_hashtable_of_strings(GHashTable *value);
91 G_GNUC_UNUSED static PyObject* PyGObjectPtr_New(GObject *obj);
92 G_GNUC_UNUSED static int set_hashtable_of_pygobject(GHashTable *a_hash, PyObject *dict);
93 G_GNUC_UNUSED static int set_hashtable_of_strings(GHashTable *a_hash, PyObject *dict);
94 G_GNUC_UNUSED static int set_list_of_strings(GList **a_list, PyObject *seq);
95 G_GNUC_UNUSED static int set_list_of_xml_nodes(GList **a_list, PyObject *seq);
96 G_GNUC_UNUSED static int set_list_of_pygobject(GList **a_list, PyObject *seq);
97 G_GNUC_UNUSED static PyObject *get_list_of_strings(const GList *a_list);
98 G_GNUC_UNUSED static PyObject *get_list_of_xml_nodes(const GList *a_list);
99 G_GNUC_UNUSED static PyObject *get_list_of_pygobject(const GList *a_list);
100 G_GNUC_UNUSED static gboolean valid_seq(PyObject *seq);
101 G_GNUC_UNUSED static void free_list(GList **a_list, GFunc free_help);
102 G_GNUC_UNUSED static time_t* get_time_t(PyObject *time);
103
104 typedef struct {
105 PyObject_HEAD
106 GObject *obj;
107 PyObject *typename;
108 } PyGObjectPtr;
109 static PyTypeObject PyGObjectPtrType;
110
111 /* utility functions */
112 static PyObject *
noneRef()113 noneRef() {
114 Py_INCREF(Py_None);
115 return Py_None;
116 }
117
118 static PyObject*
get_dict_from_hashtable_of_objects(GHashTable * value)119 get_dict_from_hashtable_of_objects(GHashTable *value)
120 {
121 GList *keys, *begin;
122 PyObject *dict,*proxy;
123 GObject *item_value;
124 PyObject *item;
125
126 dict = PyDict_New();
127
128 begin = keys = g_hash_table_get_keys(value);
129 for (; keys; keys = g_list_next(keys)) {
130 item_value = g_hash_table_lookup(value, keys->data);
131 if (item_value) {
132 item = PyGObjectPtr_New(G_OBJECT(item_value));
133 PyDict_SetItemString(dict, (char*)keys->data, item);
134 Py_DECREF(item);
135 } else {
136 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "hashtable contains a null value");
137 }
138 }
139 g_list_free(begin);
140
141 proxy = PyDictProxy_New(dict);
142 Py_DECREF(dict);
143 return proxy;
144 }
145
146 static PyObject*
get_dict_from_hashtable_of_strings(GHashTable * value)147 get_dict_from_hashtable_of_strings(GHashTable *value)
148 {
149 GList *keys, *begin;
150 PyObject *dict,*proxy;
151 char *item_value;
152 PyObject *item;
153
154 dict = PyDict_New();
155
156 if (value) {
157 begin = keys = g_hash_table_get_keys(value);
158 for (; keys; keys = g_list_next(keys)) {
159 item_value = g_hash_table_lookup(value, keys->data);
160 if (item_value) {
161 item = PyString_FromString(item_value);
162 PyDict_SetItemString(dict, (char*)keys->data, item);
163 Py_DECREF(item);
164 } else {
165 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "hashtable contains a null value");
166 }
167 }
168 g_list_free(begin);
169 }
170
171 proxy = PyDictProxy_New(dict);
172 Py_DECREF(dict);
173 return proxy;
174 }
175
176 static xmlBuffer*
xmlnode_to_xmlbuffer(xmlNode * node)177 xmlnode_to_xmlbuffer(xmlNode *node)
178 {
179 xmlOutputBufferPtr output_buffer;
180 xmlBuffer *buffer;
181
182 if (! node)
183 return NULL;
184
185 buffer = xmlBufferCreate();
186 output_buffer = xmlOutputBufferCreateBuffer(buffer, NULL);
187 xmlNodeDumpOutput(output_buffer, NULL, node, 0, 0, NULL);
188 xmlOutputBufferClose(output_buffer);
189 xmlBufferAdd(buffer, BAD_CAST "", 1);
190
191 return buffer;
192 }
193
194 static PyObject*
get_pystring_from_xml_node(xmlNode * xmlnode)195 get_pystring_from_xml_node(xmlNode *xmlnode)
196 {
197 PyObject *pystring = NULL;
198 xmlBuffer *buffer;
199
200 if (xmlnode == NULL) {
201 return NULL;
202 }
203 buffer = xmlnode_to_xmlbuffer(xmlnode);
204
205 if (buffer == NULL) {
206 pystring = NULL;
207 } else {
208 pystring = PyString_FromString((char*)xmlBufferContent(buffer));
209 xmlBufferFree(buffer);
210 }
211
212 return pystring;
213 }
214
215 static gboolean
valid_seq(PyObject * seq)216 valid_seq(PyObject *seq) {
217 if (! seq || ( seq != Py_None && ! PyTuple_Check(seq))) {
218 return 0;
219 }
220 return 1;
221 }
222
223 static void
free_list(GList ** a_list,GFunc free_help)224 free_list(GList **a_list, GFunc free_help) {
225 if (*a_list) {
226 g_list_foreach(*a_list, free_help, NULL);
227 g_list_free(*a_list);
228 }
229 }
230
231 /** Remove all elements from a_hash and replace them with
232 * the key-values pairs from the python dict.
233 * Increase reference of new values before removeing
234 * values from the hash, so if there are somme common
235 * values with RefCoun = 1 they won't be deallocated.
236 * */
237 static int
set_hashtable_of_pygobject(GHashTable * a_hash,PyObject * dict)238 set_hashtable_of_pygobject(GHashTable *a_hash, PyObject *dict) {
239 PyObject *key, *value;
240 Py_ssize_t i;
241
242 if (! a_hash) {
243 PyErr_SetString(PyExc_TypeError, "hashtable does not exist");
244 return 0;
245 }
246 if (dict != Py_None && ! PyDict_Check(dict)) {
247 PyErr_SetString(PyExc_TypeError, "value should be a frozen dict");
248 return 0;
249 }
250 i = 0;
251 // Increase ref count of common object between old and new
252 // value of the hashtable
253 while (PyDict_Next(dict, &i, &key, &value)) {
254 if (! PyString_Check(key) || ! PyObject_TypeCheck(value, &PyGObjectPtrType))
255 {
256 PyErr_SetString(PyExc_TypeError,
257 "value should be a dict, "
258 "with string keys "
259 "and GObjectPtr values");
260 goto failure;
261 }
262 g_object_ref(((PyGObjectPtr*)value)->obj);
263 }
264 g_hash_table_remove_all (a_hash);
265 i = 0;
266 while (PyDict_Next(dict, &i, &key, &value)) {
267 const char *ckey = PyString_AsString(key);
268 g_hash_table_replace (a_hash, g_strdup(ckey), ((PyGObjectPtr*)value)->obj);
269 PyStringFree(ckey);
270 }
271 return 1;
272 failure:
273 i = 0;
274 while (PyDict_Next(dict, &i, &key, &value)) {
275 if (! PyString_Check(key) || ! PyObject_TypeCheck(value, &PyGObjectPtrType))
276 break;
277 g_object_unref((PyGObjectPtr*)value);
278 }
279 return 0;
280 }
281
282 static int
set_hashtable_of_strings(GHashTable * a_hash,PyObject * dict)283 set_hashtable_of_strings(GHashTable *a_hash, PyObject *dict)
284 {
285 PyObject *key, *value;
286 Py_ssize_t i;
287
288 if (! a_hash) {
289 PyErr_SetString(PyExc_TypeError, "hashtable does not exist");
290 return 0;
291 }
292 if (dict != Py_None && ! PyDict_Check(dict)) {
293 PyErr_SetString(PyExc_TypeError, "value should be a frozen dict");
294 return 0;
295 }
296 i = 0;
297 // Increase ref count of common object between old and new
298 // value of the hashtable
299 while (PyDict_Next(dict, &i, &key, &value)) {
300 if (! PyString_Check(key) || ! PyString_Check(value))
301 {
302 PyErr_SetString(PyExc_TypeError,
303 "value should be a dict, "
304 "with string keys "
305 "and string values");
306 goto failure;
307 }
308 }
309 g_hash_table_remove_all (a_hash);
310 i = 0;
311 while (PyDict_Next(dict, &i, &key, &value)) {
312 const char *ckey = PyString_AsString(key);
313 const char *cvalue = PyString_AsString(value);
314 g_hash_table_insert (a_hash, g_strdup(ckey), g_strdup(cvalue));
315 PyStringFree(ckey);
316 PyStringFree(cvalue);
317 }
318 return 1;
319 failure:
320 return 0;
321 }
322
323 /** Set the GList* pointer, pointed by a_list, to a pointer on a new GList
324 * created by converting the python seq into a GList of char*.
325 */
326 static int
set_list_of_strings(GList ** a_list,PyObject * seq)327 set_list_of_strings(GList **a_list, PyObject *seq) {
328 GList *list = NULL;
329 int l = 0,i;
330
331 if (! valid_seq(seq)) {
332 PyErr_SetString(PyExc_TypeError,
333 "value should be a tuple of strings");
334 return 0;
335 }
336 if (seq != Py_None) {
337 l = PySequence_Length(seq);
338 }
339 for (i=0; i<l; i++) {
340 const char *astr = NULL;
341
342 PyObject *pystr = PySequence_Fast_GET_ITEM(seq, i);
343 if (! PyString_Check(pystr)) {
344 PyErr_SetString(PyExc_TypeError,
345 "value should be a tuple of strings");
346 goto failure;
347 }
348 astr = PyString_AsString(pystr);
349 list = g_list_append(list, g_strdup(astr));
350 PyStringFree(astr);
351 }
352 free_list(a_list, (GFunc)g_free);
353 *a_list = list;
354 return 1;
355 failure:
356 free_list(&list, (GFunc)g_free);
357 return 0;
358 }
359
360 /** Set the GList* pointer, pointed by a_list, to a pointer on a new GList
361 * created by converting the python seq into a GList of xmlNode*.
362 */
363 static int
set_list_of_xml_nodes(GList ** a_list,PyObject * seq)364 set_list_of_xml_nodes(GList **a_list, PyObject *seq) {
365 GList *list = NULL;
366 int l = 0, i;
367
368 if (! valid_seq(seq)) {
369 PyErr_SetString(PyExc_TypeError,
370 "value should be a tuple of strings");
371 return 0;
372 }
373 if (seq != Py_None) {
374 l = PySequence_Length(seq);
375 }
376 for (i=0; i<l; i++) {
377 PyObject *item = PySequence_Fast_GET_ITEM(seq, i);
378 xmlNode *item_node;
379 if (! PyString_Check(item)) {
380 PyErr_SetString(PyExc_TypeError,
381 "value should be a tuple of strings");
382 goto failure;
383 }
384 item_node = get_xml_node_from_pystring(item);
385 if (! item_node) {
386 PyErr_SetString(PyExc_TypeError,
387 "values should be valid XML fragments");
388 goto failure;
389 }
390 list = g_list_append(list, item_node);
391 }
392 free_list(a_list, (GFunc)xmlFreeNode);
393 *a_list = list;
394 return 1;
395 failure:
396 free_list(&list, (GFunc)xmlFreeNode);
397 return 0;
398 }
399
400 /** Set the GList* pointer, pointed by a_list, to a pointer on a new GList
401 * created by converting the python seq into a GList of GObject*.
402 */
403 static int
set_list_of_pygobject(GList ** a_list,PyObject * seq)404 set_list_of_pygobject(GList **a_list, PyObject *seq) {
405 GList *list = NULL;
406 int l = 0,i;
407
408 if (!valid_seq(seq)) {
409 PyErr_SetString(PyExc_TypeError,
410 "value should be a tuple of PyGobject");
411 return 0;
412 }
413 if (seq != Py_None) {
414 l = PySequence_Length(seq);
415 }
416 for (i=0; i<l; i++) {
417 PyObject *item = PySequence_Fast_GET_ITEM(seq, i);
418 GObject *gobject;
419 if (! PyObject_TypeCheck(item, &PyGObjectPtrType)) {
420 PyErr_SetString(PyExc_TypeError,
421 "value should be a tuple of PyGobject");
422 goto failure;
423 }
424 gobject = g_object_ref(((PyGObjectPtr*)item)->obj);
425 list = g_list_append(list, gobject);
426 }
427 free_list(a_list, (GFunc)g_object_unref);
428 *a_list = list;
429 return 1;
430 failure:
431 free_list(&list, (GFunc)g_object_unref);
432 return 0;
433 }
434
435 static xmlNode*
get_xml_node_from_pystring(PyObject * string)436 get_xml_node_from_pystring(PyObject *string) {
437 const char *utf8 = NULL;
438 Py_ssize_t size;
439 xmlNode *xml_node;
440 utf8 = get_pystring(string, &size);
441 xml_node = lasso_string_fragment_to_xmlnode(utf8, size);
442 PyStringFree(utf8);
443 return xml_node;
444 }
445
446 /** Return a tuple containing the string contained in a_list */
447 static PyObject *
get_list_of_strings(const GList * a_list)448 get_list_of_strings(const GList *a_list) {
449 PyObject *a_tuple = NULL;
450 int i = 0;
451
452 /* Cast because g_list_length does not take const but is a const function */
453 a_tuple = PyTuple_New(g_list_length((GList*)a_list));
454 if (! a_tuple)
455 goto failure;
456 if (! a_list) {
457 return a_tuple;
458 }
459 while (a_list) {
460 if (a_list->data) {
461 PyObject *str = PyString_FromString((const char*)a_list->data);
462 if (!str) {
463 goto failure;
464 }
465 PyTuple_SetItem(a_tuple, i, str);
466 i++;
467 } else {
468 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "list contains a NULL value");
469 }
470 a_list = a_list->next;
471 }
472 if (_PyTuple_Resize(&a_tuple, i))
473 goto failure;
474 return a_tuple;
475 failure:
476 PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings");
477 Py_XDECREF(a_tuple);
478 return NULL;
479 }
480
481 static PyObject *
get_list_of_xml_nodes(const GList * a_list)482 get_list_of_xml_nodes(const GList *a_list) {
483 PyObject *a_tuple = NULL;
484 int i = 0;
485
486 /* Cast because g_list_length does not take const but is a const function */
487 a_tuple = PyTuple_New(g_list_length((GList*)a_list));
488 if (! a_tuple)
489 goto failure;
490 if (! a_list) {
491 return a_tuple;
492 }
493 while (a_list) {
494 if (a_list->data) {
495 PyObject *str = get_pystring_from_xml_node((xmlNode*)a_list->data);
496 if (str) {
497 PyTuple_SetItem(a_tuple, i, str);
498 i++;
499 } else {
500 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "could not convert an xmlNode to a string");
501 }
502 } else {
503 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "list contains a NULL value");
504 }
505 a_list = a_list->next;
506 }
507 if (_PyTuple_Resize(&a_tuple, i))
508 goto failure;
509 return a_tuple;
510 failure:
511 PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings");
512 Py_XDECREF(a_tuple);
513 return NULL;
514 }
515
516 static PyObject *
get_list_of_pygobject(const GList * a_list)517 get_list_of_pygobject(const GList *a_list) {
518 PyObject *a_tuple = NULL;
519 int i = 0;
520
521 /* Cast because g_list_length does not take const but is a const function */
522 a_tuple = PyTuple_New(g_list_length((GList*)a_list));
523 if (! a_tuple)
524 goto failure;
525 if (! a_list) {
526 return a_tuple;
527 }
528 while (a_list) {
529 if (a_list->data) {
530 PyObject *pygobject;
531 pygobject = PyGObjectPtr_New((GObject*)a_list->data);
532 if (pygobject) {
533 PyTuple_SetItem(a_tuple, i, pygobject);
534 i++;
535 } else {
536 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "could not convert a GObject to a PyGobject");
537 }
538 } else {
539 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "list contains a NULL value");
540 }
541 a_list = a_list->next;
542 }
543 if (_PyTuple_Resize(&a_tuple, i))
544 goto failure;
545 return a_tuple;
546 failure:
547 PyErr_SetString(PyExc_TypeError, "Allocation problem in get_list_of_strings");
548 Py_XDECREF(a_tuple);
549 return NULL;
550 }
551
552 /**
553 * get_time_t:
554 * @time: a #PyInt
555 *
556 * Convert a python integer object to a time_t value, considering it is a unsigned 32 bit integer
557 * value.
558 *
559 * Return: a time_t* value if time is a python integer, NULL otherwise.
560 */
561 static time_t*
get_time_t(PyObject * time)562 get_time_t(PyObject *time)
563 {
564 if (time != Py_None && PyInt_Check(time)) {
565 time_t *val = malloc(sizeof(time_t));
566
567 *val = (time_t)PyInt_AS_LONG(time);
568 return val;
569 }
570 return NULL;
571 }
572
573 /* wrapper around GObject */
574 static void
PyGObjectPtr_dealloc(PyGObjectPtr * self)575 PyGObjectPtr_dealloc(PyGObjectPtr *self)
576 {
577 if (lasso_flag_memory_debug) {
578 fprintf(stderr, "dealloc (%p ptr to %p (type:%s, rc:%d))\n",
579 self, self->obj,
580 G_OBJECT_TYPE_NAME(self->obj),
581 self->obj->ref_count);
582 }
583 g_object_set_qdata_full(self->obj, lasso_wrapper_key, NULL, NULL);
584 g_object_unref(self->obj);
585 Py_XDECREF(self->typename);
586 Py_TYPE(self)->tp_free((PyObject*)self);
587 }
588
589 static int
startswith(const char * string,const char * prefix)590 startswith(const char *string, const char *prefix)
591 {
592 return strncmp(string, prefix, strlen(prefix)) == 0;
593 }
594
595 static PyObject*
PyGObjectPtr_New(GObject * obj)596 PyGObjectPtr_New(GObject *obj)
597 {
598 PyGObjectPtr *self;
599
600 if (obj == NULL) {
601 return noneRef();
602 }
603
604 self = (PyGObjectPtr*)g_object_get_qdata(obj, lasso_wrapper_key);
605 if (self != NULL) {
606 Py_INCREF(self);
607 } else {
608 const char *typename;
609
610 self = (PyGObjectPtr*)PyObject_NEW(PyGObjectPtr, &PyGObjectPtrType);
611 g_object_set_qdata_full(obj, lasso_wrapper_key, self, NULL);
612 self->obj = g_object_ref(obj);
613 typename = G_OBJECT_TYPE_NAME(obj);
614 /* XXX: Fixme !!!!! */
615 if (startswith(typename, "LassoDgme")) {
616 self->typename = PyString_FromString(typename+9);
617 } else if (startswith(typename, "Lasso")) {
618 self->typename = PyString_FromString(typename+5);
619 } else {
620 self->typename = PyString_FromString(typename);
621 }
622 }
623 return (PyObject*)self;
624 }
625
626 static PyObject *
PyGObjectPtr_repr(PyGObjectPtr * obj)627 PyGObjectPtr_repr(PyGObjectPtr *obj)
628 {
629 return PyString_FromFormat("<PyGObjectPtr to %p (type: %s, refcount: %d)>",
630 obj->obj,
631 G_OBJECT_TYPE_NAME(obj->obj),
632 obj->obj->ref_count);
633 }
634
635 static PyMemberDef PyGObjectPtr_members[] = {
636 {"typename", T_OBJECT, offsetof(PyGObjectPtr, typename), 0, "typename"},
637 {NULL, 0, 0, 0, NULL}
638 };
639
640 static PyObject*
PyGObjectPtr_get_refcount(PyGObjectPtr * self,G_GNUC_UNUSED void * closure)641 PyGObjectPtr_get_refcount(PyGObjectPtr *self, G_GNUC_UNUSED void *closure)
642 {
643 PyObject *refcount;
644
645 refcount = PyInt_FromLong(self->obj->ref_count);
646 Py_INCREF(refcount);
647 return refcount;
648 }
649
650 static PyGetSetDef PyGObjectPtr_getseters[] = {
651 {"refcount", (getter)PyGObjectPtr_get_refcount, NULL,
652 "reference count of intern GObject*", NULL},
653 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
654 };
655
656
657 static PyTypeObject PyGObjectPtrType = {
658 PyVarObject_HEAD_INIT(NULL, 0 /* ob_size */)
659 "_lasso.PyGObjectPtr", /* tp_name */
660 sizeof(PyGObjectPtr), /* tp_basicsize */
661 0, /* tp_itemsize */
662 (destructor)PyGObjectPtr_dealloc, /* tp_dealloc */
663 0, /*tp_print*/
664 0, /*tp_getattr*/
665 .tp_setattr = 0, /*tp_setattr*/
666 0, /*tp_compare*/
667 (reprfunc)PyGObjectPtr_repr, /*tp_repr*/
668 0, /*tp_as_number*/
669 0, /*tp_as_sequence*/
670 0, /*tp_as_mapping*/
671 0, /*tp_hash */
672 0, /*tp_call*/
673 0, /*tp_str*/
674 0, /*tp_getattro*/
675 0, /*tp_setattro*/
676 0, /*tp_as_buffer*/
677 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
678 "PyGObjectPtr objects", /* tp_doc */
679 0, /* tp_traverse */
680 0, /* tp_clear */
681 0, /* tp_richcompare */
682 0, /* tp_weaklistoffset */
683 0, /* tp_iter */
684 0, /* tp_iternext */
685 0, /* tp_methods */
686 .tp_members=PyGObjectPtr_members, /* tp_members */
687 PyGObjectPtr_getseters, /* tp_getset */
688 NULL,
689 NULL
690 };
691
692 static void
set_object_field(GObject ** a_gobject_ptr,PyGObjectPtr * a_pygobject)693 set_object_field(GObject **a_gobject_ptr, PyGObjectPtr *a_pygobject) {
694 if (*a_gobject_ptr) {
695 g_object_unref(*a_gobject_ptr);
696 }
697 if ((PyObject*)a_pygobject == Py_None) {
698 *a_gobject_ptr = NULL;
699 } else {
700 *a_gobject_ptr = g_object_ref(a_pygobject->obj);
701 }
702 }
703
704
get_logger_object(const char * domain)705 static PyObject *get_logger_object(const char *domain) {
706 static PyObject *_logger_object = NULL;
707 PyObject *lasso_module = NULL;
708 PyObject *logging_module = NULL;
709
710 lasso_module = PyImport_ImportModule("lasso");
711 if (lasso_module && PyObject_HasAttrString(lasso_module, "logger")) {
712 _logger_object = PyObject_GetAttrString(lasso_module, "logger");
713 if (_logger_object)
714 goto exit;
715 }
716
717 logging_module = PyImport_ImportModule("logging");
718 if (logging_module) {
719 _logger_object = PyObject_CallMethod(logging_module, "getLogger", "s", domain);
720 }
721 exit:
722 if (lasso_module) {
723 Py_DECREF(lasso_module);
724 }
725 if (logging_module) {
726 Py_DECREF(logging_module);
727 }
728 if (_logger_object == Py_None) {
729 Py_DECREF(_logger_object);
730 _logger_object = NULL;
731 }
732 return _logger_object;
733 }
734
735 static void
lasso_python_log(const char * domain,GLogLevelFlags log_level,const gchar * message,G_GNUC_UNUSED gpointer user_data)736 lasso_python_log(const char *domain, GLogLevelFlags log_level, const gchar *message,
737 G_GNUC_UNUSED gpointer user_data)
738 {
739 PyObject *logger_object = get_logger_object(domain), *result;
740 char *method = NULL;
741
742 if (! logger_object) {
743 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "neither lasso.logger nor "
744 "logging.getLogger('lasso') did return a logger", 1);
745 return;
746 }
747 switch (log_level) {
748 case G_LOG_LEVEL_DEBUG:
749 method = "debug";
750 break;
751 case G_LOG_LEVEL_INFO:
752 case G_LOG_LEVEL_MESSAGE:
753 method = "info";
754 break;
755 case G_LOG_LEVEL_WARNING:
756 method = "warning";
757 break;
758 case G_LOG_LEVEL_CRITICAL:
759 method = "error";
760 break;
761 case G_LOG_LEVEL_ERROR:
762 method = "critical";
763 break;
764 default:
765 return;
766 }
767 result = PyObject_CallMethod(logger_object, method, "ss", "%s", message);
768 Py_DECREF(logger_object);
769 if (result) {
770 Py_DECREF(result);
771 } else {
772 PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "lasso could not call method %s on its logger", method);
773 }
774 }
775