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