g2o
Loading...
Searching...
No Matches
command_args.cpp
Go to the documentation of this file.
1// g2o - General Graph Optimization
2// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright notice,
10// this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#include "command_args.h"
28
29#include <algorithm>
30#include <cstdlib>
31#include <cstring>
32#include <fstream>
33#include <functional>
34
35#include "misc.h"
36#include "os_specific.h"
37#include "string_tools.h"
38using namespace std;
39
40namespace g2o {
41
42namespace {
43
44template <typename T>
45void readVector(const std::string& s, std::vector<T>& v) {
46 v.clear();
47
48 std::vector<std::string> elements = strSplit(s, ",;");
49 for (const std::string& s : elements) {
50 T val = stringToType<T>(s);
51 v.emplace_back(val);
52 }
53}
54
55template <typename T>
56std::string writeVectorAsString(const std::vector<T>& v) {
57 std::stringstream os;
58 if (v.size()) os << v[0];
59 for (size_t i = 1; i < v.size(); i++) os << "," << v[i];
60 return os.str();
61}
62
63template <typename T>
64void parseArgument(const std::string& input, CommandArgs::CommandArgument& ca) {
65 T aux;
66 bool convertStatus = convertString(input, aux);
67 if (convertStatus) {
68 T* data = static_cast<T*>(ca.data);
69 *data = aux;
70 }
71}
72
73template <typename T>
74void parseVector(const std::string& input, CommandArgs::CommandArgument& ca) {
75 std::vector<T> aux;
76 readVector(input, aux);
77 bool convertStatus = aux.size() > 0;
78 if (convertStatus) {
79 std::vector<T>* data = static_cast<std::vector<T>*>(ca.data);
80 *data = aux;
81 }
82}
83
84template <typename T>
85std::string argument2String(const CommandArgs::CommandArgument& ca) {
86 T* data = static_cast<T*>(ca.data);
87 stringstream auxStream;
88 auxStream << *data;
89 return auxStream.str();
90}
91
92} // namespace
93
103
105
106bool CommandArgs::parseArgs(int argc, char** argv, bool exitOnError) {
107 _progName = argv[0];
108 int i;
109 for (i = 1; i < argc; i++) {
110 string name = argv[i];
111
112 if (name[0] != '-') { // each param has to start with at least one dash
113 // cerr << "Error: expecting parameter, got " << name << endl;
114 // printHelp(cerr);
115 // if (exitOnError)
116 // exit(1);
117 // return false;
118 break;
119 }
120 /* first check whether it's -- and we should not continue parsing */
121 if (name == "--") {
122 ++i;
123 break;
124 }
125
126 string::size_type dashPos = name.find_first_not_of('-');
127 if (dashPos != string::npos) name = name.substr(dashPos);
128
129 if (name == "help" || name == "h") {
130 printHelp(cout);
131 exit(0);
132 } else {
133 // command line argument parsing
134 std::vector<CommandArgument>::iterator it = _args.begin();
135 for (; it != _args.end(); ++it) {
136 if (it->name == name) {
137 if (it->type == CAT_BOOL) {
138 if (!it->parsed) {
139 bool* data = static_cast<bool*>(it->data);
140 *data = !(*data);
141 }
142 it->parsed = true;
143 } else {
144 if (i >= argc - 1) {
145 cerr << "Argument " << name << "needs value.\n";
146 printHelp(cerr);
147 if (exitOnError) exit(1);
148 return false;
149 }
150 i++;
151 str2arg(argv[i], *it);
152 it->parsed = true;
153 }
154 break;
155 }
156 }
157 if (it == _args.end()) {
158 cerr << "Error: Unknown Option '" << name
159 << "' (use -help to get list of options).\n";
160 if (exitOnError) exit(1);
161 return false;
162 }
163 }
164 } // for argv[i]
165
166 if ((int)_leftOvers.size() > argc - i) {
167 cerr << "Error: program requires parameters" << endl;
168 printHelp(cerr);
169 if (exitOnError) exit(1);
170 return false;
171 }
172 for (size_t j = 0; (i < argc && j < _leftOvers.size()); i++, j++) {
173 string* s = static_cast<string*>(_leftOvers[j].data);
174 *s = argv[i];
175 _leftOvers[j].parsed = true;
176 }
177
178 // the optional leftOvers
179 for (size_t j = 0; (i < argc && j < _leftOversOptional.size()); i++, j++) {
180 string* s = static_cast<string*>(_leftOversOptional[j].data);
181 *s = argv[i];
182 _leftOversOptional[j].parsed = true;
183 }
184
185 return true;
186}
187
188void CommandArgs::param(const std::string& name, bool& p, bool defValue,
189 const std::string& desc) {
191 ca.name = name;
192 ca.description = desc;
193 ca.type = CAT_BOOL;
194 ca.data = static_cast<void*>(&p);
195 ca.parsed = false;
196 p = defValue;
197 _args.push_back(ca);
198}
199
200void CommandArgs::param(const std::string& name, int& p, int defValue,
201 const std::string& desc) {
203 ca.name = name;
204 ca.description = desc;
205 ca.type = CAT_INT;
206 ca.data = static_cast<void*>(&p);
207 ca.parsed = false;
208 p = defValue;
209 _args.push_back(ca);
210}
211
212void CommandArgs::param(const std::string& name, float& p, float defValue,
213 const std::string& desc) {
215 ca.name = name;
216 ca.description = desc;
217 ca.type = CAT_FLOAT;
218 ca.data = static_cast<void*>(&p);
219 ca.parsed = false;
220 p = defValue;
221 _args.push_back(ca);
222}
223
224void CommandArgs::param(const std::string& name, double& p, double defValue,
225 const std::string& desc) {
227 ca.name = name;
228 ca.description = desc;
229 ca.type = CAT_DOUBLE;
230 ca.data = static_cast<void*>(&p);
231 ca.parsed = false;
232 p = defValue;
233 _args.push_back(ca);
234}
235
236void CommandArgs::param(const std::string& name, std::string& p,
237 const std::string& defValue, const std::string& desc) {
239 ca.name = name;
240 ca.description = desc;
241 ca.type = CAT_STRING;
242 ca.data = static_cast<void*>(&p);
243 ca.parsed = false;
244 p = defValue;
245 _args.push_back(ca);
246}
247
248void CommandArgs::param(const std::string& name, std::vector<int>& p,
249 const std::vector<int>& defValue,
250 const std::string& desc) {
252 ca.name = name;
253 ca.description = desc;
254 ca.type = CAT_VECTOR_INT;
255 ca.data = static_cast<void*>(&p);
256 ca.parsed = false;
257 p = defValue;
258 _args.push_back(ca);
259}
260
261void CommandArgs::param(const std::string& name, std::vector<double>& p,
262 const std::vector<double>& defValue,
263 const std::string& desc) {
265 ca.name = name;
266 ca.description = desc;
268 ca.data = static_cast<void*>(&p);
269 ca.parsed = false;
270 p = defValue;
271 _args.push_back(ca);
272}
273
274void CommandArgs::printHelp(std::ostream& os) {
275 if (_banner.size()) os << _banner << endl;
276 os << "Usage: " << _progName << (_args.size() > 0 ? " [options] " : " ");
277 if (_leftOvers.size() > 0) {
278 for (size_t i = 0; i < _leftOvers.size(); ++i) {
279 if (i > 0) os << " ";
280 os << _leftOvers[i].name;
281 }
282 }
283 if (_leftOversOptional.size() > 0) {
284 if (_leftOvers.size() > 0) os << " ";
285 for (size_t i = 0; i < _leftOversOptional.size(); ++i) {
286 if (i > 0) os << " ";
287 os << "[" << _leftOversOptional[i].name << "]";
288 }
289 }
290 os << endl << endl;
291 os << "General options:" << endl;
292 os << "-------------------------------------------" << endl;
293 os << "-help / -h Displays this help." << endl << endl;
294 if (_args.size() > 0) {
295 os << "Program Options:" << endl;
296 os << "-------------------------------------------" << endl;
297 // build up option string to print as table
298 vector<pair<string, string> > tableStrings;
299 tableStrings.reserve(_args.size());
300 size_t maxArgLen = 0;
301 for (size_t i = 0; i < _args.size(); ++i) {
302 if (_args[i].type != CAT_BOOL) {
303 string defaultValueStr = arg2str(_args[i]);
304 if (!defaultValueStr.empty())
305 tableStrings.push_back(make_pair(
306 _args[i].name + " " + type2str(_args[i].type),
307 _args[i].description + " (default: " + defaultValueStr + ")"));
308 else
309 tableStrings.push_back(
310 make_pair(_args[i].name + " " + type2str(_args[i].type),
311 _args[i].description));
312 } else
313 tableStrings.push_back(make_pair(_args[i].name, _args[i].description));
314 maxArgLen = (std::max)(maxArgLen, tableStrings.back().first.size());
315 }
316 sort(tableStrings.begin(), tableStrings.end(),
318 maxArgLen += 3;
319 for (size_t i = 0; i < tableStrings.size(); ++i) {
320 os << "-" << tableStrings[i].first;
321 for (size_t l = tableStrings[i].first.size(); l < maxArgLen; ++l)
322 os << " ";
323 os << tableStrings[i].second << endl;
324 }
325 // TODO should output description for leftOver params?
326 }
327}
328
329void CommandArgs::setBanner(const std::string& banner) { _banner = banner; }
330
331void CommandArgs::paramLeftOver(const std::string& name, std::string& p,
332 const std::string& defValue,
333 const std::string& desc, bool optional) {
335 ca.name = name;
336 ca.description = desc;
337 ca.type = CAT_STRING;
338 ca.data = static_cast<void*>(&p);
339 ca.parsed = false;
340 ca.optional = optional;
341 p = defValue;
342 if (optional)
343 _leftOversOptional.push_back(ca);
344 else
345 _leftOvers.push_back(ca);
346}
347
348const char* CommandArgs::type2str(int t) const {
349 switch (t) {
350 case CAT_DOUBLE:
351 return "<double>";
352 case CAT_FLOAT:
353 return "<float>";
354 case CAT_INT:
355 return "<int>";
356 case CAT_STRING:
357 return "<string>";
358 case CAT_BOOL:
359 return "<bool>";
360 case CAT_VECTOR_INT:
361 return "<vector_int>";
363 return "<vector_double>";
364 }
365 return "";
366}
367
368void CommandArgs::str2arg(const std::string& input, CommandArgument& ca) const {
369 switch (ca.type) {
370 case CAT_FLOAT:
371 parseArgument<float>(input, ca);
372 break;
373 case CAT_DOUBLE:
374 parseArgument<double>(input, ca);
375 break;
376 case CAT_INT:
377 parseArgument<int>(input, ca);
378 break;
379 case CAT_BOOL:
380 parseArgument<bool>(input, ca);
381 break;
382 case CAT_STRING: {
383 string* data = static_cast<string*>(ca.data);
384 *data = input;
385 } break;
386 case CAT_VECTOR_INT: {
387 parseVector<int>(input, ca);
388 } break;
389 case CAT_VECTOR_DOUBLE: {
390 parseVector<double>(input, ca);
391 } break;
392 }
393}
394
395std::string CommandArgs::arg2str(const CommandArgument& ca) const {
396 switch (ca.type) {
397 case CAT_FLOAT:
398 return argument2String<float>(ca);
399 case CAT_DOUBLE:
400 return argument2String<double>(ca);
401 case CAT_INT:
402 return argument2String<int>(ca);
403 case CAT_BOOL:
404 return argument2String<bool>(ca);
405 case CAT_STRING: {
406 string* data = static_cast<string*>(ca.data);
407 return *data;
408 }
409 case CAT_VECTOR_INT: {
410 std::vector<int>* data = static_cast<std::vector<int>*>(ca.data);
411 return writeVectorAsString(*data);
412 }
413 case CAT_VECTOR_DOUBLE: {
414 std::vector<double>* data = static_cast<std::vector<double>*>(ca.data);
415 return writeVectorAsString(*data);
416 }
417 }
418 return "";
419}
420
421bool CommandArgs::parsedParam(const std::string& param) const {
422 std::vector<CommandArgument>::const_iterator it = _args.begin();
423 for (; it != _args.end(); ++it) {
424 if (it->name == param) {
425 return it->parsed;
426 }
427 }
428 return false;
429}
430
431} // end namespace g2o
bool parseArgs(int argc, char **argv, bool exitOnError=true)
void paramLeftOver(const std::string &name, std::string &p, const std::string &defValue, const std::string &desc, bool optional=false)
std::vector< CommandArgument > _leftOversOptional
void printHelp(std::ostream &os)
void str2arg(const std::string &input, CommandArgument &ca) const
std::string _banner
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
void setBanner(const std::string &banner)
const char * type2str(int t) const
std::string _progName
std::string arg2str(const CommandArgument &ca) const
std::vector< CommandArgument > _args
bool parsedParam(const std::string &paramFlag) const
std::vector< CommandArgument > _leftOvers
some general case utility functions
bool readVector(std::istream &is, Eigen::DenseBase< Derived > &b)
Definition io_helper.h:42
CommandArgumentType
@ CAT_VECTOR_DOUBLE
@ CAT_DOUBLE
@ CAT_FLOAT
@ CAT_VECTOR_INT
@ CAT_STRING
bool convertString(const std::string &s, T &x, bool failIfLeftoverChars=true)
std::vector< std::string > strSplit(const std::string &str, const std::string &delimiters)
Definition jet.h:876