blob: ba88e15f9386911d31eee3b76e02db9148e0b352 [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001
Guido van Rossum3f5da241990-12-20 15:06:42 +00002/* Map C struct members to Python object attributes */
3
Guido van Rossum79f25d91997-04-29 20:08:16 +00004#include "Python.h"
Victor Stinner4a21e572020-04-15 02:35:41 +02005#include "structmember.h" // PyMemberDef
Guido van Rossum3f5da241990-12-20 15:06:42 +00006
Guido van Rossum6f799372001-09-20 20:46:19 +00007PyObject *
Tim Petersc3d12ac2005-12-24 06:03:06 +00008PyMember_GetOne(const char *addr, PyMemberDef *l)
Guido van Rossum6f799372001-09-20 20:46:19 +00009{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000010 PyObject *v;
Guido van Rossuma8add0e2007-05-14 22:03:55 +000011
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000012 addr += l->offset;
13 switch (l->type) {
14 case T_BOOL:
15 v = PyBool_FromLong(*(char*)addr);
16 break;
17 case T_BYTE:
18 v = PyLong_FromLong(*(char*)addr);
19 break;
20 case T_UBYTE:
21 v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
22 break;
23 case T_SHORT:
24 v = PyLong_FromLong(*(short*)addr);
25 break;
26 case T_USHORT:
27 v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
28 break;
29 case T_INT:
30 v = PyLong_FromLong(*(int*)addr);
31 break;
32 case T_UINT:
33 v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
34 break;
35 case T_LONG:
36 v = PyLong_FromLong(*(long*)addr);
37 break;
38 case T_ULONG:
39 v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
40 break;
41 case T_PYSSIZET:
42 v = PyLong_FromSsize_t(*(Py_ssize_t*)addr);
43 break;
44 case T_FLOAT:
45 v = PyFloat_FromDouble((double)*(float*)addr);
46 break;
47 case T_DOUBLE:
48 v = PyFloat_FromDouble(*(double*)addr);
49 break;
50 case T_STRING:
51 if (*(char**)addr == NULL) {
52 Py_INCREF(Py_None);
53 v = Py_None;
54 }
55 else
56 v = PyUnicode_FromString(*(char**)addr);
57 break;
58 case T_STRING_INPLACE:
59 v = PyUnicode_FromString((char*)addr);
60 break;
61 case T_CHAR:
62 v = PyUnicode_FromStringAndSize((char*)addr, 1);
63 break;
64 case T_OBJECT:
65 v = *(PyObject **)addr;
66 if (v == NULL)
67 v = Py_None;
68 Py_INCREF(v);
69 break;
70 case T_OBJECT_EX:
71 v = *(PyObject **)addr;
72 if (v == NULL)
73 PyErr_SetString(PyExc_AttributeError, l->name);
74 Py_XINCREF(v);
75 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000076 case T_LONGLONG:
Benjamin Petersonaf580df2016-09-06 10:46:49 -070077 v = PyLong_FromLongLong(*(long long *)addr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 break;
79 case T_ULONGLONG:
Benjamin Petersonaf580df2016-09-06 10:46:49 -070080 v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000081 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 case T_NONE:
83 v = Py_None;
84 Py_INCREF(v);
85 break;
86 default:
87 PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
88 v = NULL;
89 }
90 return v;
Guido van Rossum6f799372001-09-20 20:46:19 +000091}
92
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000093#define WARN(msg) \
94 do { \
95 if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) \
96 return -1; \
Guido van Rossum806c2462007-08-06 23:33:07 +000097 } while (0)
98
Guido van Rossum6f799372001-09-20 20:46:19 +000099int
100PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
101{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 PyObject *oldv;
Guido van Rossum6f799372001-09-20 20:46:19 +0000103
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 addr += l->offset;
Benjamin Petersond12362a2009-12-30 19:44:54 +0000105
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000106 if ((l->flags & READONLY))
107 {
108 PyErr_SetString(PyExc_AttributeError, "readonly attribute");
109 return -1;
110 }
111 if (v == NULL) {
112 if (l->type == T_OBJECT_EX) {
113 /* Check if the attribute is set. */
114 if (*(PyObject **)addr == NULL) {
115 PyErr_SetString(PyExc_AttributeError, l->name);
116 return -1;
117 }
118 }
119 else if (l->type != T_OBJECT) {
120 PyErr_SetString(PyExc_TypeError,
121 "can't delete numeric/char attribute");
122 return -1;
123 }
124 }
125 switch (l->type) {
126 case T_BOOL:{
127 if (!PyBool_Check(v)) {
128 PyErr_SetString(PyExc_TypeError,
129 "attribute value type must be bool");
130 return -1;
131 }
132 if (v == Py_True)
133 *(char*)addr = (char) 1;
134 else
135 *(char*)addr = (char) 0;
136 break;
137 }
138 case T_BYTE:{
139 long long_val = PyLong_AsLong(v);
140 if ((long_val == -1) && PyErr_Occurred())
141 return -1;
142 *(char*)addr = (char)long_val;
143 /* XXX: For compatibility, only warn about truncations
144 for now. */
145 if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
146 WARN("Truncation of value to char");
147 break;
148 }
149 case T_UBYTE:{
150 long long_val = PyLong_AsLong(v);
151 if ((long_val == -1) && PyErr_Occurred())
152 return -1;
153 *(unsigned char*)addr = (unsigned char)long_val;
154 if ((long_val > UCHAR_MAX) || (long_val < 0))
155 WARN("Truncation of value to unsigned char");
156 break;
157 }
158 case T_SHORT:{
159 long long_val = PyLong_AsLong(v);
160 if ((long_val == -1) && PyErr_Occurred())
161 return -1;
162 *(short*)addr = (short)long_val;
163 if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
164 WARN("Truncation of value to short");
165 break;
166 }
167 case T_USHORT:{
168 long long_val = PyLong_AsLong(v);
169 if ((long_val == -1) && PyErr_Occurred())
170 return -1;
171 *(unsigned short*)addr = (unsigned short)long_val;
172 if ((long_val > USHRT_MAX) || (long_val < 0))
173 WARN("Truncation of value to unsigned short");
174 break;
175 }
176 case T_INT:{
177 long long_val = PyLong_AsLong(v);
178 if ((long_val == -1) && PyErr_Occurred())
179 return -1;
180 *(int *)addr = (int)long_val;
181 if ((long_val > INT_MAX) || (long_val < INT_MIN))
182 WARN("Truncation of value to int");
183 break;
184 }
185 case T_UINT:{
186 unsigned long ulong_val = PyLong_AsUnsignedLong(v);
187 if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
188 /* XXX: For compatibility, accept negative int values
189 as well. */
190 PyErr_Clear();
191 ulong_val = PyLong_AsLong(v);
192 if ((ulong_val == (unsigned long)-1) &&
193 PyErr_Occurred())
194 return -1;
195 *(unsigned int *)addr = (unsigned int)ulong_val;
196 WARN("Writing negative value into unsigned field");
197 } else
198 *(unsigned int *)addr = (unsigned int)ulong_val;
199 if (ulong_val > UINT_MAX)
200 WARN("Truncation of value to unsigned int");
201 break;
202 }
203 case T_LONG:{
204 *(long*)addr = PyLong_AsLong(v);
205 if ((*(long*)addr == -1) && PyErr_Occurred())
206 return -1;
207 break;
208 }
209 case T_ULONG:{
210 *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
211 if ((*(unsigned long*)addr == (unsigned long)-1)
212 && PyErr_Occurred()) {
213 /* XXX: For compatibility, accept negative int values
214 as well. */
215 PyErr_Clear();
216 *(unsigned long*)addr = PyLong_AsLong(v);
217 if ((*(unsigned long*)addr == (unsigned long)-1)
218 && PyErr_Occurred())
219 return -1;
220 WARN("Writing negative value into unsigned field");
221 }
222 break;
223 }
224 case T_PYSSIZET:{
225 *(Py_ssize_t*)addr = PyLong_AsSsize_t(v);
226 if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
227 && PyErr_Occurred())
228 return -1;
229 break;
230 }
231 case T_FLOAT:{
232 double double_val = PyFloat_AsDouble(v);
233 if ((double_val == -1) && PyErr_Occurred())
234 return -1;
235 *(float*)addr = (float)double_val;
236 break;
237 }
238 case T_DOUBLE:
239 *(double*)addr = PyFloat_AsDouble(v);
240 if ((*(double*)addr == -1) && PyErr_Occurred())
241 return -1;
242 break;
243 case T_OBJECT:
244 case T_OBJECT_EX:
245 Py_XINCREF(v);
246 oldv = *(PyObject **)addr;
247 *(PyObject **)addr = v;
248 Py_XDECREF(oldv);
249 break;
250 case T_CHAR: {
Serhiy Storchaka85b0f5b2016-11-20 10:16:47 +0200251 const char *string;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 Py_ssize_t len;
Alexandre Vassalottia85998a2008-05-03 18:24:43 +0000253
Serhiy Storchaka06515832016-11-20 09:13:07 +0200254 string = PyUnicode_AsUTF8AndSize(v, &len);
Christian Heimes5557a9c2012-09-11 17:30:53 +0200255 if (string == NULL || len != 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 PyErr_BadArgument();
257 return -1;
258 }
259 *(char*)addr = string[0];
260 break;
261 }
262 case T_STRING:
263 case T_STRING_INPLACE:
264 PyErr_SetString(PyExc_TypeError, "readonly attribute");
265 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 case T_LONGLONG:{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700267 long long value;
268 *(long long*)addr = value = PyLong_AsLongLong(v);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 if ((value == -1) && PyErr_Occurred())
270 return -1;
271 break;
272 }
273 case T_ULONGLONG:{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700274 unsigned long long value;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
276 doesn't ??? */
277 if (PyLong_Check(v))
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700278 *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 else
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700280 *(unsigned long long*)addr = value = PyLong_AsLong(v);
281 if ((value == (unsigned long long)-1) && PyErr_Occurred())
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 return -1;
283 break;
284 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 default:
286 PyErr_Format(PyExc_SystemError,
287 "bad memberdescr type for %s", l->name);
288 return -1;
289 }
290 return 0;
Guido van Rossum6f799372001-09-20 20:46:19 +0000291}