Actually commit the numerous copyright-statement changes.
[dbus-python-phuang.git] / _dbus_bindings / abstract.c
blobd5c63db40c338f856bc76d361491b7ea78fc8624
1 /* Subclasses of built-in Python types supporting extra D-Bus functionality.
2  *
3  * Copyright (C) 2006, 2007 Collabora Ltd.
4  *
5  * Licensed under the Academic Free License version 2.1
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
23 #include <Python.h>
24 #include <structmember.h>
26 #include <stdint.h>
28 #include "dbus_bindings-internal.h"
29 #include "types-internal.h"
31 /* Dict indexed by object IDs, whose values are nonzero variant levels
32  * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct).
33  *
34  * This is a strange way to store them, but adding a __dict__ to the offending
35  * objects seems even more error-prone, given that their sizes are variable!
36  */
37 PyObject *_dbus_py_variant_levels = NULL;
39 long
40 dbus_py_variant_level_get(PyObject *obj)
42     PyObject *vl_obj;
43     PyObject *key = PyLong_FromVoidPtr(obj);
45     if (!key) {
46         return 0;
47     }
49     vl_obj = PyDict_GetItem(_dbus_py_variant_levels, key);
50     Py_DECREF(key);
52     if (!vl_obj)
53         return 0;
54     return PyInt_AsLong(vl_obj);
57 dbus_bool_t
58 dbus_py_variant_level_set(PyObject *obj, long variant_level)
60     /* key is the object's ID (= pointer) to avoid referencing it */
61     PyObject *key = PyLong_FromVoidPtr(obj);
63     if (!key) {
64         return FALSE;
65     }
67     if (variant_level <= 0) {
68         if (PyDict_GetItem (_dbus_py_variant_levels, key)) {
69             if (PyDict_DelItem (_dbus_py_variant_levels, key) < 0) {
70                 Py_DECREF(key);
71                 return FALSE;
72             }
73         }
74     }
75     else {
76         PyObject *vl_obj = PyInt_FromLong(variant_level);
77         if (!vl_obj) {
78             Py_DECREF(key);
79             return FALSE;
80         }
81         if (PyDict_SetItem (_dbus_py_variant_levels, key, vl_obj) < 0) {
82             Py_DECREF(key);
83             return FALSE;
84         }
85     }
86     Py_DECREF(key);
87     return TRUE;
90 PyObject *
91 dbus_py_variant_level_getattro(PyObject *obj, PyObject *name)
93     PyObject *key, *value;
95     if (PyString_Check(name)) {
96         Py_INCREF(name);
97     }
98     else if (PyUnicode_Check(name)) {
99         name = PyUnicode_AsEncodedString(name, NULL, NULL);
100         if (!name) {
101             return NULL;
102         }
103     }
104     else {
105         PyErr_SetString(PyExc_TypeError, "attribute name must be string");
106         return NULL;
107     }
109     if (strcmp(PyString_AS_STRING(name), "variant_level")) {
110         value = PyObject_GenericGetAttr(obj, name);
111         Py_DECREF(name);
112         return value;
113     }
115     Py_DECREF(name);
117     key = PyLong_FromVoidPtr(obj);
119     if (!key) {
120         return NULL;
121     }
123     value = PyDict_GetItem(_dbus_py_variant_levels, key);
124     Py_DECREF(key);
126     if (!value)
127         return PyInt_FromLong(0);
128     Py_INCREF(value);
129     return value;
132 /* To be invoked by destructors. Clear the variant level without touching the
133  * exception state */
134 void
135 dbus_py_variant_level_clear(PyObject *self)
137     PyObject *et, *ev, *etb;
139     /* avoid clobbering any pending exception */
140     PyErr_Fetch(&et, &ev, &etb);
141     if (!dbus_py_variant_level_set(self, 0)) {
142         /* should never happen */
143         PyErr_WriteUnraisable(self);
144     }
145     PyErr_Restore(et, ev, etb);
148 /* Support code for int subclasses. ================================== */
150 PyDoc_STRVAR(DBusPythonInt_tp_doc,\
151 "Base class for int subclasses with a ``variant_level`` attribute.\n"
152 "Do not rely on the existence of this class outside dbus-python.\n"
155 static PyMemberDef DBusPythonInt_tp_members[] = {
156     {"variant_level", T_LONG, offsetof(DBusPyIntBase, variant_level),
157      READONLY,
158      "The number of nested variants wrapping the real data. "
159      "0 if not in a variant."},
160     {NULL},
163 static PyObject *
164 DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
166     PyObject *self;
167     long variantness = 0;
168     static char *argnames[] = {"variant_level", NULL};
170     if (PyTuple_Size(args) > 1) {
171         PyErr_SetString(PyExc_TypeError,
172                         "__new__ takes at most one positional parameter");
173         return NULL;
174     }
175     if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
176                                      "|l:__new__", argnames,
177                                      &variantness)) return NULL;
178     if (variantness < 0) {
179         PyErr_SetString(PyExc_ValueError,
180                         "variant_level must be non-negative");
181         return NULL;
182     }
184     self = (PyInt_Type.tp_new)(cls, args, NULL);
185     if (self) {
186         ((DBusPyIntBase *)self)->variant_level = variantness;
187     }
188     return self;
191 static PyObject *
192 DBusPythonInt_tp_repr(PyObject *self)
194     PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
195     long variant_level = ((DBusPyIntBase *)self)->variant_level;
196     PyObject *my_repr;
198     if (!parent_repr) return NULL;
199     if (variant_level > 0) {
200         my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
201                                       self->ob_type->tp_name,
202                                       PyString_AS_STRING(parent_repr),
203                                       variant_level);
204     }
205     else {
206         my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
207                                       PyString_AS_STRING(parent_repr));
208     }
209     /* whether my_repr is NULL or not: */
210     Py_DECREF(parent_repr);
211     return my_repr;
214 PyTypeObject DBusPyIntBase_Type = {
215     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
216     0,
217     "_dbus_bindings._IntBase",
218     sizeof(DBusPyIntBase),
219     0,
220     0,                                      /* tp_dealloc */
221     0,                                      /* tp_print */
222     0,                                      /* tp_getattr */
223     0,                                      /* tp_setattr */
224     0,                                      /* tp_compare */
225     DBusPythonInt_tp_repr,                  /* tp_repr */
226     0,                                      /* tp_as_number */
227     0,                                      /* tp_as_sequence */
228     0,                                      /* tp_as_mapping */
229     0,                                      /* tp_hash */
230     0,                                      /* tp_call */
231     0,                                      /* tp_str */
232     0,                                      /* tp_getattro */
233     0,                                      /* tp_setattro */
234     0,                                      /* tp_as_buffer */
235     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
236     DBusPythonInt_tp_doc,                   /* tp_doc */
237     0,                                      /* tp_traverse */
238     0,                                      /* tp_clear */
239     0,                                      /* tp_richcompare */
240     0,                                      /* tp_weaklistoffset */
241     0,                                      /* tp_iter */
242     0,                                      /* tp_iternext */
243     0,                                      /* tp_methods */
244     DBusPythonInt_tp_members,               /* tp_members */
245     0,                                      /* tp_getset */
246     DEFERRED_ADDRESS(&PyInt_Type),          /* tp_base */
247     0,                                      /* tp_dict */
248     0,                                      /* tp_descr_get */
249     0,                                      /* tp_descr_set */
250     0,                                      /* tp_dictoffset */
251     0,                                      /* tp_init */
252     PyType_GenericAlloc,                    /* tp_alloc */
253     DBusPythonInt_tp_new,                   /* tp_new */
254     PyObject_Del,                           /* tp_free */
257 /* Support code for float subclasses. ================================ */
259 /* There's only one subclass at the moment (Double) but these are factored
260 out to make room for Float later. (Float is implemented and #if'd out) */
262 PyDoc_STRVAR(DBusPythonFloat_tp_doc,\
263 "Base class for float subclasses with a ``variant_level`` attribute.\n"
264 "Do not rely on the existence of this class outside dbus-python.\n"
267 static PyMemberDef DBusPythonFloat_tp_members[] = {
268     {"variant_level", T_LONG, offsetof(DBusPyFloatBase, variant_level),
269      READONLY,
270      "The number of nested variants wrapping the real data. "
271      "0 if not in a variant."},
272     {NULL},
275 static PyObject *
276 DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
278     PyObject *self;
279     long variantness = 0;
280     static char *argnames[] = {"variant_level", NULL};
282     if (PyTuple_Size(args) > 1) {
283         PyErr_SetString(PyExc_TypeError,
284                         "__new__ takes at most one positional parameter");
285         return NULL;
286     }
287     if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
288                                      "|l:__new__", argnames,
289                                      &variantness)) return NULL;
290     if (variantness < 0) {
291         PyErr_SetString(PyExc_ValueError,
292                         "variant_level must be non-negative");
293         return NULL;
294     }
296     self = (PyFloat_Type.tp_new)(cls, args, NULL);
297     if (self) {
298         ((DBusPyFloatBase *)self)->variant_level = variantness;
299     }
300     return self;
303 static PyObject *
304 DBusPythonFloat_tp_repr(PyObject *self)
306     PyObject *parent_repr = (PyFloat_Type.tp_repr)(self);
307     long variant_level = ((DBusPyFloatBase *)self)->variant_level;
308     PyObject *my_repr;
310     if (!parent_repr) return NULL;
311     if (variant_level > 0) {
312         my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
313                                       self->ob_type->tp_name,
314                                       PyString_AS_STRING(parent_repr),
315                                       variant_level);
316     }
317     else {
318         my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
319                                       PyString_AS_STRING(parent_repr));
320     }
321     /* whether my_repr is NULL or not: */
322     Py_DECREF(parent_repr);
323     return my_repr;
326 PyTypeObject DBusPyFloatBase_Type = {
327     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
328     0,
329     "_dbus_bindings._FloatBase",
330     sizeof(DBusPyFloatBase),
331     0,
332     0,                                      /* tp_dealloc */
333     0,                                      /* tp_print */
334     0,                                      /* tp_getattr */
335     0,                                      /* tp_setattr */
336     0,                                      /* tp_compare */
337     DBusPythonFloat_tp_repr,                /* tp_repr */
338     0,                                      /* tp_as_number */
339     0,                                      /* tp_as_sequence */
340     0,                                      /* tp_as_mapping */
341     0,                                      /* tp_hash */
342     0,                                      /* tp_call */
343     0,                                      /* tp_str */
344     0,                                      /* tp_getattro */
345     0,                                      /* tp_setattro */
346     0,                                      /* tp_as_buffer */
347     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
348     DBusPythonFloat_tp_doc,                 /* tp_doc */
349     0,                                      /* tp_traverse */
350     0,                                      /* tp_clear */
351     0,                                      /* tp_richcompare */
352     0,                                      /* tp_weaklistoffset */
353     0,                                      /* tp_iter */
354     0,                                      /* tp_iternext */
355     0,                                      /* tp_methods */
356     DBusPythonFloat_tp_members,             /* tp_members */
357     0,                                      /* tp_getset */
358     DEFERRED_ADDRESS(&PyFloat_Type),        /* tp_base */
359     0,                                      /* tp_dict */
360     0,                                      /* tp_descr_get */
361     0,                                      /* tp_descr_set */
362     0,                                      /* tp_dictoffset */
363     0,                                      /* tp_init */
364     0,                                      /* tp_alloc */
365     DBusPythonFloat_tp_new,                 /* tp_new */
368 /* Support code for str subclasses ================================== */
370 PyDoc_STRVAR(DBusPythonString_tp_doc,\
371 "Base class for str subclasses with a ``variant_level`` attribute.\n"
372 "Do not rely on the existence of this class outside dbus-python.\n"
375 static PyObject *
376 DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
378     PyObject *self;
379     long variantness = 0;
380     static char *argnames[] = {"variant_level", NULL};
382     if (PyTuple_Size(args) > 1) {
383         PyErr_SetString(PyExc_TypeError,
384                         "__new__ takes at most one positional parameter");
385         return NULL;
386     }
387     if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
388                                      "|l:__new__", argnames,
389                                      &variantness)) return NULL;
390     if (variantness < 0) {
391         PyErr_SetString(PyExc_ValueError,
392                         "variant_level must be non-negative");
393         return NULL;
394     }
396     self = (PyString_Type.tp_new)(cls, args, NULL);
397     if (self) {
398         if (!dbus_py_variant_level_set(self, variantness)) {
399             Py_DECREF(self);
400             return NULL;
401         }
402     }
403     return self;
406 static PyObject *
407 DBusPythonString_tp_repr(PyObject *self)
409     PyObject *parent_repr = (PyString_Type.tp_repr)(self);
410     PyObject *vl_obj;
411     PyObject *my_repr;
412     long variant_level;
414     if (!parent_repr) return NULL;
415     vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
416     if (!vl_obj) {
417         Py_DECREF(parent_repr);
418         return NULL;
419     }
420     variant_level = PyInt_AsLong(vl_obj);
421     Py_DECREF(vl_obj);
422     if (variant_level > 0) {
423         my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
424                                       self->ob_type->tp_name,
425                                       PyString_AS_STRING(parent_repr),
426                                       variant_level);
427     }
428     else {
429         my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
430                                       PyString_AS_STRING(parent_repr));
431     }
432     /* whether my_repr is NULL or not: */
433     Py_DECREF(parent_repr);
434     return my_repr;
437 static void
438 DBusPyStrBase_tp_dealloc(PyObject *self)
440     dbus_py_variant_level_clear(self);
441     (PyString_Type.tp_dealloc)(self);
444 PyTypeObject DBusPyStrBase_Type = {
445     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
446     0,
447     "_dbus_bindings._StrBase",
448     0,                           
449     0,
450     DBusPyStrBase_tp_dealloc,               /* tp_dealloc */
451     0,                                      /* tp_print */
452     0,                                      /* tp_getattr */
453     0,                                      /* tp_setattr */
454     0,                                      /* tp_compare */
455     DBusPythonString_tp_repr,               /* tp_repr */
456     0,                                      /* tp_as_number */
457     0,                                      /* tp_as_sequence */
458     0,                                      /* tp_as_mapping */
459     0,                                      /* tp_hash */
460     0,                                      /* tp_call */
461     0,                                      /* tp_str */
462     dbus_py_variant_level_getattro,         /* tp_getattro */
463     dbus_py_immutable_setattro,             /* tp_setattro */
464     0,                                      /* tp_as_buffer */
465     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
466     DBusPythonString_tp_doc,                /* tp_doc */
467     0,                                      /* tp_traverse */
468     0,                                      /* tp_clear */
469     0,                                      /* tp_richcompare */
470     0,                                      /* tp_weaklistoffset */
471     0,                                      /* tp_iter */
472     0,                                      /* tp_iternext */
473     0,                                      /* tp_methods */
474     0,                                      /* tp_members */
475     0,                                      /* tp_getset */
476     DEFERRED_ADDRESS(&PyString_Type),       /* tp_base */
477     0,                                      /* tp_dict */
478     0,                                      /* tp_descr_get */
479     0,                                      /* tp_descr_set */
480     0,                                      /* tp_dictoffset */
481     0,                                      /* tp_init */
482     0,                                      /* tp_alloc */
483     DBusPythonString_tp_new,                /* tp_new */
486 /* Support code for long subclasses ================================= */
488 PyDoc_STRVAR(DBusPythonLong_tp_doc,\
489 "Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
490 "Do not rely on the existence of this class outside dbus-python.\n"
493 static PyObject *
494 DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
496     PyObject *self;
497     long variantness = 0;
498     static char *argnames[] = {"variant_level", NULL};
500     if (PyTuple_Size(args) > 1) {
501         PyErr_SetString(PyExc_TypeError,
502                         "__new__ takes at most one positional parameter");
503         return NULL;
504     }
505     if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
506                                      "|l:__new__", argnames,
507                                      &variantness)) return NULL;
508     if (variantness < 0) {
509         PyErr_SetString(PyExc_ValueError,
510                         "variant_level must be non-negative");
511         return NULL;
512     }
514     self = (PyLong_Type.tp_new)(cls, args, NULL);
515     if (self) {
516         if (!dbus_py_variant_level_set(self, variantness)) {
517             Py_DECREF(self);
518             return NULL;
519         }
520     }
521     return self;
524 static PyObject *
525 DBusPythonLong_tp_repr(PyObject *self)
527     PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
528     PyObject *vl_obj;
529     PyObject *my_repr;
530     long variant_level;
532     if (!parent_repr) return NULL;
533     vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
534     if (!vl_obj) {
535         Py_DECREF(parent_repr);
536         return NULL;
537     }
538     variant_level = PyInt_AsLong(vl_obj);
539     Py_DECREF(vl_obj);
540     if (variant_level) {
541         my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
542                                       self->ob_type->tp_name,
543                                       PyString_AS_STRING(parent_repr),
544                                       variant_level);
545     }
546     else {
547         my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
548                                       PyString_AS_STRING(parent_repr));
549     }
550     /* whether my_repr is NULL or not: */
551     Py_DECREF(parent_repr);
552     return my_repr;
555 static void
556 DBusPyLongBase_tp_dealloc(PyObject *self)
558     dbus_py_variant_level_clear(self);
559     (PyLong_Type.tp_dealloc)(self);
562 PyTypeObject DBusPyLongBase_Type = {
563     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
564     0,
565     "_dbus_bindings._LongBase",
566     0,                           
567     0,
568     DBusPyLongBase_tp_dealloc,              /* tp_dealloc */
569     0,                                      /* tp_print */
570     0,                                      /* tp_getattr */
571     0,                                      /* tp_setattr */
572     0,                                      /* tp_compare */
573     DBusPythonLong_tp_repr,                 /* tp_repr */
574     0,                                      /* tp_as_number */
575     0,                                      /* tp_as_sequence */
576     0,                                      /* tp_as_mapping */
577     0,                                      /* tp_hash */
578     0,                                      /* tp_call */
579     0,                                      /* tp_str */
580     dbus_py_variant_level_getattro,         /* tp_getattro */
581     dbus_py_immutable_setattro,             /* tp_setattro */
582     0,                                      /* tp_as_buffer */
583     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
584     DBusPythonLong_tp_doc,                  /* tp_doc */
585     0,                                      /* tp_traverse */
586     0,                                      /* tp_clear */
587     0,                                      /* tp_richcompare */
588     0,                                      /* tp_weaklistoffset */
589     0,                                      /* tp_iter */
590     0,                                      /* tp_iternext */
591     0,                                      /* tp_methods */
592     0,                                      /* tp_members */
593     0,                                      /* tp_getset */
594     DEFERRED_ADDRESS(&PyLong_Type),         /* tp_base */
595     0,                                      /* tp_dict */
596     0,                                      /* tp_descr_get */
597     0,                                      /* tp_descr_set */
598     0,                                      /* tp_dictoffset */
599     0,                                      /* tp_init */
600     0,                                      /* tp_alloc */
601     DBusPythonLong_tp_new,                  /* tp_new */
604 PyObject *dbus_py_variant_level_const = NULL;
605 PyObject *dbus_py_signature_const = NULL;
606 PyObject *dbus_py__dbus_object_path__const = NULL;
608 dbus_bool_t
609 dbus_py_init_abstract(void)
611     _dbus_py_variant_levels = PyDict_New();
612     if (!_dbus_py_variant_levels) return 0;
614     dbus_py__dbus_object_path__const = PyString_InternFromString("__dbus_object_path__");
615     if (!dbus_py__dbus_object_path__const) return 0;
617     dbus_py_variant_level_const = PyString_InternFromString("variant_level");
618     if (!dbus_py_variant_level_const) return 0;
620     dbus_py_signature_const = PyString_InternFromString("signature");
621     if (!dbus_py_signature_const) return 0;
623     DBusPyIntBase_Type.tp_base = &PyInt_Type;
624     if (PyType_Ready(&DBusPyIntBase_Type) < 0) return 0;
625     /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
626     desired */
627     DBusPyIntBase_Type.tp_print = NULL;
629     DBusPyFloatBase_Type.tp_base = &PyFloat_Type;
630     if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0;
631     DBusPyFloatBase_Type.tp_print = NULL;
633     DBusPyLongBase_Type.tp_base = &PyLong_Type;
634     if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0;
635     DBusPyLongBase_Type.tp_print = NULL;
637     DBusPyStrBase_Type.tp_base = &PyString_Type;
638     if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0;
639     DBusPyStrBase_Type.tp_print = NULL;
641     return 1;
644 dbus_bool_t
645 dbus_py_insert_abstract_types(PyObject *this_module)
647     Py_INCREF(&DBusPyIntBase_Type);
648     Py_INCREF(&DBusPyLongBase_Type);
649     Py_INCREF(&DBusPyStrBase_Type);
650     Py_INCREF(&DBusPyFloatBase_Type);
651     if (PyModule_AddObject(this_module, "_IntBase",
652                            (PyObject *)&DBusPyIntBase_Type) < 0) return 0;
653     if (PyModule_AddObject(this_module, "_LongBase",
654                            (PyObject *)&DBusPyLongBase_Type) < 0) return 0;
655     if (PyModule_AddObject(this_module, "_StrBase",
656                            (PyObject *)&DBusPyStrBase_Type) < 0) return 0;
657     if (PyModule_AddObject(this_module, "_FloatBase",
658                            (PyObject *)&DBusPyFloatBase_Type) < 0) return 0;
660     return 1;