/bundles/pyml/pyml-current/pyml_stubs.c
C | 1372 lines | 1206 code | 120 blank | 46 comment | 176 complexity | f8b0bcc2179767017ea0d88039fbf649 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-4.0
1#define _GNU_SOURCE
2#include <caml/mlvalues.h>
3#include <caml/memory.h>
4#include <caml/fail.h>
5#include <caml/callback.h>
6#include <caml/custom.h>
7#include <caml/alloc.h>
8#include <sys/param.h>
9#include <string.h>
10#include <stdbool.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <errno.h>
15#include "pyml_stubs.h"
16
17static FILE *(*Python__Py_fopen)(const char *pathname, const char *mode);
18
19static void *xmalloc(size_t size)
20{
21 void *p = malloc(size);
22 if (!p) {
23 failwith("Virtual memory exhausted\n");
24 }
25 return p;
26}
27
28#ifdef _WIN32
29#include <windows.h>
30
31typedef HINSTANCE library_t;
32
33static library_t
34open_library(const char *filename)
35{
36 return LoadLibrary(filename);
37}
38
39void
40close_library(library_t library)
41{
42 if (!FreeLibrary(library)) {
43 fprintf(stderr, "close_library.\n");
44 exit(EXIT_FAILURE);
45 }
46}
47
48static library_t
49get_default_library(void)
50{
51 return GetModuleHandle(0);
52}
53
54static void *
55find_symbol(library_t library, const char *name)
56{
57 return GetProcAddress(library, name);
58}
59
60int
61unsetenv(const char *name)
62{
63 size_t len = strlen(name);
64 char string[len + 2];
65 snprintf(string, len + 2, "%s=", name);
66 return _putenv(string);
67}
68
69extern int win_CRT_fd_of_filedescr(value handle);
70
71static FILE *
72file_of_file_descr(value file_descr, const char *mode)
73{
74 CAMLparam1(file_descr);
75 int fd = win_CRT_fd_of_filedescr(file_descr);
76 FILE *result = _fdopen(dup(fd), mode);
77 CAMLreturnT(FILE *, result);
78}
79#else
80#include <dlfcn.h>
81
82typedef void *library_t;
83
84static library_t
85open_library(const char *filename)
86{
87 return dlopen(filename, RTLD_LAZY | RTLD_GLOBAL);
88}
89
90void
91close_library(library_t filename)
92{
93 if (dlclose(filename)) {
94 fprintf(stderr, "close_library: %s.\n", dlerror());
95 exit(EXIT_FAILURE);
96 }
97}
98
99static library_t
100get_default_library(void)
101{
102 return RTLD_DEFAULT;
103}
104
105static void *
106find_symbol(library_t library, const char *name)
107{
108 return dlsym(library, name);
109}
110
111static FILE *
112file_of_file_descr(value file_descr, const char *mode)
113{
114 CAMLparam1(file_descr);
115 int fd = Int_val(file_descr);
116 FILE *result = fdopen(dup(fd), mode);
117 CAMLreturnT(FILE *, result);
118}
119#endif
120
121/* The following definitions are extracted and simplified from
122#include <Python.h>
123*/
124
125typedef struct {
126 int cf_flags;
127} PyCompilerFlags;
128
129#define Py_TPFLAGS_INT_SUBCLASS (1L<<23)
130#define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24)
131#define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25)
132#define Py_TPFLAGS_TUPLE_SUBCLASS (1UL << 26)
133#define Py_TPFLAGS_BYTES_SUBCLASS (1UL << 27)
134#define Py_TPFLAGS_UNICODE_SUBCLASS (1UL << 28)
135#define Py_TPFLAGS_DICT_SUBCLASS (1UL << 29)
136#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1UL << 30)
137#define Py_TPFLAGS_TYPE_SUBCLASS (1UL << 31)
138
139#define Py_LT 0
140#define Py_LE 1
141#define Py_EQ 2
142#define Py_NE 3
143#define Py_GT 4
144#define Py_GE 5
145
146typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
147
148typedef struct PyMethodDef {
149 const char *ml_name;
150 PyCFunction ml_meth;
151 int ml_flags;
152 const char *ml_doc;
153} PyMethodDef;
154
155typedef void (*PyCapsule_Destructor)(PyObject *);
156
157static void *Python27__PyObject_NextNotImplemented;
158
159/* Global variables for the library */
160
161/* version_major != 0 iff the library is initialized */
162static int version_major;
163static int version_minor;
164
165static library_t library;
166
167/* Functions that are special enough to deserved to be wrapped specifically */
168
169/* Wrapped by pywrap_closure */
170static PyObject *(*Python_PyCFunction_NewEx)
171(PyMethodDef *, PyObject *, PyObject *);
172
173/* Wrapped by closure and capsule */
174static void *(*Python27_PyCapsule_New)
175 (void *, const char *, PyCapsule_Destructor);
176static void *(*Python27_PyCapsule_GetPointer)(PyObject *, const char *);
177static int (*Python27_PyCapsule_IsValid)(PyObject *, char *);
178static void *(*Python2_PyCObject_FromVoidPtr)(void *, void (*)(void *));
179static void *(*Python2_PyCObject_AsVoidPtr)(PyObject *);
180
181/* Hack for multi-arguments */
182static PyObject *(*Python_PyObject_CallFunctionObjArgs)(PyObject *, ...);
183static PyObject *(*Python_PyObject_CallMethodObjArgs)(
184 PyObject *, PyObject *, ...);
185
186/* Wrapped by PyErr_Fetch_wrapper */
187static void (*Python_PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
188static void (*Python_PyErr_NormalizeException)
189(PyObject **, PyObject **, PyObject **);
190
191/* Resolved differently between Python 2 and Python 3 */
192static PyObject *Python__Py_FalseStruct;
193
194/* Buffer and size */
195static int (*Python_PyString_AsStringAndSize)
196(PyObject *, char **, Py_ssize_t *);
197static int (*Python_PyObject_AsCharBuffer)
198(PyObject *, const char **, Py_ssize_t *);
199static int (*Python_PyObject_AsReadBuffer)
200(PyObject *, const void **, Py_ssize_t *);
201static int (*Python_PyObject_AsWriteBuffer)
202(PyObject *, void **, Py_ssize_t *);
203
204/* Length argument */
205static PyObject *(*Python_PyLong_FromString)(char *, char **, int);
206
207/* Internal use only */
208static void (*Python_PyMem_Free)(void *);
209
210static enum UCS { UCS_NONE, UCS2, UCS4 } ucs;
211
212/* Single instance of () */
213static PyObject *tuple_empty;
214
215#include "pyml.h"
216
217static void *getcustom( value v )
218{
219 return *((void **)Data_custom_val(v));
220}
221
222static void pydecref( value v )
223{
224 if (getcustom(v)) {
225 Py_DECREF((PyObject *)getcustom(v));
226 }
227}
228
229static int
230rich_compare_bool_nofail
231(PyObject *o1, PyObject *o2, int opid)
232{
233 int result = Python_PyObject_RichCompareBool(o1, o2, opid);
234 if (result == -1) {
235 Python_PyErr_Clear();
236 result = 0;
237 }
238 return result;
239}
240
241static int
242pycompare(value v1, value v2)
243{
244 int result;
245 PyObject *o1 = getcustom(v1);
246 PyObject *o2 = getcustom(v2);
247
248 if (o1 && !o2)
249 result = -1;
250 else if (o2 && !o1)
251 result = 1;
252 else if (!o1 && !o2)
253 result = 0;
254 else if (version_major < 3)
255 Python2_PyObject_Cmp(o1, o2, &result);
256 else if (rich_compare_bool_nofail(o1, o2, Py_EQ))
257 result = 0;
258 else if (rich_compare_bool_nofail(o1, o2, Py_LT))
259 result = -1;
260 else if (rich_compare_bool_nofail(o1, o2, Py_GT))
261 result = 1;
262 else
263 result = -1;
264
265 return result;
266}
267
268static intnat
269pyhash( value v )
270{
271 if (getcustom(v)) {
272 intnat result = Python_PyObject_Hash((PyObject *)getcustom(v));
273 if (result == -1) {
274 Python_PyErr_Clear();
275 }
276 return result;
277 }
278 else {
279 return 0;
280 }
281}
282
283static uintnat
284pydeserialize(void *dst)
285{
286 return 0L;
287}
288
289struct custom_operations pyops =
290{
291 "PythonObject",
292 pydecref,
293 pycompare,
294 pyhash,
295 custom_serialize_default,
296 pydeserialize
297};
298
299enum code {
300 CODE_NULL,
301 CODE_NONE,
302 CODE_TRUE,
303 CODE_FALSE,
304 CODE_TUPLE_EMPTY
305};
306
307static void *
308resolve(const char *symbol)
309{
310 void *result = find_symbol(library, symbol);
311 if (!result) {
312 char *fmt = "Cannot resolve %s.\n";
313 ssize_t size = snprintf(NULL, 0, fmt, symbol);
314 char *msg = xmalloc(size + 1);
315 snprintf(msg, size + 1, fmt, symbol);
316 failwith(msg);
317 }
318 return result;
319}
320
321static void *
322resolve_optional(const char *symbol)
323{
324 return find_symbol(library, symbol);
325}
326
327value
328pyml_wrap(PyObject *object, bool steal)
329{
330 CAMLparam0();
331 CAMLlocal1(v);
332 if (!object) {
333 CAMLreturn(Val_int(CODE_NULL));
334 }
335 if (object == Python__Py_NoneStruct) {
336 CAMLreturn(Val_int(CODE_NONE));
337 }
338 if (object == Python__Py_TrueStruct) {
339 CAMLreturn(Val_int(CODE_TRUE));
340 }
341 if (object == Python__Py_FalseStruct) {
342 CAMLreturn(Val_int(CODE_FALSE));
343 }
344 unsigned long flags =
345 ((struct _typeobject *) pyobjectdescr(pyobjectdescr(object)->ob_type))
346 ->tp_flags;
347 if (flags & Py_TPFLAGS_TUPLE_SUBCLASS
348 && Python_PySequence_Length(object) == 0) {
349 CAMLreturn(Val_int(CODE_TUPLE_EMPTY));
350 }
351 if (!steal) {
352 Py_INCREF(object);
353 }
354 v = caml_alloc_custom(&pyops, sizeof(PyObject *), 100, 30000000);
355 *((PyObject **)Data_custom_val(v)) = object;
356 CAMLreturn(v);
357}
358
359PyObject *
360pyml_unwrap(value v)
361{
362 if (Is_long(v))
363 switch (Int_val(v)) {
364 case CODE_NULL:
365 return NULL;
366 case CODE_NONE:
367 return Python__Py_NoneStruct;
368 case CODE_TRUE:
369 return Python__Py_TrueStruct;
370 case CODE_FALSE:
371 return Python__Py_FalseStruct;
372 case CODE_TUPLE_EMPTY:
373 return tuple_empty;
374 }
375
376 return *((PyObject **)Data_custom_val(v));
377}
378
379/*
380static value
381pyml_wrap_compilerflags(PyCompilerFlags *flags)
382{
383 CAMLparam0();
384 CAMLlocal2(ref, some);
385 if (!flags) {
386 CAMLreturn(Val_int(0));
387 }
388 else {
389 ref = caml_alloc(0, 1);
390 Store_field(ref, 0, Val_int(flags->cf_flags));
391 some = caml_alloc(0, 1);
392 Store_field(some, 0, ref);
393 CAMLreturn(some);
394 }
395}
396*/
397
398static PyCompilerFlags *
399pyml_unwrap_compilerflags(value v)
400{
401 CAMLparam1(v);
402 if (Is_block(v)) {
403 PyCompilerFlags *flags = malloc(sizeof(PyCompilerFlags));
404 flags->cf_flags = Int_val(Field(Field(v, 0), 0));
405 CAMLreturnT(PyCompilerFlags *, flags);
406 }
407 else {
408 CAMLreturnT(PyCompilerFlags *, NULL);
409 }
410}
411
412/*
413static value
414pyml_wrap_intref(int v)
415{
416 CAMLparam0();
417 CAMLlocal1(ref);
418 ref = caml_alloc(0, 1);
419 Store_field(ref, 0, Val_int(v));
420 CAMLreturn(ref);
421}
422*/
423
424static int
425pyml_unwrap_intref(value v)
426{
427 CAMLparam1(v);
428 CAMLreturnT(int, Int_val(Field(v, 0)));
429}
430
431static void *
432unwrap_capsule(PyObject *obj, const char *type)
433{
434 if (Python27_PyCapsule_GetPointer) {
435 return Python27_PyCapsule_GetPointer(obj, type);
436 }
437 else {
438 return Python2_PyCObject_AsVoidPtr(obj);
439 }
440}
441
442
443static PyObject *
444wrap_capsule(void *ptr, char *type, void (*destr)(PyObject *))
445{
446 if (Python27_PyCapsule_New) {
447 return Python27_PyCapsule_New(ptr, type, destr);
448 }
449 else {
450 return Python2_PyCObject_FromVoidPtr(ptr, (void(*)(void *))destr);
451 }
452}
453
454static PyObject *
455pycall_callback(PyObject *obj, PyObject *args)
456{
457 CAMLparam0();
458 CAMLlocal3(ml_out, ml_func, ml_args);
459 PyObject *out;
460 void *p = unwrap_capsule(obj, "ocaml-closure");
461 if (!p) {
462 Py_INCREF(Python__Py_NoneStruct);
463 return Python__Py_NoneStruct;
464 }
465 ml_func = *(value *) p;
466 ml_args = pyml_wrap(args, false);
467 ml_out = caml_callback(ml_func, ml_args);
468 out = pyml_unwrap(ml_out);
469 Py_XINCREF(out);
470 CAMLreturnT(PyObject *, out);
471}
472
473static PyObject *
474pycall_callback_with_keywords(PyObject *obj, PyObject *args, PyObject *keywords)
475{
476 CAMLparam0();
477 CAMLlocal4(ml_out, ml_func, ml_args, ml_keywords);
478 PyObject *out;
479 void *p = unwrap_capsule(obj, "ocaml-closure");
480 if (!p) {
481 Py_INCREF(Python__Py_NoneStruct);
482 return Python__Py_NoneStruct;
483 }
484 ml_func = *(value *) p;
485 ml_args = pyml_wrap(args, false);
486 ml_keywords = pyml_wrap(keywords, false);
487 ml_out = caml_callback2(ml_func, ml_args, ml_keywords);
488 out = pyml_unwrap(ml_out);
489 Py_XINCREF(out);
490 CAMLreturnT(PyObject *, out);
491}
492
493static void
494caml_destructor(PyObject *v, const char *capsule_name)
495{
496 value *valptr = (value *) unwrap_capsule(v, capsule_name);
497 caml_remove_global_root(valptr);
498 free(valptr);
499}
500
501static void
502camldestr_closure(PyObject *v)
503{
504 caml_destructor(v, "ocaml-closure");
505}
506
507static PyObject *
508camlwrap_closure(value val, void *aux_str, int size)
509{
510 value *v = (value *) malloc(sizeof(value) + size);
511 *v = val;
512 memcpy((void *)v + sizeof(value), aux_str, size);
513 caml_register_global_root(v);
514 return wrap_capsule(v, "ocaml-closure", camldestr_closure);
515}
516
517static void
518camldestr_capsule(PyObject *v)
519{
520 caml_destructor(v, "ocaml-capsule");
521}
522
523static PyObject *
524camlwrap_capsule(value val, void *aux_str, int size)
525{
526 value *v = (value *) malloc(sizeof(value) + size);
527 *v = val;
528 memcpy((void *)v + sizeof(value), aux_str, size);
529 caml_register_global_root(v);
530 return wrap_capsule(v, "ocaml-capsule", camldestr_capsule);
531}
532
533static void *
534caml_aux(PyObject *obj)
535{
536 value *v = (value *) unwrap_capsule(obj, "ocaml-closure");
537 return (void *) v + sizeof(value);
538}
539
540void
541pyml_assert_initialized()
542{
543 if (!version_major) {
544 failwith("Run 'Py.initialize ()' first");
545 }
546}
547
548void
549pyml_assert_python2()
550{
551 if (version_major != 2) {
552 pyml_assert_initialized();
553 failwith("Python 2 needed");
554 }
555}
556
557void
558pyml_assert_ucs2()
559{
560 if (ucs != UCS2) {
561 pyml_assert_initialized();
562 failwith("Python with UCS2 needed");
563 }
564}
565
566void
567pyml_assert_ucs4()
568{
569 if (ucs != UCS4) {
570 pyml_assert_initialized();
571 failwith("Python with UCS4 needed");
572 }
573}
574
575void
576pyml_assert_python3()
577{
578 if (version_major != 3) {
579 pyml_assert_initialized();
580 failwith("Python 3 needed");
581 }
582}
583
584void
585pyml_check_symbol_available(void *symbol, char *symbol_name)
586{
587 if (!symbol) {
588 char *fmt = "Symbol unavailable with this version of Python: %s.\n";
589 ssize_t size = snprintf(NULL, 0, fmt, symbol_name);
590 if (size < 0) {
591 failwith("Symbol unavailable with this version of Python.\n");
592 return;
593 }
594 char *msg = xmalloc(size + 1);
595 size = snprintf(msg, size + 1, fmt, symbol_name);
596 if (size < 0) {
597 failwith("Symbol unavailable with this version of Python.\n");
598 return;
599 }
600 failwith(msg);
601 }
602}
603
604void *
605deref_not_null(void *pointer)
606{
607 if (pointer) {
608 return *(void **) pointer;
609 }
610 else {
611 return NULL;
612 }
613}
614
615CAMLprim value
616pyml_wrap_closure(value docstring, value closure)
617{
618 CAMLparam2(docstring, closure);
619 pyml_assert_initialized();
620 PyMethodDef ml;
621 PyObject *obj;
622 PyMethodDef *ml_def;
623 ml.ml_name = "anonymous_closure";
624 if (Tag_val(closure) == 0) {
625 ml.ml_flags = 1;
626 ml.ml_meth = pycall_callback;
627 }
628 else {
629 ml.ml_flags = 3;
630 ml.ml_meth = (PyCFunction) pycall_callback_with_keywords;
631 }
632 ml.ml_doc = String_val(docstring);
633 obj = camlwrap_closure(Field(closure, 0), &ml, sizeof(ml));
634 ml_def = (PyMethodDef *) caml_aux(obj);
635 PyObject *f = Python_PyCFunction_NewEx(ml_def, obj, NULL);
636 CAMLreturn(pyml_wrap(f, true));
637}
638
639int debug_build;
640
641CAMLprim value
642py_load_library(value filename_ocaml, value debug_build_ocaml)
643{
644 CAMLparam2(filename_ocaml, debug_build_ocaml);
645 if (Is_block(filename_ocaml)) {
646 char *filename = String_val(Field(filename_ocaml, 0));
647 library = open_library(filename);
648 if (!library) {
649 failwith("Library not found");
650 }
651 }
652 else {
653 library = get_default_library();
654 }
655 Python_Py_GetVersion = find_symbol(library, "Py_GetVersion");
656 if (!Python_Py_GetVersion) {
657 failwith("No Python symbol");
658 }
659 const char *version = Python_Py_GetVersion();
660 version_major = version[0] - '0';
661 version_minor = version[2] - '0';
662 Python_PyCFunction_NewEx = resolve("PyCFunction_NewEx");
663 if ((version_major == 2 && version_minor >= 7) || version_major >= 3) {
664 Python27_PyCapsule_New = resolve("PyCapsule_New");
665 Python27_PyCapsule_GetPointer = resolve("PyCapsule_GetPointer");
666 Python27_PyCapsule_IsValid = resolve("PyCapsule_IsValid");
667 Python27__PyObject_NextNotImplemented =
668 resolve("_PyObject_NextNotImplemented");
669 }
670 Python_PyObject_CallFunctionObjArgs =
671 resolve("PyObject_CallFunctionObjArgs");
672 Python_PyObject_CallMethodObjArgs =
673 resolve("PyObject_CallMethodObjArgs");
674 Python_PyErr_Fetch = resolve("PyErr_Fetch");
675 Python_PyErr_NormalizeException = resolve("PyErr_NormalizeException");
676 Python_PyObject_AsCharBuffer = resolve("PyObject_AsCharBuffer");
677 Python_PyObject_AsReadBuffer = resolve("PyObject_AsReadBuffer");
678 Python_PyObject_AsWriteBuffer = resolve("PyObject_AsWriteBuffer");
679 if (version_major >= 3) {
680 Python__Py_FalseStruct = resolve("_Py_FalseStruct");
681 Python_PyString_AsStringAndSize = resolve("PyBytes_AsStringAndSize");
682 }
683 else {
684 Python__Py_FalseStruct = resolve("_Py_ZeroStruct");
685 Python_PyString_AsStringAndSize = resolve("PyString_AsStringAndSize");
686 }
687 Python_PyLong_FromString = resolve("PyLong_FromString");
688 Python_PyMem_Free = resolve("PyMem_Free");
689 if (version_major >= 3) {
690 Python__Py_fopen = resolve("_Py_fopen");
691 }
692 else {
693 Python2_PyCObject_FromVoidPtr = resolve("PyCObject_FromVoidPtr");
694 Python2_PyCObject_AsVoidPtr = resolve("PyCObject_AsVoidPtr");
695 }
696 if (find_symbol(library, "PyUnicodeUCS2_AsEncodedString")) {
697 ucs = UCS2;
698 }
699 else if (find_symbol(library, "PyUnicodeUCS4_AsEncodedString")) {
700 ucs = UCS4;
701 }
702 else {
703 ucs = UCS_NONE;
704 }
705#include "pyml_dlsyms.inc"
706 Python_Py_Initialize();
707 if (Is_block(debug_build_ocaml)) {
708 debug_build = Int_val(Field(debug_build_ocaml, 0));
709 }
710 else {
711 PyObject *sysconfig = Python_PyImport_ImportModule("sysconfig");
712 PyObject *get_config_var =
713 Python_PyObject_GetAttrString(sysconfig, "get_config_var");
714 PyObject *args;
715 PyObject *py_debug;
716 PyObject *debug_build_py;
717 char *py_debug_str = "Py_DEBUG";
718 if (version_major >= 3) {
719 py_debug = Python3_PyUnicode_FromStringAndSize(py_debug_str, 8);
720 }
721 else {
722 py_debug = Python2_PyString_FromStringAndSize(py_debug_str, 8);
723 }
724 if (!py_debug) {
725 failwith("py_debug");
726 }
727 args = Python_PyTuple_New(1);
728 if (!args) {
729 failwith("PyTuple_New");
730 }
731 if (Python_PyTuple_SetItem(args, 0, py_debug)) {
732 failwith("PyTuple_SetItem");
733 }
734 debug_build_py =
735 Python_PyEval_CallObjectWithKeywords(get_config_var, args, NULL);
736 if (!debug_build_py) {
737 failwith("PyEval_CallObjectWithKeywords");
738 }
739 if (version_major >= 3) {
740 debug_build = Python_PyLong_AsLong(debug_build_py);
741 }
742 else {
743 debug_build = Python2_PyInt_AsLong(debug_build_py);
744 }
745 if (debug_build == -1) {
746 failwith("AsLong");
747 }
748 }
749 tuple_empty = Python_PyTuple_New(0);
750 CAMLreturn(Val_unit);
751}
752
753struct PyObjectDebug {
754 PyObject *_ob_next; \
755 PyObject *_ob_prev;
756 PyObjectDescr descr;
757};
758
759PyObjectDescr *pyobjectdescr(PyObject *obj) {
760 if (debug_build) {
761 return &((struct PyObjectDebug *) obj)->descr;
762 }
763 else {
764 return (PyObjectDescr *) obj;
765 }
766}
767
768CAMLprim value
769py_is_debug_build()
770{
771 CAMLparam0();
772 CAMLreturn(Val_int(debug_build));
773}
774
775CAMLprim value
776py_finalize_library(value unit)
777{
778 CAMLparam1(unit);
779 pyml_assert_initialized();
780 Py_DECREF(tuple_empty);
781 if (library != get_default_library()) {
782 close_library(library);
783 }
784 version_major = 0;
785 ucs = UCS_NONE;
786 CAMLreturn(Val_unit);
787}
788
789CAMLprim value
790py_unsetenv(value name_ocaml)
791{
792 CAMLparam1(name_ocaml);
793 char *name = String_val(name_ocaml);
794 if (unsetenv(name) == -1) {
795 failwith(strerror(errno));
796 }
797 CAMLreturn(Val_unit);
798}
799
800CAMLprim value
801py_get_UCS(value unit)
802{
803 CAMLparam1(unit);
804 pyml_assert_initialized();
805 CAMLreturn(Val_int(ucs));
806}
807
808CAMLprim value
809PyNull_wrapper(value unit)
810{
811 CAMLparam1(unit);
812 CAMLreturn(Val_int(CODE_NULL));
813}
814
815CAMLprim value
816PyNone_wrapper(value unit)
817{
818 CAMLparam1(unit);
819 CAMLreturn(Val_int(CODE_NONE));
820}
821
822CAMLprim value
823PyTrue_wrapper(value unit)
824{
825 CAMLparam1(unit);
826 CAMLreturn(Val_int(CODE_TRUE));
827}
828
829CAMLprim value
830PyFalse_wrapper(value unit)
831{
832 CAMLparam1(unit);
833 CAMLreturn(Val_int(CODE_FALSE));
834}
835
836CAMLprim value
837PyTuple_Empty_wrapper(value unit)
838{
839 CAMLparam1(unit);
840 CAMLreturn(Val_int(CODE_TUPLE_EMPTY));
841}
842
843enum pytype_labels {
844 PyUnknown,
845 Bool,
846 Bytes,
847 Callable,
848 Capsule,
849 Closure,
850 Dict,
851 Float,
852 List,
853 Int,
854 Long,
855 Module,
856 NoneType,
857 Null,
858 Tuple,
859 Type,
860 Unicode,
861 Iter
862};
863
864CAMLprim value
865pytype(value object_ocaml)
866{
867 CAMLparam1(object_ocaml);
868 pyml_assert_initialized();
869 PyObject *object = pyml_unwrap(object_ocaml);
870 if (!object) {
871 CAMLreturn(Val_int(Null));
872 }
873 PyObject *ob_type = pyobjectdescr(object)->ob_type;
874 struct _typeobject *typeobj = (struct _typeobject *) pyobjectdescr(ob_type);
875 unsigned long flags = typeobj->tp_flags;
876 int result;
877 if (ob_type == Python_PyBool_Type) {
878 result = Bool;
879 }
880 else if (flags & Py_TPFLAGS_BYTES_SUBCLASS) {
881 result = Bytes;
882 }
883 else if (Python_PyCallable_Check(object)) {
884 result = Callable;
885 }
886 else if (Python27_PyCapsule_IsValid
887 && Python27_PyCapsule_IsValid(object, "ocaml-capsule")) {
888 result = Capsule;
889 }
890 else if (Python27_PyCapsule_IsValid
891 && Python27_PyCapsule_IsValid(object, "ocaml-closure")) {
892 result = Closure;
893 }
894 else if (flags & Py_TPFLAGS_DICT_SUBCLASS) {
895 result = Dict;
896 }
897 else if (ob_type == Python_PyFloat_Type ||
898 Python_PyType_IsSubtype(ob_type, Python_PyFloat_Type)) {
899 result = Float;
900 }
901 else if (flags & Py_TPFLAGS_LIST_SUBCLASS) {
902 result = List;
903 }
904 else if (flags & Py_TPFLAGS_INT_SUBCLASS) {
905 result = Int;
906 }
907 else if (flags & Py_TPFLAGS_LONG_SUBCLASS) {
908 result = Long;
909 }
910 else if (ob_type == Python_PyModule_Type ||
911 Python_PyType_IsSubtype(ob_type, Python_PyModule_Type)) {
912 result = Module;
913 }
914 else if (object == Python__Py_NoneStruct) {
915 result = NoneType;
916 }
917 else if (flags & Py_TPFLAGS_TUPLE_SUBCLASS) {
918 result = Tuple;
919 }
920 else if (flags & Py_TPFLAGS_TYPE_SUBCLASS) {
921 result = Type;
922 }
923 else if (flags & Py_TPFLAGS_UNICODE_SUBCLASS) {
924 result = Unicode;
925 }
926 else if (typeobj->tp_iternext != NULL &&
927 typeobj->tp_iternext != &Python27__PyObject_NextNotImplemented) {
928 result = Iter;
929 }
930 else {
931 result = PyUnknown;
932 }
933 CAMLreturn(Val_int(result));
934}
935
936CAMLprim value
937PyObject_CallFunctionObjArgs_wrapper(
938 value callable_ocaml, value arguments_ocaml)
939{
940 CAMLparam2(callable_ocaml, arguments_ocaml);
941 pyml_assert_initialized();
942 PyObject *callable = pyml_unwrap(callable_ocaml);
943 PyObject *result;
944 mlsize_t argument_count = Wosize_val(arguments_ocaml);
945 switch (argument_count) {
946 case 0:
947 result = Python_PyObject_CallFunctionObjArgs(callable, NULL);
948 break;
949 case 1:
950 result = Python_PyObject_CallFunctionObjArgs
951 (callable,
952 pyml_unwrap(Field(arguments_ocaml, 0)),
953 NULL);
954 break;
955 case 2:
956 result = Python_PyObject_CallFunctionObjArgs
957 (callable,
958 pyml_unwrap(Field(arguments_ocaml, 0)),
959 pyml_unwrap(Field(arguments_ocaml, 1)),
960 NULL);
961 break;
962 case 3:
963 result = Python_PyObject_CallFunctionObjArgs
964 (callable,
965 pyml_unwrap(Field(arguments_ocaml, 0)),
966 pyml_unwrap(Field(arguments_ocaml, 1)),
967 pyml_unwrap(Field(arguments_ocaml, 2)),
968 NULL);
969 break;
970 case 4:
971 result = Python_PyObject_CallFunctionObjArgs
972 (callable,
973 pyml_unwrap(Field(arguments_ocaml, 0)),
974 pyml_unwrap(Field(arguments_ocaml, 1)),
975 pyml_unwrap(Field(arguments_ocaml, 2)),
976 pyml_unwrap(Field(arguments_ocaml, 3)),
977 NULL);
978 break;
979 case 5:
980 result = Python_PyObject_CallFunctionObjArgs
981 (callable,
982 pyml_unwrap(Field(arguments_ocaml, 0)),
983 pyml_unwrap(Field(arguments_ocaml, 1)),
984 pyml_unwrap(Field(arguments_ocaml, 2)),
985 pyml_unwrap(Field(arguments_ocaml, 3)),
986 pyml_unwrap(Field(arguments_ocaml, 4)),
987 NULL);
988 break;
989 default:
990 fprintf(stderr,
991 "PyObject_CallFunctionObjArgs_wrapper not implemented for more "
992 "than 5 arguments\n");
993 exit(EXIT_FAILURE);
994 }
995
996 CAMLreturn(pyml_wrap(result, true));
997}
998
999CAMLprim value
1000PyObject_CallMethodObjArgs_wrapper(
1001 value object_ocaml, value name_ocaml, value arguments_ocaml)
1002{
1003 CAMLparam3(object_ocaml, name_ocaml, arguments_ocaml);
1004 pyml_assert_initialized();
1005 PyObject *object = pyml_unwrap(object_ocaml);
1006 PyObject *name = pyml_unwrap(name_ocaml);
1007 PyObject *result;
1008 mlsize_t argument_count = Wosize_val(arguments_ocaml);
1009 switch (argument_count) {
1010 case 0:
1011 result = Python_PyObject_CallMethodObjArgs(object, name);
1012 break;
1013 case 1:
1014 result = Python_PyObject_CallMethodObjArgs
1015 (object, name,
1016 pyml_unwrap(Field(arguments_ocaml, 0)),
1017 NULL);
1018 break;
1019 case 2:
1020 result = Python_PyObject_CallMethodObjArgs
1021 (object, name,
1022 pyml_unwrap(Field(arguments_ocaml, 0)),
1023 pyml_unwrap(Field(arguments_ocaml, 1)),
1024 NULL);
1025 break;
1026 case 3:
1027 result = Python_PyObject_CallMethodObjArgs
1028 (object, name,
1029 pyml_unwrap(Field(arguments_ocaml, 0)),
1030 pyml_unwrap(Field(arguments_ocaml, 1)),
1031 pyml_unwrap(Field(arguments_ocaml, 2)),
1032 NULL);
1033 break;
1034 case 4:
1035 result = Python_PyObject_CallMethodObjArgs
1036 (object, name,
1037 pyml_unwrap(Field(arguments_ocaml, 0)),
1038 pyml_unwrap(Field(arguments_ocaml, 1)),
1039 pyml_unwrap(Field(arguments_ocaml, 2)),
1040 pyml_unwrap(Field(arguments_ocaml, 3)),
1041 NULL);
1042 break;
1043 case 5:
1044 result = Python_PyObject_CallMethodObjArgs
1045 (object, name,
1046 pyml_unwrap(Field(arguments_ocaml, 0)),
1047 pyml_unwrap(Field(arguments_ocaml, 1)),
1048 pyml_unwrap(Field(arguments_ocaml, 2)),
1049 pyml_unwrap(Field(arguments_ocaml, 3)),
1050 pyml_unwrap(Field(arguments_ocaml, 4)),
1051 NULL);
1052 break;
1053 default:
1054 fprintf(stderr,
1055 "PyObject_CallMethodObjArgs_wrapper not implemented for more "
1056 "than 5 arguments\n");
1057 exit(EXIT_FAILURE);
1058 }
1059
1060 CAMLreturn(pyml_wrap(result, true));
1061}
1062
1063CAMLprim value
1064pyml_wrap_value(value v)
1065{
1066 CAMLparam1(v);
1067 pyml_assert_initialized();
1068 PyObject *result = camlwrap_capsule(v, NULL, 0);
1069 CAMLreturn(pyml_wrap(result, true));
1070}
1071
1072CAMLprim value
1073pyml_unwrap_value(value x_ocaml)
1074{
1075 CAMLparam1(x_ocaml);
1076 CAMLlocal1(v);
1077 pyml_assert_initialized();
1078 PyObject *x = pyml_unwrap(x_ocaml);
1079 void *p = unwrap_capsule(x, "ocaml-capsule");
1080 if (!p) {
1081 fprintf(stderr, "pyml_unwrap_value: type mismatch");
1082 exit(EXIT_FAILURE);
1083 }
1084 v = *(value *) p;
1085 CAMLreturn(v);
1086}
1087
1088CAMLprim value
1089PyErr_Fetch_wrapper(value unit)
1090{
1091 CAMLparam1(unit);
1092 CAMLlocal1(result);
1093 pyml_assert_initialized();
1094 PyObject *excType, *excValue, *excTraceback;
1095 Python_PyErr_Fetch(&excType, &excValue, &excTraceback);
1096 Python_PyErr_NormalizeException(&excType, &excValue, &excTraceback);
1097 result = caml_alloc_tuple(3);
1098 Store_field(result, 0, pyml_wrap(excType, false));
1099 Store_field(result, 1, pyml_wrap(excValue, false));
1100 Store_field(result, 2, pyml_wrap(excTraceback, false));
1101 CAMLreturn(result);
1102}
1103
1104CAMLprim value
1105pyml_wrap_string_option(char *s)
1106{
1107 CAMLparam0();
1108 CAMLlocal1(result);
1109 if (!s) {
1110 CAMLreturn(Val_int(0));
1111 }
1112 result = caml_alloc_tuple(1);
1113 Store_field(result, 0, caml_copy_string(s));
1114 CAMLreturn(result);
1115}
1116
1117CAMLprim value
1118pyrefcount(value pyobj)
1119{
1120 CAMLparam1(pyobj);
1121 PyObject *obj = pyml_unwrap(pyobj);
1122 CAMLreturn(Val_int(pyobjectdescr(obj)->ob_refcnt));
1123}
1124
1125static value
1126pyml_wrap_wide_string(wchar_t *ws)
1127{
1128 CAMLparam0();
1129 CAMLlocal1(result);
1130 size_t n = wcstombs(NULL, ws, 0);
1131 if (n == (size_t) -1) {
1132 fprintf(stderr, "pyml_wrap_wide_string failure.\n");
1133 exit(EXIT_FAILURE);
1134 }
1135 char *s = xmalloc((n + 1) * sizeof (char));
1136 wcstombs(s, ws, n);
1137 result = caml_copy_string(s);
1138 free(s);
1139 CAMLreturn(result);
1140}
1141
1142static wchar_t *
1143pyml_unwrap_wide_string(value string_ocaml)
1144{
1145 CAMLparam1(string_ocaml);
1146 char *s = String_val(string_ocaml);
1147 size_t n = mbstowcs(NULL, s, 0);
1148 if (n == (size_t) -1) {
1149 fprintf(stderr, "pyml_unwrap_wide_string failure.\n");
1150 exit(EXIT_FAILURE);
1151 }
1152 wchar_t *ws = xmalloc((n + 1) * sizeof (wchar_t));
1153 mbstowcs(ws, s, n);
1154 CAMLreturnT(wchar_t *, ws);
1155}
1156
1157static int16_t *
1158pyml_unwrap_ucs2(value array_ocaml)
1159{
1160 CAMLparam1(array_ocaml);
1161 mlsize_t len = Wosize_val(array_ocaml);
1162 int16_t *result = xmalloc(len * sizeof(int16_t));
1163 size_t i;
1164 for (i = 0; i < len; i++) {
1165 result[i] = Field(array_ocaml, i);
1166 }
1167 CAMLreturnT(int16_t *, result);
1168}
1169
1170static int32_t *
1171pyml_unwrap_ucs4(value array_ocaml)
1172{
1173 CAMLparam1(array_ocaml);
1174 mlsize_t len = Wosize_val(array_ocaml);
1175 int32_t *result = xmalloc(len * sizeof(int32_t));
1176 size_t i;
1177 for (i = 0; i < len; i++) {
1178 result[i] = Field(array_ocaml, i);
1179 }
1180 CAMLreturnT(int32_t *, result);
1181}
1182
1183static value
1184pyml_wrap_ucs2_option(int16_t *buffer)
1185{
1186 CAMLparam0();
1187 CAMLlocal2(result, array);
1188 mlsize_t len;
1189 if (buffer == NULL) {
1190 CAMLreturn(Val_int(0));
1191 }
1192 len = 0;
1193 while (buffer[len]) {
1194 len++;
1195 }
1196 array = caml_alloc_tuple(len);
1197 size_t i;
1198 for (i = 0; i < len; i++) {
1199 Store_field(array, i, buffer[i]);
1200 }
1201 result = caml_alloc_tuple(1);
1202 Store_field(result, 0, array);
1203 CAMLreturn(result);
1204}
1205
1206static value
1207pyml_wrap_ucs4_option_and_free(int32_t *buffer, bool free)
1208{
1209 CAMLparam0();
1210 CAMLlocal2(result, array);
1211 mlsize_t len;
1212 if (buffer == NULL) {
1213 CAMLreturn(Val_int(0));
1214 }
1215 len = 0;
1216 while (buffer[len]) {
1217 len++;
1218 }
1219 array = caml_alloc_tuple(len);
1220 size_t i;
1221 for (i = 0; i < len; i++) {
1222 Store_field(array, i, buffer[i]);
1223 }
1224 result = caml_alloc_tuple(1);
1225 Store_field(result, 0, array);
1226 if (free) {
1227 Python_PyMem_Free(buffer);
1228 }
1229 CAMLreturn(result);
1230}
1231
1232#define StringAndSize_wrapper(func, byte_type) \
1233 CAMLprim value \
1234 func##_wrapper(value arg_ocaml) \
1235 { \
1236 CAMLparam1(arg_ocaml); \
1237 CAMLlocal2(result, string); \
1238 PyObject *arg = pyml_unwrap(arg_ocaml); \
1239 byte_type *buffer; \
1240 Py_ssize_t length; \
1241 int return_value; \
1242 return_value = Python_##func(arg, &buffer, &length); \
1243 if (return_value == -1) { \
1244 CAMLreturn(Val_int(0)); \
1245 } \
1246 string = caml_alloc_string(length); \
1247 memcpy(String_val(string), buffer, length); \
1248 result = caml_alloc_tuple(1); \
1249 Store_field(result, 0, string); \
1250 CAMLreturn(result); \
1251 }
1252
1253StringAndSize_wrapper(PyString_AsStringAndSize, char);
1254StringAndSize_wrapper(PyObject_AsCharBuffer, const char);
1255StringAndSize_wrapper(PyObject_AsReadBuffer, const void);
1256StringAndSize_wrapper(PyObject_AsWriteBuffer, void);
1257
1258static FILE *
1259open_file(value file, const char *mode)
1260{
1261 CAMLparam1(file);
1262 FILE *result;
1263 if (Tag_val(file) == 0) {
1264 char *filename = String_val(Field(file, 0));
1265 if (version_major >= 3) {
1266 result = Python__Py_fopen(filename, mode);
1267 }
1268 else {
1269 result = fopen(filename, mode);
1270 }
1271 }
1272 else {
1273 result = file_of_file_descr(Field(file, 0), mode);
1274 }
1275 CAMLreturnT(FILE *, result);
1276}
1277
1278static void
1279close_file(value file, FILE *file_struct)
1280{
1281 CAMLparam1(file);
1282 if (Tag_val(file) == 0) {
1283 if (version_major >= 3) {
1284 /* No _Py_fclose :( */
1285 }
1286 else {
1287 fclose(file_struct);
1288 }
1289 }
1290 else if (Tag_val(file) == 1) {
1291 fclose(file_struct);
1292 }
1293 CAMLreturn0;
1294}
1295
1296/* Numpy */
1297
1298void **
1299pyml_get_pyarray_api(PyObject *c_api)
1300{
1301 if (version_major >= 3) {
1302 return (void **)Python27_PyCapsule_GetPointer(c_api, NULL);
1303 }
1304 else {
1305 return (void **)Python2_PyCObject_AsVoidPtr(c_api);
1306 }
1307}
1308
1309CAMLprim value
1310get_pyarray_type(value numpy_api_ocaml)
1311{
1312 CAMLparam1(numpy_api_ocaml);
1313 PyObject *c_api = pyml_unwrap(numpy_api_ocaml);
1314 void **PyArray_API = pyml_get_pyarray_api(c_api);
1315 PyObject *result = PyArray_API[2];
1316 CAMLreturn(pyml_wrap(result, true));
1317}
1318
1319CAMLprim value
1320pyarray_of_floatarray_wrapper(
1321 value numpy_api_ocaml, value array_type_ocaml, value array_ocaml)
1322{
1323 CAMLparam3(numpy_api_ocaml, array_type_ocaml, array_ocaml);
1324 pyml_assert_initialized();
1325 PyObject *c_api = pyml_unwrap(numpy_api_ocaml);
1326 void **PyArray_API = pyml_get_pyarray_api(c_api);
1327 PyObject *(*PyArray_New)
1328 (PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int,
1329 PyObject *) = PyArray_API[93];
1330 npy_intp length = Wosize_val(array_ocaml);
1331 void *data = (double *) array_ocaml;
1332 PyTypeObject (*PyArray_SubType) =
1333 (PyTypeObject *) pyml_unwrap(array_type_ocaml);
1334 PyObject *result = PyArray_New(
1335 PyArray_SubType, 1, &length, NPY_DOUBLE, NULL, data, 0,
1336 NPY_ARRAY_CARRAY, NULL);
1337 CAMLreturn(pyml_wrap(result, true));
1338}
1339
1340CAMLprim value
1341PyLong_FromString_wrapper(value str_ocaml, value base_ocaml)
1342{
1343 CAMLparam2(str_ocaml, base_ocaml);
1344 CAMLlocal1(result);
1345 pyml_assert_initialized();
1346 char *str = String_val(str_ocaml);
1347 char *pend;
1348 int base = Int_val(base_ocaml);
1349 PyObject *l = Python_PyLong_FromString(str, &pend, base);
1350 ssize_t len = pend - str;
1351 result = caml_alloc_tuple(2);
1352 Store_field(result, 0, pyml_wrap(l, true));
1353 Store_field(result, 1, Val_int(len));
1354 CAMLreturn(result);
1355}
1356
1357CAMLprim value
1358Python27_PyCapsule_IsValid_wrapper(value arg0_ocaml, value arg1_ocaml)
1359{
1360 CAMLparam2(arg0_ocaml, arg1_ocaml);
1361
1362 pyml_assert_initialized();
1363 if (!Python27_PyCapsule_IsValid) {
1364 failwith("PyCapsule_IsValid is only available in Python >2.7");
1365 }
1366 PyObject *arg0 = pyml_unwrap(arg0_ocaml);
1367 char *arg1 = String_val(arg1_ocaml);
1368 int result = Python27_PyCapsule_IsValid(arg0, arg1);
1369 CAMLreturn(Val_int(result));
1370}
1371
1372#include "pyml_wrappers.inc"