xref: /src/contrib/kyua/utils/cmdline/base_command.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
108334c51SBrooks Davis // Copyright 2010 The Kyua Authors.
208334c51SBrooks Davis // All rights reserved.
308334c51SBrooks Davis //
408334c51SBrooks Davis // Redistribution and use in source and binary forms, with or without
508334c51SBrooks Davis // modification, are permitted provided that the following conditions are
608334c51SBrooks Davis // met:
708334c51SBrooks Davis //
808334c51SBrooks Davis // * Redistributions of source code must retain the above copyright
908334c51SBrooks Davis //   notice, this list of conditions and the following disclaimer.
1008334c51SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
1108334c51SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
1208334c51SBrooks Davis //   documentation and/or other materials provided with the distribution.
1308334c51SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
1408334c51SBrooks Davis //   may be used to endorse or promote products derived from this software
1508334c51SBrooks Davis //   without specific prior written permission.
1608334c51SBrooks Davis //
1708334c51SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1808334c51SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1908334c51SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2008334c51SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2108334c51SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2208334c51SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2308334c51SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2408334c51SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2508334c51SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2608334c51SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2708334c51SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2808334c51SBrooks Davis 
2908334c51SBrooks Davis #include "utils/cmdline/base_command.hpp"
3008334c51SBrooks Davis 
3108334c51SBrooks Davis #include "utils/cmdline/exceptions.hpp"
3208334c51SBrooks Davis #include "utils/cmdline/options.hpp"
3308334c51SBrooks Davis #include "utils/cmdline/parser.ipp"
3408334c51SBrooks Davis #include "utils/sanity.hpp"
3508334c51SBrooks Davis 
3608334c51SBrooks Davis namespace cmdline = utils::cmdline;
3708334c51SBrooks Davis 
3808334c51SBrooks Davis 
3908334c51SBrooks Davis /// Creates a new command.
4008334c51SBrooks Davis ///
4108334c51SBrooks Davis /// \param name_ The name of the command.  Must be unique within the context of
4208334c51SBrooks Davis ///     a program and have no spaces.
4308334c51SBrooks Davis /// \param arg_list_ A textual description of the arguments received by the
4408334c51SBrooks Davis ///     command.  May be empty.
4508334c51SBrooks Davis /// \param min_args_ The minimum number of arguments required by the command.
4608334c51SBrooks Davis /// \param max_args_ The maximum number of arguments required by the command.
4708334c51SBrooks Davis ///     -1 means infinity.
4808334c51SBrooks Davis /// \param short_description_ A description of the purpose of the command.
command_proto(const std::string & name_,const std::string & arg_list_,const int min_args_,const int max_args_,const std::string & short_description_)4908334c51SBrooks Davis cmdline::command_proto::command_proto(const std::string& name_,
5008334c51SBrooks Davis                                       const std::string& arg_list_,
5108334c51SBrooks Davis                                       const int min_args_,
5208334c51SBrooks Davis                                       const int max_args_,
5308334c51SBrooks Davis                                       const std::string& short_description_) :
5408334c51SBrooks Davis     _name(name_),
5508334c51SBrooks Davis     _arg_list(arg_list_),
5608334c51SBrooks Davis     _min_args(min_args_),
5708334c51SBrooks Davis     _max_args(max_args_),
5808334c51SBrooks Davis     _short_description(short_description_)
5908334c51SBrooks Davis {
6008334c51SBrooks Davis     PRE(name_.find(' ') == std::string::npos);
6108334c51SBrooks Davis     PRE(max_args_ == -1 || min_args_ <= max_args_);
6208334c51SBrooks Davis }
6308334c51SBrooks Davis 
6408334c51SBrooks Davis 
6508334c51SBrooks Davis /// Destructor for a command.
~command_proto(void)6608334c51SBrooks Davis cmdline::command_proto::~command_proto(void)
6708334c51SBrooks Davis {
6808334c51SBrooks Davis     for (options_vector::const_iterator iter = _options.begin();
6908334c51SBrooks Davis          iter != _options.end(); iter++)
7008334c51SBrooks Davis         delete *iter;
7108334c51SBrooks Davis }
7208334c51SBrooks Davis 
7308334c51SBrooks Davis 
7408334c51SBrooks Davis /// Internal method to register a dynamically-allocated option.
7508334c51SBrooks Davis ///
7608334c51SBrooks Davis /// Always use add_option() from subclasses to add options.
7708334c51SBrooks Davis ///
7808334c51SBrooks Davis /// \param option_ The option to add.  Must have been dynamically allocated.
7908334c51SBrooks Davis ///     This grabs ownership of the pointer, which is released when the command
8008334c51SBrooks Davis ///     is destroyed.
8108334c51SBrooks Davis void
add_option_ptr(const cmdline::base_option * option_)8208334c51SBrooks Davis cmdline::command_proto::add_option_ptr(const cmdline::base_option* option_)
8308334c51SBrooks Davis {
8408334c51SBrooks Davis     try {
8508334c51SBrooks Davis         _options.push_back(option_);
8608334c51SBrooks Davis     } catch (...) {
8708334c51SBrooks Davis         delete option_;
8808334c51SBrooks Davis         throw;
8908334c51SBrooks Davis     }
9008334c51SBrooks Davis }
9108334c51SBrooks Davis 
9208334c51SBrooks Davis 
9308334c51SBrooks Davis /// Processes the command line based on the command description.
9408334c51SBrooks Davis ///
9508334c51SBrooks Davis /// \param args The raw command line to be processed.
9608334c51SBrooks Davis ///
9708334c51SBrooks Davis /// \return An object containing the list of options and free arguments found in
9808334c51SBrooks Davis /// args.
9908334c51SBrooks Davis ///
10008334c51SBrooks Davis /// \throw cmdline::usage_error If there is a problem processing the command
10108334c51SBrooks Davis ///     line.  This error is caused by invalid input from the user.
10208334c51SBrooks Davis cmdline::parsed_cmdline
parse_cmdline(const cmdline::args_vector & args) const10308334c51SBrooks Davis cmdline::command_proto::parse_cmdline(const cmdline::args_vector& args) const
10408334c51SBrooks Davis {
10508334c51SBrooks Davis     PRE(name() == args[0]);
10608334c51SBrooks Davis     const parsed_cmdline cmdline = cmdline::parse(args, options());
10708334c51SBrooks Davis 
10808334c51SBrooks Davis     const int argc = cmdline.arguments().size();
10908334c51SBrooks Davis     if (argc < _min_args)
11008334c51SBrooks Davis         throw usage_error("Not enough arguments");
11108334c51SBrooks Davis     if (_max_args != -1 && argc > _max_args)
11208334c51SBrooks Davis         throw usage_error("Too many arguments");
11308334c51SBrooks Davis 
11408334c51SBrooks Davis     return cmdline;
11508334c51SBrooks Davis }
11608334c51SBrooks Davis 
11708334c51SBrooks Davis 
11808334c51SBrooks Davis /// Gets the name of the command.
11908334c51SBrooks Davis ///
12008334c51SBrooks Davis /// \return The command name.
12108334c51SBrooks Davis const std::string&
name(void) const12208334c51SBrooks Davis cmdline::command_proto::name(void) const
12308334c51SBrooks Davis {
12408334c51SBrooks Davis     return _name;
12508334c51SBrooks Davis }
12608334c51SBrooks Davis 
12708334c51SBrooks Davis 
12808334c51SBrooks Davis /// Gets the textual representation of the arguments list.
12908334c51SBrooks Davis ///
13008334c51SBrooks Davis /// \return The description of the arguments list.
13108334c51SBrooks Davis const std::string&
arg_list(void) const13208334c51SBrooks Davis cmdline::command_proto::arg_list(void) const
13308334c51SBrooks Davis {
13408334c51SBrooks Davis     return _arg_list;
13508334c51SBrooks Davis }
13608334c51SBrooks Davis 
13708334c51SBrooks Davis 
13808334c51SBrooks Davis /// Gets the description of the purpose of the command.
13908334c51SBrooks Davis ///
14008334c51SBrooks Davis /// \return The description of the command.
14108334c51SBrooks Davis const std::string&
short_description(void) const14208334c51SBrooks Davis cmdline::command_proto::short_description(void) const
14308334c51SBrooks Davis {
14408334c51SBrooks Davis     return _short_description;
14508334c51SBrooks Davis }
14608334c51SBrooks Davis 
14708334c51SBrooks Davis 
14808334c51SBrooks Davis /// Gets the definition of the options accepted by the command.
14908334c51SBrooks Davis ///
15008334c51SBrooks Davis /// \return The list of options.
15108334c51SBrooks Davis const cmdline::options_vector&
options(void) const15208334c51SBrooks Davis cmdline::command_proto::options(void) const
15308334c51SBrooks Davis {
15408334c51SBrooks Davis     return _options;
15508334c51SBrooks Davis }
15608334c51SBrooks Davis 
15708334c51SBrooks Davis 
15808334c51SBrooks Davis /// Creates a new command.
15908334c51SBrooks Davis ///
16008334c51SBrooks Davis /// \param name_ The name of the command.  Must be unique within the context of
16108334c51SBrooks Davis ///     a program and have no spaces.
16208334c51SBrooks Davis /// \param arg_list_ A textual description of the arguments received by the
16308334c51SBrooks Davis ///     command.  May be empty.
16408334c51SBrooks Davis /// \param min_args_ The minimum number of arguments required by the command.
16508334c51SBrooks Davis /// \param max_args_ The maximum number of arguments required by the command.
16608334c51SBrooks Davis ///     -1 means infinity.
16708334c51SBrooks Davis /// \param short_description_ A description of the purpose of the command.
base_command_no_data(const std::string & name_,const std::string & arg_list_,const int min_args_,const int max_args_,const std::string & short_description_)16808334c51SBrooks Davis cmdline::base_command_no_data::base_command_no_data(
16908334c51SBrooks Davis     const std::string& name_,
17008334c51SBrooks Davis     const std::string& arg_list_,
17108334c51SBrooks Davis     const int min_args_,
17208334c51SBrooks Davis     const int max_args_,
17308334c51SBrooks Davis     const std::string& short_description_) :
17408334c51SBrooks Davis     command_proto(name_, arg_list_, min_args_, max_args_, short_description_)
17508334c51SBrooks Davis {
17608334c51SBrooks Davis }
17708334c51SBrooks Davis 
17808334c51SBrooks Davis 
17908334c51SBrooks Davis /// Entry point for the command.
18008334c51SBrooks Davis ///
18108334c51SBrooks Davis /// This delegates execution to the run() abstract function after the command
18208334c51SBrooks Davis /// line provided in args has been parsed.
18308334c51SBrooks Davis ///
18408334c51SBrooks Davis /// If this function returns, the command is assumed to have been executed
18508334c51SBrooks Davis /// successfully.  Any error must be reported by means of exceptions.
18608334c51SBrooks Davis ///
18708334c51SBrooks Davis /// \param ui Object to interact with the I/O of the command.  The command must
18808334c51SBrooks Davis ///     always use this object to write to stdout and stderr.
18908334c51SBrooks Davis /// \param args The command line passed to the command broken by word, which
19008334c51SBrooks Davis ///     includes options and arguments.
19108334c51SBrooks Davis ///
19208334c51SBrooks Davis /// \return The exit code that the program has to return.  0 on success, some
19308334c51SBrooks Davis ///     other value on error.
19408334c51SBrooks Davis /// \throw usage_error If args is invalid (i.e. if the options are mispecified
19508334c51SBrooks Davis ///     or if the arguments are invalid).
19608334c51SBrooks Davis int
main(cmdline::ui * ui,const cmdline::args_vector & args)19708334c51SBrooks Davis cmdline::base_command_no_data::main(cmdline::ui* ui,
19808334c51SBrooks Davis                                     const cmdline::args_vector& args)
19908334c51SBrooks Davis {
20008334c51SBrooks Davis     return run(ui, parse_cmdline(args));
20108334c51SBrooks Davis }
202