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    floatobject.h for an example. */
14 
15 /* Xxo objects */
16 
17 #include "Python.h"
18 
19 static PyObject *ErrorObject;
20 
21 typedef struct {
22     PyObject_HEAD
23     PyObject            *x_attr;        /* Attributes dictionary */
24 } XxoObject;
25 
26 static PyTypeObject Xxo_Type;
27 
28 #define XxoObject_Check(v)      (Py_TYPE(v) == &Xxo_Type)
29 
30 static XxoObject *
newXxoObject(PyObject * arg)31 newXxoObject(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 
43 static void
Xxo_dealloc(XxoObject * self)44 Xxo_dealloc(XxoObject *self)
45 {
46     Py_XDECREF(self->x_attr);
47     PyObject_Del(self);
48 }
49 
50 static PyObject *
Xxo_demo(XxoObject * self,PyObject * args)51 Xxo_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 
59 static PyMethodDef Xxo_methods[] = {
60     {"demo",            (PyCFunction)Xxo_demo,  METH_VARARGS,
61         PyDoc_STR("demo() -> None")},
62     {NULL,              NULL}           /* sentinel */
63 };
64 
65 static PyObject *
Xxo_getattro(XxoObject * self,PyObject * name)66 Xxo_getattro(XxoObject *self, PyObject *name)
67 {
68     if (self->x_attr != NULL) {
69         PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
70         if (v != NULL) {
71             Py_INCREF(v);
72             return v;
73         }
74         else if (PyErr_Occurred()) {
75             return NULL;
76         }
77     }
78     return PyObject_GenericGetAttr((PyObject *)self, name);
79 }
80 
81 static int
Xxo_setattr(XxoObject * self,const char * name,PyObject * v)82 Xxo_setattr(XxoObject *self, const char *name, PyObject *v)
83 {
84     if (self->x_attr == NULL) {
85         self->x_attr = PyDict_New();
86         if (self->x_attr == NULL)
87             return -1;
88     }
89     if (v == NULL) {
90         int rv = PyDict_DelItemString(self->x_attr, name);
91         if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
92             PyErr_SetString(PyExc_AttributeError,
93                 "delete non-existing Xxo attribute");
94         return rv;
95     }
96     else
97         return PyDict_SetItemString(self->x_attr, name, v);
98 }
99 
100 static PyTypeObject Xxo_Type = {
101     /* The ob_type field must be initialized in the module init function
102      * to be portable to Windows without using C++. */
103     PyVarObject_HEAD_INIT(NULL, 0)
104     "xxmodule.Xxo",             /*tp_name*/
105     sizeof(XxoObject),          /*tp_basicsize*/
106     0,                          /*tp_itemsize*/
107     /* methods */
108     (destructor)Xxo_dealloc,    /*tp_dealloc*/
109     0,                          /*tp_vectorcall_offset*/
110     (getattrfunc)0,             /*tp_getattr*/
111     (setattrfunc)Xxo_setattr,   /*tp_setattr*/
112     0,                          /*tp_as_async*/
113     0,                          /*tp_repr*/
114     0,                          /*tp_as_number*/
115     0,                          /*tp_as_sequence*/
116     0,                          /*tp_as_mapping*/
117     0,                          /*tp_hash*/
118     0,                          /*tp_call*/
119     0,                          /*tp_str*/
120     (getattrofunc)Xxo_getattro, /*tp_getattro*/
121     0,                          /*tp_setattro*/
122     0,                          /*tp_as_buffer*/
123     Py_TPFLAGS_DEFAULT,         /*tp_flags*/
124     0,                          /*tp_doc*/
125     0,                          /*tp_traverse*/
126     0,                          /*tp_clear*/
127     0,                          /*tp_richcompare*/
128     0,                          /*tp_weaklistoffset*/
129     0,                          /*tp_iter*/
130     0,                          /*tp_iternext*/
131     Xxo_methods,                /*tp_methods*/
132     0,                          /*tp_members*/
133     0,                          /*tp_getset*/
134     0,                          /*tp_base*/
135     0,                          /*tp_dict*/
136     0,                          /*tp_descr_get*/
137     0,                          /*tp_descr_set*/
138     0,                          /*tp_dictoffset*/
139     0,                          /*tp_init*/
140     0,                          /*tp_alloc*/
141     0,                          /*tp_new*/
142     0,                          /*tp_free*/
143     0,                          /*tp_is_gc*/
144 };
145 /* --------------------------------------------------------------------- */
146 
147 /* Function of two integers returning integer */
148 
149 PyDoc_STRVAR(xx_foo_doc,
150 "foo(i,j)\n\
151 \n\
152 Return the sum of i and j.");
153 
154 static PyObject *
xx_foo(PyObject * self,PyObject * args)155 xx_foo(PyObject *self, PyObject *args)
156 {
157     long i, j;
158     long res;
159     if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
160         return NULL;
161     res = i+j; /* XXX Do something here */
162     return PyLong_FromLong(res);
163 }
164 
165 
166 /* Function of no arguments returning new Xxo object */
167 
168 static PyObject *
xx_new(PyObject * self,PyObject * args)169 xx_new(PyObject *self, PyObject *args)
170 {
171     XxoObject *rv;
172 
173     if (!PyArg_ParseTuple(args, ":new"))
174         return NULL;
175     rv = newXxoObject(args);
176     if (rv == NULL)
177         return NULL;
178     return (PyObject *)rv;
179 }
180 
181 /* Example with subtle bug from extensions manual ("Thin Ice"). */
182 
183 static PyObject *
xx_bug(PyObject * self,PyObject * args)184 xx_bug(PyObject *self, PyObject *args)
185 {
186     PyObject *list, *item;
187 
188     if (!PyArg_ParseTuple(args, "O:bug", &list))
189         return NULL;
190 
191     item = PyList_GetItem(list, 0);
192     /* Py_INCREF(item); */
193     PyList_SetItem(list, 1, PyLong_FromLong(0L));
194     PyObject_Print(item, stdout, 0);
195     printf("\n");
196     /* Py_DECREF(item); */
197 
198     Py_INCREF(Py_None);
199     return Py_None;
200 }
201 
202 /* Test bad format character */
203 
204 static PyObject *
xx_roj(PyObject * self,PyObject * args)205 xx_roj(PyObject *self, PyObject *args)
206 {
207     PyObject *a;
208     long b;
209     if (!PyArg_ParseTuple(args, "O#:roj", &a, &b))
210         return NULL;
211     Py_INCREF(Py_None);
212     return Py_None;
213 }
214 
215 
216 /* ---------- */
217 
218 static PyTypeObject Str_Type = {
219     /* The ob_type field must be initialized in the module init function
220      * to be portable to Windows without using C++. */
221     PyVarObject_HEAD_INIT(NULL, 0)
222     "xxmodule.Str",             /*tp_name*/
223     0,                          /*tp_basicsize*/
224     0,                          /*tp_itemsize*/
225     /* methods */
226     0,                          /*tp_dealloc*/
227     0,                          /*tp_vectorcall_offset*/
228     0,                          /*tp_getattr*/
229     0,                          /*tp_setattr*/
230     0,                          /*tp_as_async*/
231     0,                          /*tp_repr*/
232     0,                          /*tp_as_number*/
233     0,                          /*tp_as_sequence*/
234     0,                          /*tp_as_mapping*/
235     0,                          /*tp_hash*/
236     0,                          /*tp_call*/
237     0,                          /*tp_str*/
238     0,                          /*tp_getattro*/
239     0,                          /*tp_setattro*/
240     0,                          /*tp_as_buffer*/
241     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
242     0,                          /*tp_doc*/
243     0,                          /*tp_traverse*/
244     0,                          /*tp_clear*/
245     0,                          /*tp_richcompare*/
246     0,                          /*tp_weaklistoffset*/
247     0,                          /*tp_iter*/
248     0,                          /*tp_iternext*/
249     0,                          /*tp_methods*/
250     0,                          /*tp_members*/
251     0,                          /*tp_getset*/
252     0, /* see PyInit_xx */      /*tp_base*/
253     0,                          /*tp_dict*/
254     0,                          /*tp_descr_get*/
255     0,                          /*tp_descr_set*/
256     0,                          /*tp_dictoffset*/
257     0,                          /*tp_init*/
258     0,                          /*tp_alloc*/
259     0,                          /*tp_new*/
260     0,                          /*tp_free*/
261     0,                          /*tp_is_gc*/
262 };
263 
264 /* ---------- */
265 
266 static PyObject *
null_richcompare(PyObject * self,PyObject * other,int op)267 null_richcompare(PyObject *self, PyObject *other, int op)
268 {
269     Py_INCREF(Py_NotImplemented);
270     return Py_NotImplemented;
271 }
272 
273 static PyTypeObject Null_Type = {
274     /* The ob_type field must be initialized in the module init function
275      * to be portable to Windows without using C++. */
276     PyVarObject_HEAD_INIT(NULL, 0)
277     "xxmodule.Null",            /*tp_name*/
278     0,                          /*tp_basicsize*/
279     0,                          /*tp_itemsize*/
280     /* methods */
281     0,                          /*tp_dealloc*/
282     0,                          /*tp_vectorcall_offset*/
283     0,                          /*tp_getattr*/
284     0,                          /*tp_setattr*/
285     0,                          /*tp_as_async*/
286     0,                          /*tp_repr*/
287     0,                          /*tp_as_number*/
288     0,                          /*tp_as_sequence*/
289     0,                          /*tp_as_mapping*/
290     0,                          /*tp_hash*/
291     0,                          /*tp_call*/
292     0,                          /*tp_str*/
293     0,                          /*tp_getattro*/
294     0,                          /*tp_setattro*/
295     0,                          /*tp_as_buffer*/
296     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
297     0,                          /*tp_doc*/
298     0,                          /*tp_traverse*/
299     0,                          /*tp_clear*/
300     null_richcompare,           /*tp_richcompare*/
301     0,                          /*tp_weaklistoffset*/
302     0,                          /*tp_iter*/
303     0,                          /*tp_iternext*/
304     0,                          /*tp_methods*/
305     0,                          /*tp_members*/
306     0,                          /*tp_getset*/
307     0, /* see PyInit_xx */      /*tp_base*/
308     0,                          /*tp_dict*/
309     0,                          /*tp_descr_get*/
310     0,                          /*tp_descr_set*/
311     0,                          /*tp_dictoffset*/
312     0,                          /*tp_init*/
313     0,                          /*tp_alloc*/
314     PyType_GenericNew,          /*tp_new*/
315     0,                          /*tp_free*/
316     0,                          /*tp_is_gc*/
317 };
318 
319 
320 /* ---------- */
321 
322 
323 /* List of functions defined in the module */
324 
325 static PyMethodDef xx_methods[] = {
326     {"roj",             xx_roj,         METH_VARARGS,
327         PyDoc_STR("roj(a,b) -> None")},
328     {"foo",             xx_foo,         METH_VARARGS,
329         xx_foo_doc},
330     {"new",             xx_new,         METH_VARARGS,
331         PyDoc_STR("new() -> new Xx object")},
332     {"bug",             xx_bug,         METH_VARARGS,
333         PyDoc_STR("bug(o) -> None")},
334     {NULL,              NULL}           /* sentinel */
335 };
336 
337 PyDoc_STRVAR(module_doc,
338 "This is a template module just for instruction.");
339 
340 
341 static int
xx_exec(PyObject * m)342 xx_exec(PyObject *m)
343 {
344     /* Slot initialization is subject to the rules of initializing globals.
345        C99 requires the initializers to be "address constants".  Function
346        designators like 'PyType_GenericNew', with implicit conversion to
347        a pointer, are valid C99 address constants.
348 
349        However, the unary '&' operator applied to a non-static variable
350        like 'PyBaseObject_Type' is not required to produce an address
351        constant.  Compilers may support this (gcc does), MSVC does not.
352 
353        Both compilers are strictly standard conforming in this particular
354        behavior.
355     */
356     Null_Type.tp_base = &PyBaseObject_Type;
357     Str_Type.tp_base = &PyUnicode_Type;
358 
359     /* Finalize the type object including setting type of the new type
360      * object; doing it here is required for portability, too. */
361     if (PyType_Ready(&Xxo_Type) < 0)
362         goto fail;
363 
364     /* Add some symbolic constants to the module */
365     if (ErrorObject == NULL) {
366         ErrorObject = PyErr_NewException("xx.error", NULL, NULL);
367         if (ErrorObject == NULL)
368             goto fail;
369     }
370     Py_INCREF(ErrorObject);
371     PyModule_AddObject(m, "error", ErrorObject);
372 
373     /* Add Str */
374     if (PyType_Ready(&Str_Type) < 0)
375         goto fail;
376     PyModule_AddObject(m, "Str", (PyObject *)&Str_Type);
377 
378     /* Add Null */
379     if (PyType_Ready(&Null_Type) < 0)
380         goto fail;
381     PyModule_AddObject(m, "Null", (PyObject *)&Null_Type);
382     return 0;
383  fail:
384     Py_XDECREF(m);
385     return -1;
386 }
387 
388 static struct PyModuleDef_Slot xx_slots[] = {
389     {Py_mod_exec, xx_exec},
390     {0, NULL},
391 };
392 
393 static struct PyModuleDef xxmodule = {
394     PyModuleDef_HEAD_INIT,
395     "xx",
396     module_doc,
397     0,
398     xx_methods,
399     xx_slots,
400     NULL,
401     NULL,
402     NULL
403 };
404 
405 /* Export function for the module (*must* be called PyInit_xx) */
406 
407 PyMODINIT_FUNC
PyInit_xx(void)408 PyInit_xx(void)
409 {
410     return PyModuleDef_Init(&xxmodule);
411 }
412