-
Notifications
You must be signed in to change notification settings - Fork 2
/
extend.c
183 lines (152 loc) · 4.29 KB
/
extend.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
extend.c
Extending Python with C code
A first attempt.
Create a module with a method to look up Pokémon by their index number.
Copyright (c) 2016 K Kollmann <code∆k.kollmann·moe>
*/
#include <Python.h>
#define MAXCHARS 255
#define MAXPOKE 720
/* function declarations */
static PyObject* no_poke_search(PyObject *self, PyObject *args);
static PyObject* find_pokemon_byno(PyObject *self, PyObject *args);
/* module name */
static char module_name[] = "pokemon_lookup";
/* docstrings for Python (module + methods) */
static char docstring_module[]
= "A module to test extending Python with C. "
"Lets you look up Pokémon by number.";
static char docstring_method_no_poke_search[]
= "Prints out a test message.";
static char docstring_method_find_pokemon_byno[]
= "Finds a Pokémon by its index number.";
/* C code of test print method */
static PyObject* no_poke_search(PyObject *self, PyObject *args)
{
char *text = (char *) malloc(MAXCHARS * sizeof(char));
text = "No Pokémon for you!";
printf("%s\n", text);
Py_RETURN_NONE;
}
/* C code of number print method */
static PyObject* find_pokemon_byno(PyObject *self, PyObject *args)
{
FILE *input;
char inputfilename[] = "pokedex.txt";
int count = 1, pi = 1;
char *pokemon = (char *) malloc(MAXCHARS * sizeof(char));
char line[MAXCHARS] = "\0";
if (!PyArg_ParseTuple(args, "i", &pi))
{
return NULL;
}
/* out of poke range */
if (pi < 1 || pi > MAXPOKE)
{
PyErr_SetString(PyExc_ValueError,
"a value between 1 and 720 is required");
return NULL;
}
/* within poke range */
else
{
/* check for existence of inputfilename */
if ((input=fopen(inputfilename, "r")) != NULL)
{
/*
loop through lines of input file,
stop when input number matches line number
! line will include the newline character !
*/
input=fopen(inputfilename, "r");
while (fgets(line, sizeof(line) + 2, input)) {
if (count == pi)
{
pokemon = line;
break;
}
count++;
}
fclose(input);
}
/* throw a FileNotFoundError if input file is not found */
else
{
PyErr_SetString(PyExc_FileNotFoundError,
"file containing Pokémon index not found");
return NULL;
}
}
/* remove trailing newline from pokemon string */
pokemon[strcspn(pokemon, "\n")] = 0;
return Py_BuildValue("s", pokemon);
}
/*
Method descriptions
https://docs.python.org/3/c-api/structures.html#c.PyMethodDef
Per method include:
- name of the method (when called in Python), char *
- pointer to C code of method, PyCFunction
- flags for call construction, int
- docstring contents, char *
flags:
METH_VARARGS: 2 PyObject values - self object + args
METH_KEYWORDS: self, args and dict with keyword arguments
METH_NOARGS: method without args
METH_O: method with a single object argument
& more
*/
static PyMethodDef module_methods[] =
{
{
"no_search",
no_poke_search,
METH_NOARGS,
docstring_method_no_poke_search
},
{
"lookup_no",
find_pokemon_byno,
METH_VARARGS,
docstring_method_find_pokemon_byno
},
{
NULL,
NULL,
0,
NULL
}
};
/*
Module specification
https://docs.python.org/3/c-api/module.html#c.PyModuleDef
- base, always PyModuleDef_HEAD_INIT
- name for the module (name with which it is imported), char *
- docstring for the module, char *
- module state, Py_ssize_t
- pointer to module-level functions, PyMethodDef
(more optional)
module states:
-1 for modules which don't support sub-interpreters
non-negative vals to be able to re-initialise modules
*/
static struct PyModuleDef module_definition =
{
PyModuleDef_HEAD_INIT,
module_name,
docstring_module,
-1,
module_methods
};
/*
initialisation function
needs to
- start with PyInit_ followed by module name
- match the 'name' in setup.py
*/
PyMODINIT_FUNC PyInit_pokemon_lookup(void)
{
Py_Initialize();
return PyModule_Create(&module_definition);
}