MFEM  v3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
optparser.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.googlecode.com.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #include "optparser.hpp"
13 #include "../linalg/vector.hpp"
14 #include <cctype>
15 
16 namespace mfem
17 {
18 
19 using namespace std;
20 
21 int isValidAsInt(char * s)
22 {
23  if ( s == NULL || *s == '\0' )
24  return 0; //Empty string
25 
26  if ( *s == '+' || *s == '-' )
27  ++s;
28 
29  if ( *s == '\0')
30  return 0; //sign character only
31 
32  while(*s)
33  {
34  if( !isdigit(*s) )
35  return 0;
36  ++s;
37  }
38 
39  return 1;
40 }
41 
42 int isValidAsDouble(char * s)
43 {
44  //A valid floating point number for atof using the "C" locale is formed by
45  // - an optional sign character (+ or -),
46  // - followed by a sequence of digits, optionally containing a decimal-point
47  // character (.),
48  // - optionally followed by an exponent part (an e or E character followed by
49  // an optional sign and a sequence of digits).
50 
51  if ( s == NULL || *s == '\0' )
52  return 0; //Empty string
53 
54  if ( *s == '+' || *s == '-' )
55  ++s;
56 
57  if ( *s == '\0')
58  return 0; //sign character only
59 
60  while(*s)
61  {
62  if(!isdigit(*s))
63  break;
64  ++s;
65  }
66 
67  if(*s == '\0')
68  return 1; //s = "123"
69 
70  if(*s == '.')
71  {
72  ++s;
73  while(*s)
74  {
75  if(!isdigit(*s))
76  break;
77  ++s;
78  }
79  if(*s == '\0')
80  return 1; //this is a fixed point double s = "123." or "123.45"
81  }
82 
83  if(*s == 'e' || *s == 'E')
84  {
85  ++s;
86  return isValidAsInt(s);
87  }
88  else
89  return 0; //we have encounter a wrong character
90 }
91 
92 void parseArray(char * str, Array<int> & var)
93 {
94  var.SetSize(0);
95  std::stringstream input(str);
96  int val;
97  while( input >> val)
98  var.Append(val);
99 }
100 
101 void parseVector(char * str, Vector & var)
102 {
103  int nentries = 0;
104  double val;
105  {
106  std::stringstream input(str);
107  while( input >> val)
108  ++nentries;
109  }
110 
111  var.SetSize(nentries);
112  {
113  nentries = 0;
114  std::stringstream input(str);
115  while( input >> val)
116  var(nentries++) = val;
117  }
118 }
119 
121 {
122  option_check.SetSize(options.Size());
123  option_check = 0;
124  for (int i = 1; i < argc; )
125  {
126  if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
127  {
128  // print help message
129  error_type = 1;
130  return;
131  }
132 
133  for (int j = 0; true; j++)
134  {
135  if (j >= options.Size())
136  {
137  // unrecognized option
138  error_type = 2;
139  error_idx = i;
140  return;
141  }
142 
143  if (strcmp(argv[i], options[j].short_name) == 0 ||
144  strcmp(argv[i], options[j].long_name) == 0)
145  {
146  OptionType type = options[j].type;
147 
148  if( option_check[j] )
149  {
150  error_type = 4;
151  error_idx = j;
152  return;
153  }
154  option_check[j] = 1;
155 
156  i++;
157  if (type != ENABLE && type != DISABLE && i >= argc)
158  {
159  // missing argument
160  error_type = 3;
161  error_idx = j;
162  return;
163  }
164 
165  int isValid = 1;
166  switch (options[j].type)
167  {
168  case INT:
169  isValid = isValidAsInt(argv[i]);
170  *(int *)(options[j].var_ptr) = atoi(argv[i++]);
171  break;
172  case DOUBLE:
173  isValid = isValidAsDouble(argv[i]);
174  *(double *)(options[j].var_ptr) = atof(argv[i++]);
175  break;
176  case STRING:
177  *(const char **)(options[j].var_ptr) = argv[i++];
178  break;
179  case ENABLE:
180  *(bool *)(options[j].var_ptr) = true;
181  option_check[j+1] = 1; //Do not allow to use the DISABLE Option
182  break;
183  case DISABLE:
184  *(bool *)(options[j].var_ptr) = false;
185  option_check[j-1] = 1; //Do not allow to use the ENABLE Option
186  break;
187  case ARRAY:
188  parseArray(argv[i++], *(Array<int>*)(options[j].var_ptr) );
189  break;
190  case VECTOR:
191  parseVector(argv[i++], *(Vector*)(options[j].var_ptr) );
192  break;
193  }
194 
195  if(!isValid)
196  {
197  error_type = 5;
198  error_idx = i;
199  return;
200  }
201 
202  break;
203  }
204  }
205  }
206 
207  // check for missing required options
208  for (int i = 0; i < options.Size(); i++)
209  if (options[i].required &&
210  (option_check[i] == 0 ||
211  (options[i].type == ENABLE && option_check[++i] == 0)))
212  {
213  error_type = 6; // required option missing
214  error_idx = i; // for a boolean option i is the index of DISABLE
215  return;
216  }
217 
218  error_type = 0;
219 }
220 
221 void OptionsParser::WriteValue(const Option &opt, std::ostream &out)
222 {
223  switch (opt.type)
224  {
225  case INT:
226  out << *(int *)(opt.var_ptr);
227  break;
228 
229  case DOUBLE:
230  out << *(double *)(opt.var_ptr);
231  break;
232 
233  case STRING:
234  out << *(const char **)(opt.var_ptr);
235  break;
236 
237  case ARRAY:
238  {
239  Array<int> &list = *(Array<int>*)(opt.var_ptr);
240  out << '\'';
241  if (list.Size() > 0)
242  out << list[0];
243  for (int i = 0; i < list.Size(); i++)
244  out << ' ' << list[i];
245  out << '\'';
246  break;
247  }
248 
249  case VECTOR:
250  {
251  Vector &list = *(Vector*)(opt.var_ptr);
252  out << '\'';
253  if (list.Size() > 0)
254  out << list(0);
255  for (int i = 1; i < list.Size(); i++)
256  out << ' ' << list(i);
257  out << '\'';
258  break;
259  }
260 
261  default: // provide a default to suppress warning
262  break;
263  }
264 }
265 
266 void OptionsParser::PrintOptions(ostream &out) const
267 {
268  static const char *indent = " ";
269 
270  out << "Options used:\n";
271  for (int j = 0; j < options.Size(); j++)
272  {
273  OptionType type = options[j].type;
274 
275  out << indent;
276  if (type == ENABLE)
277  {
278  if (*(bool *)(options[j].var_ptr) == true)
279  out << options[j].long_name;
280  else
281  out << options[j+1].long_name;
282  j++;
283  }
284  else
285  {
286  out << options[j].long_name << " ";
287  WriteValue(options[j], out);
288  }
289  out << '\n';
290  }
291 }
292 
293 void OptionsParser::PrintError(ostream &out) const
294 {
295  static const char *line_sep = "";
296 
297  out << line_sep;
298  switch (error_type)
299  {
300  case 2:
301  out << "Unrecognized option: " << argv[error_idx] << '\n' << line_sep;
302  break;
303 
304  case 3:
305  out << "Missing argument for the last option: " << argv[argc-1] << '\n'
306  << line_sep;
307  break;
308 
309  case 4:
310  if(options[error_idx].type == ENABLE )
311  out << "Option " << options[error_idx].long_name << " or "
312  << options[error_idx + 1].long_name
313  << " provided multiple times\n" << line_sep;
314  else if(options[error_idx].type == DISABLE)
315  out << "Option " << options[error_idx - 1].long_name << " or "
316  << options[error_idx].long_name
317  << " provided multiple times\n" << line_sep;
318  else
319  out << "Option " << options[error_idx].long_name
320  << " provided multiple times\n" << line_sep;
321  break;
322 
323  case 5:
324  out << "Wrong option format: " << argv[error_idx - 1] << " "
325  << argv[error_idx] << '\n' << line_sep;
326  break;
327 
328  case 6:
329  out << "Missing required option: " << options[error_idx].long_name
330  << '\n' << line_sep;
331  break;
332  }
333  out << endl;
334 }
335 
336 void OptionsParser::PrintHelp(ostream &out) const
337 {
338  static const char *indent = " ";
339  static const char *seprtr = ", ";
340  static const char *descr_sep = "\n\t";
341  static const char *line_sep = "";
342  static const char *types[] = { " <int>", " <double>", " <string>", "", "",
343  " '<int>...'", " '<double>...'" };
344 
345  out << indent << "-h" << seprtr << "--help" << descr_sep
346  << "Print this help message and exit.\n" << line_sep;
347  for (int j = 0; j < options.Size(); j++)
348  {
349  OptionType type = options[j].type;
350 
351  out << indent << options[j].short_name << types[type]
352  << seprtr << options[j].long_name << types[type]
353  << seprtr;
354  if (options[j].required)
355  {
356  out << "(required)";
357  }
358  else
359  {
360  if (type == ENABLE)
361  {
362  j++;
363  out << options[j].short_name << types[type] << seprtr
364  << options[j].long_name << types[type] << seprtr
365  << "current option: ";
366  if (*(bool *)(options[j].var_ptr) == true)
367  out << options[j-1].long_name;
368  else
369  out << options[j].long_name;
370  }
371  else
372  {
373  out << "current value: ";
374  WriteValue(options[j], out);
375  }
376  }
377  out << descr_sep;
378 
379  if (options[j].description)
380  out << options[j].description << '\n';
381  out << line_sep;
382  }
383 }
384 
385 void OptionsParser::PrintUsage(ostream &out) const
386 {
387  static const char *line_sep = "";
388 
389  PrintError(out);
390  out << "Usage: " << argv[0] << " [options] ...\n" << line_sep
391  << "Options:\n" << line_sep;
392  PrintHelp(out);
393 }
394 
395 }
int Size() const
Logical size of the array.
Definition: array.hpp:108
void parseVector(char *str, Vector &var)
Definition: optparser.cpp:101
void SetSize(int s)
Resizes the vector if the new size is different.
Definition: vector.hpp:248
void PrintHelp(std::ostream &out) const
Definition: optparser.cpp:336
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:330
void PrintUsage(std::ostream &out) const
Definition: optparser.cpp:385
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:293
void PrintError(std::ostream &out) const
Definition: optparser.cpp:293
void PrintOptions(std::ostream &out) const
Definition: optparser.cpp:266
Vector data type.
Definition: vector.hpp:29
int isValidAsInt(char *s)
Definition: optparser.cpp:21
void parseArray(char *str, Array< int > &var)
Definition: optparser.cpp:92
int isValidAsDouble(char *s)
Definition: optparser.cpp:42