| /* 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: |
| */ |