xref: /third_party/python/Modules/xxmodule.c (revision 7db96d56)
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
19static PyObject *ErrorObject;
20
21typedef struct {
22    PyObject_HEAD
23    PyObject            *x_attr;        /* Attributes dictionary */
24} XxoObject;
25
26static PyTypeObject Xxo_Type;
27
28#define XxoObject_Check(v)      Py_IS_TYPE(v, &Xxo_Type)
29
30static XxoObject *
31newXxoObject(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
43static void
44Xxo_dealloc(XxoObject *self)
45{
46    Py_XDECREF(self->x_attr);
47    PyObject_Free(self);
48}
49
50static PyObject *
51Xxo_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
59static PyMethodDef Xxo_methods[] = {
60    {"demo",            (PyCFunction)Xxo_demo,  METH_VARARGS,
61        PyDoc_STR("demo() -> None")},
62    {NULL,              NULL}           /* sentinel */
63};
64
65static PyObject *
66Xxo_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
81static int
82Xxo_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
100static 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
149PyDoc_STRVAR(xx_foo_doc,
150"foo(i,j)\n\
151\n\
152Return the sum of i and j.");
153
154static PyObject *
155xx_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
168static PyObject *
169xx_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
183static PyObject *
184xx_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
204static PyObject *
205xx_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
218static 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
266static PyObject *
267null_richcompare(PyObject *self, PyObject *other, int op)
268{
269    Py_INCREF(Py_NotImplemented);
270    return Py_NotImplemented;
271}
272
273static 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
325static 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
337PyDoc_STRVAR(module_doc,
338"This is a template module just for instruction.");
339
340
341static int
342xx_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
389static struct PyModuleDef_Slot xx_slots[] = {
390    {Py_mod_exec, xx_exec},
391    {0, NULL},
392};
393
394static 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
408PyMODINIT_FUNC
409PyInit_xx(void)
410{
411    return PyModuleDef_Init(&xxmodule);
412}
413