xref: /minix3/external/bsd/kyua-cli/dist/cli/cmd_help.cpp (revision 11be35a165022172ed3cea20f2b5df0307540b0e)
1*11be35a1SLionel Sambuc // Copyright 2010 Google Inc.
2*11be35a1SLionel Sambuc // All rights reserved.
3*11be35a1SLionel Sambuc //
4*11be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
5*11be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
6*11be35a1SLionel Sambuc // met:
7*11be35a1SLionel Sambuc //
8*11be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
9*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer.
10*11be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
11*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer in the
12*11be35a1SLionel Sambuc //   documentation and/or other materials provided with the distribution.
13*11be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
14*11be35a1SLionel Sambuc //   may be used to endorse or promote products derived from this software
15*11be35a1SLionel Sambuc //   without specific prior written permission.
16*11be35a1SLionel Sambuc //
17*11be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*11be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*11be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*11be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*11be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*11be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*11be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*11be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*11be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*11be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*11be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc 
29*11be35a1SLionel Sambuc #include "cli/cmd_help.hpp"
30*11be35a1SLionel Sambuc 
31*11be35a1SLionel Sambuc #include <algorithm>
32*11be35a1SLionel Sambuc #include <cstdlib>
33*11be35a1SLionel Sambuc 
34*11be35a1SLionel Sambuc #include "cli/common.ipp"
35*11be35a1SLionel Sambuc #include "utils/cmdline/commands_map.ipp"
36*11be35a1SLionel Sambuc #include "utils/cmdline/exceptions.hpp"
37*11be35a1SLionel Sambuc #include "utils/cmdline/globals.hpp"
38*11be35a1SLionel Sambuc #include "utils/cmdline/options.hpp"
39*11be35a1SLionel Sambuc #include "utils/cmdline/parser.hpp"
40*11be35a1SLionel Sambuc #include "utils/cmdline/ui.hpp"
41*11be35a1SLionel Sambuc #include "utils/defs.hpp"
42*11be35a1SLionel Sambuc #include "utils/format/macros.hpp"
43*11be35a1SLionel Sambuc #include "utils/sanity.hpp"
44*11be35a1SLionel Sambuc #include "utils/text/table.hpp"
45*11be35a1SLionel Sambuc 
46*11be35a1SLionel Sambuc namespace cmdline = utils::cmdline;
47*11be35a1SLionel Sambuc namespace config = utils::config;
48*11be35a1SLionel Sambuc namespace text = utils::text;
49*11be35a1SLionel Sambuc 
50*11be35a1SLionel Sambuc using cli::cmd_help;
51*11be35a1SLionel Sambuc 
52*11be35a1SLionel Sambuc 
53*11be35a1SLionel Sambuc namespace {
54*11be35a1SLionel Sambuc 
55*11be35a1SLionel Sambuc 
56*11be35a1SLionel Sambuc /// Creates a table with the help of a set of options.
57*11be35a1SLionel Sambuc ///
58*11be35a1SLionel Sambuc /// \param options The set of options to describe.  May be empty.
59*11be35a1SLionel Sambuc ///
60*11be35a1SLionel Sambuc /// \return A 2-column wide table with the description of the options.
61*11be35a1SLionel Sambuc static text::table
options_help(const cmdline::options_vector & options)62*11be35a1SLionel Sambuc options_help(const cmdline::options_vector& options)
63*11be35a1SLionel Sambuc {
64*11be35a1SLionel Sambuc     text::table table(2);
65*11be35a1SLionel Sambuc 
66*11be35a1SLionel Sambuc     for (cmdline::options_vector::const_iterator iter = options.begin();
67*11be35a1SLionel Sambuc          iter != options.end(); iter++) {
68*11be35a1SLionel Sambuc         const cmdline::base_option* option = *iter;
69*11be35a1SLionel Sambuc 
70*11be35a1SLionel Sambuc         std::string description = option->description();
71*11be35a1SLionel Sambuc         if (option->needs_arg() && option->has_default_value())
72*11be35a1SLionel Sambuc             description += F(" (default: %s)") % option->default_value();
73*11be35a1SLionel Sambuc 
74*11be35a1SLionel Sambuc         text::table_row row;
75*11be35a1SLionel Sambuc 
76*11be35a1SLionel Sambuc         if (option->has_short_name())
77*11be35a1SLionel Sambuc             row.push_back(F("%s, %s") % option->format_short_name() %
78*11be35a1SLionel Sambuc                           option->format_long_name());
79*11be35a1SLionel Sambuc         else
80*11be35a1SLionel Sambuc             row.push_back(F("%s") % option->format_long_name());
81*11be35a1SLionel Sambuc         row.push_back(F("%s.") % description);
82*11be35a1SLionel Sambuc 
83*11be35a1SLionel Sambuc         table.add_row(row);
84*11be35a1SLionel Sambuc     }
85*11be35a1SLionel Sambuc 
86*11be35a1SLionel Sambuc     return table;
87*11be35a1SLionel Sambuc }
88*11be35a1SLionel Sambuc 
89*11be35a1SLionel Sambuc 
90*11be35a1SLionel Sambuc /// Prints the summary of commands and generic options.
91*11be35a1SLionel Sambuc ///
92*11be35a1SLionel Sambuc /// \param ui Object to interact with the I/O of the program.
93*11be35a1SLionel Sambuc /// \param options The set of program-wide options for which to print help.
94*11be35a1SLionel Sambuc /// \param commands The set of commands for which to print help.
95*11be35a1SLionel Sambuc static void
general_help(cmdline::ui * ui,const cmdline::options_vector * options,const cmdline::commands_map<cli::cli_command> * commands)96*11be35a1SLionel Sambuc general_help(cmdline::ui* ui, const cmdline::options_vector* options,
97*11be35a1SLionel Sambuc              const cmdline::commands_map< cli::cli_command >* commands)
98*11be35a1SLionel Sambuc {
99*11be35a1SLionel Sambuc     PRE(!commands->empty());
100*11be35a1SLionel Sambuc 
101*11be35a1SLionel Sambuc     ui->out_tag_wrap(
102*11be35a1SLionel Sambuc         "Usage: ",
103*11be35a1SLionel Sambuc         F("%s [general_options] command [command_options] [args]") %
104*11be35a1SLionel Sambuc         cmdline::progname(), false);
105*11be35a1SLionel Sambuc 
106*11be35a1SLionel Sambuc     const text::table options_table = options_help(*options);
107*11be35a1SLionel Sambuc     text::widths_vector::value_type first_width =
108*11be35a1SLionel Sambuc         options_table.column_width(0);
109*11be35a1SLionel Sambuc 
110*11be35a1SLionel Sambuc     std::map< std::string, text::table > command_tables;
111*11be35a1SLionel Sambuc 
112*11be35a1SLionel Sambuc     for (cmdline::commands_map< cli::cli_command >::const_iterator
113*11be35a1SLionel Sambuc          iter = commands->begin(); iter != commands->end(); iter++) {
114*11be35a1SLionel Sambuc         const std::string& category = (*iter).first;
115*11be35a1SLionel Sambuc         const std::set< std::string >& command_names = (*iter).second;
116*11be35a1SLionel Sambuc 
117*11be35a1SLionel Sambuc         command_tables.insert(std::map< std::string, text::table >::value_type(
118*11be35a1SLionel Sambuc             category, text::table(2)));
119*11be35a1SLionel Sambuc         text::table& table = command_tables.find(category)->second;
120*11be35a1SLionel Sambuc 
121*11be35a1SLionel Sambuc         for (std::set< std::string >::const_iterator i2 = command_names.begin();
122*11be35a1SLionel Sambuc              i2 != command_names.end(); i2++) {
123*11be35a1SLionel Sambuc             const cli::cli_command* command = commands->find(*i2);
124*11be35a1SLionel Sambuc             text::table_row row;
125*11be35a1SLionel Sambuc             row.push_back(command->name());
126*11be35a1SLionel Sambuc             row.push_back(F("%s.") % command->short_description());
127*11be35a1SLionel Sambuc             table.add_row(row);
128*11be35a1SLionel Sambuc         }
129*11be35a1SLionel Sambuc 
130*11be35a1SLionel Sambuc         if (table.column_width(0) > first_width)
131*11be35a1SLionel Sambuc             first_width = table.column_width(0);
132*11be35a1SLionel Sambuc     }
133*11be35a1SLionel Sambuc 
134*11be35a1SLionel Sambuc     text::table_formatter formatter;
135*11be35a1SLionel Sambuc     formatter.set_column_width(0, first_width);
136*11be35a1SLionel Sambuc     formatter.set_column_width(1, text::table_formatter::width_refill);
137*11be35a1SLionel Sambuc     formatter.set_separator("  ");
138*11be35a1SLionel Sambuc 
139*11be35a1SLionel Sambuc     if (!options_table.empty()) {
140*11be35a1SLionel Sambuc         ui->out_wrap("");
141*11be35a1SLionel Sambuc         ui->out_wrap("Available general options:");
142*11be35a1SLionel Sambuc         ui->out_table(options_table, formatter, "  ");
143*11be35a1SLionel Sambuc     }
144*11be35a1SLionel Sambuc 
145*11be35a1SLionel Sambuc     // Iterate using the same loop as above to preserve ordering.
146*11be35a1SLionel Sambuc     for (cmdline::commands_map< cli::cli_command >::const_iterator
147*11be35a1SLionel Sambuc          iter = commands->begin(); iter != commands->end(); iter++) {
148*11be35a1SLionel Sambuc         const std::string& category = (*iter).first;
149*11be35a1SLionel Sambuc         ui->out_wrap("");
150*11be35a1SLionel Sambuc         ui->out_wrap(F("%s commands:") %
151*11be35a1SLionel Sambuc                 (category.empty() ? "Generic" : category));
152*11be35a1SLionel Sambuc         ui->out_table(command_tables.find(category)->second, formatter, "  ");
153*11be35a1SLionel Sambuc     }
154*11be35a1SLionel Sambuc 
155*11be35a1SLionel Sambuc     ui->out_wrap("");
156*11be35a1SLionel Sambuc     ui->out_wrap("See kyua(1) for more details.");
157*11be35a1SLionel Sambuc }
158*11be35a1SLionel Sambuc 
159*11be35a1SLionel Sambuc 
160*11be35a1SLionel Sambuc /// Prints help for a particular subcommand.
161*11be35a1SLionel Sambuc ///
162*11be35a1SLionel Sambuc /// \param ui Object to interact with the I/O of the program.
163*11be35a1SLionel Sambuc /// \param general_options The options that apply to all commands.
164*11be35a1SLionel Sambuc /// \param command Pointer to the command to describe.
165*11be35a1SLionel Sambuc static void
subcommand_help(cmdline::ui * ui,const utils::cmdline::options_vector * general_options,const cli::cli_command * command)166*11be35a1SLionel Sambuc subcommand_help(cmdline::ui* ui,
167*11be35a1SLionel Sambuc                 const utils::cmdline::options_vector* general_options,
168*11be35a1SLionel Sambuc                 const cli::cli_command* command)
169*11be35a1SLionel Sambuc {
170*11be35a1SLionel Sambuc     ui->out_tag_wrap(
171*11be35a1SLionel Sambuc         "Usage: ", F("%s [general_options] %s%s%s") %
172*11be35a1SLionel Sambuc         cmdline::progname() % command->name() %
173*11be35a1SLionel Sambuc         (command->options().empty() ? "" : " [command_options]") %
174*11be35a1SLionel Sambuc         (command->arg_list().empty() ? "" : (" " + command->arg_list())),
175*11be35a1SLionel Sambuc         false);
176*11be35a1SLionel Sambuc     ui->out_wrap("");
177*11be35a1SLionel Sambuc     ui->out_wrap(F("%s.") % command->short_description());
178*11be35a1SLionel Sambuc 
179*11be35a1SLionel Sambuc     const text::table general_table = options_help(*general_options);
180*11be35a1SLionel Sambuc     const text::table command_table = options_help(command->options());
181*11be35a1SLionel Sambuc 
182*11be35a1SLionel Sambuc     const text::widths_vector::value_type first_width =
183*11be35a1SLionel Sambuc         std::max(general_table.column_width(0), command_table.column_width(0));
184*11be35a1SLionel Sambuc     text::table_formatter formatter;
185*11be35a1SLionel Sambuc     formatter.set_column_width(0, first_width);
186*11be35a1SLionel Sambuc     formatter.set_column_width(1, text::table_formatter::width_refill);
187*11be35a1SLionel Sambuc     formatter.set_separator("  ");
188*11be35a1SLionel Sambuc 
189*11be35a1SLionel Sambuc     if (!general_table.empty()) {
190*11be35a1SLionel Sambuc         ui->out_wrap("");
191*11be35a1SLionel Sambuc         ui->out_wrap("Available general options:");
192*11be35a1SLionel Sambuc         ui->out_table(general_table, formatter, "  ");
193*11be35a1SLionel Sambuc     }
194*11be35a1SLionel Sambuc 
195*11be35a1SLionel Sambuc     if (!command_table.empty()) {
196*11be35a1SLionel Sambuc         ui->out_wrap("");
197*11be35a1SLionel Sambuc         ui->out_wrap("Available command options:");
198*11be35a1SLionel Sambuc         ui->out_table(command_table, formatter, "  ");
199*11be35a1SLionel Sambuc     }
200*11be35a1SLionel Sambuc 
201*11be35a1SLionel Sambuc     ui->out_wrap("");
202*11be35a1SLionel Sambuc     ui->out_wrap(F("See kyua-%s(1) for more details.") % command->name());
203*11be35a1SLionel Sambuc }
204*11be35a1SLionel Sambuc 
205*11be35a1SLionel Sambuc 
206*11be35a1SLionel Sambuc }  // anonymous namespace
207*11be35a1SLionel Sambuc 
208*11be35a1SLionel Sambuc 
209*11be35a1SLionel Sambuc /// Default constructor for cmd_help.
210*11be35a1SLionel Sambuc ///
211*11be35a1SLionel Sambuc /// \param options_ The set of program-wide options for which to provide help.
212*11be35a1SLionel Sambuc /// \param commands_ The set of commands for which to provide help.
cmd_help(const cmdline::options_vector * options_,const cmdline::commands_map<cli_command> * commands_)213*11be35a1SLionel Sambuc cmd_help::cmd_help(const cmdline::options_vector* options_,
214*11be35a1SLionel Sambuc                    const cmdline::commands_map< cli_command >* commands_) :
215*11be35a1SLionel Sambuc     cli_command("help", "[subcommand]", 0, 1, "Shows usage information"),
216*11be35a1SLionel Sambuc     _options(options_),
217*11be35a1SLionel Sambuc     _commands(commands_)
218*11be35a1SLionel Sambuc {
219*11be35a1SLionel Sambuc }
220*11be35a1SLionel Sambuc 
221*11be35a1SLionel Sambuc 
222*11be35a1SLionel Sambuc /// Entry point for the "help" subcommand.
223*11be35a1SLionel Sambuc ///
224*11be35a1SLionel Sambuc /// \param ui Object to interact with the I/O of the program.
225*11be35a1SLionel Sambuc /// \param cmdline Representation of the command line to the subcommand.
226*11be35a1SLionel Sambuc /// \param unused_user_config The runtime configuration of the program.
227*11be35a1SLionel Sambuc ///
228*11be35a1SLionel Sambuc /// \return 0 to indicate success.
229*11be35a1SLionel Sambuc int
run(utils::cmdline::ui * ui,const cmdline::parsed_cmdline & cmdline,const config::tree & UTILS_UNUSED_PARAM (user_config))230*11be35a1SLionel Sambuc cmd_help::run(utils::cmdline::ui* ui, const cmdline::parsed_cmdline& cmdline,
231*11be35a1SLionel Sambuc               const config::tree& UTILS_UNUSED_PARAM(user_config))
232*11be35a1SLionel Sambuc {
233*11be35a1SLionel Sambuc     if (cmdline.arguments().empty()) {
234*11be35a1SLionel Sambuc         general_help(ui, _options, _commands);
235*11be35a1SLionel Sambuc     } else {
236*11be35a1SLionel Sambuc         INV(cmdline.arguments().size() == 1);
237*11be35a1SLionel Sambuc         const std::string& cmdname = cmdline.arguments()[0];
238*11be35a1SLionel Sambuc         const cli::cli_command* command = _commands->find(cmdname);
239*11be35a1SLionel Sambuc         if (command == NULL)
240*11be35a1SLionel Sambuc             throw cmdline::usage_error(F("The command %s does not exist") %
241*11be35a1SLionel Sambuc                                        cmdname);
242*11be35a1SLionel Sambuc         else
243*11be35a1SLionel Sambuc             subcommand_help(ui, _options, command);
244*11be35a1SLionel Sambuc     }
245*11be35a1SLionel Sambuc 
246*11be35a1SLionel Sambuc     return EXIT_SUCCESS;
247*11be35a1SLionel Sambuc }
248