Eshu
view release on metacpan or search on metacpan
include/eshu_xs.h view on Meta::CPAN
static int eshu_xs_is_module_line(const char *content, const char *eol) {
const char *p = content;
if (eol - p < 8) return 0;
if (memcmp(p, "MODULE", 6) != 0) return 0;
p += 6;
while (p < eol && (*p == ' ' || *p == '\t')) p++;
return (p < eol && *p == '=');
}
/* XS labels: CODE, INIT, OUTPUT, PREINIT, CLEANUP, POSTCALL,
* PPCODE, BOOT, CASE, INTERFACE, INTERFACE_MACRO, PROTOTYPES,
* VERSIONCHECK, INCLUDE, FALLBACK, OVERLOAD, ALIAS, ATTRS */
static int eshu_xs_is_label(const char *content, const char *eol,
int *is_boot) {
const char *p = content;
const char *start;
int len;
*is_boot = 0;
/* must start with alpha */
include/eshu_xs.h view on Meta::CPAN
/* it also must not be a :: (package separator) */
if (p + 1 < eol && *(p + 1) == ':') return 0;
/* Known XS labels */
if ((len == 4 && memcmp(start, "CODE", 4) == 0) ||
(len == 4 && memcmp(start, "INIT", 4) == 0) ||
(len == 6 && memcmp(start, "OUTPUT", 6) == 0) ||
(len == 7 && memcmp(start, "PREINIT", 7) == 0) ||
(len == 7 && memcmp(start, "CLEANUP", 7) == 0) ||
(len == 8 && memcmp(start, "POSTCALL", 8) == 0) ||
(len == 6 && memcmp(start, "PPCODE", 6) == 0) ||
(len == 4 && memcmp(start, "CASE", 4) == 0) ||
(len == 9 && memcmp(start, "INTERFACE", 9) == 0) ||
(len == 15 && memcmp(start, "INTERFACE_MACRO", 15) == 0) ||
(len == 10 && memcmp(start, "PROTOTYPES", 10) == 0) ||
(len == 12 && memcmp(start, "VERSIONCHECK", 12) == 0) ||
(len == 7 && memcmp(start, "INCLUDE", 7) == 0) ||
(len == 8 && memcmp(start, "FALLBACK", 8) == 0) ||
(len == 8 && memcmp(start, "OVERLOAD", 8) == 0) ||
(len == 5 && memcmp(start, "ALIAS", 5) == 0) ||
(len == 5 && memcmp(start, "ATTRS", 5) == 0)) {
t/0022-xs-labels.t view on Meta::CPAN
OUTPUT:
RETVAL
CLEANUP:
free(val);
END
my $got = Eshu->indent_xs($input);
is($got, $expected, 'CLEANUP label at depth 1');
}
# PPCODE label
{
my $input = <<'END';
MODULE = Foo PACKAGE = Foo
void
get_pair()
PPCODE:
XPUSHs(sv_2mortal(newSViv(1)));
XPUSHs(sv_2mortal(newSViv(2)));
XSRETURN(2);
END
my $expected = <<'END';
MODULE = Foo PACKAGE = Foo
void
get_pair()
PPCODE:
XPUSHs(sv_2mortal(newSViv(1)));
XPUSHs(sv_2mortal(newSViv(2)));
XSRETURN(2);
END
my $got = Eshu->indent_xs($input);
is($got, $expected, 'PPCODE label at depth 1');
}
# INIT label (inside XSUB, not the Perl INIT{} block)
{
my $input = <<'END';
MODULE = Foo PACKAGE = Foo
int
sum(a, b)
int a
t/0026-xs-advanced.t view on Meta::CPAN
}
RETVAL = count;
OUTPUT:
RETVAL
END
my $got = Eshu->indent_xs($input);
is($got, $expected, 'XSUB with nested C control flow in CODE');
}
# XSUB with PPCODE (list context)
{
my $input = <<'END';
MODULE = Foo PACKAGE = Foo
void
get_pair(self)
SV * self
PPCODE:
XPUSHs(sv_2mortal(newSVpvs("key")));
XPUSHs(sv_2mortal(newSViv(42)));
END
my $expected = <<'END';
MODULE = Foo PACKAGE = Foo
void
get_pair(self)
SV * self
PPCODE:
XPUSHs(sv_2mortal(newSVpvs("key")));
XPUSHs(sv_2mortal(newSViv(42)));
END
my $got = Eshu->indent_xs($input);
is($got, $expected, 'XSUB with PPCODE for list context');
}
done_testing();
t/0242-realworld-xs.t view on Meta::CPAN
size_t n = fread(buf, 1, len, fh);
buf[n] = '\0';
RETVAL = newSVpvn(buf, n);
free(buf);
OUTPUT:
RETVAL
END
is(xs($code), $code, 'XS: XSUB with INIT guard');
}
# 6. PPCODE XSUB returning list
{
my $code = <<'END';
MODULE = ListOps PACKAGE = ListOps
void
range(from, to)
int from
int to
PPCODE:
for (int i = from; i <= to; i++) {
XPUSHs(sv_2mortal(newSViv(i)));
}
END
is(xs($code), $code, 'XS: PPCODE returning list');
}
# 7. XSUB with C helper function
{
my $code = <<'END';
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
static unsigned long
t/0242-realworld-xs.t view on Meta::CPAN
}
# 13. XSUB with SV mortal
{
my $code = <<'END';
MODULE = Fmt PACKAGE = Fmt
void
print_pairs(href)
SV *href
PPCODE:
HV *hv = (HV *)SvRV(href);
HE *he;
hv_iterinit(hv);
while ((he = hv_iternext(hv)) != NULL) {
SV *key = hv_iterkeysv(he);
SV *val = hv_iterval(hv, he);
XPUSHs(sv_2mortal(newSVpvf("%s=%s",
SvPVutf8_nolen(key), SvPVutf8_nolen(val))));
}
END
is(xs($code), $code, 'XS: PPCODE iterating hash ref');
}
# 14. XSUB with typemap
{
my $code = <<'END';
MODULE = File PACKAGE = File
FILE *
fopen_wrap(path, mode)
const char *path
t/0242-realworld-xs.t view on Meta::CPAN
SV **svp = av_fetch(in, i, 0);
av_push(out, svp ? SvREFCNT_inc(*svp) : newSV(0));
}
RETVAL = newRV_noinc((SV *)out);
OUTPUT:
RETVAL
END
is(xs($code), $code, 'XS: reverse array ref');
}
# 24. XSUB with multiple return values via PPCODE
{
my $code = <<'END';
MODULE = Math2 PACKAGE = Math2
void
divmod(a, b)
IV a
IV b
PPCODE:
if (b == 0)
Perl_croak(aTHX_ "division by zero");
EXTEND(SP, 2);
PUSHs(sv_2mortal(newSViv(a / b)));
PUSHs(sv_2mortal(newSViv(a % b)));
END
is(xs($code), $code, 'XS: divmod via PPCODE');
}
# 25. XS constant sub
{
my $code = <<'END';
MODULE = Const PACKAGE = Const
IV
PI_TIMES_1000()
CODE:
t/0242-realworld-xs.t view on Meta::CPAN
# 30
{
my $in = <<'END';
MODULE = T PACKAGE = T
void
each(aref, cb)
SV *aref
SV *cb
PPCODE:
AV *av = (AV *)SvRV(aref);
for (SSize_t i = 0; i <= av_len(av); i++) {
SV **svp = av_fetch(av, i, 0);
dSP; ENTER; SAVETMPS; PUSHMARK(SP);
XPUSHs(svp ? *svp : &PL_sv_undef);
PUTBACK; call_sv(cb, G_VOID|G_DISCARD);
FREETMPS; LEAVE;
}
END
my $exp = <<'END';
MODULE = T PACKAGE = T
void
each(aref, cb)
SV *aref
SV *cb
PPCODE:
AV *av = (AV *)SvRV(aref);
for (SSize_t i = 0; i <= av_len(av); i++) {
SV **svp = av_fetch(av, i, 0);
dSP; ENTER; SAVETMPS; PUSHMARK(SP);
XPUSHs(svp ? *svp : &PL_sv_undef);
PUTBACK; call_sv(cb, G_VOID|G_DISCARD);
FREETMPS; LEAVE;
}
END
is(xs($in), $exp, 'XS: unindented PPCODE with loop normalised');
}
# ââ idempotency tests ââââââââââââââââââââââââââââââââââââââââââââââ
for my $snippet (
"MODULE = T PACKAGE = T\n\nint\nadd(a,b)\nint a\nint b\nCODE:\nRETVAL=a+b;\nOUTPUT:\nRETVAL\n",
"MODULE = T PACKAGE = T\n\nvoid\nnoop()\nCODE:\n/* nothing */\n",
"#include \"EXTERN.h\"\n#include \"perl.h\"\n#include \"XSUB.h\"\nMODULE=T PACKAGE=T\nBOOT:\nSV*v=get_sv(\"T::VERSION\",GV_ADD);sv_setpvs(v,\"1.0\");\n",
"MODULE=T PACKAGE=T\nSV*\nhex_sv(n)\nUV n\nCODE:\nchar b[32];snprintf(b,sizeof(b),\"0x%llx\",(ull)n);RETVAL=newSVpv(b,0);\nOUTPUT:\nRETVAL\n",
"MODULE=T PACKAGE=T\nvoid\nfree_ptr(p)\nSV*p\nCODE:\nfree((void*)SvIV(p));\n",
( run in 1.166 second using v1.01-cache-2.11-cpan-4e7a2411597 )