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