From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

/* vim: set shiftwidth=4 softtabstop=4 expandtab: */
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "Python.h"
#include "perlmodule.h"
#include "py2pl.h"
#include "util.h"
#ifdef __cplusplus
}
#endif
#ifdef CREATE_PERL
static PerlInterpreter *my_perl;
#endif
staticforward PyObject * special_perl_eval(PyObject *, PyObject *);
staticforward PyObject * special_perl_use(PyObject *, PyObject *);
staticforward PyObject * special_perl_require(PyObject *, PyObject *);
/***************************************
* METHOD DECLARATIONS *
***************************************/
PyObject * newPerlPkg_object(PyObject *base, PyObject *pkg);
staticforward void PerlPkg_dealloc(PerlPkg_object *self);
staticforward PyObject * PerlPkg_repr(PerlPkg_object *self, PyObject *args);
staticforward PyObject * PerlPkg_getattr(PerlPkg_object *self, char *name);
PyObject * newPerlObj_object(SV *obj, PyObject *pkg);
staticforward void PerlObj_dealloc(PerlObj_object *self);
staticforward PyObject * PerlObj_repr(PerlObj_object *self);
staticforward PyObject * PerlObj_str(PerlObj_object *self);
staticforward PyObject * PerlObj_call(PerlObj_object *self, PyObject *args, PyObject *kw);
staticforward PyObject * PerlObj_getattr(PerlObj_object *self, char *name);
staticforward PyObject * PerlObj_mp_subscript(PerlObj_object *self, PyObject *key);
PyObject * newPerlSub_object(PyObject *base,
PyObject *pkg,
SV *cv);
PyObject * newPerlMethod_object(PyObject *base,
PyObject *pkg,
SV *obj);
PyObject * newPerlCfun_object(PyObject* (*cfun)(PyObject *self, PyObject *args));
staticforward void PerlSub_dealloc(PerlSub_object *self);
staticforward PyObject * PerlSub_call(PerlSub_object *self, PyObject *args, PyObject *kw);
staticforward PyObject * PerlSub_repr(PerlSub_object *self, PyObject *args);
staticforward PyObject * PerlSub_getattr(PerlSub_object *self, char *name);
staticforward int PerlSub_setattr(PerlSub_object *self,
char *name,
PyObject *value);
/**************************************
* METHOD DEFINITIONS *
**************************************/
/* methods of _perl_pkg */
PyObject *
newPerlPkg_object(PyObject *base, PyObject *package) {
PerlPkg_object * const self = PyObject_NEW(PerlPkg_object, &PerlPkg_type);
#if PY_MAJOR_VERSION >= 3
char * const bs = PyBytes_AsString(base);
char * const pkg = PyBytes_AsString(package);
#else
char * const bs = PyString_AsString(base);
char * const pkg = PyString_AsString(package);
#endif
char * const str = (char*)malloc((strlen(bs) + strlen(pkg) + strlen("::") + 1)
* sizeof(char));
if(!self) {
free(str);
PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Package object.\n");
return NULL;
}
sprintf(str, "%s%s::", bs, pkg);
Py_INCREF(base);
Py_INCREF(package);
self->base = base;
self->pkg = package;
#if PY_MAJOR_VERSION >= 3
self->full = PyBytes_FromString(str);
#else
self->full = PyString_FromString(str);
#endif
free(str);
return (PyObject*)self;
}
static void
PerlPkg_dealloc(PerlPkg_object *self) {
Py_XDECREF(self->pkg);
Py_XDECREF(self->base);
Py_XDECREF(self->full);
PyObject_Del(self);
}
static PyObject *
PerlPkg_repr(PerlPkg_object *self, PyObject *args) {
PyObject *s;
char * const str = (char*)malloc((strlen("<perl package: ''>")
+ PyObject_Length(self->full)
+ 1) * sizeof(char));
#if PY_MAJOR_VERSION >= 3
sprintf(str, "<perl package: '%s'>", PyBytes_AsString(self->full));
s = PyUnicode_FromString(str);
#else
sprintf(str, "<perl package: '%s'>", PyString_AsString(self->full));
s = PyString_FromString(str);
#endif
free(str);
return s;
}
static PyObject *
PerlPkg_getattr(PerlPkg_object *self, char *name) {
/*** Python Methods ***/
if (strcmp(name,"__methods__") == 0) {
return get_perl_pkg_subs(self->full);
}
else if (strcmp(name,"__members__") == 0) {
PyObject *retval = PyList_New(0);
return retval ? retval : NULL;
}
else if (strcmp(name,"__dict__") == 0) {
PyObject *retval = PyDict_New();
return retval ? retval : NULL;
}
/*** Special Names (but only for 'main' package) ***/
else if (PKG_EQ(self, "main::") && strcmp(name,"eval")==0) {
/* return a PerlSub_object which just does: eval(@_) */
return newPerlCfun_object(&special_perl_eval);
}
else if (PKG_EQ(self, "main::") && strcmp(name,"use")==0) {
/* return a PerlSub_object which just does:
* eval("use $_[0]; $_[0]->import") */
return newPerlCfun_object(&special_perl_use);
}
else if (PKG_EQ(self, "main::") && strcmp(name,"require")==0) {
/* return a PerlSub_object which just does:
* eval("require $_[0];") */
return newPerlCfun_object(&special_perl_require);
}
/*** A Perl Package, Sub, or Method ***/
else {
#if PY_MAJOR_VERSION >= 3
PyObject * const tmp = PyBytes_FromString(name);
char * const full_c = PyBytes_AsString(self->full);
#else
PyObject * const tmp = PyString_FromString(name);
char * const full_c = PyString_AsString(self->full);
#endif
PyObject * const res = perl_pkg_exists(full_c, name)
? newPerlPkg_object(self->full, tmp)
: newPerlSub_object(self->full, tmp, NULL);
Py_DECREF(tmp);
return res;
}
}
static PyObject * module_dir(PerlPkg_object *self, PyObject *args) {
return get_perl_pkg_subs(self->full);
}
static struct PyMethodDef PerlPkg_methods[] = {
{"__dir__", (PyCFunction)module_dir, METH_NOARGS, NULL},
{NULL} /* sentinel */
};
/* doc string */
static char PerlPkg_type__doc__[] =
"_perl_pkg -- Wrap a Perl package in a Python class"
;
/* type definition */
PyTypeObject PerlPkg_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_perl_pkg", /*tp_name*/
sizeof(PerlPkg_object), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PerlPkg_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)PerlPkg_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
(cmpfunc)0, /*tp_compare*/
#else
0, /*reserved*/
#endif
(reprfunc)PerlPkg_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)PerlPkg_repr, /*tp_str*/
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
PerlPkg_type__doc__, /* Documentation string */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PerlPkg_methods, /* tp_methods */
};
/* methods of _perl_obj */
PyObject *
newPerlObj_object(SV *obj, PyObject *package) {
PerlObj_object * const self = PyObject_NEW(PerlObj_object, &PerlObj_type);
if(!self) {
PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Obj object.\n");
return NULL;
}
Py_INCREF(package);
SvREFCNT_inc(obj);
self->pkg = package;
self->obj = obj;
return (PyObject*)self;
}
static void
PerlObj_dealloc(PerlObj_object *self) {
Py_XDECREF(self->pkg);
if (self->obj) sv_2mortal(self->obj); /* mortal instead of DECREF. Object might be return value */
PyObject_Del(self);
}
static PyObject *
PerlObj_repr(PerlObj_object *self) {
PyObject *s;
char * const str = (char*)malloc((strlen("<perl object: ''>")
+ PyObject_Length(self->pkg)
+ 1) * sizeof(char));
#if PY_MAJOR_VERSION >= 3
sprintf(str, "<perl object: '%s'>", PyBytes_AsString(self->pkg));
s = PyUnicode_FromString(str);
#else
sprintf(str, "<perl object: '%s'>", PyString_AsString(self->pkg));
s = PyString_FromString(str);
#endif
free(str);
return s;
}
static PyObject *
PerlObj_str(PerlObj_object *self) {
STRLEN len;
SV* const sv = ((SvTHINKFIRST(self->obj) && !SvIsCOW(self->obj)) || isGV_with_GP(self->obj))
? sv_mortalcopy(self->obj)
: self->obj;
char * const str = SvPVutf8(sv, len);
return PyUnicode_DecodeUTF8(str, len, "replace");
}
static PyObject *
PerlObj_getattr(PerlObj_object *self, char *name) {
PyObject *retval = NULL;
if (strcmp(name,"__methods__") == 0) {
return get_perl_pkg_subs(self->pkg);
}
else if (strcmp(name,"__members__") == 0) {
retval = PyList_New(0);
return retval ? retval : NULL;
}
else if (strcmp(name,"__dict__") == 0) {
retval = PyDict_New();
return retval ? retval : NULL;
}
else {
SV * const obj = (SV*)SvRV(self->obj);
HV * const pkg = SvSTASH(obj);
/* probably a request for a method */
GV * const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, name, TRUE);
if (gv && isGV(gv)) {
#if PY_MAJOR_VERSION >= 3
PyObject * const py_name = PyBytes_FromString(name);
#else
PyObject * const py_name = PyString_FromString(name);
#endif
retval = newPerlMethod_object(self->pkg, py_name, self->obj);
Py_DECREF(py_name);
}
else {
/* search for an attribute */
/* check if the object supports the __getattr__ protocol */
GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__getattr__", FALSE);
if (gv && isGV(gv)) { /* __getattr__ supported! Let's see if an attribute is found. */
dSP;
ENTER;
SAVETMPS;
SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv)));
PUSHMARK(SP);
XPUSHs(self->obj);
XPUSHs(sv_2mortal(newSVpv(name, 0)));
PUTBACK;
/* array context needed, so it's possible to return nothing (not even undef)
if the attribute does not exist */
int const count = call_sv(rv, G_ARRAY);
SPAGAIN;
if (count > 1)
croak("__getattr__ may only return a single scalar or an empty list!\n");
if (count == 1) { /* attribute exists! Now give the value back to Python */
retval = Pl2Py(POPs);
}
PUTBACK;
FREETMPS;
LEAVE;
}
if (! retval) { /* give up and raise a AttributeError */
char attribute_error[strlen(name) + 21];
sprintf(attribute_error, "attribute %s not found", name);
PyErr_SetString(PyExc_AttributeError, attribute_error);
}
}
return retval;
}
}
static PyObject*
PerlObj_mp_subscript(PerlObj_object *self, PyObject *key) {
/* check if the object supports the __getitem__ protocol */
PyObject *item = NULL;
PyObject *key_str = PyObject_Str(key); /* new reference */
#if PY_MAJOR_VERSION >= 3
PyObject* string_as_bytes = PyUnicode_AsUTF8String(key_str);/* new reference */
char * const name = PyBytes_AsString(string_as_bytes);
#else
char * const name = PyString_AsString(key_str);
#endif
SV * const obj = (SV*)SvRV(self->obj);
HV * const pkg = SvSTASH(obj);
GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__getitem__", FALSE);
if (gv && isGV(gv)) { /* __getitem__ supported! Let's see if the key is found. */
dSP;
ENTER;
SAVETMPS;
SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv)));
PUSHMARK(SP);
XPUSHs(self->obj);
XPUSHs(sv_2mortal(newSVpv(name, 0)));
PUTBACK;
/* array context needed, so it's possible to return nothing (not even undef)
if the attribute does not exist */
int const count = call_sv(rv, G_ARRAY);
SPAGAIN;
if (count > 1)
croak("__getitem__ may only return a single scalar or an empty list!\n");
if (count == 1) { /* item exists! Now give the value back to Python */
item = Pl2Py(POPs);
}
PUTBACK;
FREETMPS;
LEAVE;
if (count == 0) {
char attribute_error[strlen(name) + 21];
sprintf(attribute_error, "attribute %s not found", name);
PyErr_SetString(PyExc_KeyError, attribute_error);
}
}
else {
PyErr_Format(PyExc_TypeError, "'%.200s' object is unsubscriptable", Py_TYPE(self)->tp_name);
}
#if PY_MAJOR_VERSION >= 3
Py_DECREF(string_as_bytes);
#endif
Py_DECREF(key_str);
return item;
}
static PyObject *
PerlObj_call(PerlObj_object *self, PyObject *args, PyObject *kw) {
dSP;
int i;
int const len = PyObject_Length(args);
int count;
PyObject *retval;
ENTER;
SAVETMPS;
PUSHMARK(SP);
if (self->obj) XPUSHs(self->obj);
if (kw) { /* if keyword arguments are present, positional arguments get pushed as into an arrayref */
AV * const positional = newAV();
for (i=0; i<len; i++) {
SV * const arg = Py2Pl(PyTuple_GetItem(args, i));
av_push(positional, sv_isobject(arg) ? SvREFCNT_inc(arg) : arg);
}
XPUSHs((SV *) sv_2mortal((SV *) newRV_inc((SV *) positional)));
SV * const kw_hash = Py2Pl(kw);
XPUSHs(kw_hash);
sv_2mortal(kw_hash);
sv_2mortal((SV *)positional);
}
else {
for (i=0; i<len; i++) {
SV * const arg = Py2Pl(PyTuple_GetItem(args, i));
XPUSHs(arg);
if (! sv_isobject(arg))
sv_2mortal(arg);
}
}
PUTBACK;
/* call the function */
/* because the Perl sub *could* be arbitrary Python code,
* I probably should temporarily hold a reference here */
Py_INCREF(self);
count = perl_call_sv(self->obj, G_EVAL);
SPAGAIN;
Py_DECREF(self); /* release*/
if (SvTRUE(ERRSV)) {
PyObject *exc = Pl2Py(ERRSV);
PyErr_SetObject(PyExc_Perl, exc);
ERRSV = NULL;
return NULL;
}
/* what to return? */
if (count == 0) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (count == 1) {
retval = Pl2Py(POPs);
}
else {
AV * const lst = newAV();
av_extend(lst, count);
for (i = count - 1; i >= 0; i--) {
av_store(lst, i, SvREFCNT_inc(POPs));
}
SV * const rv_lst = newRV_inc((SV*)lst);
retval = Pl2Py(rv_lst);
SvREFCNT_dec(rv_lst);
sv_2mortal((SV*)lst); /* this will get killed shortly */
}
PUTBACK;
FREETMPS;
LEAVE;
return retval;
}
#if PY_MAJOR_VERSION >= 3 // Python 3 rich compare
static PyObject*
PerlObj_richcompare(PerlObj_object *o1, PerlObj_object *o2, int op) {
/* Unable to compare different a Perl object with something else */
if (!PerlObjObject_Check(o1) || !PerlObjObject_Check(o2)) {
Py_RETURN_FALSE;
}
/* check if the object supports the __cmp__ protocol */
SV * const obj = (SV*)SvRV(o1->obj);
HV * const pkg = SvSTASH(obj);
const char* method_name = NULL;
switch (op) {
case Py_LT: method_name = "__lt__"; break;
case Py_LE: method_name = "__le__"; break;
case Py_EQ: method_name = "__eq__"; break;
case Py_NE: method_name = "__ne__"; break;
case Py_GT: method_name = "__gt__"; break;
case Py_GE: method_name = "__ge__"; break;
}
GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, method_name, FALSE);
if (gv && isGV(gv)) {
int retval;
dSP;
ENTER;
SAVETMPS;
SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv)));
PUSHMARK(SP);
XPUSHs(o1->obj);
XPUSHs(o2->obj);
PUTBACK;
int const count = call_sv(rv, G_SCALAR);
SPAGAIN;
if (count > 1)
croak("%s may only return a single scalar!\n", method_name);
if (count == 1) { /* attribute exists! Now give the value back to Python */
SV * const result = POPs;
if(!SvIOK(result))
croak("%s must return an integer!\n", method_name);
retval = SvIV(result);
}
PUTBACK;
FREETMPS;
LEAVE;
if(retval == 0) {Py_RETURN_TRUE;}
Py_RETURN_FALSE;
}
if (SvRV(o1->obj) == SvRV(o2->obj)) {/* just compare the dereferenced object pointers */
if(op == Py_EQ) {Py_RETURN_TRUE;}
Py_RETURN_FALSE;
}
if (SvRV(o1->obj) != SvRV(o2->obj)) {
if(op == Py_NE) {Py_RETURN_TRUE;}
Py_RETURN_FALSE;
}
Py_RETURN_NOTIMPLEMENTED;
}
#else // Python 2 __cmp__ method
static int
PerlObj_compare(PerlObj_object *o1, PerlObj_object *o2) {
/* check if the object supports the __cmp__ protocol */
SV * const obj = (SV*)SvRV(o1->obj);
HV * const pkg = SvSTASH(obj);
GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__cmp__", FALSE);
if (gv && isGV(gv)) {
int retval;
dSP;
ENTER;
SAVETMPS;
SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv)));
PUSHMARK(SP);
XPUSHs(o1->obj);
XPUSHs(o2->obj);
PUTBACK;
int const count = call_sv(rv, G_SCALAR);
SPAGAIN;
if (count > 1)
croak("__cmp__ may only return a single scalar!\n");
if (count == 1) { /* attribute exists! Now give the value back to Python */
SV * const result = POPs;
if(!SvIOK(result))
croak("__cmp__ must return an integer!\n");
retval = SvIV(result);
}
PUTBACK;
FREETMPS;
LEAVE;
return retval;
}
if (SvRV(o1->obj) == SvRV(o2->obj)) /* just compare the dereferenced object pointers */
return 0;
return 1;
}
#endif
static PyObject * object_dir(PerlObj_object *self, PyObject *args) {
return get_perl_pkg_subs(self->pkg);
}
static struct PyMethodDef PerlObj_methods[] = {
{"__dir__", (PyCFunction)object_dir, METH_NOARGS, NULL},
{NULL} /* sentinel */
};
/* doc string */
static char PerlObj_type__doc__[] =
"_perl_obj -- Wrap a Perl object in a Python class"
;
PyMappingMethods mp_methods = {
(lenfunc) 0, /*mp_length*/
(binaryfunc) PerlObj_mp_subscript, /*mp_subscript*/
(objobjargproc) 0, /*mp_ass_subscript*/
};
/* type definition */
PyTypeObject PerlObj_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_perl_obj", /*tp_name*/
sizeof(PerlObj_object), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PerlObj_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)PerlObj_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
(cmpfunc)PerlObj_compare, /*tp_compare*/
#else
0, /*reserved*/
#endif
(reprfunc)PerlObj_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&mp_methods, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)PerlObj_call, /*tp_call*/
(reprfunc)PerlObj_str, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
PerlObj_type__doc__, /* Documentation string */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
#if PY_MAJOR_VERSION < 3
0, /* unused */
#else
(richcmpfunc)PerlObj_richcompare, /* tp_richcompare */
#endif
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PerlObj_methods, /* tp_methods */
};
/* methods of _perl_sub */
PyObject *
newPerlSub_object(PyObject *package, PyObject *sub, SV *cv) {
PerlSub_object * const self = PyObject_NEW(PerlSub_object, &PerlSub_type);
char *str = NULL;
if(!self) {
PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Sub object.\n");
return NULL;
}
/* initialize the name of the sub or method */
if (package && sub) {
str = malloc((PyObject_Length(package) + PyObject_Length(sub) + 1)
*sizeof(char));
#if PY_MAJOR_VERSION >= 3
sprintf(str, "%s%s", PyBytes_AsString(package),
PyBytes_AsString(sub));
#else
sprintf(str, "%s%s", PyString_AsString(package),
PyString_AsString(sub));
#endif
Py_INCREF(sub);
Py_INCREF(package);
self->sub = sub;
self->pkg = package;
#if PY_MAJOR_VERSION >= 3
self->full = PyBytes_FromString(str);
#else
self->full = PyString_FromString(str);
#endif
}
else {
self->sub = NULL;
self->pkg = NULL;
self->full = NULL;
}
/* we don't have to check for errors because we shouldn't have been
* created unless perl_get_cv worked once.
*/
if (cv) {
self->ref = cv;
self->conf = 1;
}
else if (str) {
self->ref = (SV*)perl_get_cv(str,0); /* can return NULL if not found */
self->conf = self->ref ? 1 : 0;
}
else {
croak("Can't call newPerlSub_object() with all NULL arguments!\n");
}
SvREFCNT_inc(self->ref); /* quite important -- otherwise we lose it */
self->obj = NULL;
self->flgs = G_ARRAY;
self->cfun = 0;
if (str) free(str);
return (PyObject*)self;
}
PyObject *
newPerlMethod_object(PyObject *package, PyObject *sub, SV *obj) {
PerlSub_object * const self = (PerlSub_object*)newPerlSub_object(package,
sub, NULL);
self->obj = obj;
SvREFCNT_inc(obj);
return (PyObject*)self;
}
PyObject * newPerlCfun_object(PyObject* (*cfun)(PyObject *self,
PyObject *args))
{
PerlSub_object * const self = PyObject_NEW(PerlSub_object, &PerlSub_type);
self->pkg = NULL;
self->sub = NULL;
self->full = NULL;
self->ref = NULL;
self->obj = NULL;
self->flgs = 0;
self->cfun = cfun;
return (PyObject *)self;
}
static void
PerlSub_dealloc(PerlSub_object *self) {
Py_XDECREF(self->sub);
Py_XDECREF(self->pkg);
Py_XDECREF(self->full);
if (self->obj) SvREFCNT_dec(self->obj);
if (self->ref) SvREFCNT_dec(self->ref);
PyObject_Del(self);
}
static PyObject *
PerlSub_call(PerlSub_object *self, PyObject *args, PyObject *kw) {
dSP;
int i;
int const len = PyObject_Length(args);
int count;
PyObject *retval;
/* if this wraps a C function, execute that */
if (self->cfun) return self->cfun((PyObject*)self, args);
ENTER;
SAVETMPS;
PUSHMARK(SP);
if (self->obj) XPUSHs(self->obj);
if (kw) { /* if keyword arguments are present, positional arguments get pushed as into an arrayref */
AV * const positional = newAV();
for (i=0; i<len; i++) {
SV * const arg = Py2Pl(PyTuple_GetItem(args, i));
av_push(positional, sv_isobject(arg) ? SvREFCNT_inc(arg) : arg);
}
XPUSHs((SV *) sv_2mortal((SV *) newRV_inc((SV *) positional)));
SV * const kw_hash = Py2Pl(kw);
XPUSHs(kw_hash);
sv_2mortal(kw_hash);
sv_2mortal((SV *)positional);
}
else {
for (i=0; i<len; i++) {
SV * const arg = Py2Pl(PyTuple_GetItem(args, i));
XPUSHs(arg);
if (! sv_isobject(arg))
sv_2mortal(arg);
}
}
PUTBACK;
/* call the function */
/* because the Perl sub *could* be arbitrary Python code,
* I probably should temporarily hold a reference here */
Py_INCREF(self);
if (self->ref)
count = perl_call_sv(self->ref, self->flgs | G_EVAL);
else if (self->sub && self->obj)
#if PY_MAJOR_VERSION >= 3
count = perl_call_method(PyBytes_AsString(self->sub), self->flgs | G_EVAL);
#else
count = perl_call_method(PyString_AsString(self->sub), self->flgs | G_EVAL);
#endif
else {
croak("Error: PerlSub called, but no C function, sub, or name found!\n");
}
SPAGAIN;
Py_DECREF(self); /* release*/
if (SvTRUE(ERRSV)) {
PyObject *exc = Pl2Py(ERRSV);
PyErr_SetObject(PyExc_Perl, exc);
ERRSV = NULL;
return NULL;
}
/* what to return? */
if (count == 0) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (count == 1) {
retval = Pl2Py(POPs);
}
else {
AV * const lst = newAV();
av_extend(lst, count);
for (i = count - 1; i >= 0; i--) {
av_store(lst, i, SvREFCNT_inc(POPs));
}
SV * const rv_lst = newRV_inc((SV*)lst);
retval = Pl2Py(rv_lst);
SvREFCNT_dec(rv_lst);
sv_2mortal((SV*)lst); /* this will get killed shortly */
}
PUTBACK;
FREETMPS;
LEAVE;
return retval;
}
static PyObject *
PerlSub_repr(PerlSub_object *self, PyObject *args) {
PyObject *s;
char * const str = (char*)malloc((strlen("<perl sub: ''>")
+ (self->full
? PyObject_Length(self->full)
: strlen("anonymous"))
+ 1) * sizeof(char));
#if PY_MAJOR_VERSION >= 3
sprintf(str, "<perl sub: '%s'>", (self->full
? PyBytes_AsString(self->full)
: "anonymous"));
s = PyUnicode_FromString(str);
#else
sprintf(str, "<perl sub: '%s'>", (self->full
? PyString_AsString(self->full)
: "anonymous"));
s = PyString_FromString(str);
#endif
free(str);
return s;
}
static PyObject *
PerlSub_getattr(PerlSub_object *self, char *name) {
PyObject *retval = NULL;
if (strcmp(name,"flags")==0) {
retval = PyInt_FromLong((long)self->flgs);
}
else if (strcmp(name,"G_VOID")==0) {
retval = PyInt_FromLong((long)G_VOID);
}
else if (strcmp(name,"G_SCALAR")==0) {
retval = PyInt_FromLong((long)G_SCALAR);
}
else if (strcmp(name,"G_ARRAY")==0) {
retval = PyInt_FromLong((long)G_ARRAY);
}
else if (strcmp(name,"G_DISCARD")==0) {
retval = PyInt_FromLong((long)G_DISCARD);
}
else if (strcmp(name,"G_NOARGS")==0) {
retval = PyInt_FromLong((long)G_NOARGS);
}
else if (strcmp(name,"G_EVAL")==0) {
retval = PyInt_FromLong((long)G_EVAL);
}
else if (strcmp(name,"G_KEEPERR")==0) {
retval = PyInt_FromLong((long)G_KEEPERR);
}
else {
PyErr_Format(PyExc_AttributeError,
"Attribute '%s' not found for Perl sub '%s'", name,
#if PY_MAJOR_VERSION < 3
(self->full
? PyString_AsString(self->full)
: (self->pkg ? PyString_AsString(self->pkg) : ""))
#else
(self->full
? PyBytes_AsString(self->full)
: (self->pkg ? PyBytes_AsString(self->pkg) : ""))
#endif
);
retval = NULL;
}
return retval;
}
static int
PerlSub_setattr(PerlSub_object *self, char *name, PyObject *v) {
if (strcmp(name, "flags")==0 && PyInt_Check(v)) {
self->flgs = (int)PyInt_AsLong(v);
return 0; /* success */
}
else if (strcmp(name,"flags")==0) {
PyErr_Format(PyExc_TypeError,
"'flags' can only be set from an integer. '%s'",
#if PY_MAJOR_VERSION < 3
(self->pkg ? PyString_AsString(self->pkg) : ""));
#else
(self->pkg ? PyBytes_AsString(self->pkg) : ""));
#endif
return -1; /* failure */
}
else {
PyErr_Format(PyExc_AttributeError,
"Attribute '%s' not found for Perl sub '%s'", name,
#if PY_MAJOR_VERSION < 3
(self->full
? PyString_AsString(self->full)
: (self->pkg ? PyString_AsString(self->pkg) : ""))
#else
(self->full
? PyBytes_AsString(self->full)
: (self->pkg ? PyBytes_AsString(self->pkg) : ""))
#endif
);
return -1; /* failure */
}
}
static struct PyMethodDef PerlSub_methods[] = {
{NULL, NULL} /* sentinel */
};
/* doc string */
static char PerlSub_type__doc__[] =
"_perl_sub -- Wrap a Perl sub in a Python class"
;
/* type definition */
PyTypeObject PerlSub_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_perl_sub", /*tp_name*/
sizeof(PerlSub_object), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PerlSub_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)PerlSub_getattr, /*tp_getattr*/
(setattrfunc)PerlSub_setattr, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
(cmpfunc)0, /*tp_compare*/
#else
0, /*reserved*/
#endif
(reprfunc)PerlSub_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)PerlSub_call, /*tp_call*/
(reprfunc)PerlSub_repr, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
PerlSub_type__doc__, /* Documentation string */
};
/* no module-public functions */
static PyMethodDef perl_functions[] = {
{NULL, NULL} /* sentinel */
};
static PyObject * special_perl_eval(PyObject *ignored, PyObject *args) {
dSP;
SV *code;
int i;
int count;
PyObject *retval;
PyObject * const s = PyTuple_GetItem(args, 0);
#if PY_MAJOR_VERSION >= 3
int is_string = PyBytes_Check(s) || PyUnicode_Check(s);
#else
int is_string = PyString_Check(s);
#endif
if(!is_string) {
return NULL;
}
ENTER;
SAVETMPS;
/* not necessary -- but why not? */
PUSHMARK(SP);
PUTBACK;
/* run the anonymous subroutine under G_EVAL mode */
#if PY_MAJOR_VERSION >= 3
PyObject* s_bytes = 0;
char* s_c_bytes = 0;
if(PyUnicode_Check(s)) {
s_bytes = PyUnicode_AsUTF8String(s);
s_c_bytes = PyBytes_AsString(s_bytes);
}
else s_c_bytes = PyBytes_AsString(s);
#else
char* s_c_bytes = PyString_AsString(s);
#endif
code = newSVpv(s_c_bytes,0);
count = perl_eval_sv(code, G_EVAL);
#if PY_MAJOR_VERSION >= 3
Py_XDECREF(s_bytes);
#endif
SPAGAIN;
if (SvTRUE(ERRSV)) {
warn("%s\n", SvPV_nolen(ERRSV));
}
if (count == 0) {
retval = Py_None;
Py_INCREF(retval);
}
else if (count == 1) {
SV * const s = POPs;
retval = Pl2Py(s);
}
else {
AV * const lst = newAV();
for (i=0; i<count; i++) {
av_push(lst, POPs);
}
retval = Pl2Py((SV*)lst);
sv_2mortal((SV*)lst);
}
PUTBACK;
FREETMPS;
LEAVE;
return retval;
}
static PyObject * special_perl_use(PyObject *ignored, PyObject *args) {
PyObject * s = PyTuple_GetItem(args, 0);
char *str;
#if PY_MAJOR_VERSION >= 3
int is_string = PyBytes_Check(s) || PyUnicode_Check(s);
#else
int is_string = PyString_Check(s);
#endif
if(!is_string) {
return NULL;
}
#if PY_MAJOR_VERSION >= 3
PyObject* s_bytes = 0;
char* s_c_bytes = 0;
if(PyUnicode_Check(s)) {
s_bytes = PyUnicode_AsUTF8String(s);
s_c_bytes = PyBytes_AsString(s_bytes);
}
else s_c_bytes = PyBytes_AsString(s);
#else
char* s_c_bytes = PyString_AsString(s);
#endif
Printf(("calling use...'%s'\n", s_c_bytes));
str = malloc((strlen("use ")
+ PyObject_Length(s) + 1) * sizeof(char));
sprintf(str, "use %s", s_c_bytes);
Printf(("eval-ing now!\n"));
perl_eval_pv(str, TRUE);
Printf(("'twas called!\n"));
free(str);
#if PY_MAJOR_VERSION >= 3
Py_XDECREF(s_bytes);
#endif
Py_INCREF(Py_None);
return Py_None;
}
static PyObject * special_perl_require(PyObject *ignored, PyObject *args) {
PyObject * const s = PyTuple_GetItem(args, 0);
#if PY_MAJOR_VERSION >= 3
int is_string = PyBytes_Check(s) || PyUnicode_Check(s);
#else
int is_string = PyString_Check(s);
#endif
if(!is_string) {
return NULL;
}
#if PY_MAJOR_VERSION >= 3
PyObject* s_bytes = 0;
char* s_c_bytes = 0;
if(PyUnicode_Check(s)) {
s_bytes = PyUnicode_AsUTF8String(s);
s_c_bytes = PyBytes_AsString(s_bytes);
}
else s_c_bytes = PyBytes_AsString(s);
#else
char* s_c_bytes = PyString_AsString(s);
#endif
perl_require_pv(s_c_bytes);
#if PY_MAJOR_VERSION >= 3
Py_XDECREF(s_bytes);
#endif
Py_INCREF(Py_None);
return Py_None;
}
#ifdef CREATE_PERL
static void
create_perl()
{
int argc = 1;
char * const argv[] = {
"perl"
};
/* When we create a Perl interpreter from Python, we don't get to
* dynamically load Perl modules unless that Python is patched, since
* Python doesn't expose the LDGLOBAL flag, which is required. This
* problem doesn't exist the other way because Perl exposes this
* interface.
*
* For this reason I haven't bothered provided an xs_init function.
*/
my_perl = perl_alloc();
perl_construct(my_perl);
perl_parse(my_perl, NULL, argc, argv, NULL);
perl_run(my_perl);
}
#endif
PyObject *PyExc_Perl;
void
initperl(void){
PyObject *m, *d, *p;
#if PY_MAJOR_VERSION >= 3
PyObject *dummy1 = PyBytes_FromString(""),
*dummy2 = PyBytes_FromString("main");
#else
PyObject *dummy1 = PyString_FromString(""),
*dummy2 = PyString_FromString("main");
#endif
/* Initialize the type of the new type objects here; doing it here
* is required for portability to Windows without requiring C++. */
#if PY_MAJOR_VERSION >= 3
PerlPkg_type.ob_base.ob_base.ob_type = &PyType_Type;
PyType_Ready(&PerlPkg_type);
PerlObj_type.ob_base.ob_base.ob_type = &PyType_Type;
PyType_Ready(&PerlObj_type);
PerlSub_type.ob_base.ob_base.ob_type = &PyType_Type;
PyType_Ready(&PerlSub_type);
#else
PerlPkg_type.ob_type = &PyType_Type;
PerlObj_type.ob_type = &PyType_Type;
PerlSub_type.ob_type = &PyType_Type;
#endif
/* Create the module and add the functions */
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef perl_module = {
PyModuleDef_HEAD_INIT,
"perl",
"perl -- Access a Perl interpreter transparently",
-1, /* m_size */
perl_functions, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0 /* m_free */
};
m = PyModule_Create(&perl_module);
#else
m = Py_InitModule4("perl",
perl_functions,
"perl -- Access a Perl interpreter transparently",
(PyObject*)NULL,
PYTHON_API_VERSION);
#endif
/* Now replace the package 'perl' with the 'perl' object */
m = PyImport_AddModule("sys");
d = PyModule_GetDict(m);
d = PyDict_GetItemString(d, "modules");
p = newPerlPkg_object(dummy1, dummy2);
PyDict_SetItemString(d, "perl", p);
Py_DECREF(p);
#ifdef CREATE_PERL
create_perl();
#endif
PyExc_Perl = PyErr_NewException("perl.Exception", NULL, NULL);
Py_DECREF(dummy1);
Py_DECREF(dummy2);
}