2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 #ifndef SQUID_ACL_OPTIONS_H
10 #define SQUID_ACL_OPTIONS_H
12 #include "acl/forward.h"
13 #include "sbuf/forward.h"
18 // After line continuation is handled by the preprocessor, an ACL object
19 // configuration can be visualized as a sequence of same-name "acl ..." lines:
21 // L1: acl exampleA typeT parameter1 -i parameter2 parameter3
22 // L2: acl exampleA typeT parameter4
23 // L3: acl exampleA typeT -i -n parameter5 +i parameter6
24 // L4: acl exampleA typeT -n parameter7
26 // There are two kinds of ACL options (a.k.a. flags):
28 // * Global (e.g., "-n"): Applies to all parameters regardless of where the
29 // option was discovered/parsed (e.g., "-n" on L3 affects parameter2 on L1).
30 // Declared by ACL class kids (or equivalent) via ACL::options().
32 // * Line (e.g., "-i"): Applies to the yet unparsed ACL parameters of the
33 // current "acl ..." line (e.g., "-i" on L1 has no effect on parameter4 on L2)
34 // Declared by ACLData class kids (or equivalent) via lineOptions().
36 // Here is the option:explicitly-affected-parameters map for the above exampleA:
37 // "-n": parameter1-7 (i.e. all parameters)
38 // "-i": parameter2, parameter3; parameter5
41 // The option name spelling determines the option kind and effect.
42 // Both option kinds use the same general option configuration syntax:
43 // option = name [ '=' value ]
44 // where "name" is option-specific spelling that looks like -x, +x, or --long
46 // On each "acl ..." line, global options can only appear before the first
47 // parameter, while line options can go before any parameter.
49 // XXX: The fact that global options affect previous (and subsequent) same-name
50 // "acl name ..." lines surprises and confuses those who comprehend ACLs in
51 // terms of configuration lines (which Squid effectively merges together).
55 /// A single option supported by an ACL: -x[=value] or --name[=value]
59 typedef enum { valueNone
, valueOptional
, valueRequired
} ValueExpectation
;
60 explicit Option(const char *nameThatEnables
, const char *nameThatDisables
= nullptr, ValueExpectation vex
= valueNone
);
63 /// whether the admin explicitly specified this option (i.e., whether
64 /// enable(), configureWith(), or disable() has been called)
65 virtual bool configured() const = 0;
67 /// called after parsing onName without a value (e.g., -x or --enable-x)
68 virtual void enable() const = 0;
70 /// called after parsing onName and a value (e.g., -x=v or --enable-x=v)
71 virtual void configureWith(const SBuf
&rawValue
) const = 0;
73 /// called after parsing offName (e.g., +i or --disable-x)
74 virtual void disable() const = 0;
76 /// clear enable(), configureWith(), or disable() effects
77 virtual void unconfigure() const = 0;
79 /// whether disable() has been called
80 virtual bool disabled() const = 0;
82 virtual bool valued() const = 0;
84 /// prints a configuration snippet (as an admin could have typed)
85 virtual void print(std::ostream
&os
) const = 0;
87 /// A name that must be used to explicitly enable this Option (required).
88 const char * const onName
= nullptr;
90 /// A name that must be used to explicitly disable this Option (optional).
91 /// Nil for (and only for) options that cannot be disabled().
92 const char * const offName
= nullptr;
94 ValueExpectation valueExpectation
= valueNone
; ///< expect "=value" part?
97 /// Stores configuration of a typical boolean flag or a single-value Option.
98 template <class Value
>
102 typedef Value value_type
;
104 // TODO: Some callers use .value without checking whether the option is
105 // enabled(), accessing the (default-initialized or customized) default
106 // value that way. This trick will stop working if we add valued options
107 // that can be disabled (e.g., --with-foo=x --without-foo). To support such
108 // options, store the default value separately and provide value accessor.
110 OptionValue(): value
{} {}
111 explicit OptionValue(const Value
&aValue
): value(aValue
) {}
113 /// whether the option is explicitly turned "on" (with or without a value)
114 bool enabled() const { return configured
&& !disabled
; }
115 explicit operator bool() const { return enabled(); }
117 /// go back to the default-initialized state
118 void reset() { *this = OptionValue
<Value
>(); }
120 Value value
; ///< final value storage, possibly after conversions
121 bool configured
= false; ///< whether the option was present in squid.conf
122 /* flags for configured options */
123 bool disabled
= false; ///< whether the option was turned off
124 bool valued
= false; ///< whether a configured option had a value
127 /// a type-specific Option (e.g., a boolean --toggle or -m=SBuf)
128 template <class Recipient
>
129 class TypedOption
: public Option
132 //typedef typename Recipient::value_type value_type;
133 explicit TypedOption(const char *nameThatEnables
, const char *nameThatDisables
= nullptr, ValueExpectation vex
= valueNone
):
134 Option(nameThatEnables
, nameThatDisables
, vex
) {}
136 /// who to tell when this option is enabled
137 void linkWith(Recipient
*recipient
) const
140 recipient_
= recipient
;
145 bool configured() const override
{ return recipient_
&& recipient_
->configured
; }
146 bool disabled() const override
{ return recipient_
&& recipient_
->disabled
&& /* paranoid: */ offName
; }
147 bool valued() const override
{ return recipient_
&& recipient_
->valued
; }
149 void unconfigure() const override
{
154 void enable() const override
157 recipient_
->configured
= true;
158 recipient_
->disabled
= false;
159 recipient_
->valued
= false;
160 // leave recipient_->value unchanged
163 void configureWith(const SBuf
&rawValue
) const override
166 recipient_
->configured
= true;
167 recipient_
->disabled
= false;
168 recipient_
->valued
= true;
172 void disable() const override
175 recipient_
->configured
= true;
176 recipient_
->disabled
= true;
177 recipient_
->valued
= false;
178 // leave recipient_->value unchanged
181 void print(std::ostream
&os
) const override
184 os
<< ' ' << (disabled() ? offName
: onName
);
186 os
<< '=' << recipient_
->value
;
188 // else do not report the implicit default
192 void import(const SBuf
&rawValue
) const { recipient_
->value
= rawValue
; }
194 // The "mutable" specifier demarcates set-once Option kind/behavior from the
195 // ever-changing recipient of the actual admin-configured option value.
196 mutable Recipient
*recipient_
= nullptr; ///< parsing results storage
199 /* two typical option kinds: --foo and --bar=text */
200 typedef OptionValue
<bool> BooleanOptionValue
;
201 typedef OptionValue
<SBuf
> TextOptionValue
;
202 typedef TypedOption
<BooleanOptionValue
> BooleanOption
;
203 typedef TypedOption
<TextOptionValue
> TextOption
;
205 // this specialization should never be called until we start supporting
206 // boolean option values like --name=enable or --name=false
209 BooleanOption::import(const SBuf
&) const
211 assert(!"boolean options do not have ...=values (for now)");
214 using Options
= std::vector
<const Option
*>;
216 /// parses the flags part of the being-parsed ACL, filling Option values
217 /// \param options options supported by the ACL as a whole (e.g., -n)
218 void ParseFlags(const Options
&options
);
220 /* handy for Class::options() and lineOptions() defaults */
221 const Options
&NoOptions(); ///< \returns an empty Options container
223 /// A boolean option that controls case-sensitivity (-i/+i).
224 /// An enabled (-i) state is "case insensitive".
225 /// A disabled (+i) and default states are "case sensitive".
226 const BooleanOption
&CaseSensitivityOption();
228 std::ostream
&operator <<(std::ostream
&, const Option
&);
229 std::ostream
&operator <<(std::ostream
&, const Options
&);
233 #endif /* SQUID_ACL_OPTIONS_H */