1
2/* Use this file as a template to start implementing a module that
3   also declares object types. All occurrences of 'Xxo' should be changed
4   to something reasonable for your objects. After that, all other
5   occurrences of 'xx' should be changed to something reasonable for your
6   module. If your module is named foo your sourcefile should be named
7   foomodule.c.
8
9   You will probably want to delete all references to 'x_attr' and add
10   your own types of attributes instead.  Maybe you want to name your
11   local variables other than 'self'.  If your object type is needed in
12   other files, you'll have to create a file "foobarobject.h"; see
13   intobject.h for an example. */
14
15/* Xxo objects */
16
17#include "Python.h"
18
19static PyObject *ErrorObject;
20
21typedef struct {
22    PyObject_HEAD
23    PyObject            *x_attr;        /* Attributes dictionary */
24} XxoObject;
25
26static PyTypeObject Xxo_Type;
27
28#define XxoObject_Check(v)      (Py_TYPE(v) == &Xxo_Type)
29
30static XxoObject *
31newXxoObject(PyObject *arg)
32{
33    XxoObject *self;
34    self = PyObject_New(XxoObject, &Xxo_Type);
35    if (self == NULL)
36        return NULL;
37    self->x_attr = NULL;
38    return self;
39}
40
41/* Xxo methods */
42
43static void
44Xxo_dealloc(XxoObject *self)
45{
46    Py_XDECREF(self->x_attr);
47    PyObject_Del(self);
48}
49
50static PyObject *
51Xxo_demo(XxoObject *self, PyObject *args)
52{
53    if (!PyArg_ParseTuple(args, ":demo"))
54        return NULL;
55    Py_INCREF(Py_None);
56    return Py_None;
57}
58
59static PyMethodDef Xxo_methods[] = {
60    {"demo",            (PyCFunction)Xxo_demo,  METH_VARARGS,
61        PyDoc_STR("demo() -> None")},
62    {NULL,              NULL}           /* sentinel */
63};
64
65static PyObject *
66Xxo_getattr(XxoObject *self, char *name)
67{
68    if (self->x_attr != NULL) {
69        PyObject *v = PyDict_GetItemString(self->x_attr, name);
70        if (v != NULL) {
71            Py_INCREF(v);
72            return v;
73        }
74    }
75    return Py_FindMethod(Xxo_methods, (PyObject *)self, name);
76}
77
78static int
79Xxo_setattr(XxoObject *self, char *name, PyObject *v)
80{
81    if (self->x_attr == NULL) {
82        self->x_attr = PyDict_New();
83        if (self->x_attr == NULL)
84            return -1;
85    }
86    if (v == NULL) {
87        int rv = PyDict_DelItemString(self->x_attr, name);
88        if (rv < 0)
89            PyErr_SetString(PyExc_AttributeError,
90                "delete non-existing Xxo attribute");
91        return rv;
92    }
93    else
94        return PyDict_SetItemString(self->x_attr, name, v);
95}
96
97static PyTypeObject Xxo_Type = {
98    /* The ob_type field must be initialized in the module init function
99     * to be portable to Windows without using C++. */
100    PyVarObject_HEAD_INIT(NULL, 0)
101    "xxmodule.Xxo",             /*tp_name*/
102    sizeof(XxoObject),          /*tp_basicsize*/
103    0,                          /*tp_itemsize*/
104    /* methods */
105    (destructor)Xxo_dealloc, /*tp_dealloc*/
106    0,                          /*tp_print*/
107    (getattrfunc)Xxo_getattr, /*tp_getattr*/
108    (setattrfunc)Xxo_setattr, /*tp_setattr*/
109    0,                          /*tp_compare*/
110    0,                          /*tp_repr*/
111    0,                          /*tp_as_number*/
112    0,                          /*tp_as_sequence*/
113    0,                          /*tp_as_mapping*/
114    0,                          /*tp_hash*/
115    0,                      /*tp_call*/
116    0,                      /*tp_str*/
117    0,                      /*tp_getattro*/
118    0,                      /*tp_setattro*/
119    0,                      /*tp_as_buffer*/
120    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
121    0,                      /*tp_doc*/
122    0,                      /*tp_traverse*/
123    0,                      /*tp_clear*/
124    0,                      /*tp_richcompare*/
125    0,                      /*tp_weaklistoffset*/
126    0,                      /*tp_iter*/
127    0,                      /*tp_iternext*/
128    0,                      /*tp_methods*/
129    0,                      /*tp_members*/
130    0,                      /*tp_getset*/
131    0,                      /*tp_base*/
132    0,                      /*tp_dict*/
133    0,                      /*tp_descr_get*/
134    0,                      /*tp_descr_set*/
135    0,                      /*tp_dictoffset*/
136    0,                      /*tp_init*/
137    0,                      /*tp_alloc*/
138    0,                      /*tp_new*/
139    0,                      /*tp_free*/
140    0,                      /*tp_is_gc*/
141};
142/* --------------------------------------------------------------------- */
143
144/* Function of two integers returning integer */
145
146PyDoc_STRVAR(xx_foo_doc,
147"foo(i,j)\n\
148\n\
149Return the sum of i and j.");
150
151static PyObject *
152xx_foo(PyObject *self, PyObject *args)
153{
154    long i, j;
155    long res;
156    if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
157        return NULL;
158    res = i+j; /* XXX Do something here */
159    return PyInt_FromLong(res);
160}
161
162
163/* Function of no arguments returning new Xxo object */
164
165static PyObject *
166xx_new(PyObject *self, PyObject *args)
167{
168    XxoObject *rv;
169
170    if (!PyArg_ParseTuple(args, ":new"))
171        return NULL;
172    rv = newXxoObject(args);
173    if (rv == NULL)
174        return NULL;
175    return (PyObject *)rv;
176}
177
178/* Example with subtle bug from extensions manual ("Thin Ice"). */
179
180static PyObject *
181xx_bug(PyObject *self, PyObject *args)
182{
183    PyObject *list, *item;
184
185    if (!PyArg_ParseTuple(args, "O:bug", &list))
186        return NULL;
187
188    item = PyList_GetItem(list, 0);
189    /* Py_INCREF(item); */
190    PyList_SetItem(list, 1, PyInt_FromLong(0L));
191    PyObject_Print(item, stdout, 0);
192    printf("\n");
193    /* Py_DECREF(item); */
194
195    Py_INCREF(Py_None);
196    return Py_None;
197}
198
199/* Test bad format character */
200
201static PyObject *
202xx_roj(PyObject *self, PyObject *args)
203{
204    PyObject *a;
205    long b;
206    if (!PyArg_ParseTuple(args, "O#:roj", &a, &b))
207        return NULL;
208    Py_INCREF(Py_None);
209    return Py_None;
210}
211
212
213/* ---------- */
214
215static PyTypeObject Str_Type = {
216    /* The ob_type field must be initialized in the module init function
217     * to be portable to Windows without using C++. */
218    PyVarObject_HEAD_INIT(NULL, 0)
219    "xxmodule.Str",             /*tp_name*/
220    0,                          /*tp_basicsize*/
221    0,                          /*tp_itemsize*/
222    /* methods */
223    0,                          /*tp_dealloc*/
224    0,                          /*tp_print*/
225    0,                          /*tp_getattr*/
226    0,                          /*tp_setattr*/
227    0,                          /*tp_compare*/
228    0,                          /*tp_repr*/
229    0,                          /*tp_as_number*/
230    0,                          /*tp_as_sequence*/
231    0,                          /*tp_as_mapping*/
232    0,                          /*tp_hash*/
233    0,                          /*tp_call*/
234    0,                          /*tp_str*/
235    0,                          /*tp_getattro*/
236    0,                          /*tp_setattro*/
237    0,                          /*tp_as_buffer*/
238    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
239    0,                          /*tp_doc*/
240    0,                          /*tp_traverse*/
241    0,                          /*tp_clear*/
242    0,                          /*tp_richcompare*/
243    0,                          /*tp_weaklistoffset*/
244    0,                          /*tp_iter*/
245    0,                          /*tp_iternext*/
246    0,                          /*tp_methods*/
247    0,                          /*tp_members*/
248    0,                          /*tp_getset*/
249    0, /* see initxx */         /*tp_base*/
250    0,                          /*tp_dict*/
251    0,                          /*tp_descr_get*/
252    0,                          /*tp_descr_set*/
253    0,                          /*tp_dictoffset*/
254    0,                          /*tp_init*/
255    0,                          /*tp_alloc*/
256    0,                          /*tp_new*/
257    0,                          /*tp_free*/
258    0,                          /*tp_is_gc*/
259};
260
261/* ---------- */
262
263static PyObject *
264null_richcompare(PyObject *self, PyObject *other, int op)
265{
266    Py_INCREF(Py_NotImplemented);
267    return Py_NotImplemented;
268}
269
270static PyTypeObject Null_Type = {
271    /* The ob_type field must be initialized in the module init function
272     * to be portable to Windows without using C++. */
273    PyVarObject_HEAD_INIT(NULL, 0)
274    "xxmodule.Null",            /*tp_name*/
275    0,                          /*tp_basicsize*/
276    0,                          /*tp_itemsize*/
277    /* methods */
278    0,                          /*tp_dealloc*/
279    0,                          /*tp_print*/
280    0,                          /*tp_getattr*/
281    0,                          /*tp_setattr*/
282    0,                          /*tp_compare*/
283    0,                          /*tp_repr*/
284    0,                          /*tp_as_number*/
285    0,                          /*tp_as_sequence*/
286    0,                          /*tp_as_mapping*/
287    0,                          /*tp_hash*/
288    0,                          /*tp_call*/
289    0,                          /*tp_str*/
290    0,                          /*tp_getattro*/
291    0,                          /*tp_setattro*/
292    0,                          /*tp_as_buffer*/
293    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
294    0,                          /*tp_doc*/
295    0,                          /*tp_traverse*/
296    0,                          /*tp_clear*/
297    null_richcompare,           /*tp_richcompare*/
298    0,                          /*tp_weaklistoffset*/
299    0,                          /*tp_iter*/
300    0,                          /*tp_iternext*/
301    0,                          /*tp_methods*/
302    0,                          /*tp_members*/
303    0,                          /*tp_getset*/
304    0, /* see initxx */         /*tp_base*/
305    0,                          /*tp_dict*/
306    0,                          /*tp_descr_get*/
307    0,                          /*tp_descr_set*/
308    0,                          /*tp_dictoffset*/
309    0,                          /*tp_init*/
310    0,                          /*tp_alloc*/
311    0, /* see initxx */         /*tp_new*/
312    0,                          /*tp_free*/
313    0,                          /*tp_is_gc*/
314};
315
316
317/* ---------- */
318
319
320/* List of functions defined in the module */
321
322static PyMethodDef xx_methods[] = {
323    {"roj",             xx_roj,         METH_VARARGS,
324        PyDoc_STR("roj(a,b) -> None")},
325    {"foo",             xx_foo,         METH_VARARGS,
326        xx_foo_doc},
327    {"new",             xx_new,         METH_VARARGS,
328        PyDoc_STR("new() -> new Xx object")},
329    {"bug",             xx_bug,         METH_VARARGS,
330        PyDoc_STR("bug(o) -> None")},
331    {NULL,              NULL}           /* sentinel */
332};
333
334PyDoc_STRVAR(module_doc,
335"This is a template module just for instruction.");
336
337/* Initialization function for the module (*must* be called initxx) */
338
339PyMODINIT_FUNC
340initxx(void)
341{
342    PyObject *m;
343
344    /* Due to cross platform compiler issues the slots must be filled
345     * here. It's required for portability to Windows without requiring
346     * C++. */
347    Null_Type.tp_base = &PyBaseObject_Type;
348    Null_Type.tp_new = PyType_GenericNew;
349    Str_Type.tp_base = &PyUnicode_Type;
350
351    /* Finalize the type object including setting type of the new type
352     * object; doing it here is required for portability, too. */
353    if (PyType_Ready(&Xxo_Type) < 0)
354        return;
355
356    /* Create the module and add the functions */
357    m = Py_InitModule3("xx", xx_methods, module_doc);
358    if (m == NULL)
359        return;
360
361    /* Add some symbolic constants to the module */
362    if (ErrorObject == NULL) {
363        ErrorObject = PyErr_NewException("xx.error", NULL, NULL);
364        if (ErrorObject == NULL)
365            return;
366    }
367    Py_INCREF(ErrorObject);
368    PyModule_AddObject(m, "error", ErrorObject);
369
370    /* Add Str */
371    if (PyType_Ready(&Str_Type) < 0)
372        return;
373    PyModule_AddObject(m, "Str", (PyObject *)&Str_Type);
374
375    /* Add Null */
376    if (PyType_Ready(&Null_Type) < 0)
377        return;
378    PyModule_AddObject(m, "Null", (PyObject *)&Null_Type);
379}
380