/* 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 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(); hv_store(hash, key, keylen, newRV_noinc((SV *)subhash), 0); } else { subhash = (HV *)SvRV(*hash_ent); } 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)); hv_store(hash, key, keylen, newRV_noinc((SV *)args_array), 0); } av_push(args_array, newSVpv(args, argslen)); } else { 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, Nullsv); } 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; } }); }