X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=perl_c.c;h=ce5366722ee07171212957e3e9accb4e28abdebe;hb=36b9a44ab49471646b7a3548d1e2d28c015063ad;hp=29c9776c7c9184b92dbebe0ca3ff0054c2abe32c;hpb=432e85196383810d7f6d4e695c758a8d17b96f2b;p=perl4caml.git diff --git a/perl_c.c b/perl_c.c index 29c9776..ce53667 100644 --- a/perl_c.c +++ b/perl_c.c @@ -1,6 +1,22 @@ /* Interface to Perl from OCaml. - * Copyright (C) 2003 Merjis Ltd. - * $Id: perl_c.c,v 1.10 2003-10-26 12:10:23 rich Exp $ + Copyright (C) 2003 Merjis Ltd. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + $Id: perl_c.c,v 1.25 2008-03-01 13:02:21 rich Exp $ */ #include @@ -9,57 +25,58 @@ #include #include +#define CAML_NAME_SPACE 1 + #include #include +#include #include #include #include -/* XXX This was required to avoid an error on my machine when loading the Perl - * headers. Not clear why this is missing. - */ -#define off64_t __off64_t - #include #include /* Perl requires the interpreter to be called literally 'my_perl'! */ static PerlInterpreter *my_perl; -/* Wrap up an arbitrary void pointer in an opaque OCaml object. */ -static value Val_voidptr (void *ptr); - /* Get the concrete value from an optional field. */ static value unoption (value option, value deflt); +/* Wrap up an arbitrary void pointer in an opaque OCaml object. */ +static value Val_voidptr (void *ptr); + /* Unwrap an arbitrary void pointer from an opaque OCaml object. */ #define Voidptr_val(type,rv) ((type *) Field ((rv), 0)) +#if PERL4CAML_REFCOUNTING_EXPERIMENTAL + +/* Unwrap a custom block. */ +#define Xv_val(rv) (*((void **)Data_custom_val(rv))) + +/* Wrap up an SV, AV or HV in a custom OCaml object which will decrement + * the reference count on finalization. + */ +static value Val_xv (SV *sv); + +#else + +#define Xv_val(rv) Voidptr_val (SV, (rv)) +#define Val_xv(sv) Val_voidptr ((sv)) + +#endif + /* Hide Perl types in opaque OCaml objects. */ #define Val_perl(pl) (Val_voidptr ((pl))) #define Perl_val(plv) (Voidptr_val (PerlInterpreter, (plv))) -#define Val_sv(sv) (Val_voidptr ((sv))) -#define Sv_val(svv) (Voidptr_val (SV, (svv))) -#define Val_av(av) (Val_voidptr ((av))) -#define Av_val(avv) (Voidptr_val (AV, (avv))) -#define Val_hv(hv) (Val_voidptr ((hv))) -#define Hv_val(hvv) (Voidptr_val (HV, (hvv))) - -CAMLprim value -perl4caml_init (value unit) -{ - CAMLparam1 (unit); - PERL_SYS_INIT3 (NULL, NULL, NULL); - CAMLreturn (Val_unit); -} - -CAMLprim value -perl4caml_current_interpreter (value unit) -{ - CAMLparam1 (unit); - if (my_perl == 0) raise_not_found (); - CAMLreturn (Val_perl (my_perl)); -} +#define Val_sv(sv) (Val_xv ((sv))) +#define Sv_val(svv) ((SV *) Xv_val (svv)) +#define Val_av(av) (Val_xv ((SV *)(av))) +#define Av_val(avv) ((AV *) Xv_val (avv)) +#define Val_hv(hv) (Val_xv ((SV *)(hv))) +#define Hv_val(hvv) ((HV *) Xv_val (hvv)) +#define Val_he(he) (Val_voidptr ((he))) +#define He_val(hev) (Voidptr_val (HE, (hev))) static void xs_init (pTHX) @@ -71,61 +88,19 @@ xs_init (pTHX) } CAMLprim value -perl4caml_create (value optargs, value unit) +perl4caml_init (value unit) { - CAMLparam2 (optargs, unit); - CAMLlocal1 (args); - int argc, i; - char **argv; - static char *no_args[] = { "", "-w", "-e", "0" }; - - /* Arguments given? */ - if (optargs == Val_int (0)) /* "None" */ - { - argc = 4; - argv = no_args; - } - else /* "Some args" where args is a string array. */ - { - args = Field (optargs, 0); - argc = Wosize_val (args); - argv = alloca (argc * sizeof (char *)); - for (i = 0; i < argc; ++i) argv[i] = String_val (Field (args, i)); - } + CAMLparam1 (unit); + int argc = 4; + static char *argv[] = { "", "-w", "-e", "0", NULL }; + PERL_SYS_INIT (&argc, &argv); my_perl = perl_alloc (); perl_construct (my_perl); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; - perl_parse (my_perl, xs_init, argc, argv, NULL); + perl_parse (my_perl, xs_init, argc, argv, (char **) NULL); /*perl_run (my_perl);*/ - CAMLreturn (Val_perl (my_perl)); -} - -CAMLprim value -perl4caml_destroy (value plv) -{ - CAMLparam1 (plv); - PerlInterpreter *pl = Perl_val (plv); - - perl_destruct (pl); - perl_free (pl); - - /* Current interpreter? */ - if (my_perl == pl) my_perl = 0; - - CAMLreturn (Val_unit); -} - -CAMLprim value -perl4caml_set_context (value plv) -{ - CAMLparam1 (plv); - PerlInterpreter *pl = Perl_val (plv); - - PERL_SET_CONTEXT (pl); - my_perl = pl; - CAMLreturn (Val_unit); } @@ -150,7 +125,7 @@ perl4caml_float_of_sv (value svv) CAMLparam1 (svv); SV *sv = Sv_val (svv); CAMLlocal1 (f); - f = copy_double (SvNV (sv)); + f = caml_copy_double (SvNV (sv)); CAMLreturn (f); } @@ -158,7 +133,7 @@ CAMLprim value perl4caml_sv_of_float (value fv) { CAMLparam1 (fv); - CAMLreturn (Val_sv (newSViv (Double_val (fv)))); + CAMLreturn (Val_sv (newSVnv (Double_val (fv)))); } CAMLprim value @@ -170,8 +145,8 @@ perl4caml_string_of_sv (value svv) STRLEN len; CAMLlocal1 (strv); str = SvPV (sv, len); - /* XXX This won't work if the string contains NUL. */ - strv = copy_string (str); + strv = caml_alloc_string (len); + memcpy (String_val (strv), str, len); CAMLreturn (strv); } @@ -179,7 +154,7 @@ CAMLprim value perl4caml_sv_of_string (value strv) { CAMLparam1 (strv); - CAMLreturn (Val_sv (newSVpv (String_val (strv), string_length (strv)))); + CAMLreturn (Val_sv (newSVpv (String_val (strv), caml_string_length (strv)))); } CAMLprim value @@ -191,18 +166,20 @@ perl4caml_sv_is_true (value svv) } CAMLprim value -perl4caml_sv_is_undef (value svv) +perl4caml_sv_undef (value unit) { - CAMLparam1 (svv); - SV *sv = Sv_val (svv); - CAMLreturn (SvLEN (sv) == 0 ? Val_true : Val_false); + CAMLparam1 (unit); + /*CAMLreturn (Val_sv (newSV (0)));*/ + CAMLreturn (Val_sv (&PL_sv_undef)); } CAMLprim value -perl4caml_sv_undef (value unit) +perl4caml_sv_is_undef (value svv) { - CAMLparam1 (unit); - CAMLreturn (Val_sv (newSV (0))); + CAMLparam1 (svv); + SV *sv = Sv_val (svv); + CAMLreturn (!SvPOK (sv) && !SvIOK (sv) && SvTYPE (sv) == SVt_NULL + ? Val_true : Val_false); } CAMLprim value @@ -219,25 +196,60 @@ perl4caml_sv_no (value unit) CAMLreturn (Val_sv (&PL_sv_no)); } +static int +sv_type (SV *sv) +{ +#if PERL_VERSION >= 11 + if (SvROK(sv)) return 4; +#endif + switch (SvTYPE (sv)) + { + case SVt_IV: return 1; + case SVt_NV: return 2; + case SVt_PV: return 3; +#if PERL_VERSION < 11 + case SVt_RV: return 4; +#endif + case SVt_PVAV: return 5; + case SVt_PVHV: return 6; + case SVt_PVCV: return 7; + case SVt_PVGV: return 8; + case SVt_PVMG: return 9; + default: return 0; + } +} + CAMLprim value perl4caml_sv_type (value svv) { CAMLparam1 (svv); SV *sv = Sv_val (svv); - switch (SvTYPE (sv)) - { - case SVt_IV: CAMLreturn (Val_int (1)); - case SVt_NV: CAMLreturn (Val_int (2)); - case SVt_PV: CAMLreturn (Val_int (3)); - case SVt_RV: CAMLreturn (Val_int (4)); - case SVt_PVAV: CAMLreturn (Val_int (5)); - case SVt_PVHV: CAMLreturn (Val_int (6)); - case SVt_PVCV: CAMLreturn (Val_int (7)); - case SVt_PVGV: CAMLreturn (Val_int (8)); - case SVt_PVMG: CAMLreturn (Val_int (9)); - default: CAMLreturn (Val_int (0)); - } + CAMLreturn (Val_int (sv_type (sv))); +} + +CAMLprim value +perl4caml_address_of_sv (value svv) +{ + CAMLparam1 (svv); + SV *sv = Sv_val (svv); + CAMLreturn (caml_copy_nativeint ((long) sv)); +} + +CAMLprim value +perl4caml_address_of_av (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + CAMLreturn (caml_copy_nativeint ((long) av)); +} + +CAMLprim value +perl4caml_address_of_hv (value hvv) +{ + CAMLparam1 (hvv); + HV *hv = Hv_val (hvv); + CAMLreturn (caml_copy_nativeint ((long) hv)); } CAMLprim value @@ -271,25 +283,44 @@ perl4caml_hashref (value hvv) } CAMLprim value +perl4caml_reftype (value svv) +{ + CAMLparam1 (svv); + SV *sv = Sv_val (svv); + + if (!SvROK (sv)) + caml_invalid_argument ("reftype: SV is not a reference"); + + CAMLreturn (Val_int (sv_type (SvRV (sv)))); +} + +CAMLprim value perl4caml_deref (value svv) { CAMLparam1 (svv); CAMLlocal1 (rsvv); SV *sv = Sv_val (svv); - if (SvTYPE (sv) != SVt_RV) - invalid_argument ("deref: SV is not a reference"); + if (!SvROK (sv)) + caml_invalid_argument ("deref: SV is not a reference"); switch (SvTYPE (SvRV (sv))) { case SVt_IV: case SVt_NV: case SVt_PV: +#if PERL_VERSION < 11 case SVt_RV: +#endif case SVt_PVMG: break; default: - invalid_argument ("deref: SV is not a reference to a scalar"); + caml_invalid_argument ("deref: SV is not a reference to a scalar"); } - rsvv = Val_sv (SvRV (sv)); + sv = SvRV (sv); + /* Increment the reference count because we're creating another + * value pointing at the referenced SV. + */ + sv = SvREFCNT_inc (sv); + rsvv = Val_sv (sv); CAMLreturn (rsvv); } @@ -300,15 +331,20 @@ perl4caml_deref_array (value svv) CAMLlocal1 (ravv); SV *sv = Sv_val (svv); - if (SvTYPE (sv) != SVt_RV) - invalid_argument ("deref_array: SV is not a reference"); + if (!SvROK (sv)) + caml_invalid_argument ("deref_array: SV is not a reference"); switch (SvTYPE (SvRV (sv))) { case SVt_PVAV: break; default: - invalid_argument ("deref_array: SV is not a reference to an array"); + caml_invalid_argument ("deref_array: SV is not a reference to an array"); } - ravv = Val_av ((AV *) SvRV (sv)); + sv = SvRV (sv); + /* Increment the reference count because we're creating another + * value pointing at the referenced AV. + */ + sv = SvREFCNT_inc (sv); + ravv = Val_av ((AV *) sv); CAMLreturn (ravv); } @@ -319,15 +355,20 @@ perl4caml_deref_hash (value svv) CAMLlocal1 (rhvv); SV *sv = Sv_val (svv); - if (SvTYPE (sv) != SVt_RV) - invalid_argument ("deref_array: SV is not a reference"); + if (!SvROK (sv)) + caml_invalid_argument ("deref_hash: SV is not a reference"); switch (SvTYPE (SvRV (sv))) { case SVt_PVHV: break; default: - invalid_argument ("deref_array: SV is not a reference to a hash"); + caml_invalid_argument ("deref_hash: SV is not a reference to a hash"); } - rhvv = Val_hv ((HV *) SvRV (sv)); + sv = SvRV (sv); + /* Increment the reference count because we're creating another + * value pointing at the referenced HV. + */ + sv = SvREFCNT_inc (sv); + rhvv = Val_hv ((HV *) sv); CAMLreturn (rhvv); } @@ -387,6 +428,10 @@ perl4caml_av_pop (value avv) CAMLparam1 (avv); AV *av = Av_val (avv); SV *sv = av_pop (av); + /* Increment the reference count because we're creating another + * value pointing at the referenced AV. + */ + sv = SvREFCNT_inc (sv); CAMLreturn (Val_sv (sv)); } @@ -409,6 +454,10 @@ perl4caml_av_shift (value avv) CAMLparam1 (avv); AV *av = Av_val (avv); SV *sv = av_shift (av); + /* Increment the reference count because we're creating another + * value pointing at the referenced AV. + */ + sv = SvREFCNT_inc (sv); CAMLreturn (Val_sv (sv)); } @@ -438,7 +487,11 @@ perl4caml_av_get (value avv, value i) CAMLparam2 (avv, i); AV *av = Av_val (avv); SV **svp = av_fetch (av, Int_val (i), 0); - if (svp == 0) invalid_argument ("av_get: index out of bounds"); + if (svp == 0) caml_invalid_argument ("av_get: index out of bounds"); + /* Increment the reference count because we're creating another + * value pointing at the referenced AV. + */ + *svp = SvREFCNT_inc (*svp); CAMLreturn (Val_sv (*svp)); } @@ -484,7 +537,7 @@ perl4caml_hv_set (value hvv, value key, value svv) HV *hv = Hv_val (hvv); SV *sv = Sv_val (svv); SvREFCNT_inc (sv); - if (hv_store (hv, String_val (key), string_length (key), sv, 0) == 0) + if (hv_store (hv, String_val (key), caml_string_length (key), sv, 0) == 0) SvREFCNT_dec (sv); CAMLreturn (Val_unit); } @@ -494,8 +547,12 @@ perl4caml_hv_get (value hvv, value key) { CAMLparam2 (hvv, key); HV *hv = Hv_val (hvv); - SV **svp = hv_fetch (hv, String_val (key), string_length (key), 0); - if (svp == 0) raise_not_found (); + SV **svp = hv_fetch (hv, String_val (key), caml_string_length (key), 0); + if (svp == 0) caml_raise_not_found (); + /* Increment the reference count because we're creating another + * value pointing at the referenced SV. + */ + SvREFCNT_inc (*svp); CAMLreturn (Val_sv (*svp)); } @@ -504,7 +561,7 @@ perl4caml_hv_exists (value hvv, value key) { CAMLparam2 (hvv, key); HV *hv = Hv_val (hvv); - bool r = hv_exists (hv, String_val (key), string_length (key)); + bool r = hv_exists (hv, String_val (key), caml_string_length (key)); CAMLreturn (r ? Val_true : Val_false); } @@ -513,7 +570,7 @@ perl4caml_hv_delete (value hvv, value key) { CAMLparam2 (hvv, key); HV *hv = Hv_val (hvv); - hv_delete (hv, String_val (key), string_length (key), G_DISCARD); + hv_delete (hv, String_val (key), caml_string_length (key), G_DISCARD); CAMLreturn (Val_unit); } @@ -536,6 +593,73 @@ perl4caml_hv_undef (value hvv) } CAMLprim value +perl4caml_hv_iterinit (value hvv) +{ + CAMLparam1 (hvv); + HV *hv = Hv_val (hvv); + int i = hv_iterinit (hv); + CAMLreturn (caml_copy_int32 (i)); +} + +CAMLprim value +perl4caml_hv_iternext (value hvv) +{ + CAMLparam1 (hvv); + CAMLlocal1 (hev); + HV *hv = Hv_val (hvv); + HE *he = hv_iternext (hv); + if (he == NULL) caml_raise_not_found (); + hev = Val_he (he); + CAMLreturn (hev); +} + +CAMLprim value +perl4caml_hv_iterkey (value hev) +{ + CAMLparam1 (hev); + CAMLlocal1 (strv); + HE *he = He_val (hev); + I32 len; + char *str = hv_iterkey (he, &len); + strv = caml_alloc_string (len); + memcpy (String_val (strv), str, len); + CAMLreturn (strv); +} + +CAMLprim value +perl4caml_hv_iterval (value hvv, value hev) +{ + CAMLparam2 (hvv, hev); + CAMLlocal1 (svv); + HV *hv = Hv_val (hvv); + HE *he = He_val (hev); + SV *sv = hv_iterval (hv, he); + SvREFCNT_inc (sv); + svv = Val_sv (sv); + CAMLreturn (svv); +} + +CAMLprim value +perl4caml_hv_iternextsv (value hvv) +{ + CAMLparam1 (hvv); + CAMLlocal3 (strv, svv, rv); + HV *hv = Hv_val (hvv); + char *str; I32 len; + SV *sv = hv_iternextsv (hv, &str, &len); + if (sv == NULL) caml_raise_not_found (); + SvREFCNT_inc (sv); + svv = Val_sv (sv); + strv = caml_alloc_string (len); + memcpy (String_val (strv), str, len); + /* Construct a tuple (strv, svv). */ + rv = caml_alloc_tuple (2); + Field (rv, 0) = strv; + Field (rv, 1) = svv; + CAMLreturn (rv); +} + +CAMLprim value perl4caml_get_sv (value optcreate, value name) { CAMLparam2 (optcreate, name); @@ -544,7 +668,12 @@ perl4caml_get_sv (value optcreate, value name) create = unoption (optcreate, Val_false); sv = get_sv (String_val (name), create == Val_true ? TRUE : FALSE); - if (sv == NULL) raise_not_found (); + if (sv == NULL) caml_raise_not_found (); + + /* Increment the reference count because we're creating another + * value pointing at the referenced SV. + */ + SvREFCNT_inc (sv); CAMLreturn (Val_sv (sv)); } @@ -558,7 +687,12 @@ perl4caml_get_av (value optcreate, value name) create = unoption (optcreate, Val_false); av = get_av (String_val (name), create == Val_true ? TRUE : FALSE); - if (av == NULL) raise_not_found (); + if (av == NULL) caml_raise_not_found (); + + /* Increment the reference count because we're creating another + * value pointing at the AV. + */ + SvREFCNT_inc (av); CAMLreturn (Val_av (av)); } @@ -572,7 +706,12 @@ perl4caml_get_hv (value optcreate, value name) create = unoption (optcreate, Val_false); hv = get_hv (String_val (name), create == Val_true ? TRUE : FALSE); - if (hv == NULL) raise_not_found (); + if (hv == NULL) caml_raise_not_found (); + + /* Increment the reference count because we're creating another + * value pointing at the HV. + */ + SvREFCNT_inc (hv); CAMLreturn (Val_hv (hv)); } @@ -580,18 +719,22 @@ perl4caml_get_hv (value optcreate, value name) static inline void check_perl_failure () { + CAMLparam0 (); + CAMLlocal1 (errv); + SV *errsv = get_sv ("@", TRUE); if (SvTRUE (errsv)) /* Equivalent of $@ in Perl. */ { - CAMLlocal1 (errv); STRLEN n_a; const char *err = SvPV (errsv, n_a); - errv = copy_string (err); + errv = caml_copy_string (err); - raise_with_arg (*caml_named_value ("perl4caml_perl_failure"), errv); + caml_raise_with_arg (*caml_named_value ("perl4caml_perl_failure"), errv); } + + CAMLreturn0; } CAMLprim value @@ -705,10 +848,13 @@ perl4caml_call_array (value optsv, value optfnname, value arglist) */ list = Val_int (0); for (i = 0; i < count; ++i) { - cons = alloc (2, 0); + SV *sv; + + cons = caml_alloc (2, 0); Field (cons, 1) = list; list = cons; - Field (cons, 0) = Val_sv (newSVsv (POPs)); + sv = newSVsv (POPs); + Field (cons, 0) = Val_sv (sv); } /* Restore the stack. */ @@ -879,10 +1025,13 @@ perl4caml_call_method_array (value ref, value name, value arglist) */ list = Val_int (0); for (i = 0; i < count; ++i) { - cons = alloc (2, 0); + SV *sv; + + cons = caml_alloc (2, 0); Field (cons, 1) = list; list = cons; - Field (cons, 0) = Val_sv (newSVsv (POPs)); + sv = newSVsv (POPs); + Field (cons, 0) = Val_sv (sv); } /* Restore the stack. */ @@ -1022,7 +1171,7 @@ perl4caml_call_class_method_array (value classname, value name, value arglist) */ list = Val_int (0); for (i = 0; i < count; ++i) { - cons = alloc (2, 0); + cons = caml_alloc (2, 0); Field (cons, 1) = list; list = cons; Field (cons, 0) = Val_sv (newSVsv (POPs)); @@ -1084,11 +1233,43 @@ perl4caml_call_class_method_void (value classname, value name, value arglist) static value Val_voidptr (void *ptr) { - value rv = alloc (1, Abstract_tag); /* XXX Is this correct? */ + CAMLparam0 (); + CAMLlocal1 (rv); + rv = caml_alloc (1, Abstract_tag); Field(rv, 0) = (value) ptr; - return rv; + CAMLreturn (rv); +} + +#if PERL4CAML_REFCOUNTING_EXPERIMENTAL + +static void +xv_finalize (value v) +{ + /*fprintf (stderr, "about to decrement %p\n", Xv_val (v));*/ + SvREFCNT_dec ((SV *) Xv_val (v)); +} + +static struct custom_operations xv_custom_operations = { + "xv_custom_operations", + xv_finalize, + custom_compare_default, + custom_hash_default, + custom_serialize_default, + custom_deserialize_default +}; + +static value +Val_xv (SV *sv) +{ + CAMLparam0 (); + CAMLlocal1 (rv); + rv = caml_alloc_custom (&xv_custom_operations, sizeof (void *), 0, 1); + Xv_val (rv) = sv; + CAMLreturn (rv); } +#endif /* PERL4CAML_REFCOUNTING_EXPERIMENTAL */ + static value unoption (value option, value deflt) {