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