parse_command_line.hpp
Go to the documentation of this file.
1 
13 #ifndef MLPACK_BINDINGS_CLI_PARSE_COMMAND_LINE_HPP
14 #define MLPACK_BINDINGS_CLI_PARSE_COMMAND_LINE_HPP
15 
16 #include <mlpack/core.hpp>
17 #include <boost/program_options.hpp>
18 #include "print_help.hpp"
19 
20 namespace mlpack {
21 namespace bindings {
22 namespace cli {
23 
24 // Add default parameters that are included in every program.
25 PARAM_FLAG("help", "Default help info.", "h");
26 PARAM_STRING_IN("info", "Print help on a specific option.", "", "");
27 PARAM_FLAG("verbose", "Display informational messages and the full list of "
28  "parameters and timers at the end of execution.", "v");
29 PARAM_FLAG("version", "Display the version of mlpack.", "V");
30 
35 void ParseCommandLine(int argc, char** argv)
36 {
37  // First, we need to build the boost::program_options variables for parsing.
38  using namespace boost::program_options;
39  options_description desc;
40  variables_map vmap;
41 
42  // Go through list of options in order to add them.
43  std::map<std::string, util::ParamData>& parameters = CLI::Parameters();
44  typedef std::map<std::string, util::ParamData>::const_iterator IteratorType;
45  std::map<std::string, std::string> boostNameMap;
46  for (IteratorType it = parameters.begin(); it != parameters.end(); ++it)
47  {
48  // Add the parameter to desc.
49  const util::ParamData& d = it->second;
50  CLI::GetSingleton().functionMap[d.tname]["AddToPO"](d, NULL,
51  (void*) &desc);
52 
53  // Generate the name the user passes on the command line.
54  std::string boostName;
55  CLI::GetSingleton().functionMap[d.tname]["MapParameterName"](d, NULL,
56  (void*) &boostName);
57  boostNameMap[boostName] = d.name;
58  }
59 
60  // Mark that we did parsing.
61  CLI::GetSingleton().didParse = true;
62 
63  // Parse the command line, then place the values in the right place.
64  try
65  {
66  basic_parsed_options<char> bpo(parse_command_line(argc, argv, desc));
67 
68  // Iterate over all the options, looking for duplicate parameters. If we
69  // find any, remove the duplicates. Note that vector options can have
70  // duplicates, so we check for those with max_tokens().
71  for (size_t i = 0; i < bpo.options.size(); ++i)
72  {
73  for (size_t j = i + 1; j < bpo.options.size(); ++j)
74  {
75  if ((bpo.options[i].string_key == bpo.options[j].string_key) &&
76  (desc.find(bpo.options[i].string_key,
77  false).semantic()->max_tokens() <= 1))
78  {
79  // If a duplicate is found, check to see if either one has a value.
80  if (bpo.options[i].value.size() == 0 &&
81  bpo.options[j].value.size() == 0)
82  {
83  // If neither has a value, we'll consider it a duplicate flag and
84  // remove the duplicate. It's important to not break out of this
85  // loop because there might be another duplicate later on in the
86  // vector.
87  bpo.options.erase(bpo.options.begin() + j);
88  --j; // Fix the index.
89  }
90  else
91  {
92  // If one or both has a value, produce an error and politely
93  // terminate. We pull the name from the original_tokens, rather
94  // than from the string_key, because the string_key is the parameter
95  // after aliases have been expanded.
96  Log::Fatal << "\"" << bpo.options[j].original_tokens[0] << "\" is "
97  << "defined multiple times." << std::endl;
98  }
99  }
100  }
101  }
102 
103  store(bpo, vmap);
104  }
105  catch (std::exception& ex)
106  {
107  Log::Fatal << "Caught exception from parsing command line: " << ex.what()
108  << std::endl;
109  }
110 
111  // Now iterate through the filled vmap, and overwrite default values with
112  // anything that's found on the command line.
113  for (variables_map::iterator i = vmap.begin(); i != vmap.end(); ++i)
114  {
115  // There is not a possibility of an unknown option, since
116  // boost::program_options would have already thrown an exception. Because
117  // some names may be mapped, we have to look through each ParamData object
118  // and get its boost name.
119  const std::string identifier = boostNameMap[i->first];
120  util::ParamData& param = parameters[identifier];
121  param.wasPassed = true;
122  CLI::GetSingleton().functionMap[param.tname]["SetParam"](param,
123  (void*) &vmap[i->first].value(), NULL);
124  }
125 
126  // Flush the buffer, make sure changes are propagated to vmap.
127  notify(vmap);
128 
129  // If the user specified any of the default options (--help, --version, or
130  // --info), handle those.
131 
132  // --version is prioritized over --help.
133  if (CLI::HasParam("version"))
134  {
135  std::cout << CLI::GetSingleton().ProgramName() << ": part of "
136  << util::GetVersion() << "." << std::endl;
137  exit(0); // Don't do anything else.
138  }
139 
140  // Default help message.
141  if (CLI::HasParam("help"))
142  {
143  Log::Info.ignoreInput = false;
144  PrintHelp();
145  exit(0); // The user doesn't want to run the program, he wants help.
146  }
147 
148  // Info on a specific parameter.
149  if (CLI::HasParam("info"))
150  {
151  Log::Info.ignoreInput = false;
152  std::string str = CLI::GetParam<std::string>("info");
153 
154  // The info node should always be there, but the user may not have specified
155  // anything.
156  if (str != "")
157  {
158  PrintHelp(str);
159  exit(0);
160  }
161 
162  // Otherwise just print the generalized help.
163  PrintHelp();
164  exit(0);
165  }
166 
167  // Print whether or not we have debugging symbols. This won't show anything
168  // if we have not compiled in debugging mode.
169  Log::Debug << "Compiled with debugging symbols." << std::endl;
170 
171  if (CLI::HasParam("verbose"))
172  {
173  // Give [INFO ] output.
174  Log::Info.ignoreInput = false;
175  }
176 
177  // Now, issue an error if we forgot any required options.
178  for (std::map<std::string, util::ParamData>::const_iterator iter =
179  parameters.begin(); iter != parameters.end(); ++iter)
180  {
181  const util::ParamData d = iter->second;
182  if (d.required)
183  {
184  const std::string boostName;
185  CLI::GetSingleton().functionMap[d.tname]["MapParameterName"](d, NULL,
186  (void*) &boostName);
187 
188  if (!vmap.count(boostName))
189  {
190  Log::Fatal << "Required option --" << boostName << " is undefined."
191  << std::endl;
192  }
193  }
194  }
195 }
196 
197 } // namespace cli
198 } // namespace bindings
199 } // namespace mlpack
200 
201 #endif
bool didParse
True, if CLI was used to parse command line options.
Definition: cli.hpp:311
boost::any value
The actual value that is held.
Definition: param_data.hpp:82
Linear algebra utility functions, generally performed on matrices or vectors.
Definition: add_to_po.hpp:21
bool wasPassed
True if the option was passed to the program.
Definition: param_data.hpp:66
static CLI & GetSingleton()
Retrieve the singleton.
static MLPACK_EXPORT util::NullOutStream Debug
MLPACK_EXPORT is required for global variables, so that they are properly exported by the Windows com...
Definition: log.hpp:79
bool ignoreInput
Discards input, prints nothing if true.
static std::string ProgramName()
Get the program name as set by the PROGRAM_INFO() macro.
static std::map< std::string, util::ParamData > & Parameters()
Return a modifiable list of parameters that CLI knows about.
static MLPACK_EXPORT util::PrefixedOutStream Fatal
Prints fatal messages prefixed with [FATAL], then terminates the program.
Definition: log.hpp:90
void ParseCommandLine(int argc, char **argv)
Parse the command line, setting all of the options inside of the CLI object to their appropriate give...
static MLPACK_EXPORT util::PrefixedOutStream Info
Prints informational messages if –verbose is specified, prefixed with [INFO ].
Definition: log.hpp:84
std::string GetVersion()
This will return either "mlpack x.y.z" or "mlpack master-XXXXXXX" depending on whether or not this is...
This structure holds all of the information about a single parameter, including its value (which is s...
Definition: param_data.hpp:52
std::string tname
Type information of this parameter.
Definition: param_data.hpp:61
Include all of the base components required to write mlpack methods, and the main mlpack Doxygen docu...
std::string name
Name of this parameter.
Definition: param_data.hpp:56
bool required
True if this option is required.
Definition: param_data.hpp:71
void PrintHelp(const std::string &param="")
Print the help for the given parameter.
PARAM_FLAG("help", "Default help info.", "h")
PARAM_STRING_IN("info", "Print help on a specific option.", "", "")
static bool HasParam(const std::string &identifier)
See if the specified flag was found while parsing.
FunctionMapType functionMap
Definition: cli.hpp:302