blob: 2350e31fb42d5aacfd575323f693a558d124cdf0 [file] [log] [blame]
/* 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.
*/
#define mpxs_Apache2__Directive_conftree() ap_conftree
/* XXX: this is only useful for <Perl> at the moment */
static MP_INLINE SV *mpxs_Apache2__Directive_as_string(pTHX_
ap_directive_t *self)
{
ap_directive_t *d;
SV *sv = newSVpv("", 0);
for (d = self->first_child; d; d = d->next) {
sv_catpv(sv, d->directive);
sv_catpv(sv, " ");
sv_catpv(sv, d->args);
sv_catpv(sv, "\n");
}
return sv;
}
/* Adds an entry to a hash, vivifying hash/array for multiple entries */
static void hash_insert(pTHX_ HV *hash, const char *key,
int keylen, const char *args,
int argslen, SV *value)
{
HV *subhash;
AV *args_array;
SV **hash_ent = hv_fetch(hash, key, keylen, 0);
if (value) {
if (!hash_ent) {
subhash = newHV();
(void)hv_store(hash, key, keylen, newRV_noinc((SV *)subhash), 0);
}
else {
subhash = (HV *)SvRV(*hash_ent);
}
(void)hv_store(subhash, args, argslen, value, 0);
}
else {
if (hash_ent) {
if (SvROK(*hash_ent) && (SVt_PVAV == SvTYPE(SvRV(*hash_ent)))) {
args_array = (AV *)SvRV(*hash_ent);
}
else {
args_array = newAV();
av_push(args_array, newSVsv(*hash_ent));
(void)hv_store(hash, key, keylen,
newRV_noinc((SV *)args_array), 0);
}
av_push(args_array, newSVpv(args, argslen));
}
else {
(void)hv_store(hash, key, keylen, newSVpv(args, argslen), 0);
}
}
}
static MP_INLINE SV *mpxs_Apache2__Directive_as_hash(pTHX_
ap_directive_t *tree)
{
const char *directive;
int directive_len;
const char *args;
int args_len;
HV *hash = newHV();
SV *subtree;
while (tree) {
directive = tree->directive;
directive_len = strlen(directive);
args = tree->args;
args_len = strlen(args);
if (tree->first_child) {
/* Skip the prefix '<' */
if ('<' == directive[0]) {
directive++;
directive_len--;
}
/* Skip the postfix '>' */
if ('>' == args[args_len-1]) {
args_len--;
}
subtree = mpxs_Apache2__Directive_as_hash(aTHX_ tree->first_child);
hash_insert(aTHX_ hash, directive, directive_len,
args, args_len, subtree);
}
else {
hash_insert(aTHX_ hash, directive, directive_len,
args, args_len, (SV *)NULL);
}
tree = tree->next;
}
return newRV_noinc((SV *)hash);
}
MP_STATIC XS(MPXS_Apache2__Directive_lookup)
{
dXSARGS;
if (items < 2 || items > 3) {
Perl_croak(aTHX_
"Usage: Apache2::Directive::lookup(self, key, [args])");
}
mpxs_PPCODE({
Apache2__Directive tree;
char *value;
const char *directive;
const char *args;
int args_len;
int directive_len;
char *key = (char *)SvPV_nolen(ST(1));
int scalar_context = (G_SCALAR == GIMME_V);
if (SvROK(ST(0)) && sv_derived_from(ST(0), "Apache2::Directive")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
tree = INT2PTR(Apache2__Directive,tmp);
}
else {
tree = ap_conftree;
}
if (items < 3) {
value = NULL;
}
else {
value = (char *)SvPV_nolen(ST(2));
}
while (tree) {
directive = tree->directive;
directive_len = strlen(directive);
/* Remove starting '<' for container directives */
if (directive[0] == '<') {
directive++;
directive_len--;
}
if (0 == strncasecmp(directive, key, directive_len)) {
if (value) {
args = tree->args;
args_len = strlen(args);
/* Skip the postfix '>' */
if ('>' == args[args_len-1]) {
args_len--;
}
}
if ( (!value) || (0 == strncasecmp(args, value, args_len)) ) {
if (tree->first_child) {
XPUSHs(sv_2mortal(mpxs_Apache2__Directive_as_hash(
aTHX_ tree->first_child)));
}
else {
XPUSHs(sv_2mortal(newSVpv(tree->args, 0)));
}
if (scalar_context) {
break;
}
}
}
tree = tree->next ? tree->next : NULL;
}
});
}
/*
* Local Variables:
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/