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