class PerlMethodCall { private: struct list { SV* item; struct list *next; }; struct list *args; struct list *args_tail; struct list *rets; struct list *rets_tail; I32 flags; public: PerlMethodCall() : args(NULL), args_tail(NULL), rets(NULL), rets_tail(NULL) { } ~PerlMethodCall() { finish(); } void finish() { SV* sv; while ((sv = shiftReturn())) SvREFCNT_dec(sv); while ((sv = shiftArgument())) SvREFCNT_dec(sv); } void pushReturn(SV *ret) { struct list *n = new struct list; n->item = newRV(ret); n->next = NULL; if (rets_tail) rets_tail->next = n; else if (rets) rets->next = n; else rets = n; rets_tail = n; } SV* shiftReturn() { SV* ret; struct list *frst; if (!rets) return NULL; frst = rets->next; ret = SvRV(rets->item); delete rets; rets = frst; if (!rets) rets_tail = NULL; return ret; } void pushArgument(SV *arg) { struct list *n = new struct list; n->item = newRV(arg); n->next = NULL; if (args_tail) args_tail->next = n; else if (args) args->next = n; else args = n; args_tail = n; } SV* shiftArgument() { SV* arg; struct list *frst; if (!args) return NULL; frst = args->next; arg = SvRV(args->item); delete args; args = frst; if (!args) args_tail = NULL; return arg; } void call(SV* object, const char* method_name, I32 flgs = G_SCALAR) { int i = 0; int return_count; SV* arg; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(object); while ((arg = shiftArgument())) XPUSHs(arg); PUTBACK; return_count = call_method(method_name, flgs); SPAGAIN; for (i = 0; i < return_count; ++i) pushReturn(POPs); PUTBACK; FREETMPS; LEAVE; } };