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_IS_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_Free(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         return -1;
363     }
364 
365     /* Add some symbolic constants to the module */
366     if (ErrorObject == NULL) {
367         ErrorObject = PyErr_NewException("xx.error", NULL, NULL);
368         if (ErrorObject == NULL) {
369             return -1;
370         }
371     }
372     int rc = PyModule_AddType(m, (PyTypeObject *)ErrorObject);
373     Py_DECREF(ErrorObject);
374     if (rc < 0) {
375         return -1;
376     }
377 
378     /* Add Str and Null types */
379     if (PyModule_AddType(m, &Str_Type) < 0) {
380         return -1;
381     }
382     if (PyModule_AddType(m, &Null_Type) < 0) {
383         return -1;
384     }
385 
386     return 0;
387 }
388 
389 static struct PyModuleDef_Slot xx_slots[] = {
390     {Py_mod_exec, xx_exec},
391     {0, NULL},
392 };
393 
394 static struct PyModuleDef xxmodule = {
395     PyModuleDef_HEAD_INIT,
396     "xx",
397     module_doc,
398     0,
399     xx_methods,
400     xx_slots,
401     NULL,
402     NULL,
403     NULL
404 };
405 
406 /* Export function for the module (*must* be called PyInit_xx) */
407 
408 PyMODINIT_FUNC
PyInit_xx(void)409 PyInit_xx(void)
410 {
411     return PyModuleDef_Init(&xxmodule);
412 }
413