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 PyObject *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_GC_New(XxoObject, (PyTypeObject*)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 int
Xxo_traverse(XxoObject * self,visitproc visit,void * arg)44 Xxo_traverse(XxoObject *self, visitproc visit, void *arg)
45 {
46     Py_VISIT(Py_TYPE(self));
47     Py_VISIT(self->x_attr);
48     return 0;
49 }
50 
51 static void
Xxo_finalize(XxoObject * self)52 Xxo_finalize(XxoObject *self)
53 {
54     Py_CLEAR(self->x_attr);
55 }
56 
57 static PyObject *
Xxo_demo(XxoObject * self,PyObject * args)58 Xxo_demo(XxoObject *self, PyObject *args)
59 {
60     PyObject *o = NULL;
61     if (!PyArg_ParseTuple(args, "|O:demo", &o))
62         return NULL;
63     /* Test availability of fast type checks */
64     if (o != NULL && PyUnicode_Check(o)) {
65         Py_INCREF(o);
66         return o;
67     }
68     Py_INCREF(Py_None);
69     return Py_None;
70 }
71 
72 static PyMethodDef Xxo_methods[] = {
73     {"demo",            (PyCFunction)Xxo_demo,  METH_VARARGS,
74         PyDoc_STR("demo() -> None")},
75     {NULL,              NULL}           /* sentinel */
76 };
77 
78 static PyObject *
Xxo_getattro(XxoObject * self,PyObject * name)79 Xxo_getattro(XxoObject *self, PyObject *name)
80 {
81     if (self->x_attr != NULL) {
82         PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
83         if (v != NULL) {
84             Py_INCREF(v);
85             return v;
86         }
87         else if (PyErr_Occurred()) {
88             return NULL;
89         }
90     }
91     return PyObject_GenericGetAttr((PyObject *)self, name);
92 }
93 
94 static int
Xxo_setattr(XxoObject * self,const char * name,PyObject * v)95 Xxo_setattr(XxoObject *self, const char *name, PyObject *v)
96 {
97     if (self->x_attr == NULL) {
98         self->x_attr = PyDict_New();
99         if (self->x_attr == NULL)
100             return -1;
101     }
102     if (v == NULL) {
103         int rv = PyDict_DelItemString(self->x_attr, name);
104         if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
105             PyErr_SetString(PyExc_AttributeError,
106                 "delete non-existing Xxo attribute");
107         return rv;
108     }
109     else
110         return PyDict_SetItemString(self->x_attr, name, v);
111 }
112 
113 static PyType_Slot Xxo_Type_slots[] = {
114     {Py_tp_doc, "The Xxo type"},
115     {Py_tp_traverse, Xxo_traverse},
116     {Py_tp_finalize, Xxo_finalize},
117     {Py_tp_getattro, Xxo_getattro},
118     {Py_tp_setattr, Xxo_setattr},
119     {Py_tp_methods, Xxo_methods},
120     {0, 0},
121 };
122 
123 static PyType_Spec Xxo_Type_spec = {
124     "xxlimited.Xxo",
125     sizeof(XxoObject),
126     0,
127     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
128     Xxo_Type_slots
129 };
130 
131 /* --------------------------------------------------------------------- */
132 
133 /* Function of two integers returning integer */
134 
135 PyDoc_STRVAR(xx_foo_doc,
136 "foo(i,j)\n\
137 \n\
138 Return the sum of i and j.");
139 
140 static PyObject *
xx_foo(PyObject * self,PyObject * args)141 xx_foo(PyObject *self, PyObject *args)
142 {
143     long i, j;
144     long res;
145     if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
146         return NULL;
147     res = i+j; /* XXX Do something here */
148     return PyLong_FromLong(res);
149 }
150 
151 
152 /* Function of no arguments returning new Xxo object */
153 
154 static PyObject *
xx_new(PyObject * self,PyObject * args)155 xx_new(PyObject *self, PyObject *args)
156 {
157     XxoObject *rv;
158 
159     if (!PyArg_ParseTuple(args, ":new"))
160         return NULL;
161     rv = newXxoObject(args);
162     if (rv == NULL)
163         return NULL;
164     return (PyObject *)rv;
165 }
166 
167 /* Test bad format character */
168 
169 static PyObject *
xx_roj(PyObject * self,PyObject * args)170 xx_roj(PyObject *self, PyObject *args)
171 {
172     PyObject *a;
173     long b;
174     if (!PyArg_ParseTuple(args, "O#:roj", &a, &b))
175         return NULL;
176     Py_INCREF(Py_None);
177     return Py_None;
178 }
179 
180 
181 /* ---------- */
182 
183 static PyType_Slot Str_Type_slots[] = {
184     {Py_tp_base, NULL}, /* filled out in module init function */
185     {0, 0},
186 };
187 
188 static PyType_Spec Str_Type_spec = {
189     "xxlimited.Str",
190     0,
191     0,
192     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
193     Str_Type_slots
194 };
195 
196 /* ---------- */
197 
198 static PyObject *
null_richcompare(PyObject * self,PyObject * other,int op)199 null_richcompare(PyObject *self, PyObject *other, int op)
200 {
201     Py_RETURN_NOTIMPLEMENTED;
202 }
203 
204 static PyType_Slot Null_Type_slots[] = {
205     {Py_tp_base, NULL}, /* filled out in module init */
206     {Py_tp_new, NULL},
207     {Py_tp_richcompare, null_richcompare},
208     {0, 0}
209 };
210 
211 static PyType_Spec Null_Type_spec = {
212     "xxlimited.Null",
213     0,               /* basicsize */
214     0,               /* itemsize */
215     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
216     Null_Type_slots
217 };
218 
219 /* ---------- */
220 
221 /* List of functions defined in the module */
222 
223 static PyMethodDef xx_methods[] = {
224     {"roj",             xx_roj,         METH_VARARGS,
225         PyDoc_STR("roj(a,b) -> None")},
226     {"foo",             xx_foo,         METH_VARARGS,
227         xx_foo_doc},
228     {"new",             xx_new,         METH_VARARGS,
229         PyDoc_STR("new() -> new Xx object")},
230     {NULL,              NULL}           /* sentinel */
231 };
232 
233 PyDoc_STRVAR(module_doc,
234 "This is a template module just for instruction.");
235 
236 static int
xx_modexec(PyObject * m)237 xx_modexec(PyObject *m)
238 {
239     PyObject *o;
240 
241     /* Due to cross platform compiler issues the slots must be filled
242      * here. It's required for portability to Windows without requiring
243      * C++. */
244     Null_Type_slots[0].pfunc = &PyBaseObject_Type;
245     Null_Type_slots[1].pfunc = PyType_GenericNew;
246     Str_Type_slots[0].pfunc = &PyUnicode_Type;
247 
248     Xxo_Type = PyType_FromSpec(&Xxo_Type_spec);
249     if (Xxo_Type == NULL)
250         goto fail;
251 
252     /* Add some symbolic constants to the module */
253     if (ErrorObject == NULL) {
254         ErrorObject = PyErr_NewException("xxlimited.error", NULL, NULL);
255         if (ErrorObject == NULL)
256             goto fail;
257     }
258     Py_INCREF(ErrorObject);
259     PyModule_AddObject(m, "error", ErrorObject);
260 
261     /* Add Xxo */
262     o = PyType_FromSpec(&Xxo_Type_spec);
263     if (o == NULL)
264         goto fail;
265     PyModule_AddObject(m, "Xxo", o);
266 
267     /* Add Str */
268     o = PyType_FromSpec(&Str_Type_spec);
269     if (o == NULL)
270         goto fail;
271     PyModule_AddObject(m, "Str", o);
272 
273     /* Add Null */
274     o = PyType_FromSpec(&Null_Type_spec);
275     if (o == NULL)
276         goto fail;
277     PyModule_AddObject(m, "Null", o);
278     return 0;
279  fail:
280     Py_XDECREF(m);
281     return -1;
282 }
283 
284 
285 static PyModuleDef_Slot xx_slots[] = {
286     {Py_mod_exec, xx_modexec},
287     {0, NULL}
288 };
289 
290 static struct PyModuleDef xxmodule = {
291     PyModuleDef_HEAD_INIT,
292     "xxlimited",
293     module_doc,
294     0,
295     xx_methods,
296     xx_slots,
297     NULL,
298     NULL,
299     NULL
300 };
301 
302 /* Export function for the module (*must* be called PyInit_xx) */
303 
304 PyMODINIT_FUNC
PyInit_xxlimited(void)305 PyInit_xxlimited(void)
306 {
307     return PyModuleDef_Init(&xxmodule);
308 }
309