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