blob: 5077ec47e3241ff2dc359481497e8b815b755671 [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.
*/
#include "mod_perl.h"
/* re-use the ->unset field to determine options type */
#define MpOptionsType(o) (o)->unset
#define MpOptionsTypeDir(o) MpOptionsType(o) == MpDir_f_UNSET
#define MpOptionsTypeSrv(o) MpOptionsType(o) == MpSrv_f_UNSET
#define MpOptionsTypeDir_set(o) MpOptionsType(o) = MpDir_f_UNSET
#define MpOptionsTypeSrv_set(o) MpOptionsType(o) = MpSrv_f_UNSET
#define MP_OPTIONS_TYPE_DIR MpDir_f_UNSET
#define MP_OPTIONS_TYPE_SRV MpSrv_f_UNSET
static modperl_opts_t flags_lookup(modperl_options_t *o,
const char *str)
{
switch (MpOptionsType(o)) {
case MP_OPTIONS_TYPE_SRV:
return modperl_flags_lookup_srv(str);
case MP_OPTIONS_TYPE_DIR:
return modperl_flags_lookup_dir(str);
default:
return '\0';
};
}
static const char *type_lookup(modperl_options_t *o)
{
switch (MpOptionsType(o)) {
case MP_OPTIONS_TYPE_SRV:
return "server";
case MP_OPTIONS_TYPE_DIR:
return "directory";
default:
return "unknown";
};
}
modperl_options_t *modperl_options_new(apr_pool_t *p, int type)
{
modperl_options_t *options =
(modperl_options_t *)apr_pcalloc(p, sizeof(*options));
options->opts = options->unset =
(type == MpSrvType ? MpSrv_f_UNSET : MpDir_f_UNSET);
return options;
}
const char *modperl_options_set(apr_pool_t *p, modperl_options_t *o,
const char *str)
{
modperl_opts_t opt;
char action = '\0';
const char *error = NULL;
if (*str == '+' || *str == '-') {
action = *(str++);
}
if ((opt = flags_lookup(o, str)) == -1) {
error = apr_pstrcat(p, "Invalid per-", type_lookup(o),
" PerlOption: ", str, NULL);
if (MpOptionsTypeDir(o)) {
modperl_options_t dummy;
MpOptionsTypeSrv_set(&dummy);
if (flags_lookup(&dummy, str) == -1) {
error = apr_pstrcat(p, error,
" (only allowed per-server)",
NULL);
}
}
return error;
}
#ifndef USE_ITHREADS
else if (MpOptionsTypeSrv(o)) {
if (MpSrvOPT_ITHREAD_ONLY(opt)) {
return apr_pstrcat(p, "PerlOption `", str,
"' requires an ithreads enabled Perl", NULL);
}
}
#endif
o->opts_seen |= opt;
if (action == '-') {
o->opts_remove |= opt;
o->opts_add &= ~opt;
o->opts &= ~opt;
}
else if (action == '+') {
o->opts_add |= opt;
o->opts_remove &= ~opt;
o->opts |= opt;
}
else {
o->opts |= opt;
}
return NULL;
}
modperl_options_t *modperl_options_merge(apr_pool_t *p,
modperl_options_t *base,
modperl_options_t *add)
{
modperl_options_t *conf = modperl_options_new(p, 0);
memcpy((char *)conf, (const char *)base, sizeof(*base));
if (add->opts & add->unset) {
/* there was no explicit setting of add->opts, so we merge
* preserve the invariant (opts_add & opts_remove) == 0
*/
conf->opts_add =
(conf->opts_add & ~add->opts_remove) | add->opts_add;
conf->opts_remove =
(conf->opts_remove & ~add->opts_add) | add->opts_remove;
conf->opts =
(conf->opts & ~conf->opts_remove) | conf->opts_add;
}
else {
/* otherwise we just copy, because an explicit opts setting
* overrides all earlier +/- modifiers
*/
conf->opts = add->opts;
conf->opts_add = add->opts_add;
conf->opts_remove = add->opts_remove;
}
conf->opts_seen |= add->opts_seen;
return conf;
}
/*
* Local Variables:
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/