xref: /freebsd/contrib/kyua/utils/cmdline/options.hpp (revision b0d29bc4)
1 // Copyright 2010 The Kyua Authors.
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 /// \file utils/cmdline/options.hpp
30 /// Definitions of command-line options.
31 
32 #if !defined(UTILS_CMDLINE_OPTIONS_HPP)
33 #define UTILS_CMDLINE_OPTIONS_HPP
34 
35 #include "utils/cmdline/options_fwd.hpp"
36 
37 #include <string>
38 #include <utility>
39 #include <vector>
40 
41 #include "utils/fs/path_fwd.hpp"
42 
43 namespace utils {
44 namespace cmdline {
45 
46 
47 /// Type-less base option class.
48 ///
49 /// This abstract class provides the most generic representation of options.  It
50 /// allows defining options with both short and long names, with and without
51 /// arguments and with and without optional values.  These are all the possible
52 /// combinations supported by the getopt_long(3) function, on which this is
53 /// built.
54 ///
55 /// The internal values (e.g. the default value) of a generic option are all
56 /// represented as strings.  However, from the caller's perspective, this is
57 /// suboptimal.  Hence why this class must be specialized: the subclasses
58 /// provide type-specific accessors and provide automatic validation of the
59 /// types (e.g. a string '3foo' is not passed to an integer option).
60 ///
61 /// Given that subclasses are used through templatized code, they must provide:
62 ///
63 /// <ul>
64 ///     <li>A public option_type typedef that defines the type of the
65 ///     option.</li>
66 ///
67 ///     <li>A convert() method that takes a string and converts it to
68 ///     option_type.  The string can be assumed to be convertible to the
69 ///     destination type.  Should not raise exceptions.</li>
70 ///
71 ///     <li>A validate() method that matches the implementation of convert().
72 ///     This method can throw option_argument_value_error if the string cannot
73 ///     be converted appropriately.  If validate() does not throw, then
74 ///     convert() must execute successfully.</li>
75 /// </ul>
76 ///
77 /// TODO(jmmv): Many methods in this class are split into two parts: has_foo()
78 /// and foo(), the former to query if the foo is available and the latter to get
79 /// the foo.  It'd be very nice if we'd use something similar Boost.Optional to
80 /// simplify this interface altogether.
81 class base_option {
82     /// Short name of the option; 0 to indicate that none is available.
83     char _short_name;
84 
85     /// Long name of the option.
86     std::string _long_name;
87 
88     /// Textual description of the purpose of the option.
89     std::string _description;
90 
91     /// Descriptive name of the required argument; empty if not allowed.
92     std::string _arg_name;
93 
94     /// Whether the option has a default value or not.
95     ///
96     /// \todo We should probably be using the optional class here.
97     bool _has_default_value;
98 
99     /// If _has_default_value is true, the default value.
100     std::string _default_value;
101 
102 public:
103     base_option(const char, const char*, const char*, const char* = NULL,
104                 const char* = NULL);
105     base_option(const char*, const char*, const char* = NULL,
106                 const char* = NULL);
107     virtual ~base_option(void);
108 
109     bool has_short_name(void) const;
110     char short_name(void) const;
111     const std::string& long_name(void) const;
112     const std::string& description(void) const;
113 
114     bool needs_arg(void) const;
115     const std::string& arg_name(void) const;
116 
117     bool has_default_value(void) const;
118     const std::string& default_value(void) const;
119 
120     std::string format_short_name(void) const;
121     std::string format_long_name(void) const;
122 
123     virtual void validate(const std::string&) const;
124 };
125 
126 
127 /// Definition of a boolean option.
128 ///
129 /// A boolean option can be specified once in the command line, at which point
130 /// is set to true.  Such an option cannot carry optional arguments.
131 class bool_option : public base_option {
132 public:
133     bool_option(const char, const char*, const char*);
134     bool_option(const char*, const char*);
~bool_option(void)135     virtual ~bool_option(void) {}
136 
137     /// The data type of this option.
138     typedef bool option_type;
139 };
140 
141 
142 /// Definition of an integer option.
143 class int_option : public base_option {
144 public:
145     int_option(const char, const char*, const char*, const char*,
146                const char* = NULL);
147     int_option(const char*, const char*, const char*, const char* = NULL);
~int_option(void)148     virtual ~int_option(void) {}
149 
150     /// The data type of this option.
151     typedef int option_type;
152 
153     virtual void validate(const std::string& str) const;
154     static int convert(const std::string& str);
155 };
156 
157 
158 /// Definition of a comma-separated list of strings.
159 class list_option : public base_option {
160 public:
161     list_option(const char, const char*, const char*, const char*,
162                 const char* = NULL);
163     list_option(const char*, const char*, const char*, const char* = NULL);
~list_option(void)164     virtual ~list_option(void) {}
165 
166     /// The data type of this option.
167     typedef std::vector< std::string > option_type;
168 
169     virtual void validate(const std::string&) const;
170     static option_type convert(const std::string&);
171 };
172 
173 
174 /// Definition of an option representing a path.
175 ///
176 /// The path pointed to by the option may not exist, but it must be
177 /// syntactically valid.
178 class path_option : public base_option {
179 public:
180     path_option(const char, const char*, const char*, const char*,
181                 const char* = NULL);
182     path_option(const char*, const char*, const char*, const char* = NULL);
~path_option(void)183     virtual ~path_option(void) {}
184 
185     /// The data type of this option.
186     typedef utils::fs::path option_type;
187 
188     virtual void validate(const std::string&) const;
189     static utils::fs::path convert(const std::string&);
190 };
191 
192 
193 /// Definition of a property option.
194 ///
195 /// A property option is an option whose required arguments are of the form
196 /// 'name=value'.  Both components of the property are treated as free-form
197 /// non-empty strings; any other validation must happen on the caller side.
198 ///
199 /// \todo Would be nice if the delimiter was parametrizable.  With the current
200 ///     parser interface (convert() being a static method), the only way to do
201 ///     this would be to templatize this class.
202 class property_option : public base_option {
203 public:
204     property_option(const char, const char*, const char*, const char*);
205     property_option(const char*, const char*, const char*);
~property_option(void)206     virtual ~property_option(void) {}
207 
208     /// The data type of this option.
209     typedef std::pair< std::string, std::string > option_type;
210 
211     virtual void validate(const std::string& str) const;
212     static option_type convert(const std::string& str);
213 };
214 
215 
216 /// Definition of a free-form string option.
217 ///
218 /// This class provides no restrictions on the argument passed to the option.
219 class string_option : public base_option {
220 public:
221     string_option(const char, const char*, const char*, const char*,
222                   const char* = NULL);
223     string_option(const char*, const char*, const char*, const char* = NULL);
~string_option(void)224     virtual ~string_option(void) {}
225 
226     /// The data type of this option.
227     typedef std::string option_type;
228 
229     virtual void validate(const std::string& str) const;
230     static std::string convert(const std::string& str);
231 };
232 
233 
234 }  // namespace cmdline
235 }  // namespace utils
236 
237 #endif  // !defined(UTILS_CMDLINE_OPTIONS_HPP)
238