|  | 
 | /* Map C struct members to Python object attributes */ | 
 |  | 
 | #include "Python.h" | 
 |  | 
 | #include "structmember.h" | 
 |  | 
 | PyObject * | 
 | PyMember_GetOne(const char *addr, PyMemberDef *l) | 
 | { | 
 |     PyObject *v; | 
 |  | 
 |     addr += l->offset; | 
 |     switch (l->type) { | 
 |     case T_BOOL: | 
 |         v = PyBool_FromLong(*(char*)addr); | 
 |         break; | 
 |     case T_BYTE: | 
 |         v = PyLong_FromLong(*(char*)addr); | 
 |         break; | 
 |     case T_UBYTE: | 
 |         v = PyLong_FromUnsignedLong(*(unsigned char*)addr); | 
 |         break; | 
 |     case T_SHORT: | 
 |         v = PyLong_FromLong(*(short*)addr); | 
 |         break; | 
 |     case T_USHORT: | 
 |         v = PyLong_FromUnsignedLong(*(unsigned short*)addr); | 
 |         break; | 
 |     case T_INT: | 
 |         v = PyLong_FromLong(*(int*)addr); | 
 |         break; | 
 |     case T_UINT: | 
 |         v = PyLong_FromUnsignedLong(*(unsigned int*)addr); | 
 |         break; | 
 |     case T_LONG: | 
 |         v = PyLong_FromLong(*(long*)addr); | 
 |         break; | 
 |     case T_ULONG: | 
 |         v = PyLong_FromUnsignedLong(*(unsigned long*)addr); | 
 |         break; | 
 |     case T_PYSSIZET: | 
 |         v = PyLong_FromSsize_t(*(Py_ssize_t*)addr); | 
 |         break; | 
 |     case T_FLOAT: | 
 |         v = PyFloat_FromDouble((double)*(float*)addr); | 
 |         break; | 
 |     case T_DOUBLE: | 
 |         v = PyFloat_FromDouble(*(double*)addr); | 
 |         break; | 
 |     case T_STRING: | 
 |         if (*(char**)addr == NULL) { | 
 |             Py_INCREF(Py_None); | 
 |             v = Py_None; | 
 |         } | 
 |         else | 
 |             v = PyUnicode_FromString(*(char**)addr); | 
 |         break; | 
 |     case T_STRING_INPLACE: | 
 |         v = PyUnicode_FromString((char*)addr); | 
 |         break; | 
 |     case T_CHAR: | 
 |         v = PyUnicode_FromStringAndSize((char*)addr, 1); | 
 |         break; | 
 |     case T_OBJECT: | 
 |         v = *(PyObject **)addr; | 
 |         if (v == NULL) | 
 |             v = Py_None; | 
 |         Py_INCREF(v); | 
 |         break; | 
 |     case T_OBJECT_EX: | 
 |         v = *(PyObject **)addr; | 
 |         if (v == NULL) | 
 |             PyErr_SetString(PyExc_AttributeError, l->name); | 
 |         Py_XINCREF(v); | 
 |         break; | 
 | #ifdef HAVE_LONG_LONG | 
 |     case T_LONGLONG: | 
 |         v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr); | 
 |         break; | 
 |     case T_ULONGLONG: | 
 |         v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr); | 
 |         break; | 
 | #endif /* HAVE_LONG_LONG */ | 
 |     case T_NONE: | 
 |         v = Py_None; | 
 |         Py_INCREF(v); | 
 |         break; | 
 |     default: | 
 |         PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); | 
 |         v = NULL; | 
 |     } | 
 |     return v; | 
 | } | 
 |  | 
 | #define WARN(msg)                                               \ | 
 |     do {                                                        \ | 
 |     if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0)         \ | 
 |         return -1;                                              \ | 
 |     } while (0) | 
 |  | 
 | int | 
 | PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) | 
 | { | 
 |     PyObject *oldv; | 
 |  | 
 |     addr += l->offset; | 
 |  | 
 |     if ((l->flags & READONLY)) | 
 |     { | 
 |         PyErr_SetString(PyExc_AttributeError, "readonly attribute"); | 
 |         return -1; | 
 |     } | 
 |     if (v == NULL) { | 
 |         if (l->type == T_OBJECT_EX) { | 
 |             /* Check if the attribute is set. */ | 
 |             if (*(PyObject **)addr == NULL) { | 
 |                 PyErr_SetString(PyExc_AttributeError, l->name); | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |         else if (l->type != T_OBJECT) { | 
 |             PyErr_SetString(PyExc_TypeError, | 
 |                             "can't delete numeric/char attribute"); | 
 |             return -1; | 
 |         } | 
 |     } | 
 |     switch (l->type) { | 
 |     case T_BOOL:{ | 
 |         if (!PyBool_Check(v)) { | 
 |             PyErr_SetString(PyExc_TypeError, | 
 |                             "attribute value type must be bool"); | 
 |             return -1; | 
 |         } | 
 |         if (v == Py_True) | 
 |             *(char*)addr = (char) 1; | 
 |         else | 
 |             *(char*)addr = (char) 0; | 
 |         break; | 
 |         } | 
 |     case T_BYTE:{ | 
 |         long long_val = PyLong_AsLong(v); | 
 |         if ((long_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(char*)addr = (char)long_val; | 
 |         /* XXX: For compatibility, only warn about truncations | 
 |            for now. */ | 
 |         if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN)) | 
 |             WARN("Truncation of value to char"); | 
 |         break; | 
 |         } | 
 |     case T_UBYTE:{ | 
 |         long long_val = PyLong_AsLong(v); | 
 |         if ((long_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(unsigned char*)addr = (unsigned char)long_val; | 
 |         if ((long_val > UCHAR_MAX) || (long_val < 0)) | 
 |             WARN("Truncation of value to unsigned char"); | 
 |         break; | 
 |         } | 
 |     case T_SHORT:{ | 
 |         long long_val = PyLong_AsLong(v); | 
 |         if ((long_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(short*)addr = (short)long_val; | 
 |         if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) | 
 |             WARN("Truncation of value to short"); | 
 |         break; | 
 |         } | 
 |     case T_USHORT:{ | 
 |         long long_val = PyLong_AsLong(v); | 
 |         if ((long_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(unsigned short*)addr = (unsigned short)long_val; | 
 |         if ((long_val > USHRT_MAX) || (long_val < 0)) | 
 |             WARN("Truncation of value to unsigned short"); | 
 |         break; | 
 |         } | 
 |     case T_INT:{ | 
 |         long long_val = PyLong_AsLong(v); | 
 |         if ((long_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(int *)addr = (int)long_val; | 
 |         if ((long_val > INT_MAX) || (long_val < INT_MIN)) | 
 |             WARN("Truncation of value to int"); | 
 |         break; | 
 |         } | 
 |     case T_UINT:{ | 
 |         unsigned long ulong_val = PyLong_AsUnsignedLong(v); | 
 |         if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) { | 
 |             /* XXX: For compatibility, accept negative int values | 
 |                as well. */ | 
 |             PyErr_Clear(); | 
 |             ulong_val = PyLong_AsLong(v); | 
 |             if ((ulong_val == (unsigned long)-1) && | 
 |                 PyErr_Occurred()) | 
 |                 return -1; | 
 |             *(unsigned int *)addr = (unsigned int)ulong_val; | 
 |             WARN("Writing negative value into unsigned field"); | 
 |         } else | 
 |             *(unsigned int *)addr = (unsigned int)ulong_val; | 
 |         if (ulong_val > UINT_MAX) | 
 |             WARN("Truncation of value to unsigned int"); | 
 |         break; | 
 |         } | 
 |     case T_LONG:{ | 
 |         *(long*)addr = PyLong_AsLong(v); | 
 |         if ((*(long*)addr == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         break; | 
 |         } | 
 |     case T_ULONG:{ | 
 |         *(unsigned long*)addr = PyLong_AsUnsignedLong(v); | 
 |         if ((*(unsigned long*)addr == (unsigned long)-1) | 
 |             && PyErr_Occurred()) { | 
 |             /* XXX: For compatibility, accept negative int values | 
 |                as well. */ | 
 |             PyErr_Clear(); | 
 |             *(unsigned long*)addr = PyLong_AsLong(v); | 
 |             if ((*(unsigned long*)addr == (unsigned long)-1) | 
 |                 && PyErr_Occurred()) | 
 |                 return -1; | 
 |             WARN("Writing negative value into unsigned field"); | 
 |         } | 
 |         break; | 
 |         } | 
 |     case T_PYSSIZET:{ | 
 |         *(Py_ssize_t*)addr = PyLong_AsSsize_t(v); | 
 |         if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1) | 
 |             && PyErr_Occurred()) | 
 |                         return -1; | 
 |         break; | 
 |         } | 
 |     case T_FLOAT:{ | 
 |         double double_val = PyFloat_AsDouble(v); | 
 |         if ((double_val == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         *(float*)addr = (float)double_val; | 
 |         break; | 
 |         } | 
 |     case T_DOUBLE: | 
 |         *(double*)addr = PyFloat_AsDouble(v); | 
 |         if ((*(double*)addr == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         break; | 
 |     case T_OBJECT: | 
 |     case T_OBJECT_EX: | 
 |         Py_XINCREF(v); | 
 |         oldv = *(PyObject **)addr; | 
 |         *(PyObject **)addr = v; | 
 |         Py_XDECREF(oldv); | 
 |         break; | 
 |     case T_CHAR: { | 
 |         char *string; | 
 |         Py_ssize_t len; | 
 |  | 
 |         if (!PyUnicode_Check(v)) { | 
 |             PyErr_BadArgument(); | 
 |             return -1; | 
 |         } | 
 |         string = _PyUnicode_AsStringAndSize(v, &len); | 
 |         if (len != 1) { | 
 |             PyErr_BadArgument(); | 
 |             return -1; | 
 |         } | 
 |         *(char*)addr = string[0]; | 
 |         break; | 
 |         } | 
 |     case T_STRING: | 
 |     case T_STRING_INPLACE: | 
 |         PyErr_SetString(PyExc_TypeError, "readonly attribute"); | 
 |         return -1; | 
 | #ifdef HAVE_LONG_LONG | 
 |     case T_LONGLONG:{ | 
 |         PY_LONG_LONG value; | 
 |         *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v); | 
 |         if ((value == -1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         break; | 
 |         } | 
 |     case T_ULONGLONG:{ | 
 |         unsigned PY_LONG_LONG value; | 
 |         /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong | 
 |             doesn't ??? */ | 
 |         if (PyLong_Check(v)) | 
 |             *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v); | 
 |         else | 
 |             *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsLong(v); | 
 |         if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred()) | 
 |             return -1; | 
 |         break; | 
 |         } | 
 | #endif /* HAVE_LONG_LONG */ | 
 |     default: | 
 |         PyErr_Format(PyExc_SystemError, | 
 |                      "bad memberdescr type for %s", l->name); | 
 |         return -1; | 
 |     } | 
 |     return 0; | 
 | } |