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 addr += l->offset; 174 175 if ((l->flags & READONLY)) 176 { 177 PyErr_SetString(PyExc_TypeError, "readonly attribute"); 178 return -1; 179 } 180 if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) { 181 PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); 182 return -1; 183 } 184 if (v == NULL) { 185 if (l->type == T_OBJECT_EX) { 186 /* Check if the attribute is set. */ 187 if (*(PyObject **)addr == NULL) { 188 PyErr_SetString(PyExc_AttributeError, l->name); 189 return -1; 190 } 191 } 192 else if (l->type != T_OBJECT) { 193 PyErr_SetString(PyExc_TypeError, 194 "can't delete numeric/char attribute"); 195 return -1; 196 } 197 } 198 switch (l->type) { 199 case T_BOOL:{ 200 if (!PyBool_Check(v)) { 201 PyErr_SetString(PyExc_TypeError, 202 "attribute value type must be bool"); 203 return -1; 204 } 205 if (v == Py_True) 206 *(char*)addr = (char) 1; 207 else 208 *(char*)addr = (char) 0; 209 break; 210 } 211 case T_BYTE:{ 212 long long_val = PyInt_AsLong(v); 213 if ((long_val == -1) && PyErr_Occurred()) 214 return -1; 215 *(char*)addr = (char)long_val; 216 /* XXX: For compatibility, only warn about truncations 217 for now. */ 218 if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN)) 219 WARN("Truncation of value to char"); 220 break; 221 } 222 case T_UBYTE:{ 223 long long_val = PyInt_AsLong(v); 224 if ((long_val == -1) && PyErr_Occurred()) 225 return -1; 226 *(unsigned char*)addr = (unsigned char)long_val; 227 if ((long_val > UCHAR_MAX) || (long_val < 0)) 228 WARN("Truncation of value to unsigned char"); 229 break; 230 } 231 case T_SHORT:{ 232 long long_val = PyInt_AsLong(v); 233 if ((long_val == -1) && PyErr_Occurred()) 234 return -1; 235 *(short*)addr = (short)long_val; 236 if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) 237 WARN("Truncation of value to short"); 238 break; 239 } 240 case T_USHORT:{ 241 long long_val = PyInt_AsLong(v); 242 if ((long_val == -1) && PyErr_Occurred()) 243 return -1; 244 *(unsigned short*)addr = (unsigned short)long_val; 245 if ((long_val > USHRT_MAX) || (long_val < 0)) 246 WARN("Truncation of value to unsigned short"); 247 break; 248 } 249 case T_INT:{ 250 long long_val = PyInt_AsLong(v); 251 if ((long_val == -1) && PyErr_Occurred()) 252 return -1; 253 *(int *)addr = (int)long_val; 254 if ((long_val > INT_MAX) || (long_val < INT_MIN)) 255 WARN("Truncation of value to int"); 256 break; 257 } 258 case T_UINT:{ 259 unsigned long ulong_val = PyLong_AsUnsignedLong(v); 260 if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) { 261 /* XXX: For compatibility, accept negative int values 262 as well. */ 263 PyErr_Clear(); 264 ulong_val = PyLong_AsLong(v); 265 if ((ulong_val == (unsigned long)-1) && 266 PyErr_Occurred()) 267 return -1; 268 *(unsigned int *)addr = (unsigned int)ulong_val; 269 WARN("Writing negative value into unsigned field"); 270 } else 271 *(unsigned int *)addr = (unsigned int)ulong_val; 272 if (ulong_val > UINT_MAX) 273 WARN("Truncation of value to unsigned int"); 274 break; 275 } 276 case T_LONG:{ 277 *(long*)addr = PyLong_AsLong(v); 278 if ((*(long*)addr == -1) && PyErr_Occurred()) 279 return -1; 280 break; 281 } 282 case T_ULONG:{ 283 *(unsigned long*)addr = PyLong_AsUnsignedLong(v); 284 if ((*(unsigned long*)addr == (unsigned long)-1) 285 && PyErr_Occurred()) { 286 /* XXX: For compatibility, accept negative int values 287 as well. */ 288 PyErr_Clear(); 289 *(unsigned long*)addr = PyLong_AsLong(v); 290 if ((*(unsigned long*)addr == (unsigned long)-1) 291 && PyErr_Occurred()) 292 return -1; 293 WARN("Writing negative value into unsigned field"); 294 } 295 break; 296 } 297 case T_PYSSIZET:{ 298 *(Py_ssize_t*)addr = PyInt_AsSsize_t(v); 299 if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1) 300 && PyErr_Occurred()) 301 return -1; 302 break; 303 } 304 case T_FLOAT:{ 305 double double_val = PyFloat_AsDouble(v); 306 if ((double_val == -1) && PyErr_Occurred()) 307 return -1; 308 *(float*)addr = (float)double_val; 309 break; 310 } 311 case T_DOUBLE: 312 *(double*)addr = PyFloat_AsDouble(v); 313 if ((*(double*)addr == -1) && PyErr_Occurred()) 314 return -1; 315 break; 316 case T_OBJECT: 317 case T_OBJECT_EX: 318 Py_XINCREF(v); 319 oldv = *(PyObject **)addr; 320 *(PyObject **)addr = v; 321 Py_XDECREF(oldv); 322 break; 323 case T_CHAR: 324 if (PyString_Check(v) && PyString_Size(v) == 1) { 325 *(char*)addr = PyString_AsString(v)[0]; 326 } 327 else { 328 PyErr_BadArgument(); 329 return -1; 330 } 331 break; 332 case T_STRING: 333 case T_STRING_INPLACE: 334 PyErr_SetString(PyExc_TypeError, "readonly attribute"); 335 return -1; 336 #ifdef HAVE_LONG_LONG 337 case T_LONGLONG:{ 338 PY_LONG_LONG value; 339 *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v); 340 if ((value == -1) && PyErr_Occurred()) 341 return -1; 342 break; 343 } 344 case T_ULONGLONG:{ 345 unsigned PY_LONG_LONG value; 346 /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong 347 doesn't ??? */ 348 if (PyLong_Check(v)) 349 *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v); 350 else 351 *(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v); 352 if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred()) 353 return -1; 354 break; 355 } 356 #endif /* HAVE_LONG_LONG */ 357 default: 358 PyErr_Format(PyExc_SystemError, 359 "bad memberdescr type for %s", l->name); 360 return -1; 361 } 362 return 0; 363 } 364