Medusa-XS
view release on metacpan or search on metacpan
lib/Medusa/XS.xs view on Meta::CPAN
# ------------------------------------------------------------------ #
# XSUB: Clean dumper output (legacy compat - passes through to Loo) #
# ------------------------------------------------------------------ #
SV *
clean_dumper(input)
SV *input
CODE:
/* Legacy: with Loo, dump output is already clean.
* This just returns the input for backward compatibility. */
RETVAL = newSVsv(input);
OUTPUT:
RETVAL
# ------------------------------------------------------------------ #
# XSUB: SV serializer via Loo #
# ------------------------------------------------------------------ #
SV *
dump_sv(value)
SV *value
PREINIT:
DDCStyle style;
HV *log_config;
HV *options = NULL;
int use_colour = 0;
const char *theme = NULL;
CODE:
/* Read colour settings from %LOG{OPTIONS} */
log_config = get_hv("Medusa::XS::LOG", 0);
if (log_config) {
SV **svp = hv_fetchs(log_config, "OPTIONS", 0);
if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVHV) {
options = (HV *)SvRV(*svp);
use_colour = medusa_resolve_colour(aTHX_ options);
theme = medusa_resolve_theme(aTHX_ options);
}
}
medusa_loo_style_init(aTHX_ &style, use_colour, theme);
RETVAL = medusa_dump_param(aTHX_ value, &style);
ddc_style_destroy(aTHX_ &style);
OUTPUT:
RETVAL
# ------------------------------------------------------------------ #
# XSUB: Wrap a subroutine with auditing #
# ------------------------------------------------------------------ #
void
wrap_sub(coderef, method_name = NULL)
SV *coderef
SV *method_name
PREINIT:
CV *cv;
CV *wrapper;
const char *method;
STRLEN method_len;
const char *pkg;
STRLEN pkg_len;
GV *gv;
PPCODE:
/* Get the CV from the coderef */
if (!SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) {
croak("wrap_sub: argument must be a code reference");
}
cv = (CV *)SvRV(coderef);
/* Get method name from CV or argument */
if (method_name && SvOK(method_name)) {
method = SvPV(method_name, method_len);
} else {
gv = CvGV(cv);
if (gv) {
method = GvNAME(gv);
method_len = GvNAMELEN(gv);
} else {
method = "__ANON__";
method_len = 8;
}
}
/* Get package name from CV */
gv = CvGV(cv);
if (gv && GvSTASH(gv)) {
pkg = HvNAME(GvSTASH(gv));
pkg_len = pkg ? strlen(pkg) : 0;
} else {
pkg = "main";
pkg_len = 4;
}
/* Inject the audit wrapper */
inject_audit_wrapper(aTHX_ cv, method, method_len, pkg, pkg_len);
/* Return the wrapped CV */
XPUSHs(coderef);
XSRETURN(1);
bool
is_audited(coderef)
SV *coderef
PREINIT:
CV *cv;
CODE:
if (!SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) {
RETVAL = FALSE;
} else {
cv = (CV *)SvRV(coderef);
RETVAL = CV_IS_AUDITED(cv) ? TRUE : FALSE;
}
OUTPUT:
RETVAL
SV *
_make_test_audit_op(method, package)
const char *method
const char *package
CODE:
/* Legacy test hook â AUDITOP struct removed, return confirmation */
RETVAL = newSVpvf("AUDIT_CACHE@%s::%s", package, method);
OUTPUT:
RETVAL
# ------------------------------------------------------------------ #
# XSUB: _apply_deferred_wraps - Re-install wrappers queued on 5.10 #
# ------------------------------------------------------------------ #
void
_apply_deferred_wraps()
PPCODE:
medusa_check_apply_wraps(aTHX_ NULL);
XSRETURN(0);
# ------------------------------------------------------------------ #
# XSUB: log_message - Full XS logging implementation #
# ------------------------------------------------------------------ #
void
log_message(...)
PREINIT:
HV *params;
int i;
PPCODE:
/* Build params hash from @_ */
if (items % 2 != 0) {
croak("log_message: odd number of arguments");
}
params = newHV();
for (i = 0; i < items; i += 2) {
SV *key = ST(i);
SV *val = ST(i+1);
STRLEN len;
const char *k = SvPV(key, len);
hv_store(params, k, len, SvREFCNT_inc(val), 0);
}
medusa_xs_log_message(aTHX_ params);
SvREFCNT_dec((SV *)params);
XSRETURN(0);
# ------------------------------------------------------------------ #
# XSUB: xs_format_message - XS default FORMAT_MESSAGE #
# ------------------------------------------------------------------ #
SV *
xs_format_message(...)
PREINIT:
HV *params;
HV *log_config;
int i;
CODE:
/* Build params hash from @_ */
if (items % 2 != 0) {
croak("xs_format_message: odd number of arguments");
}
params = newHV();
for (i = 0; i < items; i += 2) {
SV *key = ST(i);
SV *val = ST(i+1);
STRLEN len;
const char *k = SvPV(key, len);
hv_store(params, k, len, SvREFCNT_inc(val), 0);
}
log_config = get_hv("Medusa::XS::LOG", 0);
if (!log_config) {
log_config = newHV();
}
RETVAL = medusa_xs_format_message(aTHX_ params, log_config);
SvREFCNT_dec((SV *)params);
OUTPUT:
RETVAL
# ------------------------------------------------------------------ #
# XSUB: init_logger - Initialize the logger from LOG_INIT #
# ------------------------------------------------------------------ #
void
init_logger()
PREINIT:
HV *log_config;
SV **svp;
PPCODE:
log_config = get_hv("Medusa::XS::LOG", 0);
if (!log_config) {
XSRETURN(0);
}
/* Check if LOG already initialized */
svp = hv_fetchs(log_config, "LOG", 0);
if (svp && SvROK(*svp)) {
XSRETURN(0);
}
/* Call LOG_INIT */
svp = hv_fetchs(log_config, "LOG_INIT", 0);
if (svp && SvROK(*svp)) {
dSP;
SV *log_obj;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
PUTBACK;
count = call_sv(*svp, G_SCALAR);
SPAGAIN;
if (count >= 1) {
log_obj = POPs;
if (SvROK(log_obj)) {
hv_stores(log_config, "LOG", SvREFCNT_inc(log_obj));
}
}
PUTBACK;
FREETMPS;
LEAVE;
}
XSRETURN(0);
# ------------------------------------------------------------------ #
# XSUB: import - Set up calling package to use Medusa::XS #
# ------------------------------------------------------------------ #
void
import(...)
PREINIT:
HV *log_config;
const char *caller_pkg;
HV *caller_stash;
AV *isa;
GV *isa_gv;
int i;
PPCODE:
/* Check for odd number of args (after class name) */
if ((items - 1) % 2 != 0) {
croak("odd number of params passed in import");
}
/* Get caller package */
caller_pkg = CopSTASHPV(PL_curcop);
if (!caller_pkg) caller_pkg = "main";
/* Push Medusa::XS onto caller's @ISA */
caller_stash = gv_stashpv(caller_pkg, GV_ADD);
isa_gv = gv_fetchpvn_flags("ISA", 3, GV_ADD, SVt_PVAV);
if (caller_stash) {
GV *pkg_isa = gv_fetchmethod_autoload(caller_stash, "ISA", FALSE);
SV *isa_name = newSVpvf("%s::ISA", caller_pkg);
AV *isa_av = get_av(SvPV_nolen(isa_name), GV_ADD);
SvREFCNT_dec(isa_name);
av_push(isa_av, newSVpvs("Medusa::XS"));
}
/* Process key=value pairs into %LOG (make copies of values) */
log_config = get_hv("Medusa::XS::LOG", GV_ADD);
for (i = 1; i < items; i += 2) {
SV *key = ST(i);
SV *val = ST(i + 1);
STRLEN klen;
const char *kstr = SvPV(key, klen);
/* Use newSVsv to copy - stack values may be read-only */
hv_store(log_config, kstr, klen, newSVsv(val), 0);
}
XSRETURN(0);
# ------------------------------------------------------------------ #
# XSUB: MODIFY_CODE_ATTRIBUTES - Handle :Audit attribute #
# ------------------------------------------------------------------ #
void
MODIFY_CODE_ATTRIBUTES(pkg, coderef, ...)
SV *pkg
SV *coderef
PREINIT:
CV *cv;
GV *gv;
const char *method_name = "__ANON__";
STRLEN method_len = 8;
const char *pkg_name;
STRLEN pkg_len;
HV *audited;
int i;
bool found_audit = FALSE;
PPCODE:
/* Check if any attribute is "Audit" */
for (i = 2; i < items; i++) {
STRLEN len;
const char *attr = SvPV(ST(i), len);
if (len >= 5 && strncmp(attr, "Audit", 5) == 0) {
found_audit = TRUE;
break;
}
}
if (!found_audit) {
/* Return remaining attributes (none handled) */
for (i = 2; i < items; i++) {
XPUSHs(ST(i));
}
XSRETURN(items - 2);
}
/* Get the CV */
if (!SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) {
croak("MODIFY_CODE_ATTRIBUTES: not a code reference");
}
cv = (CV *)SvRV(coderef);
/* Initialize logger */
{
dSP;
PUSHMARK(SP);
PUTBACK;
call_pv("Medusa::XS::init_logger", G_DISCARD);
}
/* Get method name from CV's GV */
gv = CvGV(cv);
if (gv) {
method_name = GvNAME(gv);
method_len = GvNAMELEN(gv);
}
/* Get package name */
pkg_name = SvPV(pkg, pkg_len);
/* Track in %AUDITED */
audited = get_hv("Medusa::XS::AUDITED", GV_ADD);
{
char addr_key[32];
int addr_len = snprintf(addr_key, sizeof(addr_key), "%lu",
(unsigned long)PTR2UV(cv));
hv_store(audited, addr_key, addr_len, newSViv(1), 0);
}
/* Wrap the sub with XS auditing */
inject_audit_wrapper(aTHX_ cv, method_name, method_len,
pkg_name, pkg_len);
/* Return empty list (we handled Audit, no unhandled attrs) */
XSRETURN(0);
# ------------------------------------------------------------------ #
# XSUB: FETCH_CODE_ATTRIBUTES - Report attributes on a coderef #
# ------------------------------------------------------------------ #
void
FETCH_CODE_ATTRIBUTES(pkg, coderef)
SV *pkg
SV *coderef
PREINIT:
CV *cv;
HV *audited;
bool is_audited_cv = FALSE;
PPCODE:
PERL_UNUSED_VAR(pkg);
if (!SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) {
XSRETURN(0);
}
cv = (CV *)SvRV(coderef);
/* Check %AUDITED hash */
audited = get_hv("Medusa::XS::AUDITED", 0);
if (audited) {
char addr_key[32];
int addr_len = snprintf(addr_key, sizeof(addr_key), "%lu",
(unsigned long)PTR2UV(cv));
if (hv_exists(audited, addr_key, addr_len)) {
is_audited_cv = TRUE;
}
}
/* Check XS magic */
if (!is_audited_cv && CV_IS_AUDITED(cv)) {
is_audited_cv = TRUE;
}
if (is_audited_cv) {
XPUSHs(sv_2mortal(newSVpvs("Audit")));
XSRETURN(1);
}
XSRETURN(0);
# ================================================================== #
# Medusa::XS::Logger â Pure XS file logger with flock #
# ================================================================== #
MODULE = Medusa::XS PACKAGE = Medusa::XS::Logger
SV *
new(pkg, ...)
const char *pkg
PREINIT:
MedusaLogger *logger;
SV *self_rv;
SV *self_sv;
const char *filename = "audit.log";
STRLEN filename_len;
HV *args;
SV **svp;
I32 i;
CODE:
/* Parse args: new(file => 'x') or new({file => 'x'}) */
if (items == 2 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVHV) {
args = (HV *)SvRV(ST(1));
} else if (items > 1 && (items - 1) % 2 == 0) {
args = newHV();
sv_2mortal((SV *)args);
for (i = 1; i < items; i += 2) {
const char *key;
STRLEN klen;
key = SvPV(ST(i), klen);
(void)hv_store(args, key, klen, SvREFCNT_inc(ST(i+1)), 0);
( run in 0.626 second using v1.01-cache-2.11-cpan-5511b514fd6 )