$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
option_parser.hh
1 // Copyright (C) 2011, 2012 EPITA Research and Development Laboratory
2 // (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef SCRIBO_DEBUG_OPTION_PARSER_HH
28 # define SCRIBO_DEBUG_OPTION_PARSER_HH
29 
30 # include <map>
31 # include <scribo/debug/option_check.hh>
32 
33 namespace scribo
34 {
35 
36  namespace debug
37  {
38 
39  struct arg_data
40  {
41  const char* name;
42  const char* desc;
43  };
44 
45 
46  struct toggle_data
47  {
48  const char* name;
49  const char* desc;
50  bool enabled;
51  };
52 
53 
54  struct opt_data
55  {
56  const char *name;
57  const char *desc;
58  const char *format;
59  bool (*fcheck)(const std::vector<const char *>&);
60  int n_args;
61  const char *by_default;
62  };
63 
64 
66  {
67  public:
68  option_parser(const arg_data arg_desc[],
69  const toggle_data toggle_desc[],
70  const opt_data opt_desc[]);
71 
72  bool parse(int argc, char *argv[]);
73 
74  void print_help() const;
75 
76  bool is_enabled(const char *toggle_name) const;
77  bool is_set(const char *opt_name) const;
78 
79  std::vector<const char *> opt_values(const char *opt_name) const;
80  std::string opt_value(const char *opt_name) const;
81 
82  const char* arg(const char *) const;
83 
84  void set_verbose_enabled(bool b);
85 
86 
87  private:
88  typedef std::map<std::string, bool> toggles_t;
89  typedef std::vector<const char *> vector_t;
90  typedef std::map<std::string, vector_t> opts_t;
91  typedef std::map<std::string, const char *> args_t;
92 
93  bool validate_toggle(const char *name, const char *fullname) const;
94  bool validate_option(const char *name, const char *fullname, int& opt_id) const;
95 
96  args_t args_;
97  toggles_t toggles_;
98  opts_t opts_;
99  unsigned required_argc_;
100  const char *name_;
101 
102  const arg_data *arg_desc_;
103  const toggle_data *toggle_desc_;
104  const opt_data *opt_desc_;
105 
106  bool verbose;
107  };
108 
109 
110 # ifndef MLN_INCLUDE_ONLY
111 
112  inline
113  option_parser::option_parser(const arg_data arg_desc[],
114  const toggle_data toggle_desc[],
115  const opt_data opt_desc[])
116  : arg_desc_(arg_desc), toggle_desc_(toggle_desc), opt_desc_(opt_desc),
117  verbose(false)
118  {
119  for (required_argc_ = 0; arg_desc_[required_argc_].name; ++required_argc_)
120  ; // None
121 
122  // Setting up toggles.
123  for (int i = 0; toggle_desc_[i].name; ++i)
124  toggles_[toggle_desc_[i].name] = toggle_desc_[i].enabled;
125 
126  // Settings up default option values (if available)
127  for (int i = 0; opt_desc_[i].name; ++i)
128  if (opt_desc_[i].by_default)
129  opts_[opt_desc_[i].name].push_back(opt_desc_[i].by_default);
130  }
131 
132 
133  inline
134  bool
135  option_parser::validate_toggle(const char *name, const char *fullname) const
136  {
137  if (toggles_.find(name) == toggles_.end())
138  {
139  std::cerr << "Error: invalid toggle " << fullname << std::endl;
140  return false;
141  }
142 
143  return true;
144  }
145 
146 
147  inline
148  bool
149  option_parser::validate_option(const char *name, const char *fullname,
150  int& opt_id) const
151  {
152  // Get option id.
153  opt_id = 0;
154  for (; opt_desc_[opt_id].name && strcmp(opt_desc_[opt_id].name, name); ++opt_id)
155  ;
156 
157  // Does this option really exist?
158  if (!opt_desc_[opt_id].name)
159  {
160  std::cerr << "Error: invalid option " << fullname << std::endl;
161  return false;
162  }
163 
164  return true;
165  }
166 
167 
168  inline
169  bool
170  option_parser::parse(int argc, char *argv[])
171  {
172  bool no_error = true;
173  unsigned nrequired_argc = 0;
174 
175  // Get application name.
176  name_ = argv[0];
177  char **arg_end = argv + argc;
178  ++argv;
179 
180  while (argv < arg_end)
181  {
182  switch(argv[0][0])
183  {
184  case '-':
185  switch(argv[0][1])
186  {
187  // Toggle or option.
188  case '-':
189  if (! strncmp(argv[0], "--enable-", 9))
190  {
191  if (!validate_toggle(argv[0] + 9, argv[0]))
192  {
193  no_error = false;
194  break;
195  }
196 
197  toggles_[argv[0] + 9] = true; // enable
198  if (verbose)
199  std::cout << "> Toggle " << argv[0] + 9
200  << " enabled" << std::endl;
201  }
202  else if (! strncmp(argv[0], "--disable-", 10))
203  {
204  if (!validate_toggle(argv[0] + 10, argv[0]))
205  {
206  no_error = false;
207  break;
208  }
209 
210  toggles_[argv[0] + 10] = false; // disable
211  if (verbose)
212  std::cout << "> Toggle " << argv[0] + 10
213  << " disabled" << std::endl;
214  }
215  else // Option
216  {
217  char *opt = argv[0] + 2;
218  opts_[opt] = vector_t();
219 
220  // Checking if it is --help
221  if (!strcmp(argv[0], "--help"))
222  {
223  print_help();
224  exit(0);
225  }
226 
227  int opt_id = 0;
228  if (!validate_option(opt, argv[0], opt_id))
229  {
230  no_error = false;
231  break;
232  }
233 
234  if (verbose)
235  std::cout << " * Looking for arguments for option "
236  << opt << std::endl;
237 
238  // Clear potential previous values
239  opts_[opt].clear();
240 
241  // Switch to option args.
242  char **arg_lookup = argv + opt_desc_[opt_id].n_args;
243  ++argv;
244 
245  // Retrieving the expected arguments
246  while (argv < arg_end && argv <= arg_lookup)
247  {
248  opts_[opt].push_back(argv[0]);
249  ++argv;
250  }
251 
252  // Checking if we found all the option arguments.
253  if (argv <= arg_lookup)
254  {
255  std::cerr << "Error: missing arguments for option "
256  << opt << std::endl;
257  no_error = false;
258  break;
259  }
260 
261  --argv; // Don't move now to the next program argument,
262 
263  // Checking option parameter if possible.
264  if (opt_desc_[opt_id].fcheck
265  && !opt_desc_[opt_id].fcheck(opts_[opt]))
266  {
267  no_error = false;
268  break;
269  }
270 
271  // it will be done here [1].
272 
273  if (verbose)
274  {
275  std::cout << "> Set option " << opt << " to ";
276  for (vector_t::const_iterator it = opts_[opt].begin();
277  it != opts_[opt].end(); ++it)
278  std::cout << *it << " ";
279  std::cout << std::endl;
280  }
281  }
282  break;
283 
284  // Error
285  default:
286  std::cerr << "Error: invalid option " << argv[0] << std::endl;
287  no_error = false;
288  }
289  ++argv; // Moving to the next program argument. [1]
290  break;
291 
292  // I/O parameters
293  default:
294  if (nrequired_argc == required_argc_)
295  {
296  std::cerr << "Error: wrong number of arguments! \""
297  << argv[0] << "\" was not expected!" << std::endl;
298  no_error = false;
299  }
300  else
301  {
302  args_[arg_desc_[nrequired_argc].name] = argv[0];
303  ++nrequired_argc;
304  }
305  ++argv;
306  break;
307  }
308  }
309 
310  if (nrequired_argc != required_argc_)
311  {
312  if (nrequired_argc)
313  std::cerr << "Error: wrong number of arguments!" << std::endl;
314  no_error = false;
315  }
316 
317  if (! no_error)
318  {
319  std::cout << std::endl;
320  std::cout << "--------------" << std::endl;
321  print_help();
322  }
323 
324  return no_error;
325  }
326 
327  std::string add_space(const char* name)
328  {
329  std::string str;
330 
331  int len = 20 - strlen(name);
332  for (int i = 0; i < len; ++i)
333  str += " ";
334  str += " ";
335 
336  return str;
337  }
338 
339  inline
340  void
341  option_parser::print_help() const
342  {
343  std::cout << " Usage: " << name_;
344  for (int i = 0; arg_desc_[i].name; ++i)
345  std::cout << " " << arg_desc_[i].name;
346 
347  if (opt_desc_[0].name)
348  std::cout << " [OPTIONS]";
349 
350  if (toggle_desc_[0].name)
351  std::cout << " [TOGGLES]" << std::endl;
352 
353  std::cout << std::endl << std::endl;
354 
355  std::cout << " List of the mandatory arguments:"
356  << std::endl << std::endl;
357 
358  for (int i = 0; arg_desc_[i].name; ++i)
359  std::cout << " " << arg_desc_[i].name << add_space(arg_desc_[i].name)
360  << arg_desc_[i].desc << std::endl;
361 
362  std::cout << std::endl << std::endl;
363 
364  // Display options if needed.
365  if (opt_desc_[0].name)
366  {
367  std::cout << " [OPTIONS] can be replaced by one or several "
368  << "following options :" << std::endl << std::endl;
369 
370  for (int i = 0; opt_desc_[i].name; ++i)
371  {
372  std::cout << " " << "--" << opt_desc_[i].name << " ";
373 
374  if (opt_desc_[i].format)
375  std::cout << opt_desc_[i].format << std::endl;
376 
377  std::cout << "\t" << opt_desc_[i].desc << std::endl;
378 
379  if (opt_desc_[i].by_default)
380  std::cout << "\tDefault value: " << opt_desc_[i].by_default << std::endl;
381 
382  std::cout << std::endl;
383  }
384 
385  std::cout << " --help" << std::endl;
386  std::cout << "\t Display this help." << std::endl << std::endl;
387 
388  std::cout << std::endl << std::endl;
389  }
390 
391  // Display toggles if needed.
392  if (toggle_desc_[0].name)
393  {
394  std::cout << " [TOGGLES] can be replaced by one or several "
395  << "following toggle names prefixed by --enable- or --disable- :"
396  << std::endl << std::endl;
397 
398  for (int i = 0; toggle_desc_[i].name; ++i)
399  std::cout << " " << toggle_desc_[i].name << add_space(toggle_desc_[i].name)
400  << toggle_desc_[i].desc << std::endl;
401 
402  std::cout << std::endl << std::endl;
403  }
404 
405  std::cout << "------------" << std::endl;
406  std::cout << "EPITA/LRDE - Scribo 2008-2011" << std::endl;
407  }
408 
409 
410  inline
411  bool
412  option_parser::is_enabled(const char *toggle_name) const
413  {
414  toggles_t::const_iterator it = toggles_.find(toggle_name);
415  return it->second;
416  }
417 
418 
419  inline
420  bool
421  option_parser::is_set(const char *opt_name) const
422  {
423  return opts_.find(opt_name) != opts_.end();
424  }
425 
426 
427  inline
428  std::vector<const char*>
429  option_parser::opt_values(const char *opt_name) const
430  {
431  opts_t::const_iterator it = opts_.find(opt_name);
432  mln_assertion(it != opts_.end());
433  return it->second;
434  }
435 
436 
437  inline
438  std::string
439  option_parser::opt_value(const char *opt_name) const
440  {
441  opts_t::const_iterator it = opts_.find(opt_name);
442  mln_assertion(it != opts_.end());
443  return it->second[0];
444  }
445 
446 
447  inline
448  const char*
449  option_parser::arg(const char* name) const
450  {
451  mln_assertion(args_.find(name) != args_.end());
452  return args_.find(name)->second;
453  }
454 
455 
456  inline
457  void
458  option_parser::set_verbose_enabled(bool b)
459  {
460  verbose = b;
461  }
462 
463 
464 # endif // ! MLN_INCLUDE_ONLY
465 
466  } // end of namespace scribo::debug
467 
468 } // end of namespace scribo
469 
470 #endif // ! SCRIBO_DEBUG_OPTION_PARSER_HH