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 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, &copy);
     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, &copy, 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