MP_STATIC XS(XS_APR__Request__Param_nil)
{
dXSARGS;
(void)items;
XSRETURN_EMPTY;
}
APR_INLINE
static SV *apreq_xs_find_bb_obj(pTHX_ SV *in)
{
while (in && SvROK(in)) {
SV *sv = SvRV(in);
switch (SvTYPE(sv)) {
MAGIC *mg;
case SVt_PVIO:
if (SvMAGICAL(sv) && (mg = mg_find(sv, PERL_MAGIC_tiedscalar))) {
in = mg->mg_obj;
break;
}
Perl_croak(aTHX_ "panic: cannot find tied scalar in pvio magic");
case SVt_PVMG:
if (SvOBJECT(sv) && SvIOKp(sv))
return sv;
default:
Perl_croak(aTHX_ "panic: unsupported SV type: %d", SvTYPE(sv));
}
}
return in;
}
/* XXX these Apache::Upload::Brigade funcs need a makeover as vanilla XS. */
MP_STATIC XS(apreq_xs_brigade_copy)
{
dXSARGS;
apr_bucket_brigade *bb, *bb_copy;
char *class;
SV *sv, *obj;
IV iv;
if (items != 2 || !SvPOK(ST(0)) || !SvROK(ST(1)))
Perl_croak(aTHX_ "Usage: APR::Request::Brigade->new($bb)");
class = SvPV_nolen(ST(0));
obj = apreq_xs_find_bb_obj(aTHX_ ST(1));
iv = SvIVX(obj);
bb = INT2PTR(apr_bucket_brigade *, iv);
bb_copy = apr_brigade_create(bb->p, bb->bucket_alloc);
apreq_brigade_copy(bb_copy, bb);
sv = sv_setref_pv(newSV(0), class, bb_copy);
if (SvTAINTED(obj))
SvTAINTED_on(SvRV(sv));
ST(0) = sv_2mortal(sv);
XSRETURN(1);
}
MP_STATIC XS(apreq_xs_brigade_read)
{
dXSARGS;
apr_bucket_brigade *bb;
apr_bucket *e, *end;
IV want = -1, offset = 0;
SV *sv, *obj;
apr_status_t s;
char *buf;
switch (items) {
case 4:
offset = SvIV(ST(3));
case 3:
want = SvIV(ST(2));
case 2:
sv = ST(1);
(void)SvUPGRADE(sv, SVt_PV);
if (SvROK(ST(0))) {
IV iv;
obj = apreq_xs_find_bb_obj(aTHX_ ST(0));
iv = SvIVX(obj);
bb = INT2PTR(apr_bucket_brigade *, iv);
break;
}
default:
Perl_croak(aTHX_ "Usage: $bb->READ($buf,$len,$off)");
}
if (want == 0) {
SvCUR_set(sv, offset);
XSRETURN_IV(0);
}
if (APR_BRIGADE_EMPTY(bb)) {
SvCUR_set(sv, offset);
XSRETURN_UNDEF;
}
if (want == -1) {
const char *data;
apr_size_t dlen;
e = APR_BRIGADE_FIRST(bb);
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
apreq_xs_croak(aTHX_ newHV(), Nullsv, s,
"APR::Request::Brigade::READ",
"APR::Error");
want = dlen;
end = APR_BUCKET_NEXT(e);
}
else {
switch (s = apr_brigade_partition(bb, (apr_off_t)want, &end)) {
apr_off_t len;
case APR_INCOMPLETE:
s = apr_brigade_length(bb, 1, &len);
if (s != APR_SUCCESS)
apreq_xs_croak(aTHX_ newHV(), Nullsv, s,
"APR::Request::Brigade::READ",
"APR::Error");
want = len;
case APR_SUCCESS:
break;
default:
apreq_xs_croak(aTHX_ newHV(), Nullsv, s,
"APR::Request::Brigade::READ",
"APR::Error");
}
}
SvGROW(sv, want + offset + 1);
buf = SvPVX(sv) + offset;
SvCUR_set(sv, want + offset);
if (SvTAINTED(obj))
SvTAINTED_on(sv);
while ((e = APR_BRIGADE_FIRST(bb)) != end) {
const char *data;
apr_size_t dlen;
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
apreq_xs_croak(aTHX_ newHV(), Nullsv, s,
"APR::Request::Brigade::READ",
"APR::Error");
memcpy(buf, data, dlen);
buf += dlen;
apr_bucket_delete(e);
}
*buf = 0;
SvPOK_only(sv);
SvSETMAGIC(sv);
XSRETURN_IV(want);
}
MP_STATIC XS(apreq_xs_brigade_readline)
{
dXSARGS;
apr_bucket_brigade *bb;
apr_bucket *e;
SV *sv, *obj;
IV iv;
apr_status_t s;
unsigned tainted;
if (items != 1 || !SvROK(ST(0)))
Perl_croak(aTHX_ "Usage: $bb->READLINE");
obj = apreq_xs_find_bb_obj(aTHX_ ST(0));
iv = SvIVX(obj);
bb = INT2PTR(apr_bucket_brigade *, iv);
if (APR_BRIGADE_EMPTY(bb))
XSRETURN(0);
tainted = SvTAINTED(obj);
XSprePUSH;
sv = sv_2mortal(newSVpvn("",0));
if (tainted)
SvTAINTED_on(sv);
XPUSHs(sv);
while (!APR_BRIGADE_EMPTY(bb)) {
const char *data;
apr_size_t dlen;
const char *eol;
e = APR_BRIGADE_FIRST(bb);
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
apreq_xs_croak(aTHX_ newHV(), Nullsv, s,
"APR::Request::Brigade::READLINE",
"APR::Error");
eol = memchr(data, '\012', dlen); /* look for LF (linefeed) */
if (eol != NULL) {
if (eol < data + dlen - 1) {
dlen = eol - data + 1;
apr_bucket_split(e, dlen);
}
sv_catpvn(sv, data, dlen);
apr_bucket_delete(e);
if (GIMME_V != G_ARRAY || APR_BRIGADE_EMPTY(bb))
break;
sv = sv_2mortal(newSVpvn("",0));
if (tainted)
SvTAINTED_on(sv);
XPUSHs(sv);
}
else {
sv_catpvn(sv, data, dlen);
apr_bucket_delete(e);
}
}
PUTBACK;
}