Path: blob/main/contrib/kyua/utils/cmdline/options.hpp
48179 views
// Copyright 2010 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728/// \file utils/cmdline/options.hpp29/// Definitions of command-line options.3031#if !defined(UTILS_CMDLINE_OPTIONS_HPP)32#define UTILS_CMDLINE_OPTIONS_HPP3334#include "utils/cmdline/options_fwd.hpp"3536#include <string>37#include <utility>38#include <vector>3940#include "utils/fs/path_fwd.hpp"4142namespace utils {43namespace cmdline {444546/// Type-less base option class.47///48/// This abstract class provides the most generic representation of options. It49/// allows defining options with both short and long names, with and without50/// arguments and with and without optional values. These are all the possible51/// combinations supported by the getopt_long(3) function, on which this is52/// built.53///54/// The internal values (e.g. the default value) of a generic option are all55/// represented as strings. However, from the caller's perspective, this is56/// suboptimal. Hence why this class must be specialized: the subclasses57/// provide type-specific accessors and provide automatic validation of the58/// types (e.g. a string '3foo' is not passed to an integer option).59///60/// Given that subclasses are used through templatized code, they must provide:61///62/// <ul>63/// <li>A public option_type typedef that defines the type of the64/// option.</li>65///66/// <li>A convert() method that takes a string and converts it to67/// option_type. The string can be assumed to be convertible to the68/// destination type. Should not raise exceptions.</li>69///70/// <li>A validate() method that matches the implementation of convert().71/// This method can throw option_argument_value_error if the string cannot72/// be converted appropriately. If validate() does not throw, then73/// convert() must execute successfully.</li>74/// </ul>75///76/// TODO(jmmv): Many methods in this class are split into two parts: has_foo()77/// and foo(), the former to query if the foo is available and the latter to get78/// the foo. It'd be very nice if we'd use something similar Boost.Optional to79/// simplify this interface altogether.80class base_option {81/// Short name of the option; 0 to indicate that none is available.82char _short_name;8384/// Long name of the option.85std::string _long_name;8687/// Textual description of the purpose of the option.88std::string _description;8990/// Descriptive name of the required argument; empty if not allowed.91std::string _arg_name;9293/// Whether the option has a default value or not.94///95/// \todo We should probably be using the optional class here.96bool _has_default_value;9798/// If _has_default_value is true, the default value.99std::string _default_value;100101public:102base_option(const char, const char*, const char*, const char* = NULL,103const char* = NULL);104base_option(const char*, const char*, const char* = NULL,105const char* = NULL);106virtual ~base_option(void);107108bool has_short_name(void) const;109char short_name(void) const;110const std::string& long_name(void) const;111const std::string& description(void) const;112113bool needs_arg(void) const;114const std::string& arg_name(void) const;115116bool has_default_value(void) const;117const std::string& default_value(void) const;118119std::string format_short_name(void) const;120std::string format_long_name(void) const;121122virtual void validate(const std::string&) const;123};124125126/// Definition of a boolean option.127///128/// A boolean option can be specified once in the command line, at which point129/// is set to true. Such an option cannot carry optional arguments.130class bool_option : public base_option {131public:132bool_option(const char, const char*, const char*);133bool_option(const char*, const char*);134virtual ~bool_option(void) {}135136/// The data type of this option.137typedef bool option_type;138};139140141/// Definition of an integer option.142class int_option : public base_option {143public:144int_option(const char, const char*, const char*, const char*,145const char* = NULL);146int_option(const char*, const char*, const char*, const char* = NULL);147virtual ~int_option(void) {}148149/// The data type of this option.150typedef int option_type;151152virtual void validate(const std::string& str) const;153static int convert(const std::string& str);154};155156157/// Definition of a comma-separated list of strings.158class list_option : public base_option {159public:160list_option(const char, const char*, const char*, const char*,161const char* = NULL);162list_option(const char*, const char*, const char*, const char* = NULL);163virtual ~list_option(void) {}164165/// The data type of this option.166typedef std::vector< std::string > option_type;167168virtual void validate(const std::string&) const;169static option_type convert(const std::string&);170};171172173/// Definition of an option representing a path.174///175/// The path pointed to by the option may not exist, but it must be176/// syntactically valid.177class path_option : public base_option {178public:179path_option(const char, const char*, const char*, const char*,180const char* = NULL);181path_option(const char*, const char*, const char*, const char* = NULL);182virtual ~path_option(void) {}183184/// The data type of this option.185typedef utils::fs::path option_type;186187virtual void validate(const std::string&) const;188static utils::fs::path convert(const std::string&);189};190191192/// Definition of a property option.193///194/// A property option is an option whose required arguments are of the form195/// 'name=value'. Both components of the property are treated as free-form196/// non-empty strings; any other validation must happen on the caller side.197///198/// \todo Would be nice if the delimiter was parametrizable. With the current199/// parser interface (convert() being a static method), the only way to do200/// this would be to templatize this class.201class property_option : public base_option {202public:203property_option(const char, const char*, const char*, const char*);204property_option(const char*, const char*, const char*);205virtual ~property_option(void) {}206207/// The data type of this option.208typedef std::pair< std::string, std::string > option_type;209210virtual void validate(const std::string& str) const;211static option_type convert(const std::string& str);212};213214215/// Definition of a free-form string option.216///217/// This class provides no restrictions on the argument passed to the option.218class string_option : public base_option {219public:220string_option(const char, const char*, const char*, const char*,221const char* = NULL);222string_option(const char*, const char*, const char*, const char* = NULL);223virtual ~string_option(void) {}224225/// The data type of this option.226typedef std::string option_type;227228virtual void validate(const std::string& str) const;229static std::string convert(const std::string& str);230};231232233} // namespace cmdline234} // namespace utils235236#endif // !defined(UTILS_CMDLINE_OPTIONS_HPP)237238239