Don't leak memory in _StringBase and _LongBase repr()
[dbus-python-phuang.git] / _dbus_bindings / abstract.c
blob57a4e0452ae5af96f4104ea1853d7fc12f585eb6
1 /* Subclasses of built-in Python types supporting extra D-Bus functionality.
3 * Copyright (C) 2006 Collabora Ltd.
5 * Licensed under the Academic Free License version 2.1
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program 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 General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <Python.h>
24 #include <structmember.h>
26 #include <stdint.h>
28 #include "dbus_bindings-internal.h"
29 #include "types-internal.h"
31 /* Support code for int subclasses. ================================== */
33 PyDoc_STRVAR(DBusPythonInt_tp_doc,\
34 "Base class for int subclasses with a ``variant_level`` attribute.\n"
35 "Do not rely on the existence of this class outside dbus-python.\n"
38 static PyMemberDef DBusPythonInt_tp_members[] = {
39 {"variant_level", T_LONG, offsetof(DBusPyIntBase, variant_level),
40 READONLY,
41 "The number of nested variants wrapping the real data. "
42 "0 if not in a variant."},
43 {NULL},
46 static PyObject *
47 DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
49 PyObject *self;
50 long variantness = 0;
51 static char *argnames[] = {"variant_level", NULL};
53 if (PyTuple_Size(args) > 1) {
54 PyErr_SetString(PyExc_TypeError,
55 "__new__ takes at most one positional parameter");
56 return NULL;
58 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
59 "|l:__new__", argnames,
60 &variantness)) return NULL;
61 if (variantness < 0) {
62 PyErr_SetString(PyExc_ValueError,
63 "variant_level must be non-negative");
64 return NULL;
67 self = (PyInt_Type.tp_new)(cls, args, NULL);
68 if (self) {
69 ((DBusPyIntBase *)self)->variant_level = variantness;
71 return self;
74 static PyObject *
75 DBusPythonInt_tp_repr(PyObject *self)
77 PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
78 long variant_level = ((DBusPyIntBase *)self)->variant_level;
79 PyObject *my_repr;
81 if (!parent_repr) return NULL;
82 if (variant_level > 0) {
83 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
84 self->ob_type->tp_name,
85 PyString_AS_STRING(parent_repr),
86 variant_level);
88 else {
89 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
90 PyString_AS_STRING(parent_repr));
92 /* whether my_repr is NULL or not: */
93 Py_DECREF(parent_repr);
94 return my_repr;
97 PyTypeObject DBusPyIntBase_Type = {
98 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
100 "_dbus_bindings._IntBase",
101 sizeof(DBusPyIntBase),
103 0, /* tp_dealloc */
104 0, /* tp_print */
105 0, /* tp_getattr */
106 0, /* tp_setattr */
107 0, /* tp_compare */
108 DBusPythonInt_tp_repr, /* tp_repr */
109 0, /* tp_as_number */
110 0, /* tp_as_sequence */
111 0, /* tp_as_mapping */
112 0, /* tp_hash */
113 0, /* tp_call */
114 0, /* tp_str */
115 0, /* tp_getattro */
116 0, /* tp_setattro */
117 0, /* tp_as_buffer */
118 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
119 DBusPythonInt_tp_doc, /* tp_doc */
120 0, /* tp_traverse */
121 0, /* tp_clear */
122 0, /* tp_richcompare */
123 0, /* tp_weaklistoffset */
124 0, /* tp_iter */
125 0, /* tp_iternext */
126 0, /* tp_methods */
127 DBusPythonInt_tp_members, /* tp_members */
128 0, /* tp_getset */
129 DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */
130 0, /* tp_dict */
131 0, /* tp_descr_get */
132 0, /* tp_descr_set */
133 0, /* tp_dictoffset */
134 0, /* tp_init */
135 PyType_GenericAlloc, /* tp_alloc */
136 DBusPythonInt_tp_new, /* tp_new */
137 PyObject_Del, /* tp_free */
140 /* Support code for float subclasses. ================================ */
142 /* There's only one subclass at the moment (Double) but these are factored
143 out to make room for Float later. (Float is implemented and #if'd out) */
145 PyDoc_STRVAR(DBusPythonFloat_tp_doc,\
146 "Base class for float subclasses with a ``variant_level`` attribute.\n"
147 "Do not rely on the existence of this class outside dbus-python.\n"
150 static PyMemberDef DBusPythonFloat_tp_members[] = {
151 {"variant_level", T_LONG, offsetof(DBusPyFloatBase, variant_level),
152 READONLY,
153 "The number of nested variants wrapping the real data. "
154 "0 if not in a variant."},
155 {NULL},
158 static PyObject *
159 DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
161 PyObject *self;
162 long variantness = 0;
163 static char *argnames[] = {"variant_level", NULL};
165 if (PyTuple_Size(args) > 1) {
166 PyErr_SetString(PyExc_TypeError,
167 "__new__ takes at most one positional parameter");
168 return NULL;
170 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
171 "|l:__new__", argnames,
172 &variantness)) return NULL;
173 if (variantness < 0) {
174 PyErr_SetString(PyExc_ValueError,
175 "variant_level must be non-negative");
176 return NULL;
179 self = (PyFloat_Type.tp_new)(cls, args, NULL);
180 if (self) {
181 ((DBusPyFloatBase *)self)->variant_level = variantness;
183 return self;
186 static PyObject *
187 DBusPythonFloat_tp_repr(PyObject *self)
189 PyObject *parent_repr = (PyFloat_Type.tp_repr)(self);
190 long variant_level = ((DBusPyFloatBase *)self)->variant_level;
191 PyObject *my_repr;
193 if (!parent_repr) return NULL;
194 if (variant_level > 0) {
195 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
196 self->ob_type->tp_name,
197 PyString_AS_STRING(parent_repr),
198 variant_level);
200 else {
201 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
202 PyString_AS_STRING(parent_repr));
204 /* whether my_repr is NULL or not: */
205 Py_DECREF(parent_repr);
206 return my_repr;
209 PyTypeObject DBusPyFloatBase_Type = {
210 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
212 "_dbus_bindings._FloatBase",
213 sizeof(DBusPyFloatBase),
215 0, /* tp_dealloc */
216 0, /* tp_print */
217 0, /* tp_getattr */
218 0, /* tp_setattr */
219 0, /* tp_compare */
220 DBusPythonFloat_tp_repr, /* tp_repr */
221 0, /* tp_as_number */
222 0, /* tp_as_sequence */
223 0, /* tp_as_mapping */
224 0, /* tp_hash */
225 0, /* tp_call */
226 0, /* tp_str */
227 0, /* tp_getattro */
228 0, /* tp_setattro */
229 0, /* tp_as_buffer */
230 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
231 DBusPythonFloat_tp_doc, /* tp_doc */
232 0, /* tp_traverse */
233 0, /* tp_clear */
234 0, /* tp_richcompare */
235 0, /* tp_weaklistoffset */
236 0, /* tp_iter */
237 0, /* tp_iternext */
238 0, /* tp_methods */
239 DBusPythonFloat_tp_members, /* tp_members */
240 0, /* tp_getset */
241 DEFERRED_ADDRESS(&PyFloat_Type), /* tp_base */
242 0, /* tp_dict */
243 0, /* tp_descr_get */
244 0, /* tp_descr_set */
245 0, /* tp_dictoffset */
246 0, /* tp_init */
247 0, /* tp_alloc */
248 DBusPythonFloat_tp_new, /* tp_new */
251 /* Support code for str subclasses ================================== */
253 PyDoc_STRVAR(DBusPythonString_tp_doc,\
254 "Base class for str subclasses with a ``variant_level`` attribute.\n"
255 "Do not rely on the existence of this class outside dbus-python.\n"
258 static PyObject *
259 DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
261 PyObject *self;
262 PyObject *variantness = NULL;
263 static char *argnames[] = {"variant_level", NULL};
265 if (PyTuple_Size(args) > 1) {
266 PyErr_SetString(PyExc_TypeError,
267 "__new__ takes at most one positional parameter");
268 return NULL;
270 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
271 "|O!:__new__", argnames,
272 &PyInt_Type, &variantness)) return NULL;
273 if (!variantness) {
274 variantness = PyInt_FromLong(0);
275 if (!variantness) return NULL;
277 if (PyInt_AS_LONG(variantness) < 0) {
278 PyErr_SetString(PyExc_ValueError,
279 "variant_level must be non-negative");
280 return NULL;
283 self = (PyString_Type.tp_new)(cls, args, NULL);
284 if (self) {
285 PyObject_GenericSetAttr(self, dbus_py_variant_level_const, variantness);
287 return self;
290 static PyObject *
291 DBusPythonString_tp_repr(PyObject *self)
293 PyObject *parent_repr = (PyString_Type.tp_repr)(self);
294 PyObject *vl_obj;
295 PyObject *my_repr;
296 long variant_level;
298 if (!parent_repr) return NULL;
299 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
300 if (!vl_obj) {
301 Py_DECREF(parent_repr);
302 return NULL;
304 variant_level = PyInt_AsLong(vl_obj);
305 Py_DECREF(vl_obj);
306 if (variant_level > 0) {
307 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
308 self->ob_type->tp_name,
309 PyString_AS_STRING(parent_repr),
310 variant_level);
312 else {
313 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
314 PyString_AS_STRING(parent_repr));
316 /* whether my_repr is NULL or not: */
317 Py_DECREF(parent_repr);
318 return my_repr;
321 PyTypeObject DBusPyStrBase_Type = {
322 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
324 "_dbus_bindings._StrBase",
325 INT_MAX, /* placeholder */
327 0, /* tp_dealloc */
328 0, /* tp_print */
329 0, /* tp_getattr */
330 0, /* tp_setattr */
331 0, /* tp_compare */
332 DBusPythonString_tp_repr, /* tp_repr */
333 0, /* tp_as_number */
334 0, /* tp_as_sequence */
335 0, /* tp_as_mapping */
336 0, /* tp_hash */
337 0, /* tp_call */
338 0, /* tp_str */
339 PyObject_GenericGetAttr, /* tp_getattro */
340 dbus_py_immutable_setattro, /* tp_setattro */
341 0, /* tp_as_buffer */
342 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
343 DBusPythonString_tp_doc, /* tp_doc */
344 0, /* tp_traverse */
345 0, /* tp_clear */
346 0, /* tp_richcompare */
347 0, /* tp_weaklistoffset */
348 0, /* tp_iter */
349 0, /* tp_iternext */
350 0, /* tp_methods */
351 0, /* tp_members */
352 0, /* tp_getset */
353 DEFERRED_ADDRESS(&PyString_Type), /* tp_base */
354 0, /* tp_dict */
355 0, /* tp_descr_get */
356 0, /* tp_descr_set */
357 -sizeof(void *), /* tp_dictoffset */
358 0, /* tp_init */
359 0, /* tp_alloc */
360 DBusPythonString_tp_new, /* tp_new */
363 /* Support code for long subclasses ================================= */
365 PyDoc_STRVAR(DBusPythonLong_tp_doc,\
366 "Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
367 "Do not rely on the existence of this class outside dbus-python.\n"
370 static PyObject *
371 DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
373 PyObject *self;
374 PyObject *variantness = NULL;
375 static char *argnames[] = {"variant_level", NULL};
377 if (PyTuple_Size(args) > 1) {
378 PyErr_SetString(PyExc_TypeError,
379 "__new__ takes at most one positional parameter");
380 return NULL;
382 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
383 "|O!:__new__", argnames,
384 &PyInt_Type, &variantness)) return NULL;
385 if (!variantness) {
386 variantness = PyInt_FromLong(0);
387 if (!variantness) return NULL;
389 if (PyInt_AS_LONG(variantness) < 0) {
390 PyErr_SetString(PyExc_ValueError,
391 "variant_level must be non-negative");
392 return NULL;
395 self = (PyLong_Type.tp_new)(cls, args, NULL);
396 if (self) {
397 PyObject_GenericSetAttr(self, dbus_py_variant_level_const, variantness);
399 return self;
402 static PyObject *
403 DBusPythonLong_tp_repr(PyObject *self)
405 PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
406 PyObject *vl_obj;
407 PyObject *my_repr;
408 long variant_level;
410 if (!parent_repr) return NULL;
411 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
412 if (!vl_obj) {
413 Py_DECREF(parent_repr);
414 return NULL;
416 variant_level = PyInt_AsLong(vl_obj);
417 Py_DECREF(vl_obj);
418 if (variant_level) {
419 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
420 self->ob_type->tp_name,
421 PyString_AS_STRING(parent_repr),
422 variant_level);
424 else {
425 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
426 PyString_AS_STRING(parent_repr));
428 /* whether my_repr is NULL or not: */
429 Py_DECREF(parent_repr);
430 return my_repr;
433 PyTypeObject DBusPyLongBase_Type = {
434 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
436 "_dbus_bindings._LongBase",
437 INT_MAX, /* placeholder */
439 0, /* tp_dealloc */
440 0, /* tp_print */
441 0, /* tp_getattr */
442 0, /* tp_setattr */
443 0, /* tp_compare */
444 DBusPythonLong_tp_repr, /* tp_repr */
445 0, /* tp_as_number */
446 0, /* tp_as_sequence */
447 0, /* tp_as_mapping */
448 0, /* tp_hash */
449 0, /* tp_call */
450 0, /* tp_str */
451 PyObject_GenericGetAttr, /* tp_getattro */
452 dbus_py_immutable_setattro, /* tp_setattro */
453 0, /* tp_as_buffer */
454 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
455 DBusPythonLong_tp_doc, /* tp_doc */
456 0, /* tp_traverse */
457 0, /* tp_clear */
458 0, /* tp_richcompare */
459 0, /* tp_weaklistoffset */
460 0, /* tp_iter */
461 0, /* tp_iternext */
462 0, /* tp_methods */
463 0, /* tp_members */
464 0, /* tp_getset */
465 DEFERRED_ADDRESS(&PyLong_Type), /* tp_base */
466 0, /* tp_dict */
467 0, /* tp_descr_get */
468 0, /* tp_descr_set */
469 -sizeof(PyObject *), /* tp_dictoffset */
470 0, /* tp_init */
471 0, /* tp_alloc */
472 DBusPythonLong_tp_new, /* tp_new */
475 PyObject *dbus_py_variant_level_const = NULL;
476 PyObject *dbus_py_signature_const = NULL;
477 PyObject *dbus_py__dbus_object_path__const = NULL;
479 dbus_bool_t
480 dbus_py_init_abstract(void)
482 dbus_py__dbus_object_path__const = PyString_InternFromString("__dbus_object_path__");
483 if (!dbus_py__dbus_object_path__const) return 0;
485 dbus_py_variant_level_const = PyString_InternFromString("variant_level");
486 if (!dbus_py_variant_level_const) return 0;
488 dbus_py_signature_const = PyString_InternFromString("signature");
489 if (!dbus_py_signature_const) return 0;
491 DBusPyIntBase_Type.tp_base = &PyInt_Type;
492 if (PyType_Ready(&DBusPyIntBase_Type) < 0) return 0;
493 /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
494 desired */
495 DBusPyIntBase_Type.tp_print = NULL;
497 DBusPyFloatBase_Type.tp_base = &PyFloat_Type;
498 if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0;
499 DBusPyFloatBase_Type.tp_print = NULL;
501 /* Add a pointer for the instance dict, aligning to sizeof(PyObject *)
502 * to make sure the offset of -sizeof(PyObject *) is right. */
503 DBusPyLongBase_Type.tp_basicsize = PyLong_Type.tp_basicsize
504 + 2*sizeof(PyObject *) - 1;
505 DBusPyLongBase_Type.tp_basicsize /= sizeof(PyObject *);
506 DBusPyLongBase_Type.tp_basicsize *= sizeof(PyObject *);
507 DBusPyLongBase_Type.tp_base = &PyLong_Type;
508 if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0;
509 DBusPyLongBase_Type.tp_print = NULL;
511 DBusPyStrBase_Type.tp_basicsize = PyString_Type.tp_basicsize
512 + 2*sizeof(PyObject *) - 1;
513 DBusPyStrBase_Type.tp_basicsize /= sizeof(PyObject *);
514 DBusPyStrBase_Type.tp_basicsize *= sizeof(PyObject *);
515 DBusPyStrBase_Type.tp_base = &PyString_Type;
516 if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0;
517 DBusPyStrBase_Type.tp_print = NULL;
519 return 1;
522 dbus_bool_t
523 dbus_py_insert_abstract_types(PyObject *this_module)
525 Py_INCREF(&DBusPyIntBase_Type);
526 Py_INCREF(&DBusPyLongBase_Type);
527 Py_INCREF(&DBusPyStrBase_Type);
528 Py_INCREF(&DBusPyFloatBase_Type);
529 if (PyModule_AddObject(this_module, "_IntBase",
530 (PyObject *)&DBusPyIntBase_Type) < 0) return 0;
531 if (PyModule_AddObject(this_module, "_LongBase",
532 (PyObject *)&DBusPyLongBase_Type) < 0) return 0;
533 if (PyModule_AddObject(this_module, "_StrBase",
534 (PyObject *)&DBusPyStrBase_Type) < 0) return 0;
535 if (PyModule_AddObject(this_module, "_FloatBase",
536 (PyObject *)&DBusPyFloatBase_Type) < 0) return 0;
538 return 1;