Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
run.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_LIBTOOL_RUN_TCC__
6 #define __ZETH_LIBTOOL_RUN_TCC__
7 
8 #include "libtool/run.hpp"
9 
10 namespace libtool
11 {
12 
13 namespace internal
14 {
15 
16 template<typename GlobalOptionsT>
17 void print_usage(
18  const char *const *argv,
19  const po::options_description &options,
20  const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands)
21 {
22  std::cout << "Usage:\n"
23  << " " << argv[0] << " [OPTIONS] COMMAND [ARGS] ...\n\n"
24  << options;
25 
26  std::cout << "\nCommands:\n";
27 
28  // list_commands(commands);
29  using entry_t = std::pair<std::string, subcommand<GlobalOptionsT> *>;
30 
31  // +4 here to ensure minimal space between command name and description
32  const size_t cmd_name_padded =
33  4 + std::max_element(
34  subcommands.begin(),
35  subcommands.end(),
36  [](const entry_t &a, const entry_t &b) {
37  return a.first.size() < b.first.size();
38  })
39  ->first.size();
40 
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";
45  }
46 
47  std::cout << std::endl;
48 }
49 
50 template<typename GlobalOptionsT>
51 int run_subcommand(
52  const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands,
53  const std::string &command_name,
54  const char *argv0,
55  const std::vector<std::string> &command_args,
56  const GlobalOptionsT &global_options)
57 {
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");
62  }
63 
64  subcommand<GlobalOptionsT> *sub = sub_it->second;
65  return sub->execute(argv0, command_args, global_options);
66 }
67 
68 } // namespace internal
69 
70 template<typename GlobalOptionsT>
71 int run_command(
72  command<GlobalOptionsT> &command,
73  GlobalOptionsT &options,
74  const std::map<std::string, subcommand<GlobalOptionsT> *> &subcommands,
75  int argc,
76  char **argv)
77 {
78  po::options_description global("Global options");
79  po::options_description all("");
80 
81  // Default --help option
82  global.add_options()("help,h", "Show this help message and exit");
83 
84  // Global options
85  command.initialize_global_options(global, all);
86 
87  // Add a single positional "command" option.
88  po::positional_options_description pos;
89  all.add_options()(
90  "command", po::value<std::string>(), "Command to execute")(
91  "subargs",
92  po::value<std::vector<std::string>>(),
93  "Arguments to command");
94  pos.add("command", 1).add("subargs", -1);
95 
96  auto usage = [&argv, &global, &subcommands]() {
97  internal::print_usage<GlobalOptionsT>(argv, global, subcommands);
98  };
99 
100  try {
101  po::variables_map vm;
102  po::parsed_options parsed = po::command_line_parser(argc, argv)
103  .options(all)
104  .positional(pos)
105  .allow_unregistered()
106  .run();
107  po::store(parsed, vm);
108 
109  const bool help_flag = (bool)vm.count("help");
110 
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")) {
116  if (help_flag) {
117  usage();
118  return 0;
119  }
120  std::cerr << "error: no command specified\n";
121  usage();
122  return 1;
123  }
124 
125  // Parse the global options
126  command.parse_global_options(options, vm);
127 
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];
133 
134  // Add the --help flag back, if given (it was absorbed by the global
135  // parser above).
136  if (help_flag) {
137  subargs.push_back("--help");
138  }
139 
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;
144  usage();
145  }
146 
147  return 1;
148 }
149 
150 } // namespace libtool
151 
152 #endif // __ZETH_LIBTOOL_RUN_TCC__