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