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