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
43namespace utils {
44namespace 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.
81class 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
102public:
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.
131class bool_option : public base_option {
132public:
133    bool_option(const char, const char*, const char*);
134    bool_option(const char*, const char*);
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.
143class int_option : public base_option {
144public:
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);
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.
159class list_option : public base_option {
160public:
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);
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.
178class path_option : public base_option {
179public:
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);
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.
202class property_option : public base_option {
203public:
204    property_option(const char, const char*, const char*, const char*);
205    property_option(const char*, const char*, const char*);
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.
219class string_option : public base_option {
220public:
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);
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