g2o
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 <cstdlib>
30 #include <cstring>
31 #include <fstream>
32 #include <algorithm>
33 #include <functional>
34 
35 #include "os_specific.h"
36 using namespace std;
37 
38 namespace g2o {
39 
40 // forward declarations
41 std::istream& operator>>(std::istream& is, std::vector<int>& v);
42 std::ostream& operator<<(std::ostream& os, const std::vector<int>& v);
43 std::istream& operator>>(std::istream& is, std::vector<double>& v);
44 std::ostream& operator<<(std::ostream& os, const std::vector<double>& v);
45 
46 std::istream& operator>>(std::istream& is, std::vector<int>& v){
47  string s;
48  if (! (is >> s) )
49  return is;
50 
51  const char* c = s.c_str();
52  char* caux = const_cast<char*>(c);
53 
54  v.clear();
55  bool hasNextValue=true;
56  while(hasNextValue){
57  int i = static_cast<int>(strtol(c,&caux,10));
58  if (c!=caux){
59  c=caux;
60  c++;
61  v.push_back(i);
62  } else
63  hasNextValue = false;
64  }
65  return is;
66 }
67 
68 std::ostream& operator<<(std::ostream& os, const std::vector<int>& v){
69  if (v.size()){
70  os << v[0];
71  }
72  for (size_t i=1; i<v.size(); i++){
73  os << "," << v[i];
74  }
75  return os;
76 }
77 
81 template<typename T>
82 bool convertString(const std::string& s, T& x)
83 {
84  std::istringstream i(s);
85  if (! (i >> x))
86  return false;
87  return true;
88 }
89 
91 template<class T1, class T2, class Pred = std::less<T1> >
92 struct CmpPairFirst {
93  bool operator()(const std::pair<T1,T2>& left, const std::pair<T1,T2>& right) {
94  return Pred()(left.first, right.first);
95  }
96 };
97 
99 {
101 };
102 
103 CommandArgs::CommandArgs()
104 {
105 }
106 
107 CommandArgs::~CommandArgs()
108 {
109 }
110 
111 bool CommandArgs::parseArgs(int argc, char** argv, bool exitOnError)
112 {
113  _progName = argv[0];
114  int i;
115  for (i = 1; i < argc; i++) {
116  string name = argv[i];
117 
118  if (name[0] != '-') { // each param has to start with at least one dash
119  //cerr << "Error: expecting parameter, got " << name << endl;
120  //printHelp(cerr);
121  //if (exitOnError)
122  //exit(1);
123  //return false;
124  break;
125  }
126  /* first check whether it's -- and we should not continue parsing */
127  if (name == "--") {
128  ++i;
129  break;
130  }
131 
132  string::size_type dashPos = name.find_first_not_of('-');
133  if (dashPos != string::npos)
134  name = name.substr(dashPos);
135 
136  if (name == "help" || name == "h") {
137  printHelp(cout);
138  exit(0);
139  }
140  else {
141  // command line argument parsing
142  std::vector<CommandArgument>::iterator it = _args.begin();
143  for ( ; it != _args.end(); ++it) {
144  if (it->name == name) {
145  if (it->type == CAT_BOOL) {
146  if (!it->parsed) {
147  bool* data = static_cast<bool*>(it->data);
148  *data = !(*data);
149  }
150  it->parsed = true;
151  } else {
152  if(i >= argc-1) {
153  cerr << "Argument " << name << "needs value.\n";
154  printHelp(cerr);
155  if (exitOnError)
156  exit(1);
157  return false;
158  }
159  i++;
160  str2arg(argv[i], *it);
161  it->parsed = true;
162  }
163  break;
164  }
165  }
166  if (it == _args.end()) {
167  cerr << "Error: Unknown Option '" << name << "' (use -help to get list of options).\n";
168  if (exitOnError)
169  exit(1);
170  return false;
171  }
172 
173  }
174 
175  } // for argv[i]
176 
177  if ((int)_leftOvers.size() > argc - i) {
178  cerr << "Error: program requires parameters" << endl;
179  printHelp(cerr);
180  if (exitOnError)
181  exit(1);
182  return false;
183  }
184  for (size_t j = 0; (i < argc && j < _leftOvers.size()); i++, j++) {
185  string* s = static_cast<string*>(_leftOvers[j].data);
186  *s = argv[i];
187  }
188 
189  // the optional leftOvers
190  for (size_t j = 0; (i < argc && j < _leftOversOptional.size()); i++, j++) {
191  string* s = static_cast<string*>(_leftOversOptional[j].data);
192  *s = argv[i];
193  }
194 
195  return true;
196 }
197 
198 void CommandArgs::param(const std::string& name, bool& p, bool defValue, const std::string& desc)
199 {
200  CommandArgument ca;
201  ca.name = name;
202  ca.description = desc;
203  ca.type = CAT_BOOL;
204  ca.data = static_cast<void*>(&p);
205  ca.parsed = false;
206  p = defValue;
207  _args.push_back(ca);
208 }
209 
210 void CommandArgs::param(const std::string& name, int& p, int defValue, const std::string& desc)
211 {
212  CommandArgument ca;
213  ca.name = name;
214  ca.description = desc;
215  ca.type = CAT_INT;
216  ca.data = static_cast<void*>(&p);
217  ca.parsed = false;
218  p = defValue;
219  _args.push_back(ca);
220 }
221 
222 void CommandArgs::param(const std::string& name, float& p, float defValue, const std::string& desc)
223 {
224  CommandArgument ca;
225  ca.name = name;
226  ca.description = desc;
227  ca.type = CAT_FLOAT;
228  ca.data = static_cast<void*>(&p);
229  ca.parsed = false;
230  p = defValue;
231  _args.push_back(ca);
232 }
233 
234 void CommandArgs::param(const std::string& name, double& p, double defValue, const std::string& desc)
235 {
236  CommandArgument ca;
237  ca.name = name;
238  ca.description = desc;
239  ca.type = CAT_DOUBLE;
240  ca.data = static_cast<void*>(&p);
241  ca.parsed = false;
242  p = defValue;
243  _args.push_back(ca);
244 }
245 
246 void CommandArgs::param(const std::string& name, std::string& p, const std::string& defValue, const std::string& desc)
247 {
248  CommandArgument ca;
249  ca.name = name;
250  ca.description = desc;
251  ca.type = CAT_STRING;
252  ca.data = static_cast<void*>(&p);
253  ca.parsed = false;
254  p = defValue;
255  _args.push_back(ca);
256 }
257 
258 void CommandArgs::param(const std::string& name, std::vector<int>& p, const std::vector<int>& defValue, const std::string& desc){
259  CommandArgument ca;
260  ca.name = name;
261  ca.description = desc;
262  ca.type = CAT_VECTOR_INT;
263  ca.data = static_cast<void*>(&p);
264  ca.parsed = false;
265  p = defValue;
266  _args.push_back(ca);
267 }
268 
269 void CommandArgs::param(const std::string& name, std::vector<double>& p, const std::vector<double>& defValue, const std::string& desc)
270 {
271  CommandArgument ca;
272  ca.name = name;
273  ca.description = desc;
274  ca.type = CAT_VECTOR_DOUBLE;
275  ca.data = static_cast<void*>(&p);
276  ca.parsed = false;
277  p = defValue;
278  _args.push_back(ca);
279 }
280 
281 void CommandArgs::printHelp(std::ostream& os)
282 {
283  if (_banner.size())
284  os << _banner << endl;
285  os << "Usage: " << _progName << (_args.size()>0?" [options] ":" ");
286  if (_leftOvers.size() > 0) {
287  for (size_t i = 0; i < _leftOvers.size(); ++i) {
288  if (i > 0)
289  os << " ";
290  os << _leftOvers[i].name;
291  }
292  }
293  if (_leftOversOptional.size() > 0) {
294  if (_leftOvers.size() > 0)
295  os << " ";
296  for (size_t i = 0; i < _leftOversOptional.size(); ++i) {
297  if (i > 0)
298  os << " ";
299  os << "[" << _leftOversOptional[i].name << "]";
300  }
301  }
302  os << endl << endl;
303  os << "General options:" << endl;
304  os << "-------------------------------------------" << endl;
305  os << "-help / -h Displays this help." << endl << endl;
306  if (_args.size() > 0) {
307  os << "Program Options:" << endl;
308  os << "-------------------------------------------" << endl;
309  // build up option string to print as table
310  vector<pair<string, string> > tableStrings;
311  tableStrings.reserve(_args.size());
312  size_t maxArgLen = 0;
313  for (size_t i = 0; i < _args.size(); ++i) {
314  if (_args[i].type != CAT_BOOL) {
315  string defaultValueStr = arg2str(_args[i]);
316  if (! defaultValueStr.empty())
317  tableStrings.push_back(make_pair(_args[i].name + " " + type2str(_args[i].type), _args[i].description + " (default: " + defaultValueStr + ")"));
318  else
319  tableStrings.push_back(make_pair(_args[i].name + " " + type2str(_args[i].type), _args[i].description));
320  } else
321  tableStrings.push_back(make_pair(_args[i].name, _args[i].description));
322  maxArgLen = (std::max)(maxArgLen, tableStrings.back().first.size());
323  }
324  sort(tableStrings.begin(), tableStrings.end(), CmpPairFirst<string,string>());
325  maxArgLen += 3;
326  for (size_t i = 0; i < tableStrings.size(); ++i) {
327  os << "-" << tableStrings[i].first;
328  for (size_t l = tableStrings[i].first.size(); l < maxArgLen; ++l)
329  os << " ";
330  os << tableStrings[i].second << endl;
331  }
332  // TODO should output description for leftOver params?
333  }
334 }
335 
336 
337 void CommandArgs::setBanner(const std::string& banner)
338 {
339  _banner = banner;
340 }
341 
342 void CommandArgs::paramLeftOver(const std::string& name, std::string& p, const std::string& defValue, const std::string& desc, bool optional)
343 {
344  CommandArgument ca;
345  ca.name = name;
346  ca.description = desc;
347  ca.type = CAT_STRING;
348  ca.data = static_cast<void*>(&p);
349  ca.parsed = false;
350  ca.optional = optional;
351  p = defValue;
352  if (optional)
353  _leftOversOptional.push_back(ca);
354  else
355  _leftOvers.push_back(ca);
356 }
357 
358 const char* CommandArgs::type2str(int t) const
359 {
360  switch (t) {
361  case CAT_DOUBLE:
362  return "<double>";
363  case CAT_FLOAT:
364  return "<float>";
365  case CAT_INT:
366  return "<int>";
367  case CAT_STRING:
368  return "<string>";
369  case CAT_BOOL:
370  return "<bool>";
371  case CAT_VECTOR_INT:
372  return "<vector_int>";
373  case CAT_VECTOR_DOUBLE:
374  return "<vector_double>";
375  }
376  return "";
377 }
378 
379 void CommandArgs::str2arg(const std::string& input, CommandArgument& ca) const
380 {
381  switch (ca.type) {
382  case CAT_FLOAT:
383  {
384  float aux;
385  bool convertStatus = convertString(input, aux);
386  if (convertStatus) {
387  float* data = static_cast<float*>(ca.data);
388  *data = aux;
389  }
390  }
391  break;
392  case CAT_DOUBLE:
393  {
394  double aux;
395  bool convertStatus = convertString(input, aux);
396  if (convertStatus) {
397  double* data = static_cast<double*>(ca.data);
398  *data = aux;
399  }
400  }
401  break;
402  case CAT_INT:
403  {
404  int aux;
405  bool convertStatus = convertString(input, aux);
406  if (convertStatus) {
407  int* data = static_cast<int*>(ca.data);
408  *data = aux;
409  }
410  }
411  break;
412  case CAT_BOOL:
413  {
414  bool aux;
415  bool convertStatus = convertString(input, aux);
416  if (convertStatus) {
417  bool* data = static_cast<bool*>(ca.data);
418  *data = aux;
419  }
420  }
421  break;
422  case CAT_STRING:
423  {
424  string* data = static_cast<string*>(ca.data);
425  *data = input;
426  }
427  break;
428  case CAT_VECTOR_INT:
429  {
430  std::vector<int> aux;
431  bool convertStatus = convertString(input, aux);
432  if (convertStatus) {
433  std::vector<int>* data = static_cast< std::vector<int>* >(ca.data);
434  *data = aux;
435  }
436  }
437  break;
438  case CAT_VECTOR_DOUBLE:
439  {
440  std::vector<double> aux;
441  bool convertStatus = convertString(input, aux);
442  if (convertStatus) {
443  std::vector<double>* data = static_cast< std::vector<double>* >(ca.data);
444  *data = aux;
445  }
446  }
447  break;
448  }
449 }
450 
451 std::string CommandArgs::arg2str(const CommandArgument& ca) const
452 {
453  switch (ca.type) {
454  case CAT_FLOAT:
455  {
456  float* data = static_cast<float*>(ca.data);
457  stringstream auxStream;
458  auxStream << *data;
459  return auxStream.str();
460  }
461  case CAT_DOUBLE:
462  {
463  double* data = static_cast<double*>(ca.data);
464  stringstream auxStream;
465  auxStream << *data;
466  return auxStream.str();
467  }
468  case CAT_INT:
469  {
470  int* data = static_cast<int*>(ca.data);
471  stringstream auxStream;
472  auxStream << *data;
473  return auxStream.str();
474  }
475  case CAT_BOOL:
476  {
477  bool* data = static_cast<bool*>(ca.data);
478  stringstream auxStream;
479  auxStream << *data;
480  return auxStream.str();
481  }
482  case CAT_STRING:
483  {
484  string* data = static_cast<string*>(ca.data);
485  return *data;
486  }
487  case CAT_VECTOR_INT:
488  {
489  std::vector<int> * data = static_cast< std::vector<int> * >(ca.data);
490  stringstream auxStream;
491  auxStream << (*data);
492  return auxStream.str();
493  }
494  case CAT_VECTOR_DOUBLE:
495  {
496  std::vector<double> * data = static_cast< std::vector<double> * >(ca.data);
497  stringstream auxStream;
498  auxStream << (*data);
499  return auxStream.str();
500  }
501  }
502  return "";
503 }
504 
505 std::string CommandArgs::trim(const std::string& s) const
506 {
507  if(s.length() == 0)
508  return s;
509  string::size_type b = s.find_first_not_of(" \t\n");
510  string::size_type e = s.find_last_not_of(" \t\n");
511  if(b == string::npos)
512  return "";
513  return std::string(s, b, e - b + 1);
514 }
515 
516 
517 std::istream& operator>>(std::istream& is, std::vector<double>& v){
518  string s;
519  if (! (is >> s) )
520  return is;
521 
522  const char* c = s.c_str();
523  char* caux = const_cast<char*>(c);
524 
525  v.clear();
526  bool hasNextValue=true;
527  while(hasNextValue){
528  double i=strtod(c,&caux);
529  if (c!=caux){
530  c=caux;
531  c++;
532  v.push_back(i);
533  } else
534  hasNextValue = false;
535  }
536  return is;
537 }
538 
539 std::ostream& operator<<(std::ostream& os, const std::vector<double>& v)
540 {
541  if (v.size())
542  os << v[0];
543  for (size_t i=1; i<v.size(); i++)
544  os << ";" << v[i];
545  return os;
546 }
547 
548 bool CommandArgs::parsedParam(const std::string& param) const
549 {
550  std::vector<CommandArgument>::const_iterator it = _args.begin();
551  for ( ; it != _args.end(); ++it) {
552  if (it->name == param) {
553  return it->parsed;
554  }
555  }
556  return false;
557 }
558 
559 } // end namespace g2o
std::istream & operator>>(std::istream &is, std::vector< double > &v)
std::string trim(const std::string &s)
bool convertString(const std::string &s, T &x)
CommandArgumentType
bool operator()(const std::pair< T1, T2 > &left, const std::pair< T1, T2 > &right)