|
1 |
|
2 /* Map C struct members to Python object attributes */ |
|
3 |
|
4 #include "Python.h" |
|
5 |
|
6 #include "structmember.h" |
|
7 |
|
8 static PyObject * |
|
9 listmembers(struct memberlist *mlist) |
|
10 { |
|
11 int i, n; |
|
12 PyObject *v; |
|
13 for (n = 0; mlist[n].name != NULL; n++) |
|
14 ; |
|
15 v = PyList_New(n); |
|
16 if (v != NULL) { |
|
17 for (i = 0; i < n; i++) |
|
18 PyList_SetItem(v, i, |
|
19 PyString_FromString(mlist[i].name)); |
|
20 if (PyErr_Occurred()) { |
|
21 Py_DECREF(v); |
|
22 v = NULL; |
|
23 } |
|
24 else { |
|
25 PyList_Sort(v); |
|
26 } |
|
27 } |
|
28 return v; |
|
29 } |
|
30 |
|
31 PyObject * |
|
32 PyMember_Get(const char *addr, struct memberlist *mlist, const char *name) |
|
33 { |
|
34 struct memberlist *l; |
|
35 |
|
36 if (strcmp(name, "__members__") == 0) |
|
37 return listmembers(mlist); |
|
38 for (l = mlist; l->name != NULL; l++) { |
|
39 if (strcmp(l->name, name) == 0) { |
|
40 PyMemberDef copy; |
|
41 copy.name = l->name; |
|
42 copy.type = l->type; |
|
43 copy.offset = l->offset; |
|
44 copy.flags = l->flags; |
|
45 copy.doc = NULL; |
|
46 return PyMember_GetOne(addr, ©); |
|
47 } |
|
48 } |
|
49 PyErr_SetString(PyExc_AttributeError, name); |
|
50 return NULL; |
|
51 } |
|
52 |
|
53 PyObject * |
|
54 PyMember_GetOne(const char *addr, PyMemberDef *l) |
|
55 { |
|
56 PyObject *v; |
|
57 if ((l->flags & READ_RESTRICTED) && |
|
58 PyEval_GetRestricted()) { |
|
59 PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); |
|
60 return NULL; |
|
61 } |
|
62 addr += l->offset; |
|
63 switch (l->type) { |
|
64 case T_BOOL: |
|
65 v = PyBool_FromLong(*(char*)addr); |
|
66 break; |
|
67 case T_BYTE: |
|
68 v = PyInt_FromLong(*(char*)addr); |
|
69 break; |
|
70 case T_UBYTE: |
|
71 v = PyLong_FromUnsignedLong(*(unsigned char*)addr); |
|
72 break; |
|
73 case T_SHORT: |
|
74 v = PyInt_FromLong(*(short*)addr); |
|
75 break; |
|
76 case T_USHORT: |
|
77 v = PyLong_FromUnsignedLong(*(unsigned short*)addr); |
|
78 break; |
|
79 case T_INT: |
|
80 v = PyInt_FromLong(*(int*)addr); |
|
81 break; |
|
82 case T_UINT: |
|
83 v = PyLong_FromUnsignedLong(*(unsigned int*)addr); |
|
84 break; |
|
85 case T_LONG: |
|
86 v = PyInt_FromLong(*(long*)addr); |
|
87 break; |
|
88 case T_ULONG: |
|
89 v = PyLong_FromUnsignedLong(*(unsigned long*)addr); |
|
90 break; |
|
91 case T_PYSSIZET: |
|
92 v = PyInt_FromSsize_t(*(Py_ssize_t*)addr); |
|
93 break; |
|
94 case T_FLOAT: |
|
95 v = PyFloat_FromDouble((double)*(float*)addr); |
|
96 break; |
|
97 case T_DOUBLE: |
|
98 v = PyFloat_FromDouble(*(double*)addr); |
|
99 break; |
|
100 case T_STRING: |
|
101 if (*(char**)addr == NULL) { |
|
102 Py_INCREF(Py_None); |
|
103 v = Py_None; |
|
104 } |
|
105 else |
|
106 v = PyString_FromString(*(char**)addr); |
|
107 break; |
|
108 case T_STRING_INPLACE: |
|
109 v = PyString_FromString((char*)addr); |
|
110 break; |
|
111 case T_CHAR: |
|
112 v = PyString_FromStringAndSize((char*)addr, 1); |
|
113 break; |
|
114 case T_OBJECT: |
|
115 v = *(PyObject **)addr; |
|
116 if (v == NULL) |
|
117 v = Py_None; |
|
118 Py_INCREF(v); |
|
119 break; |
|
120 case T_OBJECT_EX: |
|
121 v = *(PyObject **)addr; |
|
122 if (v == NULL) |
|
123 PyErr_SetString(PyExc_AttributeError, l->name); |
|
124 Py_XINCREF(v); |
|
125 break; |
|
126 #ifdef HAVE_LONG_LONG |
|
127 case T_LONGLONG: |
|
128 v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr); |
|
129 break; |
|
130 case T_ULONGLONG: |
|
131 v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr); |
|
132 break; |
|
133 #endif /* HAVE_LONG_LONG */ |
|
134 default: |
|
135 PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); |
|
136 v = NULL; |
|
137 } |
|
138 return v; |
|
139 } |
|
140 |
|
141 int |
|
142 PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v) |
|
143 { |
|
144 struct memberlist *l; |
|
145 |
|
146 for (l = mlist; l->name != NULL; l++) { |
|
147 if (strcmp(l->name, name) == 0) { |
|
148 PyMemberDef copy; |
|
149 copy.name = l->name; |
|
150 copy.type = l->type; |
|
151 copy.offset = l->offset; |
|
152 copy.flags = l->flags; |
|
153 copy.doc = NULL; |
|
154 return PyMember_SetOne(addr, ©, v); |
|
155 } |
|
156 } |
|
157 |
|
158 PyErr_SetString(PyExc_AttributeError, name); |
|
159 return -1; |
|
160 } |
|
161 |
|
162 #define WARN(msg) \ |
|
163 do { \ |
|
164 if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) \ |
|
165 return -1; \ |
|
166 } while (0) |
|
167 |
|
168 int |
|
169 PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) |
|
170 { |
|
171 PyObject *oldv; |
|
172 |
|
173 if ((l->flags & READONLY) || l->type == T_STRING) |
|
174 { |
|
175 PyErr_SetString(PyExc_TypeError, "readonly attribute"); |
|
176 return -1; |
|
177 } |
|
178 if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) { |
|
179 PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); |
|
180 return -1; |
|
181 } |
|
182 if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) { |
|
183 PyErr_SetString(PyExc_TypeError, |
|
184 "can't delete numeric/char attribute"); |
|
185 return -1; |
|
186 } |
|
187 addr += l->offset; |
|
188 switch (l->type) { |
|
189 case T_BOOL:{ |
|
190 if (!PyBool_Check(v)) { |
|
191 PyErr_SetString(PyExc_TypeError, |
|
192 "attribute value type must be bool"); |
|
193 return -1; |
|
194 } |
|
195 if (v == Py_True) |
|
196 *(char*)addr = (char) 1; |
|
197 else |
|
198 *(char*)addr = (char) 0; |
|
199 break; |
|
200 } |
|
201 case T_BYTE:{ |
|
202 long long_val = PyInt_AsLong(v); |
|
203 if ((long_val == -1) && PyErr_Occurred()) |
|
204 return -1; |
|
205 *(char*)addr = (char)long_val; |
|
206 /* XXX: For compatibility, only warn about truncations |
|
207 for now. */ |
|
208 if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN)) |
|
209 WARN("Truncation of value to char"); |
|
210 break; |
|
211 } |
|
212 case T_UBYTE:{ |
|
213 long long_val = PyInt_AsLong(v); |
|
214 if ((long_val == -1) && PyErr_Occurred()) |
|
215 return -1; |
|
216 *(unsigned char*)addr = (unsigned char)long_val; |
|
217 if ((long_val > UCHAR_MAX) || (long_val < 0)) |
|
218 WARN("Truncation of value to unsigned char"); |
|
219 break; |
|
220 } |
|
221 case T_SHORT:{ |
|
222 long long_val = PyInt_AsLong(v); |
|
223 if ((long_val == -1) && PyErr_Occurred()) |
|
224 return -1; |
|
225 *(short*)addr = (short)long_val; |
|
226 if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) |
|
227 WARN("Truncation of value to short"); |
|
228 break; |
|
229 } |
|
230 case T_USHORT:{ |
|
231 long long_val = PyInt_AsLong(v); |
|
232 if ((long_val == -1) && PyErr_Occurred()) |
|
233 return -1; |
|
234 *(unsigned short*)addr = (unsigned short)long_val; |
|
235 if ((long_val > USHRT_MAX) || (long_val < 0)) |
|
236 WARN("Truncation of value to unsigned short"); |
|
237 break; |
|
238 } |
|
239 case T_INT:{ |
|
240 long long_val = PyInt_AsLong(v); |
|
241 if ((long_val == -1) && PyErr_Occurred()) |
|
242 return -1; |
|
243 *(int *)addr = (int)long_val; |
|
244 if ((long_val > INT_MAX) || (long_val < INT_MIN)) |
|
245 WARN("Truncation of value to int"); |
|
246 break; |
|
247 } |
|
248 case T_UINT:{ |
|
249 unsigned long ulong_val = PyLong_AsUnsignedLong(v); |
|
250 if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) { |
|
251 /* XXX: For compatibility, accept negative int values |
|
252 as well. */ |
|
253 PyErr_Clear(); |
|
254 ulong_val = PyLong_AsLong(v); |
|
255 if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) |
|
256 return -1; |
|
257 *(unsigned int *)addr = (unsigned int)ulong_val; |
|
258 WARN("Writing negative value into unsigned field"); |
|
259 } else |
|
260 *(unsigned int *)addr = (unsigned int)ulong_val; |
|
261 if (ulong_val > UINT_MAX) |
|
262 WARN("Truncation of value to unsigned int"); |
|
263 break; |
|
264 } |
|
265 case T_LONG:{ |
|
266 *(long*)addr = PyLong_AsLong(v); |
|
267 if ((*(long*)addr == -1) && PyErr_Occurred()) |
|
268 return -1; |
|
269 break; |
|
270 } |
|
271 case T_ULONG:{ |
|
272 *(unsigned long*)addr = PyLong_AsUnsignedLong(v); |
|
273 if ((*(unsigned long*)addr == (unsigned long)-1) |
|
274 && PyErr_Occurred()) { |
|
275 /* XXX: For compatibility, accept negative int values |
|
276 as well. */ |
|
277 PyErr_Clear(); |
|
278 *(unsigned long*)addr = PyLong_AsLong(v); |
|
279 if ((*(unsigned long*)addr == (unsigned int)-1) |
|
280 && PyErr_Occurred()) |
|
281 return -1; |
|
282 WARN("Writing negative value into unsigned field"); |
|
283 } |
|
284 break; |
|
285 } |
|
286 case T_PYSSIZET:{ |
|
287 *(Py_ssize_t*)addr = PyInt_AsSsize_t(v); |
|
288 if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1) |
|
289 && PyErr_Occurred()) |
|
290 return -1; |
|
291 break; |
|
292 } |
|
293 case T_FLOAT:{ |
|
294 double double_val = PyFloat_AsDouble(v); |
|
295 if ((double_val == -1) && PyErr_Occurred()) |
|
296 return -1; |
|
297 *(float*)addr = (float)double_val; |
|
298 break; |
|
299 } |
|
300 case T_DOUBLE: |
|
301 *(double*)addr = PyFloat_AsDouble(v); |
|
302 if ((*(double*)addr == -1) && PyErr_Occurred()) |
|
303 return -1; |
|
304 break; |
|
305 case T_OBJECT: |
|
306 case T_OBJECT_EX: |
|
307 Py_XINCREF(v); |
|
308 oldv = *(PyObject **)addr; |
|
309 *(PyObject **)addr = v; |
|
310 Py_XDECREF(oldv); |
|
311 break; |
|
312 case T_CHAR: |
|
313 if (PyString_Check(v) && PyString_Size(v) == 1) { |
|
314 *(char*)addr = PyString_AsString(v)[0]; |
|
315 } |
|
316 else { |
|
317 PyErr_BadArgument(); |
|
318 return -1; |
|
319 } |
|
320 break; |
|
321 #ifdef HAVE_LONG_LONG |
|
322 case T_LONGLONG:{ |
|
323 PY_LONG_LONG value; |
|
324 *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v); |
|
325 if ((value == -1) && PyErr_Occurred()) |
|
326 return -1; |
|
327 break; |
|
328 } |
|
329 case T_ULONGLONG:{ |
|
330 unsigned PY_LONG_LONG value; |
|
331 /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong |
|
332 doesn't ??? */ |
|
333 if (PyLong_Check(v)) |
|
334 *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v); |
|
335 else |
|
336 *(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v); |
|
337 if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred()) |
|
338 return -1; |
|
339 break; |
|
340 } |
|
341 #endif /* HAVE_LONG_LONG */ |
|
342 default: |
|
343 PyErr_Format(PyExc_SystemError, |
|
344 "bad memberdescr type for %s", l->name); |
|
345 return -1; |
|
346 } |
|
347 return 0; |
|
348 } |