1 /* *****************************************************************
2 MESQUITE -- The Mesh Quality Improvement Toolkit
3
4 Copyright 2008 Sandia National Laboratories. Developed at the
5 University of Wisconsin--Madison under SNL contract number
6 624796. The U.S. Government and the University of Wisconsin
7 retain certain rights to this software.
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 (lgpl.txt) along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 (2008) kraftche@cae.wisc.edu
24
25 ***************************************************************** */
26
27
28 /** \file CLArgs.hpp
29 * \brief
30 * \author Jason Kraftcheck
31 */
32
33 #ifndef MSQ_CLARGS_HPP
34 #define MSQ_CLARGS_HPP
35
36
37 class CLArgImpl;
38
39 #include "Mesquite.hpp"
40 #include <iosfwd>
41 #include <vector>
42 #include <string>
43 #include <sstream>
44 #include <iterator>
45
46 /**\brief Parse command-line arguments
47 *
48 * This class provides a mechanism for parsing and to some extend validating
49 * command-line arguments. Use of this class can be divided into three steps:
50 *
51 * 1) Call *_flag and arg methods to define acceptable command line arguments
52 *
53 * 2) Call parse_options to parse the command line arguments according to
54 * acceptable flags defined in step 1.
55 *
56 * 3) Check the values in registerd callback class instances.
57 *
58 * The '-h' flag is reserved for reqesting a description of the allowable
59 * arguments (help). If it is encountered inside parse_options, the help
60 * will be printed and the program will be terminated w/out returning from
61 * parse_options.
62 *
63 * The '-M' flag is similar to '-h', except that the help is written
64 * in UNIX 'man page' format.
65 */
66 class CLArgs
67 {
68 public:
69
70 /**\brief Base class for callback interface (type-independent functions) */
71 class ArgIBase {
72 private: bool wasSeen; //!< Keep track of whether or not this flag was encountered
ArgIBase()73 public: ArgIBase() : wasSeen(false) {} //!< constructor
~ArgIBase()74 virtual ~ArgIBase() {} //!< virtual destructor for proper cleanup
75 /**\brief Get short description string for usage output or empty string for default*/
brief() const76 virtual std::string brief() const { return std::string(); }
77 /**\brief Get short description string for UNIX man page output or empty string for default */
manstr() const78 virtual std::string manstr() const { return std::string(); }
79 /**\brief Get optional additional info to print with flag description */
desc_append() const80 virtual std::string desc_append() const { return std::string(); }
81 /**\brief Get optional string containing default value for option if not specified by user */
default_str() const82 virtual std::string default_str() const { return std::string(); }
83 /**\brief Mark this flag as having been specified by the user */
set_seen()84 void set_seen() { wasSeen = true; }
85 /**\brief Test if the user specified this flag */
seen() const86 bool seen() const { return wasSeen; }
87 };
88
89 /**\brief Interface for type-specific callback classes */
90 template <typename T> class ArgTemplateI : public ArgIBase {
91 public: virtual bool value( const T& val ) = 0;
92 };
93 /**\brief Trivial implementation for type-specific classes */
94 template <typename T> class ArgTemplate :public ArgTemplateI<T> {
95 private: T mValue; //!< The default or user-specified value for an option.
96 bool haveDefault; //!< True if app. provided default value.
~ArgTemplate()97 public: virtual ~ArgTemplate() {}
value(const T & val)98 virtual bool value( const T& val ) //!< Set value
99 {
100 mValue = val;
101 ArgTemplateI<T>::set_seen();
102 return true;
103 }
value() const104 const T& value() const { return mValue; } //!< get value
105 /**\brief Initialize with default value */
ArgTemplate(const T & initial_value)106 ArgTemplate( const T& initial_value ) : mValue(initial_value), haveDefault(true) {}
107 /**\brief Initialize without default value */
ArgTemplate()108 ArgTemplate() : mValue(T()), haveDefault(false) {}
109 /**\brief Get string representation of default value, or empty string of no default value */
default_str() const110 virtual std::string default_str() const {
111 std::ostringstream ss;
112 if (haveDefault)
113 ss << mValue;
114 return ss.str();
115 }
116
117 };
118
119 /**\brief Trivial implementation for type-specific classes */
120 template <typename T> class ArgListTemplate : public ArgTemplateI< std::vector<T> > {
121 private: std::vector<T> mValue; //!< The default or user-specified value for an option.
122 bool haveDefault; //!< True if app. provided default value.
~ArgListTemplate()123 public: virtual ~ArgListTemplate() {}
value(const std::vector<T> & val)124 virtual bool value( const std::vector<T>& val ) //!< Set value
125 {
126 mValue = val;
127 ArgTemplateI< std::vector<T> >::set_seen();
128 return true;
129 }
value() const130 const std::vector<T>& value() const { return mValue; } //!< get value
131 /**\brief Initialize with default value */
ArgListTemplate(const std::vector<T> & initial_value)132 ArgListTemplate( const std::vector<T>& initial_value ) : mValue(initial_value), haveDefault(true) {}
133 /**\brief Initialize without default value */
ArgListTemplate()134 ArgListTemplate() : haveDefault(false) {}
135 /**\brief Get string representation of default value, or empty string of no default value */
default_str() const136 virtual std::string default_str() const {
137 std::ostringstream ss;
138 std::copy( mValue.begin(), mValue.end(),
139 std::ostream_iterator<T>( ss, ", " ) );
140 return ss.str();
141 }
142
143 };
144
145 /**\brief Callback API for a string argument */
146 typedef ArgTemplateI< std::string > StringArgI;
147 /**\brief Callback API for an integer argument */
148 typedef ArgTemplateI< int > IntArgI;
149 /**\brief Callback API for a long integer argument */
150 typedef ArgTemplateI< long > LongArgI;
151 /**\brief Callback API for a double-precision floating-point argument */
152 typedef ArgTemplateI< double > DoubleArgI;
153 /**\brief Callback API for a Boolean or toggle argument */
154 typedef ArgTemplateI< bool > ToggleArgI;
155 /**\brief Callback API for an integer list argument */
156 typedef ArgTemplateI< std::vector<int> > IntListArgI;
157 /**\brief Callback API for a double list argument */
158 typedef ArgTemplateI< std::vector<double> > DoubleListArgI;
159
160 /**\brief Trivial callback implementation for a string argument */
161 typedef ArgTemplate< std::string> StringArg;
162 /**\brief Trivial callback implementation for an integer argument */
163 typedef ArgTemplate< int > IntArg;
164 /**\brief Trivial callback implementation for a long integer argument */
165 typedef ArgTemplate< long > LongArg;
166 /**\brief Trivial callback implementation for a ouble-precision floating-point argument */
167 typedef ArgTemplate< double > DoubleArg;
168 /**\brief Trivial callback implementation for a Boolean or toggle argument */
169 typedef ArgTemplate< bool > ToggleArg;
170 /**\brief Trivial callback implementation for an integer list argument */
171 typedef ArgListTemplate< int > IntListArg;
172 /**\brief Trivial callback implementation for a double list argument */
173 typedef ArgListTemplate< double > DoubleListArg;
174
175 /**\brief String arugment that is limited to a list of acceptable keywords
176 *
177 * A specialized string arugment implementation that limits the
178 * acceptable string argument to one of a list of keywords.
179 * A case-insensitive comparison is done with the allowed keywords.
180 * The "value" has the case of the keyword rather than the case
181 * used in the literal value specified in the command line argument.
182 */
183 class KeyWordArg : public StringArg
184 {
185 private:
186 std::vector< std::string > mKeyWords;
187 void initialize( const char* keyword_list[], int list_length );
188 public:
KeyWordArg(const char * keyword_list[],int list_length)189 KeyWordArg( const char* keyword_list[], int list_length )
190 { initialize( keyword_list, list_length ); }
KeyWordArg(const char * default_val,const char * keyword_list[],int list_length)191 KeyWordArg( const char* default_val, const char* keyword_list[], int list_length )
192 : StringArg( default_val )
193 { initialize( keyword_list, list_length ); }
194 virtual bool value( const std::string& val );
195 virtual std::string brief() const;
196 virtual std::string manstr() const;
197 static bool compare_no_case( const char* s1, const char* s2 );
198 };
199
200 class IntRange
201 {
202 private:
203 int mMin, mMax;
204 public:
205 IntRange( const int* min, const int* max );
206 bool is_valid( int val ) const;
207 std::string desc_append() const;
208 };
209
210 /**\brief Integer argument constrained to a range of valid values. */
211 class IntRangeArg : public IntArg
212 {
213 private:
214 IntRange mRange;
215 public:
IntRangeArg(const int * min=0,const int * max=0)216 IntRangeArg( const int* min = 0, const int* max = 0 )
217 : mRange( min, max ) {}
IntRangeArg(int default_val,const int * min,const int * max)218 IntRangeArg( int default_val, const int* min, const int* max )
219 : IntArg(default_val), mRange( min, max ) {}
220 bool value( const int& val );
value() const221 const int& value() const { return IntArg::value(); }
desc_append() const222 std::string desc_append() const
223 { return mRange.desc_append(); }
224 };
225
226 /**\brief Integer list argument constrained to a range of valid values. */
227 class IntListRangeArg : public IntListArg
228 {
229 private:
230 IntRange mRange;
231 public:
IntListRangeArg(const int * min=0,const int * max=0)232 IntListRangeArg( const int* min = 0, const int* max = 0 )
233 : mRange( min, max ) {}
234 bool value( const std::vector<int>& val );
value() const235 const std::vector<int>& value() const { return IntListArg::value(); }
desc_append() const236 std::string desc_append() const
237 { return mRange.desc_append(); }
238 };
239
240 class DoubleRange
241 {
242 private:
243 bool haveMin, haveMax, mInclusive;
244 double mMin, mMax;
245 public:
246 DoubleRange( const double* min, const double* max, bool inclusive );
247 bool is_valid( double value ) const;
248 std::string desc_append() const;
249 };
250
251 /**\brief Double argument constrained to a range of valid values. */
252 class DoubleRangeArg : public DoubleArg
253 {
254 private:
255 DoubleRange mRange;
256 public:
DoubleRangeArg(const double * min=0,const double * max=0,bool inclusive=true)257 DoubleRangeArg( const double* min = 0,
258 const double* max = 0,
259 bool inclusive = true )
260 : mRange( min, max, inclusive )
261 {}
DoubleRangeArg(double default_val,const double * min=0,const double * max=0,bool inclusive=true)262 DoubleRangeArg( double default_val,
263 const double* min = 0,
264 const double* max = 0,
265 bool inclusive = true )
266 : DoubleArg(default_val),
267 mRange( min, max, inclusive )
268 {}
269 bool value( const double& val );
value() const270 const double& value() const { return DoubleArg::value(); }
desc_append() const271 std::string desc_append() const
272 { return mRange.desc_append(); }
273 };
274
275 /**\brief Double list argument constrained to a range of valid values. */
276 class DoubleListRangeArg : public DoubleListArg
277 {
278 private:
279 DoubleRange mRange;
280 public:
DoubleListRangeArg(const double * min=0,const double * max=0,bool inclusive=true)281 DoubleListRangeArg( const double* min = 0,
282 const double* max = 0,
283 bool inclusive = true )
284 : mRange( min, max, inclusive )
285 {}
286 bool value( const std::vector<double>& val );
value() const287 const std::vector<double>& value() const { return DoubleListArg::value(); }
desc_append() const288 std::string desc_append() const
289 { return mRange.desc_append(); }
290 };
291
292
293
294 public:
295
296 /**\brief Define basic program
297 *
298 *\param progname The program name
299 *\param brief_desc A brief description of the purpose of the program.
300 *\param desc Program description for documentation.
301 */
302 CLArgs( const char* progname, const char* brief_desc, const char* desc );
303
304 ~CLArgs();
305
306 /**\brief Check if flag is undefined */
307 bool is_flag_available( char fl ) const;
308
309 /**\brief Register a flag that requires a string argument.
310 *
311 * Define a flag of the form "-f <somestring>".
312 *\param fl The character for the flag.
313 *\param name The name of the flag argument
314 *\param desc A description of the purpose of the flag and argument.
315 *\parma callback Object instance to which to pass the parsed argument value.
316 *\return false if flag is already in use, true otherwise.
317 */
318 bool str_flag( char fl,
319 const char* name,
320 const char* desc,
321 StringArgI* callback );
322
323 /**\brief Register a flag that requires an integer argument.
324 *
325 * Define a flag of the form "-f <int>".
326 *\param fl The character for the flag.
327 *\param name The name of the flag argument
328 *\param desc A description of the purpose of the flag and argument.
329 *\parma callback Object instance to which to pass the parsed argument value.
330 *\return false if flag is already in use, true otherwise.
331 */
332 bool int_flag( char fl,
333 const char* name,
334 const char* desc,
335 IntArgI* callback );
336
337 /**\brief Register a flag that requires an integer argument.
338 *
339 * Define a flag of the form "-f <int>".
340 *\param fl The character for the flag.
341 *\param name The name of the flag argument
342 *\param desc A description of the purpose of the flag and argument.
343 *\parma callback Object instance to which to pass the parsed argument value.
344 *\return false if flag is already in use, true otherwise.
345 */
346 bool long_flag( char fl,
347 const char* name,
348 const char* desc,
349 LongArgI* callback );
350
351 /**\brief Register a flag that requires a real umber argument.
352 *
353 * Define a flag of the form "-f <double>".
354 *\param fl The character for the flag.
355 *\param name The name of the flag argument
356 *\param desc A description of the purpose of the flag and argument.
357 *\parma callback Object instance to which to pass the parsed argument value.
358 *\param inclusive If true, accept 'min' or 'max': [min,max]. If
359 * false, reject 'min' and 'max' values: (min,max).
360 *\return false if flag is already in use, true otherwise.
361 */
362 bool double_flag( char fl,
363 const char* name,
364 const char* desc,
365 DoubleArgI* callback );
366
367 /**\brief Register a pair of flags that accept no arguments and have
368 * opposing affects.
369 *
370 * Regstier a flag of the form [-f|-F], where one implies a true
371 * state and the other a false state (i.e. enable or disable some
372 * functionality.)
373 *\param on_flag Flag corresponding to true or 'on' state.
374 *\param off_flag Flag corresponding to false or 'off' state.
375 *\param desc A description of the purpose of the flag and argument.
376 *\parma callback Object instance to which to pass the parsed argument value.
377 *\return false if flag is already in use, true otherwise.
378 */
379 bool toggle_flag( char on_flag,
380 char off_flag,
381 const char* desc,
382 ToggleArgI* callback );
383
384 /**\brief Register a flag with no value.
385 *
386 * Define a flag such that the state of the option is considered
387 * to be false unless flag is specified. If the flag is specified,
388 * the option is considered to be true.
389 *\param fl The character for the flag.
390 *\param desc A description of the purpose of the flag and argument.
391 *\parma callback Object instance to which to pass the parsed argument value.
392 *\return false if flag is already in use, true otherwise.
393 */
394 bool toggle_flag( char fl, const char* desc, ToggleArgI* callback );
395
396
397 /**\brief Register a flag that accepts a list of positive integer arguments.
398 *
399 * Define a flag that accepts a list of ranges of positive integer values
400 * separated by commas. A zero value is rejected. Ranges can be either
401 * a single value or pair of values separated by a dash. For example:
402 * "-f 1,4-10,2,20-25".
403 *
404 * Use 'get_int_list' to query values of flag.
405 *
406 *\param fl The character for the flag.
407 *\param desc A description of the purpose of the flag and argument.
408 *\parma callback Object instance to which to pass the parsed argument value.
409 *\return false if flag is already in use, true otherwise.
410 */
411 bool id_list_flag( char fl, const char* desc, IntListArgI* callback );
412
413 /**\brief Register a flag that requires a comma-separated
414 * list of integer values.
415 *
416 * Define a flag that has an integer list for its arguments. The
417 * integers must be specified as a comma-separated list.
418 *
419 * Use 'limit_list_flag' to limit the number of values accepted
420 * in the argument. If 'limit_list_flag' is never called, any
421 * number of argument values will be accepted.
422 *
423 *\param fl The character for the flag.
424 *\param desc A description of the purpose of the flag and argument.
425 *\parma callback Object instance to which to pass the parsed argument value.
426 *\return false if flag is already in use, true otherwise.
427 */
428 bool int_list_flag( char fl, const char* desc, IntListArgI* callback );
429
430 /**\brief Register a flag that requires a comma-separated
431 * list of double values.
432 *
433 * Define a flag that has an double list for its arguments. The
434 * values must be specified as a comma-separated list.
435 *
436 * Use 'limit_list_flag' to limit the number of values accepted
437 * in the argument. If 'limit_list_flag' is never called, any
438 * number of argument values will be accepted.
439 *
440 *\param fl The character for the flag.
441 *\param desc A description of the purpose of the flag and argument.
442 *\parma callback Object instance to which to pass the parsed argument value.
443 *\return false if flag is already in use, true otherwise.
444 */
445 bool double_list_flag( char fl,
446 const char* desc,
447 DoubleListArgI* callback );
448
449 /**\brief Set a limit on the number of values accepted for a list-type
450 * flag. May be called multiple times for a flag.
451 *
452 * Add a limit on the number of values accepted for a list-type flag.
453 * This function may be called multiple times if the flag should
454 * accept a finite set of different arugment value counts.
455 *
456 *\param fl The flag
457 *\param num_values The number of values to accept
458 *\param value_names An array of 'num_value' strings specifying the
459 * name of each value.
460 *\return false if flag is not defined as a list-type flag or this
461 * method has already been called with the same flag AND
462 * number of values. True otherwise.
463 */
464 bool limit_list_flag( char fl,
465 int num_values,
466 const char* const* value_names );
467
468 /**\brief Specify that an argument without a flag is expected.
469 *
470 * Arguments are parsed in the order they are added, with the
471 * exception that all optional args are parsed after all required
472 * args.
473 * \param name 'name' of argument to display in help (e.g. "output_file");
474 */
475 void add_required_arg( const char* name );
476 void add_optional_arg( const char* name );
477
478 /**\brief Parse argument list.
479 *
480 *\param argc The argument list length passed to the main() routine.
481 * The first value is assumed to be the executable name.
482 * This this value must be at least 1.
483 *\param argv The argument list as passed to main().
484 *\param args_out The list of non-flag arguments encountered, as
485 * defined by the 'args' method. If the 'args' method
486 * has not been called, no non-flag arguments are accepted
487 * and this list will be empty.
488 *\param error_stream stream to which to write error messages.
489 *\return true if all arguments were accepted. false otherwise.
490 */
491 bool parse_options( int argc,
492 char* argv[],
493 std::vector< std::string >& args_out,
494 std::ostream& error_stream );
495
496
497
498
499 /**\brief Write help
500 *
501 * Write help text to passed stream.
502 */
503 void print_help( std::ostream& stream ) const;
504
505 /**\brief Write UNIX man page
506 *
507 * Write man page to passed stream.
508 */
509 void print_man_page( std::ostream& stream ) const;
510
511 /**\brief prinint usage (brief help)
512 */
513 void print_usage( std::ostream& stream ) const;
514
515 private:
516
517 CLArgImpl* impl;
518 };
519
operator <<(std::ostream & str,const std::vector<T> & list)520 template <typename T> std::ostream& operator<<( std::ostream& str, const std::vector<T>& list )
521 {
522 typename std::vector<T>::const_iterator i = list.begin();
523 if (i != list.end()) {
524 str << *i;
525 for (++i; i != list.end(); ++i)
526 str << ',' << *i;
527 }
528 return str;
529 }
530
531 #endif
532