1 #ifndef MOAB_PROGRAM_OPTIONS_H
2 #define MOAB_PROGRAM_OPTIONS_H
3
4 #include <vector>
5 #include <map>
6 #include <string>
7 #include <iostream>
8
9 class ProgOpt;
10
11 /** A simple command-line option parser and help utility
12 *
13 * Utility class to specify a program's command-line options arguments, produce a help message
14 * explaining how they work, and parse user's command line input (producing useful errors messages
15 * if any problems arise). Loosely (okay, very loosely) inspired by boost program_options.
16 *
17 * Options are specified by a comma-separated namestring. An option named "foo,f" can be specified
18 * three ways on the command line: "-f val", "--foo val", or "--foo=val". The types of options
19 * and arguments are specified by function templates. Valid template values for positional argument
20 * and options are int, double, and std::string. void may also be used in options, and it indicates
21 * a command line option that does not take an argument.
22 *
23 * Example usage:
24 * ProgOptions po( "Example usage of ProgOptions" );
25 * po.addOpt<void>( "verbose,v", "Turn on verbose messages" );
26 * po.addOpt<std::string> ("foo", "Specify the foo string" );
27 * int x = 0;
28 * po.addOpt<int>( ",x", "Specify the x number", &x ); // x will be automatically set when options
29 * parsed po.parseCommandLine( argc, argv ); bool verbose = po.numOptSet("verbose") > 0; std::string
30 * foo; if( !po.getOpt( "foo", &foo ) ) foo = "default";
31 * ...
32 *
33 * See the file dagmc_preproc.cpp in the dagmc directory for a real-world example.
34 */
35 class ProgOptions
36 {
37
38 public:
39 /**
40 * Flags for addOpt and addRequiredArg functions; may be combined with bitwise arithmetic
41 * (though not all combinations make sense!)
42 **/
43
44 /// Set for a flag that, when detected, prints help text and halts program.
45 /// Constructor creates such a flag by default, so the user shouldn't need to use this directly.
46 static const int help_flag = 1 << 0;
47
48 /// Flag indicating that an option should be given a "cancel" flag.
49 /// This creates, for option --foo, an additional option --no-foo that
50 /// clears all previously read instances of the foo option
51 static const int add_cancel_opt = 1 << 1;
52
53 /// When applied to a flag argument (one with template type void), indicate that the
54 /// value 'false' should be stored into the pointer that was given at option creation time.
55 /// This overrides the default behavior, which is to store the value 'true'.
56 static const int store_false = 1 << 2;
57
58 /// Specify a numerical flag where any positive integer is an acceptable
59 /// value. E.g. --dimension=3 is equivalent to -3. Only values in the
60 /// range [0,9] are accepted and the flag type must be integer.
61 static const int int_flag = 1 << 3;
62
63 /** Substitue any occurance of the '%' symbol in a string with
64 * the the MPI rank of this process in MPI_COMM_WORLD. This
65 * option has no effect if not compiled with MPI. This flag
66 * has no effect for non-string options.
67 */
68 static const int rank_subst = 1 << 4;
69
70 /// Set for a flag that, when detected, will call printVersion() and halt the program.
71 static const int version_flag = 1 << 5;
72
73 /// unimplemented flag for required arguments that may be given multiple times
74 // const static int accept_multiple;
75
76 /**
77 * @param helptext A brief summary of the program's function, to be printed
78 * when the help flag is detected
79 */
80 ProgOptions( const std::string& helptext = "", const std::string& briefdesc = "" );
81 ~ProgOptions();
82
83 /** Specify the program version
84 *
85 * Set the program version to a given string. This will be printed when printVersion()
86 * is called.
87 * @param version_string The version string
88 * @param addflag If true, a default '--version' option will be added. If false,
89 * the version will be set, but no option will be added to the parser.
90 */
91 void setVersion( const std::string& version_string, bool addFlag = true );
92
93 /** Specify a new command-line option
94 *
95 * Instruct the parser to accept a new command-line argument, as well as specifying
96 * how the argument should be handled. The template parameter indicates the type of
97 * command-line option being specified: acceptable types are void (indicating a flag
98 * without an argument), int, double, and std::string.
99 *
100 * @param namestring The command-line options name(s). Format is longname,shortname.
101 * If the comma is omitted, or appears only at the end, this option will have
102 * no shortname; if the comma is the first letter of the namestring, the option
103 * has no longname.
104 * @param helpstring The help information displayed for the option when the program is
105 * invoked with --help
106 * @param value A pointer to memory in which to store the parsed value for this option.
107 * If NULL, then the value of the option must be queried using the getOpt function.
108 * If the template parameter is void and value is non-NULL, treat value as a bool*
109 * and store 'true' into it when the flag is encountered. (See also store_false, above)
110 * @param flags Option behavior flags, which should come from static vars in the ProgOptions
111 * class
112 */
113 template < typename T >
114 void addOpt( const std::string& namestring, const std::string& helpstring, T* value, int flags = 0 );
115
116 /** Specify a new command-line option
117 *
118 * This funtion is identical to the 4-arg version, but omits the value parameter, which
119 * is assumed to be NULL
120 */
121 template < typename T >
122 void addOpt( const std::string& namestring, const std::string& helpstring, int flags = 0 )
123 {
124 addOpt< T >( namestring, helpstring, NULL, flags );
125 }
126
127 /** Add a new line of help text to the option help printout
128 *
129 * Add a line of text to the option-related help. Called between calls to addOpt(),
130 * this function can be used to divide the option list into groups of related options
131 * to make the help text more convenient.
132 */
133 void addOptionHelpHeading( const std::string& );
134
135 /** Add required positional argument
136 *
137 * Add a new required positional argument. The order in which arguments are specified
138 * is the order in which they will be expected on the command line.
139 * The template parameter may be int, double, or std::string (but not void)
140 * @param helpname The name to give the argument in the help text
141 * @param helpstring The help text for the argument
142 * @param value Pointer to where parsed value from command line should be stored.
143 * If NULL, the value must be queried using getReqArg()
144 */
145 template < typename T >
146 void addRequiredArg( const std::string& helpname, const std::string& helpstring, T* value = NULL, int flags = 0 );
147
148 /** Add optional positional arguments
149 *
150 * Specify location in ordered argument list at which optional arguments
151 * may occur. Optional arguments are allowed at only one location
152 * it argument list (this function may not be called more than once.).
153 * The template parameter may be int, double, or std::string (but not void)
154 * @param count The maximum number of optional arguments. Specify zero for unlimited.
155 * @param helpname The name to give the argument in the help text
156 * @param helpstring The help text for the arguments
157 */
158 template < typename T >
159 void addOptionalArgs( unsigned max_count,
160 const std::string& helpname,
161 const std::string& helpstring,
162 int flags = 0 );
163
164 /**
165 * Print the full help to the given stream
166 */
167 void printHelp( std::ostream& str = std::cout );
168
169 /**
170 * Print only the usage message to the given stream
171 */
172 void printUsage( std::ostream& str = std::cout );
173
174 /**
175 * Print the version string to the given stream
176 */
177 void printVersion( std::ostream& str = std::cout );
178
179 /**
180 * Parse command-line inputs as given to main()
181 */
182 void parseCommandLine( int argc, char* argv[] );
183
184 /**
185 *
186 * Get the value of the named option.
187 * @param namestring The name string given when the option was created. This need not be
188 * idential to the created name; only the longname, or the shortname (with comma prefix),
189 * will also work.
190 * @param value Pointer to location to store option argument, if any is found
191 * @return True if the option was set and its argument was stored into value; false otherwise.
192 */
193 template < typename T >
194 bool getOpt( const std::string& namestring, T* value );
195
196 /**
197 * Get a list of values for the named option-- one value for each time it was
198 * given on the command line.
199 *
200 * This function cannot be called with void as the template parameter;
201 * compilers will reject vector<void> as a type. This means it cannot be
202 * called for flag-type options. To count the number of times a given flag
203 * was specified, use numOptSet()
204 * @param namestring See similar argument to getOpt()
205 * @param values Reference to list to store values into. Will have as many entries
206 * as there were instances of this option on the command line
207 */
208 template < typename T >
209 void getOptAllArgs( const std::string& namestring, std::vector< T >& values );
210
211 /**
212 * @param namestring See similar argument to getOpt()
213 * @return The number of times the named option appeared on the command line.
214 */
215 int numOptSet( const std::string& namestring );
216
217 /**
218 * Retrieve the value of a required command-line argument by name
219 * @param namestring The helpname that was given to addRequiredArg when the
220 * desired argument was created
221 */
222 template < typename T >
223 T getReqArg( const std::string& namestring );
224
225 /**
226 * Append the values of any required or optional arguments
227 * @param namestring The helpname that was given to addRequiredArg or
228 * addOptionalArgs.
229 */
230 template < typename T >
231 void getArgs( const std::string& namestring, std::vector< T >& values );
232
233 /**
234 * Prints an error message to std::cerr, along with a brief usage message,
235 * then halts the program. Used throughout ProgramOptions implementation.
236 * Users may call this directly if they detect an incorrect usage of program
237 * options that the ProgramOptions wasn't able to detect itself.
238 * @param message The error message to print before program halt.
239 */
240 void error( const std::string& message );
241
242 /**
243 * Write help data formatted for use as a unix man page.
244 */
245 void write_man_page( std::ostream& to_this_stream );
246
247 protected:
248 std::string get_option_usage_prefix( const ProgOpt& option );
249
250 void get_namestrings( const std::string& input, std::string* l, std::string* s );
251
252 ProgOpt* lookup( const std::map< std::string, ProgOpt* >&, const std::string& );
253 ProgOpt* lookup_option( const std::string& );
254
255 bool evaluate( const ProgOpt& opt, void* target, const std::string& option, unsigned* arg_idx = NULL );
256 bool process_option( ProgOpt* opt, std::string arg, const char* value = 0 );
257
258 std::map< std::string, ProgOpt* > long_names;
259 std::map< std::string, ProgOpt* > short_names;
260 std::map< std::string, ProgOpt* > required_args;
261
262 typedef std::pair< ProgOpt*, std::string > help_line;
263 std::vector< help_line > option_help_strings;
264 std::vector< help_line > arg_help_strings;
265 std::vector< std::string > main_help;
266 std::string brief_help;
267
268 bool expect_optional_args;
269 unsigned optional_args_position, max_optional_args;
270
271 std::string progname;
272 std::string progversion;
273
274 // if an option was specified with the int_flag, this
275 // will contain the long name of the option
276 std::string number_option_name;
277 };
278
279 #endif /* MOAB_PROGRAM_OPTIONS_H */