Options.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 #include "squid.h"
10 #include "acl/Options.h"
11 #include "ConfigParser.h"
12 #include "debug/Stream.h"
13 #include "sbuf/Stream.h"
14 
15 #include <iostream>
16 #include <utility>
17 #include <vector>
18 
19 namespace Acl {
20 
23 {
24 public:
27  bool extractOne();
28 
29  /* extracted option details (after successful extraction */
31  bool hasValue = false;
32  const SBuf &value() const;
33 
34 protected:
35  bool advance();
36  void extractWhole();
37  void extractShort();
38 
39 private:
43  bool sawValue_ = false;
44 };
45 
48 {
49 public:
50  explicit OptionsParser(const Options &options);
51 
52  // fill previously supplied options container, throwing on errors
53  void parse();
54 
55 private:
56  using SupportedOption = std::pair<const Option *, bool /* enable */ >;
57  SupportedOption supportedOption(const SBuf &name) const;
58 
59  const Options &options_;
60 };
61 
62 } // namespace Acl
63 
64 /* Acl::Option */
65 
66 Acl::Option::Option(const char * const nameThatEnables, const char * const nameThatDisables, const ValueExpectation vex):
67  onName(nameThatEnables),
68  offName(nameThatDisables),
69  valueExpectation(vex)
70 {
71  assert(onName);
72 }
73 
74 /* Acl::OptionExtractor */
75 
76 const SBuf &
78 {
79  Must(hasValue);
80  return value_;
81 }
82 
83 bool
85 {
86  if (!prefix_.isEmpty()) {
87  extractShort(); // continue with the previously extracted flags
88  return true;
89  }
90 
91  if (!advance())
92  return false; // end of options (and, possibly, the whole "acl" directive)
93 
94  if (prefix_.length() < 2)
95  throw TexcHere(ToSBuf("truncated(?) ACL flag: ", prefix_)); // single - or +
96 
97  if (prefix_[0] == '-' && prefix_[1] == '-') {
98  if (prefix_.length() == 2)
99  return false; // skipped "--", an explicit end-of-options marker
100  extractWhole();
101  return true;
102  }
103 
104  if (prefix_.length() == 2) { // common trivial case: -x or +y
105  extractWhole();
106  return true;
107  }
108 
109  // -xyz or +xyz
110  letterPos_ = 1;
111  extractShort();
112  return true;
113 }
114 
116 bool
118 {
119  const char *next = ConfigParser::PeekAtToken();
120  if (!next)
121  return false; // end of the "acl" line
122 
123  const char nextChar = *next;
124  if (!(nextChar == '-' || nextChar == '+'))
125  return false; // start of ACL parameters
126 
127  sawValue_ = strchr(next, '='); // TODO: Make ConfigParser reject '^=.*' tokens
128  if (sawValue_) {
129  char *rawPrefix = nullptr;
130  char *rawValue = nullptr;
131  if (!ConfigParser::NextKvPair(rawPrefix, rawValue))
132  throw TexcHere(ToSBuf("Malformed acl option=value: ", next));
133  prefix_.assign(rawPrefix);
134  value_.assign(rawValue);
135  } else {
136  prefix_.assign(next);
137  ConfigParser::NextToken(); // consume what we have peeked at
138  }
139  return true;
140 }
141 
143 void
145 {
146  debugs(28, 8, "from " << prefix_ << " value: " << sawValue_);
147  hasValue = sawValue_;
148  name = prefix_;
149  prefix_.clear();
150 }
151 
153 void
155 {
156  debugs(28, 8, "from " << prefix_ << " at " << letterPos_ << " value: " << sawValue_);
157  name.assign(prefix_.rawContent(), 1); // leading - or +
158  name.append(prefix_.at(letterPos_++));
159  if (letterPos_ >= prefix_.length()) { // got last flag in the sequence
160  hasValue = sawValue_;
161  prefix_.clear();
162  } else {
163  hasValue = false;
164  }
165 }
166 
167 /* Acl::OptionsParser */
168 
170  options_(options)
171 {
172 }
173 
177 {
178  for (const auto option: options_) {
179  if (name.cmp(option->onName) == 0)
180  return SupportedOption(option, true);
181  if (option->offName && name.cmp(option->offName) == 0)
182  return SupportedOption(option, false);
183  }
184 
185  throw TexcHere(ToSBuf("unsupported ACL option: ", name));
186 }
187 
188 void
190 {
191  OptionExtractor oex;
192  while (oex.extractOne()) {
193  const auto explicitOption = supportedOption(oex.name);
194  const auto &option = *explicitOption.first;
195  if (explicitOption.second) {
196  /* configuration enables this option */
197  if (option.configured())
198  debugs(28, 7, "acl uses multiple " << oex.name << " options");
199  switch (option.valueExpectation)
200  {
201  case Option::valueNone:
202  if (oex.hasValue)
203  throw TexcHere(ToSBuf("unexpected value for an ACL option: ", oex.name, '=', oex.value()));
204  option.enable();
205  break;
207  if (!oex.hasValue)
208  throw TexcHere(ToSBuf("missing required value for ACL option ", oex.name));
209  option.configureWith(oex.value());
210  break;
212  if (oex.hasValue)
213  option.configureWith(oex.value());
214  else
215  option.enable();
216  break;
217  }
218  } else {
219  if (oex.hasValue)
220  throw TexcHere(ToSBuf("unexpected value when disabling an ACL option: ", oex.name, '=', oex.value()));
221  option.disable();
222  }
223  }
224 }
225 
226 void
227 Acl::ParseFlags(const Options &options)
228 {
229  OptionsParser parser(options);
230  parser.parse();
231 }
232 
233 const Acl::Options &
235 {
236  static const Options none;
237  return none;
238 }
239 
240 const Acl::BooleanOption &
242 {
243  static const BooleanOption MyOption("-i", "+i");
244  return MyOption;
245 }
246 
247 std::ostream &
248 Acl::operator <<(std::ostream &os, const Option &option)
249 {
250  option.print(os);
251  return os;
252 }
253 
254 std::ostream &
255 Acl::operator <<(std::ostream &os, const Options &options)
256 {
257  for (const auto option: options)
258  os << *option;
259 
260  // TODO: Remember "--" presence and print that delimiter when present.
261  // Detecting its need is difficult because parameter flags start with "-".
262  return os;
263 }
264 
void extractWhole()
handles -x[=option] or –foo[=option]
Definition: Options.cc:144
a type-specific Option (e.g., a boolean –toggle or -m=SBuf)
Definition: Options.h:129
std::vector< const Option * > Options
Definition: Options.h:217
const SBuf & value() const
extracted option value (requires hasValue)
Definition: Options.cc:77
const Options & options_
caller-supported, linked options
Definition: Options.cc:59
SBuf name
extracted option name, including dash(es)
Definition: Options.cc:30
Definition: SBuf.h:93
static char * PeekAtToken()
parses/validates/stores ACL options; skips/preserves parameter flags
Definition: Options.cc:47
Definition: Acl.cc:33
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:63
bool advance()
extracts a token with the next option/flag(s) or returns false
Definition: Options.cc:117
const BooleanOption & CaseSensitivityOption()
Definition: Options.cc:241
SBuf prefix_
option name(s), including leading dash(es)
Definition: Options.cc:40
bool hasValue
whether the option has a value (-x=value)
Definition: Options.cc:31
void ParseFlags(const Options &options)
Definition: Options.cc:227
MemBlob::size_type size_type
Definition: SBuf.h:96
std::pair< const Option *, bool > SupportedOption
Definition: Options.cc:56
@ valueNone
Definition: Options.h:59
A single option supported by an ACL: -x[=value] or –name[=value].
Definition: Options.h:56
#define assert(EX)
Definition: assert.h:17
static bool NextKvPair(char *&key, char *&value)
const char *const onName
A name that must be used to explicitly enable this Option (required).
Definition: Options.h:88
static char * NextToken()
const Options & NoOptions()
Definition: Options.cc:234
void extractShort()
handles one flag letter inside an -xyx[=option] or +xyz[=option] sequence
Definition: Options.cc:154
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:279
low-level parser that extracts but does not interpret ACL options
Definition: Options.cc:22
bool sawValue_
the current option sequence had a value
Definition: Options.cc:43
@ valueOptional
Definition: Options.h:59
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
ValueExpectation
Definition: Options.h:59
#define Must(condition)
Definition: TextException.h:75
SBuf value_
the last seen value of some option
Definition: Options.cc:41
Option(const char *nameThatEnables, const char *nameThatDisables=nullptr, ValueExpectation vex=valueNone)
Definition: Options.cc:66
OptionsParser(const Options &options)
Definition: Options.cc:169
SBuf::size_type letterPos_
letter position inside an -xyz sequence
Definition: Options.cc:42
@ valueRequired
Definition: Options.h:59
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
virtual void print(std::ostream &os) const =0
prints a configuration snippet (as an admin could have typed)
std::ostream & operator<<(std::ostream &o, const Answer &a)
Definition: Acl.h:109
SupportedOption supportedOption(const SBuf &name) const
Definition: Options.cc:176

 

Introduction

Documentation

Support

Miscellaneous