blob: c99002e701d26772bf961e1a0354624072dcc681 [file] [log] [blame]
/*
** Copyright 2003-2004 The Apache Software Foundation
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef APREQ_XS_POSTPERL_H
#define APREQ_XS_POSTPERL_H
/* avoid namespace collisions from perl's XSUB.h */
#include "modperl_perl_unembed.h"
/* backward compatibility macros support */
#include "ppport.h"
/**
* @file apreq_xs_postperl.h
* @brief XS include file for making Cookie.so and Request.so
*
*/
/**
* @defgroup XS Perl
* @ingroup GLUE
* @{
*/
/**
* Trace through magic objects & hashrefs looking for original object.
* @param in The starting SV *.
* @param key The first letter of key is used to search a hashref for
* the desired object.
* @return The object, if found; otherwise NULL.
*/
APR_INLINE
static SV *apreq_xs_find_obj(pTHX_ SV *in, const char *key)
{
const char altkey[] = { '_', key[0] };
while (in && SvROK(in)) {
SV *sv = SvRV(in);
switch (SvTYPE(sv)) {
MAGIC *mg;
SV **svp;
case SVt_PVHV:
if (SvMAGICAL(sv) && (mg = mg_find(sv,PERL_MAGIC_tied))) {
in = mg->mg_obj;
break;
}
else if ((svp = hv_fetch((HV *)sv, key, 1, FALSE)) ||
(svp = hv_fetch((HV *)sv, altkey, 2, FALSE)))
{
in = *svp;
break;
}
Perl_croak(aTHX_ "attribute hash has no '%s' key!", key);
case SVt_PVMG:
if (SvOBJECT(sv) && SvIOKp(sv))
return sv;
default:
Perl_croak(aTHX_ "panic: unsupported SV type: %d", SvTYPE(sv));
}
}
return in;
}
/* conversion function templates based on modperl-2's sv2request_rec */
/**
* Searches a perl object ref with apreq_xs_find_obj
* and produces a pointer to the object's C analog.
*/
APR_INLINE
static void *apreq_xs_perl2c(pTHX_ SV* in, const char *name)
{
SV *sv = apreq_xs_find_obj(aTHX_ in, name);
if (sv == NULL)
return NULL;
else
return (void *)SvIVX(sv);
}
APR_INLINE
static SV *apreq_xs_perl_sv2env(pTHX_ SV *sv)
{
MAGIC *mg;
if ((mg = mg_find(sv, PERL_MAGIC_ext)))
return mg->mg_obj;
Perl_croak(aTHX_ "Can't find magic environment");
return NULL; /* not reached */
}
/**
* Searches a perl object ref with apreq_xs_find_obj
* and produces a pointer to the underlying C environment.
*/
/**
* Converts a C object, with environment, to a Perl object.
* @param obj C object.
* @param env C environment.
* @param class Class perl object will be blessed into.
* @param parent XXX
* @return Reference to the new Perl object in class.
*/
APR_INLINE
static SV *apreq_xs_c2perl(pTHX_ void *obj, void *env, const char *class, SV *parent)
{
SV *rv = sv_setref_pv(newSV(0), class, obj);
if (env) {
/* We use the old idiom for sv_magic() below,
* because perl 5.6 mangles the env pointer on
* the recommended 5.8.x invocation
*
* sv_magic(SvRV(rv), Nullsv, PERL_MAGIC_ext, env, 0);
*
* 5.8.x is OK with the old way as well, but in the future
* we may have to use "#if PERL_VERSION < 8" ...
*/
sv_magic(SvRV(rv), parent, PERL_MAGIC_ext, Nullch, -1);
SvMAGIC(SvRV(rv))->mg_ptr = env;
}
return rv;
}
#define apreq_xs_2sv(t,class,parent) \
apreq_xs_c2perl(aTHX_ t, env, class, parent)
#define apreq_xs_sv2(type,sv)((apreq_##type##_t *) \
apreq_xs_perl2c(aTHX_ sv, #type))
#define apreq_xs_sv2env(sv) ((void *)SvIVX((apreq_xs_perl_sv2env(aTHX_ sv))))
/** Converts apreq_env to a Perl package, which forms the
* base class for Apache::Request and Apache::Cookie::Jar objects.
*/
#define APREQ_XS_DEFINE_ENV(type) \
static XS(apreq_xs_##type##_env) \
{ \
char *class = NULL; \
dXSARGS; \
SV *sv, *obj; \
/* map environment to package */ \
if (items != 1) \
Perl_croak(aTHX_ "Usage: $obj->env"); \
\
if (strcmp(apreq_env_name, "APACHE2") == 0) \
class = "Apache::RequestRec"; \
else if (strcmp(apreq_env_name, "CGI") == 0) \
class = "APR::Pool"; \
\
/* else if ... add more conditionals here as \
additional environments become supported */ \
\
if (class == NULL) \
XSRETURN(0); \
\
XSprePUSH; \
if (SvROK(ST(0))) { \
obj = apreq_xs_find_obj(aTHX_ ST(0), #type); \
sv = apreq_xs_perl_sv2env(aTHX_ obj); \
XPUSHs(sv_2mortal(newRV_inc(sv))); \
} \
else \
XPUSHs(sv_2mortal(newSVpv(class, 0))); \
\
XSRETURN(1); \
}
#define APREQ_XS_DEFINE_CONFIG(attr) \
static XS(apreq_xs_##attr##_config) \
{ \
dXSARGS; \
SV *sv, *obj; \
int j; \
\
if (items % 2 != 1 || !SvROK(ST(0))) \
Perl_croak(aTHX_ "usage: $obj->config(%settings)"); \
\
sv = ST(0); \
obj = apreq_xs_find_obj(aTHX_ sv, #attr); \
\
for (j = 1; j + 1 < items; j += 2) { \
STRLEN alen; \
const char *attr = SvPVbyte(ST(j),alen); \
\
if (strcasecmp(attr,"VALUE_CLASS") == 0) \
{ \
STRLEN vlen; \
const char *val = SvPV(ST(j+1), vlen); \
MAGIC *mg = mg_find(obj, PERL_MAGIC_ext); \
\
if (mg->mg_len > 0) { \
Safefree(mg->mg_ptr); \
} \
mg->mg_ptr = savepvn(val, vlen); \
mg->mg_len = vlen; \
\
} \
else { \
Perl_warn(aTHX_ "$obj->config(%settings): " \
"Unrecognized attribute %s, skipped", attr); \
} \
} \
\
XSRETURN(0); \
}
/** requires definition of apreq_xs_##type##2sv(t,class,parent) macro */
#define APREQ_XS_DEFINE_MAKE(type) \
static XS(apreq_xs_make_##type) \
{ \
dXSARGS; \
void *env; \
apr_pool_t *pool; \
const char *key, *val, *class; \
STRLEN klen, vlen; \
apreq_##type##_t *t; \
\
if (items != 4 || SvROK(ST(0)) || !SvROK(ST(1))) \
Perl_croak(aTHX_ "Usage: $class->make($env, $name, $val)"); \
\
class = SvPV_nolen(ST(0)); \
env = (void *)SvIVX(SvRV(ST(1))); \
pool = apreq_env_pool(env); \
key = SvPVbyte(ST(2), klen); \
val = SvPVbyte(ST(3), vlen); \
t = apreq_make_##type(pool, key, klen, val, vlen); \
XSprePUSH; \
XPUSHs(sv_2mortal(apreq_xs_##type##2sv(t,class,SvRV(ST(1))))); \
XSRETURN(1); \
}
static APR_INLINE
void apreq_xs_croak(pTHX_ HV *data, apr_status_t rc, const char *func,
const char *class)
{
HV *stash = gv_stashpvn(class, strlen(class), FALSE);
sv_setsv(ERRSV, sv_2mortal(sv_bless(newRV_noinc((SV*)data), stash)));
sv_setiv(*hv_fetch(data, "rc", 2, 1), rc);
sv_setpv(*hv_fetch(data, "file", 4, 1), CopFILE(PL_curcop));
sv_setiv(*hv_fetch(data, "line", 4, 1), CopLINE(PL_curcop));
sv_setpv(*hv_fetch(data, "func", 4, 1), func);
Perl_croak(aTHX_ Nullch);
}
#define APREQ_XS_THROW_ERROR(attr, status, func, errpkg) do { \
if (!sv_derived_from(sv, errpkg)) { \
HV *hv = newHV(); \
SV *rv = newRV_inc(obj); \
sv_setsv(*hv_fetch(hv, "_" #attr, 2, 1), sv_2mortal(rv)); \
apreq_xs_croak(aTHX_ hv, status, func, errpkg); \
} \
} while (0)
/** @} */
#endif /* APREQ_XS_POSTPERL_H */