alpar@85: /* -*- C++ -*- alpar@85: * alpar@85: * This file is a part of LEMON, a generic C++ optimization library alpar@85: * alpar@85: * Copyright (C) 2003-2008 alpar@85: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@85: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@85: * alpar@85: * Permission to use, modify and distribute this software is granted alpar@85: * provided that this copyright notice appears in all copies. For alpar@85: * precise terms see the accompanying LICENSE file. alpar@85: * alpar@85: * This software is provided "AS IS" with no warranty of any kind, alpar@85: * express or implied, and with no claim as to its suitability for any alpar@85: * purpose. alpar@85: * alpar@85: */ alpar@85: alpar@85: #ifndef LEMON_ARG_PARSER alpar@85: #define LEMON_ARG_PARSER alpar@85: alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: #include alpar@85: alpar@85: ///\ingroup misc alpar@85: ///\file kpeter@88: ///\brief A tool to parse command line arguments. alpar@85: alpar@85: namespace lemon { alpar@85: alpar@85: ///Command line arguments parser alpar@85: alpar@85: ///\ingroup misc kpeter@88: ///Command line arguments parser. alpar@85: /// kpeter@88: ///For a complete example see the \ref arg_parser_demo.cc demo file. alpar@85: class ArgParser { alpar@85: alpar@85: static void _showHelp(void *p); alpar@85: protected: alpar@85: alpar@85: int _argc; alpar@85: const char **_argv; alpar@85: alpar@85: enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 }; alpar@85: alpar@85: class ParData { alpar@85: public: alpar@85: union { alpar@85: bool *bool_p; alpar@85: int *int_p; alpar@85: double *double_p; alpar@85: std::string *string_p; alpar@85: struct { alpar@85: void (*p)(void *); alpar@85: void *data; alpar@85: } func_p; alpar@85: alpar@85: }; alpar@85: std::string help; alpar@85: bool mandatory; alpar@85: OptType type; alpar@85: bool set; alpar@85: bool ingroup; alpar@85: bool has_syn; alpar@85: bool syn; alpar@85: bool self_delete; alpar@85: ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false), alpar@85: has_syn(false), syn(false), self_delete(false) {} alpar@85: }; alpar@85: alpar@85: typedef std::map Opts; alpar@85: Opts _opts; alpar@85: alpar@85: class GroupData alpar@85: { alpar@85: public: alpar@85: typedef std::list Opts; alpar@85: Opts opts; alpar@85: bool only_one; alpar@85: bool mandatory; alpar@85: GroupData() :only_one(false), mandatory(false) {} alpar@85: }; alpar@85: alpar@85: typedef std::map Groups; alpar@85: Groups _groups; alpar@85: alpar@85: struct OtherArg alpar@85: { alpar@85: std::string name; alpar@85: std::string help; alpar@85: OtherArg(std::string n, std::string h) :name(n), help(h) {} alpar@85: alpar@85: }; alpar@85: alpar@85: std::vector _others_help; alpar@85: std::vector _file_args; alpar@85: std::string _command_name; alpar@87: alpar@87: alpar@87: private: alpar@87: //Bind a function to an option. alpar@87: alpar@87: //\param name The name of the option. The leading '-' must be omitted. alpar@87: //\param help A help string. alpar@87: //\retval func The function to be called when the option is given. It alpar@87: // must be of type "void f(void *)" alpar@87: //\param data Data to be passed to \c func alpar@87: ArgParser &funcOption(const std::string &name, alpar@87: const std::string &help, alpar@87: void (*func)(void *),void *data); alpar@85: alpar@85: public: alpar@85: alpar@85: ///\e alpar@85: ArgParser(int argc, const char **argv); alpar@85: alpar@85: ~ArgParser(); alpar@85: alpar@85: ///Add a new integer type option alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param value A default value for the option alpar@85: ///\param obl Indicate if the option is mandatory. alpar@85: ArgParser &intOption(const std::string &name, alpar@85: const std::string &help, alpar@85: int value=0, bool obl=false); alpar@85: alpar@86: ///Add a new floating point type option alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param value A default value for the option alpar@85: ///\param obl Indicate if the option is mandatory. alpar@85: ArgParser &doubleOption(const std::string &name, alpar@85: const std::string &help, alpar@85: double value=0, bool obl=false); alpar@85: alpar@85: ///Add a new bool type option alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param value A default value for the option alpar@85: ///\param obl Indicate if the option is mandatory. alpar@85: ////\note A mandatory bool obtion is of very little use.) alpar@85: ArgParser &boolOption(const std::string &name, alpar@85: const std::string &help, alpar@85: bool value=false, bool obl=false); alpar@85: alpar@85: ///Add a new string type option alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param value A default value for the option alpar@85: ///\param obl Indicate if the option is mandatory. alpar@85: ArgParser &stringOption(const std::string &name, alpar@85: const std::string &help, alpar@85: std::string value="", bool obl=false); alpar@85: kpeter@88: ///\name Options with external storage alpar@85: ///Using this functions, the value of the option will be directly written alpar@85: ///into a variable once the option appears in the command line. alpar@85: alpar@85: ///@{ alpar@85: alpar@85: ///Add a new integer type option with a storage reference alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param obl Indicate if the option is mandatory. alpar@85: ///\retval ref The value of the argument will be written to this variable. alpar@85: ArgParser &refOption(const std::string &name, alpar@85: const std::string &help, alpar@85: int &ref, bool obl=false); alpar@85: alpar@85: ///Add a new floating type option with a storage reference alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param obl Indicate if the option is mandatory. alpar@85: ///\retval ref The value of the argument will be written to this variable. alpar@85: ArgParser &refOption(const std::string &name, alpar@85: const std::string &help, alpar@85: double &ref, bool obl=false); alpar@85: alpar@85: ///Add a new bool type option with a storage reference alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@90: ///\param obl Indicate if the option is mandatory. alpar@85: ///\retval ref The value of the argument will be written to this variable. alpar@85: ////\note A mandatory bool obtion is of very little use.) alpar@85: ArgParser &refOption(const std::string &name, alpar@85: const std::string &help, alpar@85: bool &ref, bool obl=false); alpar@85: alpar@85: ///Add a new string type option with a storage reference alpar@85: alpar@85: ///\param name The name of the option. The leading '-' must be omitted. alpar@85: ///\param help A help string. alpar@85: ///\retval ref The value of the argument will be written to this variable. alpar@85: ///\param obl Indicate if the option is mandatory. alpar@85: ArgParser &refOption(const std::string &name, alpar@85: const std::string &help, alpar@85: std::string &ref, bool obl=false); alpar@85: alpar@85: ///@} alpar@85: alpar@85: ///\name Option Groups and Synonyms alpar@85: /// alpar@85: alpar@85: ///@{ alpar@85: alpar@85: ///Boundle some options into a group alpar@85: alpar@85: /// You can group some option by calling this function repeatedly for each kpeter@88: /// option to be grouped with the same groupname. kpeter@88: ///\param group The group name. kpeter@88: ///\param opt The option name. alpar@85: ArgParser &optionGroup(const std::string &group, alpar@85: const std::string &opt); alpar@85: alpar@85: ///Make the members of a group exclusive alpar@85: alpar@85: ///If you call this function for a group, than at most one of them can be alpar@85: ///given at the same time alpar@85: ArgParser &onlyOneGroup(const std::string &group); alpar@85: alpar@85: ///Make a group mandatory alpar@85: alpar@85: ///Using this function, at least one of the members of \c group alpar@85: ///must be given. alpar@85: ArgParser &mandatoryGroup(const std::string &group); alpar@85: alpar@85: ///Create synonym to an option alpar@85: kpeter@88: ///With this function you can create a synonym \c syn of the alpar@85: ///option \c opt. alpar@85: ArgParser &synonym(const std::string &syn, alpar@85: const std::string &opt); alpar@85: alpar@85: ///@} alpar@85: alpar@85: ///Give help string for non-parsed arguments. alpar@85: alpar@85: ///With this function you can give help string for non-parsed arguments. kpeter@88: ///The parameter \c name will be printed in the short usage line, while alpar@85: ///\c help gives a more detailed description. alpar@85: ArgParser &other(const std::string &name, alpar@85: const std::string &help=""); alpar@85: kpeter@88: ///Give back the non-option type arguments. alpar@85: kpeter@88: ///Give back a reference to a vector consisting of the program arguments alpar@85: ///not starting with a '-' character. alpar@85: std::vector &files() { return _file_args; } alpar@85: alpar@85: ///Give back the command name (the 0th argument) alpar@85: const std::string &commandName() { return _command_name; } alpar@85: alpar@85: void show(std::ostream &os,Opts::iterator i); alpar@85: void show(std::ostream &os,Groups::iterator i); alpar@85: void showHelp(Opts::iterator i); alpar@85: void showHelp(std::vector::iterator i); alpar@85: void shortHelp(); alpar@85: void showHelp(); alpar@85: alpar@85: void unknownOpt(std::string arg); alpar@85: alpar@85: void requiresValue(std::string arg, OptType t); alpar@85: void checkMandatories(); alpar@85: alpar@85: ///Start the parsing process alpar@85: ArgParser &parse(); alpar@85: alpar@85: /// Synonym for parse() alpar@85: ArgParser &run() alpar@85: { alpar@85: return parse(); alpar@85: } alpar@85: alpar@85: ///Check if an opion has been given to the command. alpar@85: bool given(std::string op) alpar@85: { alpar@85: Opts::iterator i = _opts.find(op); alpar@85: return i!=_opts.end()?i->second.set:false; alpar@85: } alpar@85: alpar@85: alpar@85: ///Magic type for operator[] alpar@85: alpar@85: ///This is the type of the return value of ArgParser::operator[](). kpeter@88: ///It automatically converts to \c int, \c double, \c bool or kpeter@88: ///\c std::string if the type of the option matches, otherwise it kpeter@88: ///throws an exception (i.e. it performs runtime type checking). alpar@85: class RefType alpar@85: { alpar@85: ArgParser &_parser; alpar@85: std::string _name; alpar@85: public: alpar@85: ///\e alpar@85: RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {} alpar@85: ///\e alpar@85: operator bool() alpar@85: { alpar@85: Opts::iterator i = _parser._opts.find(_name); alpar@85: LEMON_ASSERT(i==_parser._opts.end(), alpar@85: std::string()+"Unkown option: '"+_name+"'"); alpar@85: LEMON_ASSERT(i->second.type!=ArgParser::BOOL, alpar@85: std::string()+"'"+_name+"' is a bool option"); alpar@85: return *(i->second.bool_p); alpar@85: } alpar@85: ///\e alpar@85: operator std::string() alpar@85: { alpar@85: Opts::iterator i = _parser._opts.find(_name); alpar@85: LEMON_ASSERT(i==_parser._opts.end(), alpar@85: std::string()+"Unkown option: '"+_name+"'"); alpar@85: LEMON_ASSERT(i->second.type!=ArgParser::STRING, alpar@85: std::string()+"'"+_name+"' is a string option"); alpar@85: return *(i->second.string_p); alpar@85: } alpar@85: ///\e alpar@85: operator double() alpar@85: { alpar@85: Opts::iterator i = _parser._opts.find(_name); alpar@85: LEMON_ASSERT(i==_parser._opts.end(), alpar@85: std::string()+"Unkown option: '"+_name+"'"); alpar@85: LEMON_ASSERT(i->second.type!=ArgParser::DOUBLE && alpar@85: i->second.type!=ArgParser::INTEGER, alpar@85: std::string()+"'"+_name+"' is a floating point option"); alpar@85: return i->second.type==ArgParser::DOUBLE ? alpar@85: *(i->second.double_p) : *(i->second.int_p); alpar@85: } alpar@85: ///\e alpar@85: operator int() alpar@85: { alpar@85: Opts::iterator i = _parser._opts.find(_name); alpar@85: LEMON_ASSERT(i==_parser._opts.end(), alpar@85: std::string()+"Unkown option: '"+_name+"'"); alpar@85: LEMON_ASSERT(i->second.type!=ArgParser::INTEGER, alpar@85: std::string()+"'"+_name+"' is an integer option"); alpar@85: return *(i->second.int_p); alpar@85: } alpar@85: alpar@85: }; alpar@85: alpar@85: ///Give back the value of an option alpar@85: kpeter@88: ///Give back the value of an option. alpar@85: ///\sa RefType alpar@85: RefType operator[](const std::string &n) alpar@85: { alpar@85: return RefType(*this, n); alpar@85: } alpar@85: alpar@85: }; alpar@85: } alpar@85: alpar@85: alpar@85: alpar@85: #endif // LEMON_MAIN_PARAMS