// With gcc: GNU-C99 is OK if string.h comes first, but plain C99 isn’t.
#include "xshelper.h"
#include <string.h>
#define _CROAK_STRINGIFY_REFERENCE(sv) \
croak("%" SVf " given where string expected!", sv)
SV* _MY_xsh_ptr_to_svrv (pTHX_ void* ptr, HV* stash) {
SV* referent = newSVuv( PTR2UV(ptr) );
SV* retval = newRV_noinc(referent);
sv_bless(retval, stash);
return retval;
}
/* ---------------------------------------------------------------------- */
bool xsh_sv_streq (pTHX_ SV* sv, const char* b) {
if (SvROK(sv)) _CROAK_STRINGIFY_REFERENCE(sv);
if (SvOK(sv)) {
STRLEN alen;
const char* a = SvPVbyte(sv, alen);
if (NULL != memchr(a, '\0', alen)) {
return strEQ(a, b);
}
}
return false;
}
char* _MY_xsh_sv_to_str (pTHX_ SV* sv, bool is_utf8) {
if (SvROK(sv)) _CROAK_STRINGIFY_REFERENCE(sv);
char *str = is_utf8 ? SvPVutf8_nolen(sv) : SvPVbyte_nolen(sv);
size_t len = strnlen(str, 1 + SvCUR(sv));
if (len != SvCUR(sv)) {
croak("Cannot convert scalar to C string (NUL byte detected, offset %zu)", len);
}
return str;
}
UV _MY_xsh_sv_to_uv (pTHX_ SV* sv) {
if (SvROK(sv)) _CROAK_STRINGIFY_REFERENCE(sv);
if (SvUOK(sv)) return SvUV(sv);
UV myuv = SvUV(sv);
SV* sv2 = newSVuv(myuv);
if (sv_eq(sv, sv2)) return myuv;
croak("`%" SVf "` given where unsigned integer expected!", sv);
}
IV _MY_xsh_sv_to_iv (pTHX_ SV* sv) {
if (SvROK(sv)) _CROAK_STRINGIFY_REFERENCE(sv);
if (SvIOK(sv)) return SvIV(sv);
IV myiv = SvIV(sv);
SV* sv2 = newSViv(myiv);
if (sv_eq(sv, sv2)) return myiv;
croak("`%" SVf "` given where integer expected!", sv);
}
/* ---------------------------------------------------------------------- */
#define _SET_ARGS(object, args) { \
unsigned argscount = 0; \
\
if (args) { \
while (args[argscount] != NULL) { \
argscount++; \
} \
} \
\
ENTER; \
SAVETMPS; \
\
PUSHMARK(SP); \
\
EXTEND(SP, 1 + argscount); \
\
if (object) PUSHs( sv_mortalcopy(object) ); \
\
unsigned a=0; \
while (a < argscount) mPUSHs( args[a++] ); \
\
PUTBACK; \
}
void xsh_call_object_method_void (pTHX_ SV* object, const char* methname, SV** args) {
dSP;
_SET_ARGS(object, args);
call_method( methname, G_DISCARD | G_VOID );
FREETMPS;
LEAVE;
}
SV* xsh_call_object_method_scalar (pTHX_ SV* object, const char* methname, SV** args) {
dSP;
_SET_ARGS(object, args);
int got = call_method( methname, G_SCALAR );
SPAGAIN;
assert(got < 2);
SV* ret = got ? SvREFCNT_inc(POPs) : NULL;
PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
void _MY_xsh_call_sv_trap_void (pTHX_ SV* cbref, SV** args, const char *warnprefix) {
dSP;
_SET_ARGS(NULL, args);
call_sv(cbref, G_VOID|G_DISCARD|G_EVAL);
SV* err = ERRSV;
if (err && SvTRUE(err)) {
warn("%s%" SVf, warnprefix, err);
}
FREETMPS;
LEAVE;
}