/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* This file must not contain any symbols from apache/mod_perl (apr * and perl are OK). Also try to keep all the mod_perl specific * functions (even if they don't contain symbols from apache/mod_perl * on in modperl_util.c, unless we want them elsewhere. That is * needed in order to keep the libraries used outside mod_perl * small */ #include "modperl_common_util.h" /* Prefetch magic requires perl 5.8 */ #if MP_PERL_VERSION_AT_LEAST(5, 8, 0) /* A custom MGVTBL with mg_copy slot filled in allows us to FETCH a * table entry immediately during iteration. For multivalued keys * this is essential in order to get the value corresponding to the * current key, otherwise values() will always report the first value * repeatedly. With this MGVTBL the keys() list always matches up * with the values() list, even in the multivalued case. We only * prefetch the value during iteration, because the prefetch adds * overhead (an unnecessary FETCH call) to EXISTS and STORE * operations. This way they are only "penalized" when the perl * program is iterating via each(), which seems to be a reasonable * tradeoff. */ MP_INLINE static int modperl_table_magic_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *name, int namelen) { /* prefetch the value whenever we're iterating over the keys */ MAGIC *tie_magic = mg_find(nsv, PERL_MAGIC_tiedelem); SV *obj = SvRV(tie_magic->mg_obj); if (SvCUR(obj)) { SvGETMAGIC(nsv); } return 0; } static const MGVTBL modperl_table_magic_prefetch = {0, 0, 0, 0, 0, modperl_table_magic_copy}; #endif /* End of prefetch magic */ MP_INLINE SV *modperl_hash_tie(pTHX_ const char *classname, SV *tsv, void *p) { SV *hv = (SV*)newHV(); SV *rsv = sv_newmortal(); sv_setref_pv(rsv, classname, p); /* Prefetch magic requires perl 5.8 */ #if MP_PERL_VERSION_AT_LEAST(5, 8, 0) sv_magicext(hv, NULL, PERL_MAGIC_ext, NULL, Nullch, -1); SvMAGIC(hv)->mg_virtual = (MGVTBL *)&modperl_table_magic_prefetch; SvMAGIC(hv)->mg_flags |= MGf_COPY; #endif /* End of prefetch magic */ sv_magic(hv, rsv, PERL_MAGIC_tied, Nullch, 0); return SvREFCNT_inc(sv_bless(sv_2mortal(newRV_noinc(hv)), gv_stashpv(classname, TRUE))); } MP_INLINE SV *modperl_hash_tied_object_rv(pTHX_ const char *classname, SV *tsv) { if (sv_derived_from(tsv, classname)) { if (SVt_PVHV == SvTYPE(SvRV(tsv))) { SV *hv = SvRV(tsv); MAGIC *mg; if (SvMAGICAL(hv)) { if ((mg = mg_find(hv, PERL_MAGIC_tied))) { return mg->mg_obj; } else { Perl_warn(aTHX_ "Not a tied hash: (magic=%c)", mg->mg_type); } } else { Perl_warn(aTHX_ "SV is not tied"); } } else { return tsv; } } else { Perl_croak(aTHX_ "argument is not a blessed reference " "(expecting an %s derived object)", classname); } return &PL_sv_undef; } MP_INLINE void *modperl_hash_tied_object(pTHX_ const char *classname, SV *tsv) { SV *rv = modperl_hash_tied_object_rv(aTHX_ classname, tsv); if (SvROK(rv)) { return INT2PTR(void *, SvIVX(SvRV(rv))); } else { return NULL; } } /* same as Symbol::gensym() */ SV *modperl_perl_gensym(pTHX_ char *pack) { GV *gv = newGVgen(pack); SV *rv = newRV((SV*)gv); (void)hv_delete(gv_stashpv(pack, TRUE), GvNAME(gv), GvNAMELEN(gv), G_DISCARD); return rv; } /* XXX: sv_setref_uv does not exist in 5.6.x */ MP_INLINE SV *modperl_perl_sv_setref_uv(pTHX_ SV *rv, const char *classname, UV uv) { sv_setuv(newSVrv(rv, classname), uv); return rv; } MP_INLINE modperl_uri_t *modperl_uri_new(apr_pool_t *p) { modperl_uri_t *uri = (modperl_uri_t *)apr_pcalloc(p, sizeof(*uri)); uri->pool = p; return uri; }