X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=perl_c.c;h=3214e34bf8653eff826c664f7f71949ee9db1427;hb=efab5abed48d08e735c652c8454d14393c006c0e;hp=53365b3cde02d08220e77a315fa13f739ef674f9;hpb=16900866ff592a4c28e84579b28dd20efedd8613;p=perl4caml.git diff --git a/perl_c.c b/perl_c.c index 53365b3..3214e34 100644 --- a/perl_c.c +++ b/perl_c.c @@ -1,6 +1,6 @@ /* Interface to Perl from OCaml. * Copyright (C) 2003 Merjis Ltd. - * $Id: perl_c.c,v 1.1 2003-10-11 18:25:52 rich Exp $ + * $Id: perl_c.c,v 1.14 2004-02-03 12:38:57 rich Exp $ */ #include @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -20,83 +21,74 @@ */ #define off64_t __off64_t +/* XXX This is required by Perl >= 5.8.2. */ +#define __USE_GNU +#include + #include #include /* Perl requires the interpreter to be called literally 'my_perl'! */ static PerlInterpreter *my_perl; +/* 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)) -/* 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))) +#if PERL4CAML_REFCOUNTING_EXPERIMENTAL -CAMLprim value -perl4caml_init (value unit) -{ - PERL_SYS_INIT3 (NULL, NULL, NULL); - return Val_unit; -} +/* Unwrap a custom block. */ +#define Xv_val(rv) (*((void **)Data_custom_val(rv))) -CAMLprim value -perl4caml_create (value optargs, value unit) -{ - CAMLparam2 (optargs, unit); - CAMLlocal1 (args); - int argc, i; - char **argv; - static char *no_args[] = { "", "-e", "0" }; +/* 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); - /* Arguments given? */ - if (optargs == Val_int (0)) /* "None" */ - { - argc = 3; - 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)); - } +#else - my_perl = perl_alloc (); - perl_construct (my_perl); - PL_exit_flags |= PERL_EXIT_DESTRUCT_END; - perl_parse (my_perl, NULL, argc, argv, NULL); - perl_run (my_perl); +#define Xv_val(rv) Voidptr_val (SV, (rv)) +#define Val_xv(sv) Val_voidptr ((sv)) - CAMLreturn (Val_perl (my_perl)); -} +#endif -CAMLprim value -perl4caml_destroy (value plv) -{ - CAMLparam1 (plv); - PerlInterpreter *pl = Perl_val (plv); +/* 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_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)) - perl_destruct (pl); - perl_free (pl); +static void +xs_init (pTHX) +{ + char *file = __FILE__; + EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); - CAMLreturn (Val_unit); + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); } CAMLprim value -perl4caml_set_context (value plv) +perl4caml_init (value unit) { - CAMLparam1 (plv); - PerlInterpreter *pl = Perl_val (plv); + CAMLparam1 (unit); + int argc = 4; + static char *argv[] = { "", "-w", "-e", "0" }; - PERL_SET_CONTEXT (pl); - my_perl = pl; + PERL_SYS_INIT3 (NULL, NULL, NULL); + 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_run (my_perl);*/ CAMLreturn (Val_unit); } @@ -155,57 +147,946 @@ perl4caml_sv_of_string (value strv) } CAMLprim value -perl4caml_call_scalar (value fnname, value arglist) +perl4caml_sv_is_true (value svv) +{ + CAMLparam1 (svv); + SV *sv = Sv_val (svv); + CAMLreturn (SvTRUE (sv) ? Val_true : Val_false); +} + +CAMLprim value +perl4caml_sv_undef (value unit) +{ + CAMLparam1 (unit); + CAMLreturn (Val_sv (newSV (0))); +} + +CAMLprim value +perl4caml_sv_yes (value unit) +{ + CAMLparam1 (unit); + CAMLreturn (Val_sv (&PL_sv_yes)); +} + +CAMLprim value +perl4caml_sv_no (value unit) +{ + CAMLparam1 (unit); + CAMLreturn (Val_sv (&PL_sv_no)); +} + +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)); + } +} + +CAMLprim value +perl4caml_scalarref (value svv) +{ + CAMLparam1 (svv); + CAMLlocal1 (rsvv); + SV *sv = Sv_val (svv); + rsvv = Val_sv (newRV_inc (sv)); + CAMLreturn (rsvv); +} + +CAMLprim value +perl4caml_arrayref (value avv) +{ + CAMLparam1 (avv); + CAMLlocal1 (rsvv); + AV *av = Av_val (avv); + rsvv = Val_sv (newRV_inc ((SV *) av)); + CAMLreturn (rsvv); +} + +CAMLprim value +perl4caml_hashref (value hvv) +{ + CAMLparam1 (hvv); + CAMLlocal1 (rsvv); + HV *hv = Hv_val (hvv); + rsvv = Val_sv (newRV_inc ((SV *) hv)); + CAMLreturn (rsvv); +} + +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"); + switch (SvTYPE (SvRV (sv))) { + case SVt_IV: + case SVt_NV: + case SVt_PV: + case SVt_RV: + case SVt_PVMG: + break; + default: + invalid_argument ("deref: SV is not a reference to a scalar"); + } + rsvv = Val_sv (SvRV (sv)); + CAMLreturn (rsvv); +} + +CAMLprim value +perl4caml_deref_array (value svv) +{ + CAMLparam1 (svv); + CAMLlocal1 (ravv); + SV *sv = Sv_val (svv); + + if (SvTYPE (sv) != SVt_RV) + 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"); + } + ravv = Val_av ((AV *) SvRV (sv)); + CAMLreturn (ravv); +} + +CAMLprim value +perl4caml_deref_hash (value svv) +{ + CAMLparam1 (svv); + CAMLlocal1 (rhvv); + SV *sv = Sv_val (svv); + + if (SvTYPE (sv) != SVt_RV) + invalid_argument ("deref_array: 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"); + } + rhvv = Val_hv ((HV *) SvRV (sv)); + CAMLreturn (rhvv); +} + +CAMLprim value +perl4caml_av_empty (value unit) +{ + CAMLparam1 (unit); + AV *av = newAV (); + CAMLreturn (Val_av (av)); +} + +/* We don't know in advance how long the list will be, which makes this + * a little harder. + */ +CAMLprim value +perl4caml_av_of_sv_list (value svlistv) +{ + CAMLparam1 (svlistv); + CAMLlocal1 (svv); + SV *sv, **svlist = 0; + int alloc = 0, size = 0; + AV *av; + + for (; svlistv != Val_int (0); svlistv = Field (svlistv, 1)) + { + svv = Field (svlistv, 0); + sv = Sv_val (svv); + if (size >= alloc) { + alloc = alloc == 0 ? 1 : alloc * 2; + svlist = realloc (svlist, alloc * sizeof (SV *)); + } + svlist[size++] = sv; + } + + av = av_make (size, svlist); + + if (alloc > 0) free (svlist); /* Free memory allocated to SV list. */ + + CAMLreturn (Val_av (av)); +} + +/* XXX av_map would be faster if we also had sv_list_of_av. */ + +CAMLprim value +perl4caml_av_push (value avv, value svv) +{ + CAMLparam2 (avv, svv); + AV *av = Av_val (avv); + SV *sv = Sv_val (svv); + av_push (av, sv); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_av_pop (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + SV *sv = av_pop (av); + CAMLreturn (Val_sv (sv)); +} + +CAMLprim value +perl4caml_av_unshift (value avv, value svv) +{ + CAMLparam2 (avv, svv); + AV *av = Av_val (avv); + SV *sv = Sv_val (svv); + av_unshift (av, 1); + SvREFCNT_inc (sv); + if (av_store (av, 0, sv) == 0) + SvREFCNT_dec (sv); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_av_shift (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + SV *sv = av_shift (av); + CAMLreturn (Val_sv (sv)); +} + +CAMLprim value +perl4caml_av_length (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + CAMLreturn (Val_int (av_len (av) + 1)); +} + +CAMLprim value +perl4caml_av_set (value avv, value i, value svv) +{ + CAMLparam3 (avv, i, svv); + AV *av = Av_val (avv); + SV *sv = Sv_val (svv); + SvREFCNT_inc (sv); + if (av_store (av, Int_val (i), sv) == 0) + SvREFCNT_dec (sv); + CAMLreturn (Val_unit); +} + +CAMLprim value +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"); + CAMLreturn (Val_sv (*svp)); +} + +CAMLprim value +perl4caml_av_clear (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + av_clear (av); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_av_undef (value avv) +{ + CAMLparam1 (avv); + AV *av = Av_val (avv); + av_undef (av); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_av_extend (value avv, value i) +{ + CAMLparam2 (avv, i); + AV *av = Av_val (avv); + av_extend (av, Int_val (i)); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_hv_empty (value unit) +{ + CAMLparam1 (unit); + HV *hv = newHV (); + CAMLreturn (Val_hv (hv)); +} + +CAMLprim value +perl4caml_hv_set (value hvv, value key, value svv) +{ + CAMLparam3 (hvv, key, 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) + SvREFCNT_dec (sv); + CAMLreturn (Val_unit); +} + +CAMLprim value +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 (); + CAMLreturn (Val_sv (*svp)); +} + +CAMLprim value +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)); + CAMLreturn (r ? Val_true : Val_false); +} + +CAMLprim value +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); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_hv_clear (value hvv) +{ + CAMLparam1 (hvv); + HV *hv = Hv_val (hvv); + hv_clear (hv); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_hv_undef (value hvv) +{ + CAMLparam1 (hvv); + HV *hv = Hv_val (hvv); + hv_undef (hv); + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_get_sv (value optcreate, value name) +{ + CAMLparam2 (optcreate, name); + CAMLlocal1 (create); + SV *sv; + + create = unoption (optcreate, Val_false); + sv = get_sv (String_val (name), create == Val_true ? TRUE : FALSE); + if (sv == NULL) raise_not_found (); + + CAMLreturn (Val_sv (sv)); +} + +CAMLprim value +perl4caml_get_av (value optcreate, value name) +{ + CAMLparam2 (optcreate, name); + CAMLlocal1 (create); + AV *av; + + create = unoption (optcreate, Val_false); + av = get_av (String_val (name), create == Val_true ? TRUE : FALSE); + if (av == NULL) raise_not_found (); + + CAMLreturn (Val_av (av)); +} + +CAMLprim value +perl4caml_get_hv (value optcreate, value name) +{ + CAMLparam2 (optcreate, name); + CAMLlocal1 (create); + HV *hv; + + create = unoption (optcreate, Val_false); + hv = get_hv (String_val (name), create == Val_true ? TRUE : FALSE); + if (hv == NULL) raise_not_found (); + + CAMLreturn (Val_hv (hv)); +} + +static inline void +check_perl_failure () +{ + 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); + + raise_with_arg (*caml_named_value ("perl4caml_perl_failure"), errv); + } +} + +CAMLprim value +perl4caml_call (value optsv, value optfnname, value arglist) { - CAMLparam2 (fnname, arglist); + CAMLparam3 (optsv, optfnname, arglist); dSP; int count; SV *sv; - CAMLlocal2 (errv, svv); + CAMLlocal3 (errv, svv, fnname); ENTER; SAVETMPS; /* Push the parameter list. */ PUSHMARK (SP); - /* XXX NOT IMPLEMENTED YET. */ + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + PUTBACK; - count = call_pv (String_val (fnname), G_EVAL|G_SCALAR); + if (optsv != Val_int (0)) + { + svv = unoption (optsv, Val_false); + sv = Sv_val (svv); + count = call_sv (sv, G_EVAL|G_SCALAR); + } + else if (optfnname != Val_int (0)) + { + fnname = unoption (optfnname, Val_false); + count = call_pv (String_val (fnname), G_EVAL|G_SCALAR); + } + else + { + fprintf (stderr, + "Perl.call: must supply either 'sv' or 'fn' parameters."); + abort (); + } SPAGAIN; assert (count == 1); /* Pretty sure it should never be anything else. */ - /* Pop return value off the stack and restore Perl stack. Note that the - * return value on the stack is mortal, so we need to take a copy. + /* Pop return value off the stack. Note that the return value on the + * stack is mortal, so we need to take a copy. */ sv = newSVsv (POPs); PUTBACK; FREETMPS; LEAVE; - /* Died with an error? */ - if (SvTRUE (ERRSV)) + check_perl_failure (); + + svv = Val_sv (sv); + CAMLreturn (svv); +} + +CAMLprim value +perl4caml_call_array (value optsv, value optfnname, value arglist) +{ + CAMLparam3 (optsv, optfnname, arglist); + dSP; + int i, count; + SV *sv; + CAMLlocal5 (errv, svv, fnname, list, cons); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) { - STRLEN n_a; - const char *err = SvPV (ERRSV, n_a); /* Equivalent of $@ in Perl. */ + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } - errv = copy_string (err); + PUTBACK; - raise_with_arg (*caml_named_value ("perl4caml_perl_failure"), errv); + if (optsv != Val_int (0)) + { + svv = unoption (optsv, Val_false); + sv = Sv_val (svv); + count = call_sv (sv, G_EVAL|G_ARRAY); } - else + else if (optfnname != Val_int (0)) { - svv = Val_sv (sv); - CAMLreturn (svv); + fnname = unoption (optfnname, Val_false); + count = call_pv (String_val (fnname), G_EVAL|G_ARRAY); } + else + { + fprintf (stderr, + "Perl.call_array: must supply either 'sv' or 'fn' parameters."); + abort (); + } + + SPAGAIN; + + /* Pop all the return values off the stack into a list. Values on the + * stack are mortal, so we must copy them. + */ + list = Val_int (0); + for (i = 0; i < count; ++i) { + SV *sv; + + cons = alloc (2, 0); + Field (cons, 1) = list; + list = cons; + sv = newSVsv (POPs); + Field (cons, 0) = Val_sv (sv); + } + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (list); +} + +CAMLprim value +perl4caml_call_void (value optsv, value optfnname, value arglist) +{ + CAMLparam3 (optsv, optfnname, arglist); + dSP; + int count; + SV *sv; + CAMLlocal3 (errv, svv, fnname); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + if (optsv != Val_int (0)) + { + svv = unoption (optsv, Val_false); + sv = Sv_val (svv); + count = call_sv (sv, G_EVAL|G_VOID); + } + else if (optfnname != Val_int (0)) + { + fnname = unoption (optfnname, Val_false); + count = call_pv (String_val (fnname), G_EVAL|G_VOID|G_DISCARD); + } + else + { + fprintf (stderr, + "Perl.call_void: must supply either 'sv' or 'fn' parameters."); + abort (); + } + + SPAGAIN; + + assert (count == 0); + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_eval (value expr) +{ + CAMLparam1 (expr); + dSP; + SV *sv; + CAMLlocal2 (errv, svv); + + sv = eval_pv (String_val (expr), G_SCALAR); + + check_perl_failure (); + + svv = Val_sv (sv); + CAMLreturn (svv); +} + +CAMLprim value +perl4caml_call_method (value ref, value name, value arglist) +{ + CAMLparam3 (ref, name, arglist); + dSP; + int count; + SV *sv; + CAMLlocal2 (errv, svv); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + sv = Sv_val (ref); + XPUSHs (sv_2mortal (newSVsv (sv))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_SCALAR); + + SPAGAIN; + + assert (count == 1); /* Pretty sure it should never be anything else. */ + + /* Pop return value off the stack. Note that the return value on the + * stack is mortal, so we need to take a copy. + */ + sv = newSVsv (POPs); + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + svv = Val_sv (sv); + CAMLreturn (svv); } -value +CAMLprim value +perl4caml_call_method_array (value ref, value name, value arglist) +{ + CAMLparam3 (ref, name, arglist); + dSP; + int count, i; + SV *sv; + CAMLlocal4 (errv, svv, list, cons); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + sv = Sv_val (ref); + XPUSHs (sv_2mortal (newSVsv (sv))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_ARRAY); + + SPAGAIN; + + /* Pop all return values off the stack. Note that the return values on the + * stack are mortal, so we need to take a copy. + */ + list = Val_int (0); + for (i = 0; i < count; ++i) { + SV *sv; + + cons = alloc (2, 0); + Field (cons, 1) = list; + list = cons; + sv = newSVsv (POPs); + Field (cons, 0) = Val_sv (sv); + } + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (list); +} + +CAMLprim value +perl4caml_call_method_void (value ref, value name, value arglist) +{ + CAMLparam3 (ref, name, arglist); + dSP; + int count; + SV *sv; + CAMLlocal2 (errv, svv); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + sv = Sv_val (ref); + XPUSHs (sv_2mortal (newSVsv (sv))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_VOID|G_DISCARD); + + SPAGAIN; + + assert (count == 0); + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (Val_unit); +} + +CAMLprim value +perl4caml_call_class_method (value classname, value name, value arglist) +{ + CAMLparam3 (classname, name, arglist); + dSP; + int count; + SV *sv; + CAMLlocal2 (errv, svv); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + XPUSHs (sv_2mortal (newSVpv (String_val (classname), 0))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_SCALAR); + + SPAGAIN; + + assert (count == 1); /* Pretty sure it should never be anything else. */ + + /* Pop return value off the stack. Note that the return value on the + * stack is mortal, so we need to take a copy. + */ + sv = newSVsv (POPs); + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + svv = Val_sv (sv); + CAMLreturn (svv); +} + +CAMLprim value +perl4caml_call_class_method_array (value classname, value name, value arglist) +{ + CAMLparam3 (classname, name, arglist); + dSP; + int count, i; + SV *sv; + CAMLlocal4 (errv, svv, list, cons); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + XPUSHs (sv_2mortal (newSVpv (String_val (classname), 0))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_ARRAY); + + SPAGAIN; + + /* Pop all return values off the stack. Note that the return values on the + * stack are mortal, so we need to take a copy. + */ + list = Val_int (0); + for (i = 0; i < count; ++i) { + cons = alloc (2, 0); + Field (cons, 1) = list; + list = cons; + Field (cons, 0) = Val_sv (newSVsv (POPs)); + } + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (list); +} + +CAMLprim value +perl4caml_call_class_method_void (value classname, value name, value arglist) +{ + CAMLparam3 (classname, name, arglist); + dSP; + int count; + SV *sv; + CAMLlocal2 (errv, svv); + + ENTER; + SAVETMPS; + + /* Push the parameter list. */ + PUSHMARK (SP); + + XPUSHs (sv_2mortal (newSVpv (String_val (classname), 0))); + + /* Iteration over the linked list. */ + for (; arglist != Val_int (0); arglist = Field (arglist, 1)) + { + svv = Field (arglist, 0); + sv = Sv_val (svv); + XPUSHs (sv_2mortal (newSVsv (sv))); + } + + PUTBACK; + + count = call_method (String_val (name), G_EVAL|G_VOID|G_DISCARD); + + SPAGAIN; + + assert (count == 0); + + /* Restore the stack. */ + PUTBACK; + FREETMPS; + LEAVE; + + check_perl_failure (); + + CAMLreturn (Val_unit); +} + +static value Val_voidptr (void *ptr) { - value rv = alloc (1, Abstract_tag); /* XXX Is this correct? */ + CAMLparam0 (); + CAMLlocal1 (rv); + rv = alloc (1, Abstract_tag); Field(rv, 0) = (value) ptr; - return rv; + CAMLreturn (rv); +} + +#if PERL4CAML_REFCOUNTING_EXPERIMENTAL + +static void +xv_finalize (value 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 = 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) +{ + if (option == Val_int (0)) /* "None" */ + return deflt; + else /* "Some 'a" */ + return Field (option, 0); }