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