xref: /netbsd-src/external/bsd/kyua-cli/dist/utils/cmdline/options.cpp (revision 6b3a42af15b5e090c339512c790dd68f3d11a9d8)
1 // Copyright 2010 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "utils/cmdline/options.hpp"
30 
31 #include <stdexcept>
32 #include <vector>
33 
34 #include "utils/cmdline/exceptions.hpp"
35 #include "utils/defs.hpp"
36 #include "utils/format/macros.hpp"
37 #include "utils/fs/exceptions.hpp"
38 #include "utils/sanity.hpp"
39 #include "utils/text/operations.ipp"
40 
41 namespace cmdline = utils::cmdline;
42 namespace text = utils::text;
43 
44 
45 /// Constructs a generic option with both a short and a long name.
46 ///
47 /// \param short_name_ The short name for the option.
48 /// \param long_name_ The long name for the option.
49 /// \param description_ A user-friendly description for the option.
50 /// \param arg_name_ If not NULL, specifies that the option must receive an
51 ///     argument and specifies the name of such argument for documentation
52 ///     purposes.
53 /// \param default_value_ If not NULL, specifies that the option has a default
54 ///     value for the mandatory argument.
base_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)55 cmdline::base_option::base_option(const char short_name_,
56                                   const char* long_name_,
57                                   const char* description_,
58                                   const char* arg_name_,
59                                   const char* default_value_) :
60     _short_name(short_name_),
61     _long_name(long_name_),
62     _description(description_),
63     _arg_name(arg_name_ == NULL ? "" : arg_name_),
64     _has_default_value(default_value_ != NULL),
65     _default_value(default_value_ == NULL ? "" : default_value_)
66 {
67     INV(short_name_ != '\0');
68 }
69 
70 
71 /// Constructs a generic option with a long name only.
72 ///
73 /// \param long_name_ The long name for the option.
74 /// \param description_ A user-friendly description for the option.
75 /// \param arg_name_ If not NULL, specifies that the option must receive an
76 ///     argument and specifies the name of such argument for documentation
77 ///     purposes.
78 /// \param default_value_ If not NULL, specifies that the option has a default
79 ///     value for the mandatory argument.
base_option(const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)80 cmdline::base_option::base_option(const char* long_name_,
81                                   const char* description_,
82                                   const char* arg_name_,
83                                   const char* default_value_) :
84     _short_name('\0'),
85     _long_name(long_name_),
86     _description(description_),
87     _arg_name(arg_name_ == NULL ? "" : arg_name_),
88     _has_default_value(default_value_ != NULL),
89     _default_value(default_value_ == NULL ? "" : default_value_)
90 {
91 }
92 
93 
94 /// Destructor for the option.
~base_option(void)95 cmdline::base_option::~base_option(void)
96 {
97 }
98 
99 
100 /// Checks whether the option has a short name or not.
101 ///
102 /// \return True if the option has a short name, false otherwise.
103 bool
has_short_name(void) const104 cmdline::base_option::has_short_name(void) const
105 {
106     return _short_name != '\0';
107 }
108 
109 
110 /// Returns the short name of the option.
111 ///
112 /// \pre has_short_name() must be true.
113 ///
114 /// \return The short name.
115 char
short_name(void) const116 cmdline::base_option::short_name(void) const
117 {
118     PRE(has_short_name());
119     return _short_name;
120 }
121 
122 
123 /// Returns the long name of the option.
124 ///
125 /// \return The long name.
126 const std::string&
long_name(void) const127 cmdline::base_option::long_name(void) const
128 {
129     return _long_name;
130 }
131 
132 
133 /// Returns the description of the option.
134 ///
135 /// \return The description.
136 const std::string&
description(void) const137 cmdline::base_option::description(void) const
138 {
139     return _description;
140 }
141 
142 
143 /// Checks whether the option needs an argument or not.
144 ///
145 /// \return True if the option needs an argument, false otherwise.
146 bool
needs_arg(void) const147 cmdline::base_option::needs_arg(void) const
148 {
149     return !_arg_name.empty();
150 }
151 
152 
153 /// Returns the argument name of the option for documentation purposes.
154 ///
155 /// \pre needs_arg() must be true.
156 ///
157 /// \return The argument name.
158 const std::string&
arg_name(void) const159 cmdline::base_option::arg_name(void) const
160 {
161     INV(needs_arg());
162     return _arg_name;
163 }
164 
165 
166 /// Checks whether the option has a default value for its argument.
167 ///
168 /// \pre needs_arg() must be true.
169 ///
170 /// \return True if the option has a default value, false otherwise.
171 bool
has_default_value(void) const172 cmdline::base_option::has_default_value(void) const
173 {
174     PRE(needs_arg());
175     return _has_default_value;
176 }
177 
178 
179 /// Returns the default value for the argument to the option.
180 ///
181 /// \pre has_default_value() must be true.
182 ///
183 /// \return The default value.
184 const std::string&
default_value(void) const185 cmdline::base_option::default_value(void) const
186 {
187     INV(has_default_value());
188     return _default_value;;
189 }
190 
191 
192 /// Formats the short name of the option for documentation purposes.
193 ///
194 /// \return A string describing the option's short name.
195 std::string
format_short_name(void) const196 cmdline::base_option::format_short_name(void) const
197 {
198     PRE(has_short_name());
199 
200     if (needs_arg()) {
201         return F("-%s %s") % short_name() % arg_name();
202     } else {
203         return F("-%s") % short_name();
204     }
205 }
206 
207 
208 /// Formats the long name of the option for documentation purposes.
209 ///
210 /// \return A string describing the option's long name.
211 std::string
format_long_name(void) const212 cmdline::base_option::format_long_name(void) const
213 {
214     if (needs_arg()) {
215         return F("--%s=%s") % long_name() % arg_name();
216     } else {
217         return F("--%s") % long_name();
218     }
219 }
220 
221 
222 
223 /// Ensures that an argument passed to the option is valid.
224 ///
225 /// This must be reimplemented by subclasses that describe options with
226 /// arguments.
227 ///
228 /// \param unused_str The argument to validate as provided by the user in the
229 ///     command line.
230 ///
231 /// \throw cmdline::option_argument_value_error Subclasses must raise this
232 ///     exception to indicate the cases in which str is invalid.
233 void
validate(const std::string & UTILS_UNUSED_PARAM (str)) const234 cmdline::base_option::validate(const std::string& UTILS_UNUSED_PARAM(str)) const
235 {
236     UNREACHABLE_MSG("Option does not support an argument");
237 }
238 
239 
240 /// Constructs a boolean option with both a short and a long name.
241 ///
242 /// \param short_name_ The short name for the option.
243 /// \param long_name_ The long name for the option.
244 /// \param description_ A user-friendly description for the option.
bool_option(const char short_name_,const char * long_name_,const char * description_)245 cmdline::bool_option::bool_option(const char short_name_,
246                                   const char* long_name_,
247                                   const char* description_) :
248     base_option(short_name_, long_name_, description_)
249 {
250 }
251 
252 
253 /// Constructs a boolean option with a long name only.
254 ///
255 /// \param long_name_ The long name for the option.
256 /// \param description_ A user-friendly description for the option.
bool_option(const char * long_name_,const char * description_)257 cmdline::bool_option::bool_option(const char* long_name_,
258                                   const char* description_) :
259     base_option(long_name_, description_)
260 {
261 }
262 
263 
264 /// Constructs an integer option with both a short and a long name.
265 ///
266 /// \param short_name_ The short name for the option.
267 /// \param long_name_ The long name for the option.
268 /// \param description_ A user-friendly description for the option.
269 /// \param arg_name_ The name of the mandatory argument, for documentation
270 ///     purposes.
271 /// \param default_value_ If not NULL, the default value for the mandatory
272 ///     argument.
int_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)273 cmdline::int_option::int_option(const char short_name_,
274                                 const char* long_name_,
275                                 const char* description_,
276                                 const char* arg_name_,
277                                 const char* default_value_) :
278     base_option(short_name_, long_name_, description_, arg_name_,
279                 default_value_)
280 {
281 }
282 
283 
284 /// Constructs an integer option with a long name only.
285 ///
286 /// \param long_name_ The long name for the option.
287 /// \param description_ A user-friendly description for the option.
288 /// \param arg_name_ The name of the mandatory argument, for documentation
289 ///     purposes.
290 /// \param default_value_ If not NULL, the default value for the mandatory
291 ///     argument.
int_option(const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)292 cmdline::int_option::int_option(const char* long_name_,
293                                 const char* description_,
294                                 const char* arg_name_,
295                                 const char* default_value_) :
296     base_option(long_name_, description_, arg_name_, default_value_)
297 {
298 }
299 
300 
301 /// Ensures that an integer argument passed to the int_option is valid.
302 ///
303 /// \param raw_value The argument representing an integer as provided by the
304 ///     user.
305 ///
306 /// \throw cmdline::option_argument_value_error If the integer provided in
307 ///     raw_value is invalid.
308 void
validate(const std::string & raw_value) const309 cmdline::int_option::validate(const std::string& raw_value) const
310 {
311     try {
312         (void)text::to_type< int >(raw_value);
313     } catch (const std::runtime_error& e) {
314         throw cmdline::option_argument_value_error(
315             F("--%s") % long_name(), raw_value, "Not a valid integer");
316     }
317 }
318 
319 
320 /// Converts an integer argument to a native integer.
321 ///
322 /// \param raw_value The argument representing an integer as provided by the
323 ///     user.
324 ///
325 /// \return The integer.
326 ///
327 /// \pre validate(raw_value) must be true.
328 int
convert(const std::string & raw_value)329 cmdline::int_option::convert(const std::string& raw_value)
330 {
331     try {
332         return text::to_type< int >(raw_value);
333     } catch (const std::runtime_error& e) {
334         PRE_MSG(false, F("Raw value '%s' for int option not properly "
335                          "validated: %s") % raw_value % e.what());
336     }
337 }
338 
339 
340 /// Constructs a list option with both a short and a long name.
341 ///
342 /// \param short_name_ The short name for the option.
343 /// \param long_name_ The long name for the option.
344 /// \param description_ A user-friendly description for the option.
345 /// \param arg_name_ The name of the mandatory argument, for documentation
346 ///     purposes.
347 /// \param default_value_ If not NULL, the default value for the mandatory
348 ///     argument.
list_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)349 cmdline::list_option::list_option(const char short_name_,
350                                   const char* long_name_,
351                                   const char* description_,
352                                   const char* arg_name_,
353                                   const char* default_value_) :
354     base_option(short_name_, long_name_, description_, arg_name_,
355                 default_value_)
356 {
357 }
358 
359 
360 /// Constructs a list option with a long name only.
361 ///
362 /// \param long_name_ The long name for the option.
363 /// \param description_ A user-friendly description for the option.
364 /// \param arg_name_ The name of the mandatory argument, for documentation
365 ///     purposes.
366 /// \param default_value_ If not NULL, the default value for the mandatory
367 ///     argument.
list_option(const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)368 cmdline::list_option::list_option(const char* long_name_,
369                                   const char* description_,
370                                   const char* arg_name_,
371                                   const char* default_value_) :
372     base_option(long_name_, description_, arg_name_, default_value_)
373 {
374 }
375 
376 
377 /// Ensures that a lisstring argument passed to the list_option is valid.
378 ///
379 /// \param unused_raw_value The argument representing a list as provided by the
380 ///     user.
381 void
validate(const std::string & UTILS_UNUSED_PARAM (raw_value)) const382 cmdline::list_option::validate(
383     const std::string& UTILS_UNUSED_PARAM(raw_value)) const
384 {
385     // Any list is potentially valid; the caller must check for semantics.
386 }
387 
388 
389 /// Converts a string argument to a vector.
390 ///
391 /// \param raw_value The argument representing a list as provided by the user.
392 ///
393 /// \return The list.
394 ///
395 /// \pre validate(raw_value) must be true.
396 cmdline::list_option::option_type
convert(const std::string & raw_value)397 cmdline::list_option::convert(const std::string& raw_value)
398 {
399     try {
400         return text::split(raw_value, ',');
401     } catch (const std::runtime_error& e) {
402         PRE_MSG(false, F("Raw value '%s' for list option not properly "
403                          "validated: %s") % raw_value % e.what());
404     }
405 }
406 
407 
408 /// Constructs a path option with both a short and a long name.
409 ///
410 /// \param short_name_ The short name for the option.
411 /// \param long_name_ The long name for the option.
412 /// \param description_ A user-friendly description for the option.
413 /// \param arg_name_ The name of the mandatory argument, for documentation
414 ///     purposes.
415 /// \param default_value_ If not NULL, the default value for the mandatory
416 ///     argument.
path_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)417 cmdline::path_option::path_option(const char short_name_,
418                                   const char* long_name_,
419                                   const char* description_,
420                                   const char* arg_name_,
421                                   const char* default_value_) :
422     base_option(short_name_, long_name_, description_, arg_name_,
423                 default_value_)
424 {
425 }
426 
427 
428 /// Constructs a path option with a long name only.
429 ///
430 /// \param long_name_ The long name for the option.
431 /// \param description_ A user-friendly description for the option.
432 /// \param arg_name_ The name of the mandatory argument, for documentation
433 ///     purposes.
434 /// \param default_value_ If not NULL, the default value for the mandatory
435 ///     argument.
path_option(const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)436 cmdline::path_option::path_option(const char* long_name_,
437                                   const char* description_,
438                                   const char* arg_name_,
439                                   const char* default_value_) :
440     base_option(long_name_, description_, arg_name_, default_value_)
441 {
442 }
443 
444 
445 /// Ensures that a path argument passed to the path_option is valid.
446 ///
447 /// \param raw_value The argument representing a path as provided by the user.
448 ///
449 /// \throw cmdline::option_argument_value_error If the path provided in
450 ///     raw_value is invalid.
451 void
validate(const std::string & raw_value) const452 cmdline::path_option::validate(const std::string& raw_value) const
453 {
454     try {
455         (void)utils::fs::path(raw_value);
456     } catch (const utils::fs::error& e) {
457         throw cmdline::option_argument_value_error(F("--%s") % long_name(),
458                                                    raw_value, e.what());
459     }
460 }
461 
462 
463 /// Converts a path argument to a utils::fs::path.
464 ///
465 /// \param raw_value The argument representing a path as provided by the user.
466 ///
467 /// \return The path.
468 ///
469 /// \pre validate(raw_value) must be true.
470 utils::fs::path
convert(const std::string & raw_value)471 cmdline::path_option::convert(const std::string& raw_value)
472 {
473     try {
474         return utils::fs::path(raw_value);
475     } catch (const std::runtime_error& e) {
476         PRE_MSG(false, F("Raw value '%s' for path option not properly "
477                          "validated: %s") % raw_value % e.what());
478     }
479 }
480 
481 
482 /// Constructs a property option with both a short and a long name.
483 ///
484 /// \param short_name_ The short name for the option.
485 /// \param long_name_ The long name for the option.
486 /// \param description_ A user-friendly description for the option.
487 /// \param arg_name_ The name of the mandatory argument, for documentation
488 ///     purposes.  Must include the '=' delimiter.
property_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_)489 cmdline::property_option::property_option(const char short_name_,
490                                           const char* long_name_,
491                                           const char* description_,
492                                           const char* arg_name_) :
493     base_option(short_name_, long_name_, description_, arg_name_)
494 {
495     PRE(arg_name().find('=') != std::string::npos);
496 }
497 
498 
499 /// Constructs a property option with a long name only.
500 ///
501 /// \param long_name_ The long name for the option.
502 /// \param description_ A user-friendly description for the option.
503 /// \param arg_name_ The name of the mandatory argument, for documentation
504 ///     purposes.  Must include the '=' delimiter.
property_option(const char * long_name_,const char * description_,const char * arg_name_)505 cmdline::property_option::property_option(const char* long_name_,
506                                           const char* description_,
507                                           const char* arg_name_) :
508     base_option(long_name_, description_, arg_name_)
509 {
510     PRE(arg_name().find('=') != std::string::npos);
511 }
512 
513 
514 /// Validates the argument to a property option.
515 ///
516 /// \param raw_value The argument provided by the user.
517 void
validate(const std::string & raw_value) const518 cmdline::property_option::validate(const std::string& raw_value) const
519 {
520     const std::string::size_type pos = raw_value.find('=');
521     if (pos == std::string::npos)
522         throw cmdline::option_argument_value_error(
523             F("--%s") % long_name(), raw_value,
524             F("Argument does not have the form '%s'") % arg_name());
525 
526     const std::string key = raw_value.substr(0, pos);
527     if (key.empty())
528         throw cmdline::option_argument_value_error(
529             F("--%s") % long_name(), raw_value, "Empty property name");
530 
531     const std::string value = raw_value.substr(pos + 1);
532     if (value.empty())
533         throw cmdline::option_argument_value_error(
534             F("--%s") % long_name(), raw_value, "Empty value");
535 }
536 
537 
538 /// Returns the property option in a key/value pair form.
539 ///
540 /// \param raw_value The argument provided by the user.
541 ///
542 /// \return raw_value The key/value pair representation of the property.
543 ///
544 /// \pre validate(raw_value) must be true.
545 cmdline::property_option::option_type
convert(const std::string & raw_value)546 cmdline::property_option::convert(const std::string& raw_value)
547 {
548     const std::string::size_type pos = raw_value.find('=');
549     return std::make_pair(raw_value.substr(0, pos), raw_value.substr(pos + 1));
550 }
551 
552 
553 /// Constructs a string option with both a short and a long name.
554 ///
555 /// \param short_name_ The short name for the option.
556 /// \param long_name_ The long name for the option.
557 /// \param description_ A user-friendly description for the option.
558 /// \param arg_name_ The name of the mandatory argument, for documentation
559 ///     purposes.
560 /// \param default_value_ If not NULL, the default value for the mandatory
561 ///     argument.
string_option(const char short_name_,const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)562 cmdline::string_option::string_option(const char short_name_,
563                                       const char* long_name_,
564                                       const char* description_,
565                                       const char* arg_name_,
566                                       const char* default_value_) :
567     base_option(short_name_, long_name_, description_, arg_name_,
568                 default_value_)
569 {
570 }
571 
572 
573 /// Constructs a string option with a long name only.
574 ///
575 /// \param long_name_ The long name for the option.
576 /// \param description_ A user-friendly description for the option.
577 /// \param arg_name_ The name of the mandatory argument, for documentation
578 ///     purposes.
579 /// \param default_value_ If not NULL, the default value for the mandatory
580 ///     argument.
string_option(const char * long_name_,const char * description_,const char * arg_name_,const char * default_value_)581 cmdline::string_option::string_option(const char* long_name_,
582                                       const char* description_,
583                                       const char* arg_name_,
584                                       const char* default_value_) :
585     base_option(long_name_, description_, arg_name_, default_value_)
586 {
587 }
588 
589 
590 /// Does nothing; all string values are valid arguments to a string_option.
591 ///
592 /// \param unused_raw_value The argument provided by the user.
593 void
validate(const std::string & UTILS_UNUSED_PARAM (raw_value)) const594 cmdline::string_option::validate(
595     const std::string& UTILS_UNUSED_PARAM(raw_value)) const
596 {
597     // Nothing to do.
598 }
599 
600 
601 /// Returns the string unmodified.
602 ///
603 /// \param raw_value The argument provided by the user.
604 ///
605 /// \return raw_value
606 ///
607 /// \pre validate(raw_value) must be true.
608 std::string
convert(const std::string & raw_value)609 cmdline::string_option::convert(const std::string& raw_value)
610 {
611     return raw_value;
612 }
613