summaryrefslogtreecommitdiff
path: root/c/cglob.c
blob: e97767c9d75c1603577d06a151e89fe25816f793 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

typedef void *(*gs_fetch_addr_fn)(void);

typedef struct {
    PyObject_HEAD

    PyObject         *gs_name;
    CTypeDescrObject *gs_type;
    char             *gs_data;
    gs_fetch_addr_fn  gs_fetch_addr;

} GlobSupportObject;

static void glob_support_dealloc(GlobSupportObject *gs)
{
    Py_DECREF(gs->gs_name);
    Py_DECREF(gs->gs_type);
    PyObject_Del(gs);
}

static PyTypeObject GlobSupport_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "_cffi_backend.__FFIGlobSupport",
    sizeof(GlobSupportObject),
    0,
    (destructor)glob_support_dealloc,           /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_compare */
    0,                                          /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    0,                                          /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
};

#define GlobSupport_Check(ob)  (Py_TYPE(ob) == &GlobSupport_Type)

static PyObject *make_global_var(PyObject *name, CTypeDescrObject *type,
                                 char *addr, gs_fetch_addr_fn fetch_addr)
{
    GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type);
    if (gs == NULL)
        return NULL;

    Py_INCREF(name);
    Py_INCREF(type);
    gs->gs_name = name;
    gs->gs_type = type;
    gs->gs_data = addr;
    gs->gs_fetch_addr = fetch_addr;
    return (PyObject *)gs;
}

static void *fetch_global_var_addr(GlobSupportObject *gs)
{
    void *data;
    if (gs->gs_data != NULL) {
        data = gs->gs_data;
    }
    else {
        Py_BEGIN_ALLOW_THREADS
        restore_errno();
        data = gs->gs_fetch_addr();
        save_errno();
        Py_END_ALLOW_THREADS
    }
    if (data == NULL) {
        PyErr_Format(FFIError, "global variable '%s' is at address NULL",
                     PyText_AS_UTF8(gs->gs_name));
        return NULL;
    }
    return data;
}

static PyObject *read_global_var(GlobSupportObject *gs)
{
    void *data = fetch_global_var_addr(gs);
    if (data == NULL)
        return NULL;
    return convert_to_object(data, gs->gs_type);
}

static int write_global_var(GlobSupportObject *gs, PyObject *obj)
{
    void *data = fetch_global_var_addr(gs);
    if (data == NULL)
        return -1;
    return convert_from_object(data, gs->gs_type, obj);
}

static PyObject *cg_addressof_global_var(GlobSupportObject *gs)
{
    void *data;
    PyObject *x, *ptrtype = new_pointer_type(gs->gs_type);
    if (ptrtype == NULL)
        return NULL;

    data = fetch_global_var_addr(gs);
    if (data != NULL)
        x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype);
    else
        x = NULL;
    Py_DECREF(ptrtype);
    return x;
}