• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include "parse_c_type.c"
3 #include "realize_c_type.c"
4 
5 #define CFFI_VERSION_MIN            0x2601
6 #define CFFI_VERSION_CHAR16CHAR32   0x2801
7 #define CFFI_VERSION_MAX            0x28FF
8 
9 typedef struct FFIObject_s FFIObject;
10 typedef struct LibObject_s LibObject;
11 
12 static PyTypeObject FFI_Type;   /* forward */
13 static PyTypeObject Lib_Type;   /* forward */
14 
15 #include "ffi_obj.c"
16 #include "cglob.c"
17 #include "lib_obj.c"
18 #include "cdlopen.c"
19 #include "commontypes.c"
20 #include "call_python.c"
21 
22 
init_ffi_lib(PyObject * m)23 static int init_ffi_lib(PyObject *m)
24 {
25     PyObject *x;
26     int i, res;
27     static char init_done = 0;
28 
29     if (PyType_Ready(&FFI_Type) < 0)
30         return -1;
31     if (PyType_Ready(&Lib_Type) < 0)
32         return -1;
33 
34     if (!init_done) {
35         if (init_global_types_dict(FFI_Type.tp_dict) < 0)
36             return -1;
37 
38         FFIError = PyErr_NewException("ffi.error", NULL, NULL);
39         if (FFIError == NULL)
40             return -1;
41         if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0)
42             return -1;
43         if (PyDict_SetItemString(FFI_Type.tp_dict, "CType",
44                                  (PyObject *)&CTypeDescr_Type) < 0)
45             return -1;
46         if (PyDict_SetItemString(FFI_Type.tp_dict, "CData",
47                                  (PyObject *)&CData_Type) < 0)
48             return -1;
49         if (PyDict_SetItemString(FFI_Type.tp_dict, "buffer",
50                                  (PyObject *)&MiniBuffer_Type) < 0)
51             return -1;
52 
53         for (i = 0; all_dlopen_flags[i].name != NULL; i++) {
54             x = PyInt_FromLong(all_dlopen_flags[i].value);
55             if (x == NULL)
56                 return -1;
57             res = PyDict_SetItemString(FFI_Type.tp_dict,
58                                        all_dlopen_flags[i].name, x);
59             Py_DECREF(x);
60             if (res < 0)
61                 return -1;
62         }
63         init_done = 1;
64     }
65 
66     x = (PyObject *)&FFI_Type;
67     Py_INCREF(x);
68     if (PyModule_AddObject(m, "FFI", x) < 0)
69         return -1;
70     x = (PyObject *)&Lib_Type;
71     Py_INCREF(x);
72     if (PyModule_AddObject(m, "Lib", x) < 0)
73         return -1;
74 
75     return 0;
76 }
77 
make_included_tuples(char * module_name,const char * const * ctx_includes,PyObject ** included_ffis,PyObject ** included_libs)78 static int make_included_tuples(char *module_name,
79                                 const char *const *ctx_includes,
80                                 PyObject **included_ffis,
81                                 PyObject **included_libs)
82 {
83     Py_ssize_t num = 0;
84     const char *const *p_include;
85 
86     if (ctx_includes == NULL)
87         return 0;
88 
89     for (p_include = ctx_includes; *p_include; p_include++) {
90         num++;
91     }
92     *included_ffis = PyTuple_New(num);
93     *included_libs = PyTuple_New(num);
94     if (*included_ffis == NULL || *included_libs == NULL)
95         goto error;
96 
97     num = 0;
98     for (p_include = ctx_includes; *p_include; p_include++) {
99         PyObject *included_ffi, *included_lib;
100         PyObject *m = PyImport_ImportModule(*p_include);
101         if (m == NULL)
102             goto import_error;
103 
104         included_ffi = PyObject_GetAttrString(m, "ffi");
105         PyTuple_SET_ITEM(*included_ffis, num, included_ffi);
106 
107         included_lib = (included_ffi == NULL) ? NULL :
108                        PyObject_GetAttrString(m, "lib");
109         PyTuple_SET_ITEM(*included_libs, num, included_lib);
110 
111         Py_DECREF(m);
112         if (included_lib == NULL)
113             goto import_error;
114 
115         if (!FFIObject_Check(included_ffi) ||
116             !LibObject_Check(included_lib))
117             goto import_error;
118         num++;
119     }
120     return 0;
121 
122  import_error:
123     PyErr_Format(PyExc_ImportError,
124                  "while loading %.200s: failed to import ffi, lib from %.200s",
125                  module_name, *p_include);
126  error:
127     Py_XDECREF(*included_ffis); *included_ffis = NULL;
128     Py_XDECREF(*included_libs); *included_libs = NULL;
129     return -1;
130 }
131 
_my_Py_InitModule(char * module_name)132 static PyObject *_my_Py_InitModule(char *module_name)
133 {
134 #if PY_MAJOR_VERSION >= 3
135     struct PyModuleDef *module_def, local_module_def = {
136         PyModuleDef_HEAD_INIT,
137         module_name,
138         NULL,
139         -1,
140         NULL, NULL, NULL, NULL, NULL
141     };
142     /* note: the 'module_def' is allocated dynamically and leaks,
143        but anyway the C extension module can never be unloaded */
144     module_def = PyMem_Malloc(sizeof(struct PyModuleDef));
145     if (module_def == NULL)
146         return PyErr_NoMemory();
147     *module_def = local_module_def;
148     return PyModule_Create(module_def);
149 #else
150     return Py_InitModule(module_name, NULL);
151 #endif
152 }
153 
b_init_cffi_1_0_external_module(PyObject * self,PyObject * arg)154 static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg)
155 {
156     PyObject *m, *modules_dict;
157     FFIObject *ffi;
158     LibObject *lib;
159     Py_ssize_t version, num_exports;
160     char *module_name, *exports, *module_name_with_lib;
161     void **raw;
162     const struct _cffi_type_context_s *ctx;
163 
164     raw = (void **)PyLong_AsVoidPtr(arg);
165     if (raw == NULL)
166         return NULL;
167 
168     module_name = (char *)raw[0];
169     version = (Py_ssize_t)raw[1];
170     exports = (char *)raw[2];
171     ctx = (const struct _cffi_type_context_s *)raw[3];
172 
173     if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
174         if (!PyErr_Occurred())
175             PyErr_Format(PyExc_ImportError,
176                 "cffi extension module '%s' uses an unknown version tag %p. "
177                 "This module might need a more recent version of cffi "
178                 "than the one currently installed, which is %s",
179                 module_name, (void *)version, CFFI_VERSION);
180         return NULL;
181     }
182 
183     /* initialize the exports array */
184     num_exports = 25;
185     if (ctx->flags & 1)    /* set to mean that 'extern "Python"' is used */
186         num_exports = 26;
187     if (version >= CFFI_VERSION_CHAR16CHAR32)
188         num_exports = 28;
189     memcpy(exports, (char *)cffi_exports, num_exports * sizeof(void *));
190 
191     /* make the module object */
192     m = _my_Py_InitModule(module_name);
193     if (m == NULL)
194         return NULL;
195 
196     /* build the FFI and Lib object inside this new module */
197     ffi = ffi_internal_new(&FFI_Type, ctx);
198     Py_XINCREF(ffi);    /* make the ffi object really immortal */
199     if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
200         return NULL;
201 
202     lib = lib_internal_new(ffi, module_name, NULL);
203     if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
204         return NULL;
205 
206     if (make_included_tuples(module_name, ctx->includes,
207                              &ffi->types_builder.included_ffis,
208                              &lib->l_types_builder->included_libs) < 0)
209         return NULL;
210 
211     /* add manually 'module_name.lib' in sys.modules:
212        see test_import_from_lib */
213     modules_dict = PySys_GetObject("modules");
214     if (!modules_dict)
215         return NULL;
216     module_name_with_lib = alloca(strlen(module_name) + 5);
217     strcpy(module_name_with_lib, module_name);
218     strcat(module_name_with_lib, ".lib");
219     if (PyDict_SetItemString(modules_dict, module_name_with_lib,
220                              (PyObject *)lib) < 0)
221         return NULL;
222 
223 #if PY_MAJOR_VERSION >= 3
224     /* add manually 'module_name' in sys.modules: it seems that
225        Py_InitModule() is not enough to do that */
226     if (PyDict_SetItemString(modules_dict, module_name, m) < 0)
227         return NULL;
228 #endif
229 
230     return m;
231 }
232