1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_LIBTOOL_RUN_TCC__
6 #define __ZETH_LIBTOOL_RUN_TCC__
8 #include "libtool/run.hpp"
16 template<typename GlobalOptionsT>
18 const char *const *argv,
19 const po::options_description &options,
20 const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands)
22 std::cout << "Usage:\n"
23 << " " << argv[0] << " [OPTIONS] COMMAND [ARGS] ...\n\n"
26 std::cout << "\nCommands:\n";
28 // list_commands(commands);
29 using entry_t = std::pair<std::string, subcommand<GlobalOptionsT> *>;
31 // +4 here to ensure minimal space between command name and description
32 const size_t cmd_name_padded =
36 [](const entry_t &a, const entry_t &b) {
37 return a.first.size() < b.first.size();
41 for (const auto &cmd : subcommands) {
42 const size_t padding = cmd_name_padded - cmd.first.size();
43 std::cout << " " << cmd.first << std::string(padding, ' ')
44 << cmd.second->description() << "\n";
47 std::cout << std::endl;
50 template<typename GlobalOptionsT>
52 const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands,
53 const std::string &command_name,
55 const std::vector<std::string> &command_args,
56 const GlobalOptionsT &global_options)
58 const typename std::map<std::string, subcommand<GlobalOptionsT> *>::
59 const_iterator sub_it = subcommands.find(command_name);
60 if (sub_it == subcommands.end()) {
61 throw po::error("invalid command");
64 subcommand<GlobalOptionsT> *sub = sub_it->second;
65 return sub->execute(argv0, command_args, global_options);
68 } // namespace internal
70 template<typename GlobalOptionsT>
72 command<GlobalOptionsT> &command,
73 GlobalOptionsT &options,
74 const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands,
78 po::options_description global("Global options");
79 po::options_description all("");
81 // Default --help option
82 global.add_options()("help,h", "Show this help message and exit");
85 command.initialize_global_options(global, all);
87 // Add a single positional "command" option.
88 po::positional_options_description pos;
90 "command", po::value<std::string>(), "Command to execute")(
92 po::value<std::vector<std::string>>(),
93 "Arguments to command");
94 pos.add("command", 1).add("subargs", -1);
96 auto usage = [&argv, &global, &subcommands]() {
97 internal::print_usage<GlobalOptionsT>(argv, global, subcommands);
101 po::variables_map vm;
102 po::parsed_options parsed = po::command_line_parser(argc, argv)
105 .allow_unregistered()
107 po::store(parsed, vm);
109 const bool help_flag = (bool)vm.count("help");
111 // If no command was given, print the top-level usage message. If a
112 // help flag was specified, exit normally, otherwise print an error
113 // message and exit with error. (If a command was given, the help flag
114 // is passed to the subcommand).
115 if (!vm.count("command")) {
120 std::cerr << "error: no command specified\n";
125 // Parse the global options
126 command.parse_global_options(options, vm);
128 // Execute the subcommand
129 const std::string subcommand(vm["command"].as<std::string>());
130 std::vector<std::string> subargs =
131 po::collect_unrecognized(parsed.options, po::include_positional);
132 subargs[0] = std::string(argv[0]) + " " + subargs[0];
134 // Add the --help flag back, if given (it was absorbed by the global
137 subargs.push_back("--help");
140 return internal::run_subcommand(
141 subcommands, subcommand, argv[0], subargs, options);
142 } catch (po::error &error) {
143 std::cerr << " ERROR: " << error.what() << std::endl;
150 } // namespace libtool
152 #endif // __ZETH_LIBTOOL_RUN_TCC__