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