Zen
A cross-platform functional programming language

/home/renji/Data/projects/zenlang/sources/zbl/CmdLine.hpp

Go to the documentation of this file.
00001 
00005 #pragma once
00006 
00008 namespace zbl {
00009     namespace {
00011 
00015         template <typename T>
00016         inline void setValue(const z::string& str, T& val);
00017 
00022         template <>
00023         inline void setValue<bool>(const z::string& str, bool& val) {
00024             unused(str);
00025             val = true;
00026         }
00027 
00032         template <>
00033         inline void setValue<int>(const z::string& str, int& val) {
00034             val = str.toLong();
00035         }
00036 
00041         template <>
00042         inline void setValue<z::string>(const z::string& str, z::string& val) {
00043             val = str;
00044         }
00045 
00050         template <>
00051         inline void setValue<z::stringlist>(const z::string& str, z::stringlist& val) {
00052             val.append(str);
00053         }
00054     }
00055 
00057 
00059     template <typename ObjT, typename T>
00060     struct callMethod {
00066         static inline void call(const z::string& str, ObjT& (ObjT::*fn)(const T& val), ObjT& obj);
00067     };
00068 
00071     template <typename ObjT>
00072     struct callMethod<ObjT, bool> {
00078         static inline void call(const z::string& str, ObjT& (ObjT::*fn)(const bool& val), ObjT& obj) {
00079             unused(str);
00080             (obj.*fn)(true);
00081         }
00082     };
00083 
00086     template <typename ObjT>
00087     struct callMethod<ObjT, int> {
00093         static inline void call(const z::string& str, ObjT& (ObjT::*fn)(const int& val), ObjT& obj) {
00094             (obj.*fn)(str.toLong());
00095         }
00096     };
00097 
00100     template <typename ObjT>
00101     struct callMethod<ObjT, z::string> {
00107         static inline void call(const z::string& str, ObjT& (ObjT::*fn)(const z::string& val), ObjT& obj) {
00108             (obj.*fn)(str);
00109         }
00110     };
00111 
00112     namespace {
00114 
00118         template <typename T>
00119         inline bool shouldInc(const bool& val) {
00120             return val;
00121         }
00122 
00127         template <>
00128         inline bool shouldInc<bool>(const bool& val) {
00129             unused(val);
00130             return false;
00131         }
00132     }
00133 
00135 
00137     class OptionBase {
00138     public:
00144         inline OptionBase(const z::string& sname, const z::string& lname, const z::string& desc) : _sname(sname), _lname(lname), _desc(desc){}
00145 
00146     public:
00151         virtual void handle(const bool& isOption, z::stringlist::iterator& it) = 0;
00152 
00157         inline  void show(z::stream& str, const int& w = 32) const;
00158 
00159     private:
00161         z::string _sname;
00162 
00164         z::string _lname;
00165 
00167         z::string _desc;
00168     };
00169 
00172     template <typename T>
00173     class OptionVar : public OptionBase {
00174     public:
00181         inline OptionVar(const z::string& sname, const z::string& lname, const z::string& desc, T& val) : OptionBase(sname, lname, desc), _val(val) {}
00182 
00183     public:
00188         virtual void handle(const bool& isOption, z::stringlist::iterator& it) {
00189             if(shouldInc<T>(isOption))
00190                 ++it;
00191             if(!it.end())
00192                 setValue<T>(*it, _val);
00193         }
00194 
00195     private:
00197         T& _val;
00198     };
00199 
00202     template <typename ObjT, typename T>
00203     class OptionCall : public OptionBase {
00204     public:
00212         inline OptionCall(const z::string& sname, const z::string& lname, const z::string& desc, ObjT& (ObjT::*fn)(const T& val), ObjT& obj)
00213           : OptionBase(sname, lname, desc), _fn(fn), _obj(obj) {}
00214 
00215     public:
00220         virtual void handle(const bool& isOption, z::stringlist::iterator& it) {
00221             if(shouldInc<T>(isOption))
00222                 ++it;
00223             if(!it.end()) {
00224                 callMethod<ObjT, T>::call(*it, _fn, _obj);
00225             }
00226         }
00227 
00228     private:
00230         ObjT& (ObjT::*_fn)(const T& val);
00231 
00233         ObjT& _obj;
00234     };
00235 
00236     inline void OptionBase::show(z::stream& str, const int& w) const {
00237         if((_sname.length() > 0) && (_lname.length() > 0)) {
00238             z::string rv = _sname + z::string(", ") + _lname;
00239             str << "  " << rv.leftJustified(w) << _desc << z::end();
00240         } else {
00241             str << "  " << _desc << z::end();
00242         }
00243     }
00244 
00247     class CmdLine {
00248     private:
00250         typedef z::sharedptr<OptionBase> OptPtr_t;
00251 
00253         typedef z::list<OptPtr_t> OptList_t;
00254 
00256         typedef z::dict<z::string, OptionBase* > Map_t;
00257 
00259         typedef z::list<OptionBase* > List_t;
00260 
00261     public:
00264         class Command {
00265         public:
00268             inline Command() : _value(0), _posArg(0) {}
00269 
00270         private:
00278             template <typename T>
00279             inline OptionBase& createVar(const z::string& sname, const z::string& lname, const z::string& desc, T& val);
00280 
00289             template <typename ObjT, typename T>
00290             inline OptionBase& createCall(const z::string& sname, const z::string& lname, const z::string& desc, ObjT& (ObjT::*fn)(const T& val), ObjT& obj );
00291 
00292         public:
00299             template <typename T>
00300             inline void addOptionVar(const z::string& sname, const z::string& lname, const z::string& desc, T& val);
00301 
00309             template <typename ObjT, typename T>
00310             inline void addOptionCall(const z::string& sname, const z::string& lname, const z::string& desc, ObjT& (ObjT::*fn)(const T& val), ObjT& obj );
00311 
00316             template <typename T>
00317             inline void addParameterVar(const z::string& desc, T& val);
00318 
00323             inline void addParameterListVar(const z::string& desc, z::stringlist& list);
00324 
00330             template <typename ObjT>
00331             inline void addParameterListCall(const z::string& desc, ObjT& (ObjT::*fn)(const z::string& val), ObjT& obj);
00332 
00333         public:
00335             OptList_t _optList;
00336 
00338             z::string _key;
00339 
00341             z::string _desc;
00342 
00344             int _value;
00345 
00346         public:
00348             Map_t _map;
00349 
00351             List_t _list;
00352 
00353         public:
00355             OptionBase* _posArg;
00356         };
00357 
00358     private:
00360         typedef z::dict<z::string, Command > CmdMap_t;
00361 
00363         typedef z::list<Command* > CmdList_t;
00364 
00365     public:
00368         CmdLine(const z::string& desc) : _desc(desc) {}
00369 
00370     public:
00377         inline Command& addCommand(const z::string& cmd, int value, const z::string& desc);
00378 
00379     public:
00383         inline const int& getCommand() const;
00384 
00388         inline const z::string& getError() const;
00389 
00390     public:
00396         inline int parse(int argc, char* argv[]);
00397 
00402         inline int parse(const z::stringlist& args);
00403 
00407         inline void show(z::stream& str) const;
00408 
00409     private:
00414         inline const Command* hasCommandMap(z::stringlist::iterator& it);
00415 
00420         inline const Command& getCommandMap(z::stringlist::iterator& it);
00421 
00422     private:
00424         CmdMap_t _cmdMap;
00425 
00427         CmdList_t _cmdList;
00428 
00429     private:
00431         z::string _appName;
00432 
00434         int _command;
00435 
00437         z::string _desc;
00438 
00440         z::string _error;
00441     };
00442 
00443     template <typename T>
00444     inline OptionBase& CmdLine::Command::createVar(const z::string& sname, const z::string& lname, const z::string& desc, T& val) {
00445         OptPtr_t opt(new OptionVar<T>(sname, lname, desc, val));
00446         _optList.append(opt);
00447         return *opt;
00448     }
00449 
00450     template <typename ObjT, typename T>
00451     inline OptionBase& CmdLine::Command::createCall(const z::string& sname, const z::string& lname, const z::string& desc, ObjT& (ObjT::*fn)(const T& val), ObjT& obj ) {
00452         OptPtr_t opt(new OptionCall<ObjT, T>(sname, lname, desc, fn, obj));
00453         _optList.append(opt);
00454         return *opt;
00455     }
00456 
00457     template <typename T>
00458     inline void CmdLine::Command::addOptionVar(const z::string& sname, const z::string& lname, const z::string& desc, T& val) {
00459         OptionBase& opt = createVar(sname, lname, desc, val);
00460         _map[sname] = ptr(opt);
00461         _map[lname] = ptr(opt);
00462     }
00463 
00464     template <typename ObjT, typename T>
00465     inline void CmdLine::Command::addOptionCall(const z::string& sname, const z::string& lname, const z::string& desc, ObjT& (ObjT::*fn)(const T& val), ObjT& obj ) {
00466         OptionBase& opt = createCall(sname, lname, desc, fn, obj);
00467         _map[sname] = ptr(opt);
00468         _map[lname] = ptr(opt);
00469     }
00470 
00471     template <typename T>
00472     inline void CmdLine::Command::addParameterVar(const z::string& desc, T& val) {
00473         OptionBase& par = createVar(z::string(""), z::string(""), desc, val);
00474         _list.append(ptr(par));
00475     }
00476 
00477     inline void CmdLine::Command::addParameterListVar(const z::string& desc, z::stringlist& list) {
00478         assert(0 == _posArg);
00479         OptionBase& par = createVar(z::string(""), z::string(""), desc, list);
00480         _posArg = ptr(par);
00481     }
00482 
00483     template <typename ObjT>
00484     inline void CmdLine::Command::addParameterListCall(const z::string& desc, ObjT& (ObjT::*fn)(const z::string& val), ObjT& obj) {
00485         assert(0 == _posArg);
00486         OptionBase& par = createCall(z::string(""), z::string(""), desc, fn, obj);
00487         _posArg = ptr(par);
00488     }
00489 
00490     inline const int& CmdLine::getCommand() const {
00491         assert(_cmdMap.size() > 0);
00492         return _command;
00493     }
00494 
00495     inline const z::string& CmdLine::getError() const {
00496         return _error;
00497     }
00498 
00499     inline CmdLine::Command& CmdLine::addCommand(const z::string& cmd, int value, const z::string& desc) {
00500         assert(!_cmdMap.has(cmd));
00501         Command& cmdd = _cmdMap[cmd];
00502         cmdd._key  = cmd;
00503         cmdd._desc = desc;
00504         cmdd._value = value;
00505         _cmdList.append(ptr(cmdd));
00506         return cmdd;
00507     }
00508 
00509     inline void CmdLine::show(z::stream& str) const {
00510         // check if there is at least 1 non-empty command
00511         bool hasCmd = false;
00512         for(CmdList_t::iterator cit(_cmdList); !cit.end();++cit) {
00513             const Command& cmd = ref(*cit);
00514             if(cmd._key.length() > 0) {
00515                 hasCmd = true;
00516                 break;
00517             }
00518         }
00519         str << _appName << " <command> <options> " << z::end();
00520         if(_desc.length() > 0) {
00521             str << _desc << z::end();
00522         }
00523 
00524         if(hasCmd) {
00525             str << "commands: ";
00526             z::string sep = z::string("");
00527             for(CmdList_t::iterator cit(_cmdList); !cit.end();++cit) {
00528                 const Command& cmd = ref(*cit);
00529                 str << sep << ((cmd._key.length() > 0)?(cmd._key):z::string("<none>"));
00530                 sep = z::string(", ");
00531             }
00532             str << z::end();
00533             str << z::end();
00534         }
00535 
00536         for(CmdList_t::iterator cit(_cmdList); !cit.end();++cit) {
00537             const Command& cmd = ref(*cit);
00538             if(cmd._key.length() > 0) {
00539                 str << cmd._key << ": " << cmd._desc << z::end();
00540             }
00541 
00542             for(OptList_t::iterator it(cmd._optList); !it.end(); ++it) {
00543                 const OptionBase& opt = **it;
00544                 opt.show(str);
00545             }
00546             str << z::end();
00547         }
00548     }
00549 
00550     inline const CmdLine::Command* CmdLine::hasCommandMap(z::stringlist::iterator& it) {
00551         if (it.end()) {
00552             // if 'it' is at end of list, return true if we have a def command
00553             if(_cmdMap.has(z::string("")))
00554                 return ptr(_cmdMap[z::string("")]);
00555             return 0;
00556         }
00557 
00558         // assume *it is a command, find it in _cmdMap
00559         CmdMap_t::found f1 = _cmdMap.find(*it);
00560         if(f1) {
00561             ++it;
00562             return ptr(*f1);
00563         }
00564 
00565         // if *it not found, but we have a def command, return true.
00566         CmdMap_t::found f2 = _cmdMap.find(z::string(""));
00567         if(f2) {
00568             return ptr(*f2);
00569         }
00570 
00571         return 0;
00572     }
00573 
00574     inline const CmdLine::Command& CmdLine::getCommandMap(z::stringlist::iterator& it) {
00575         // if command is not found and there is a default, use that.
00576         if (it.end()) {
00577             // if there is no default, we should reach this point at all.
00578             assert(_cmdMap.has(z::string("")));
00579             return _cmdMap[z::string("")];
00580         }
00581 
00582         assert(!it.end());
00583         z::string command = *it;
00584 
00585         if((!_cmdMap.has(command)) && (_cmdMap.has(z::string("")))) {
00586             return _cmdMap[z::string("")];
00587         }
00588 
00589         assert(_cmdMap.has(command));
00590         ++it;
00591         return _cmdMap[command];
00592     }
00593 
00594     inline int CmdLine::parse(const z::stringlist& args) {
00595         z::stringlist::iterator it(args);
00596 
00597         // first argument is app name
00598         _appName = *it;
00599         ++it;
00600 
00601         // next is command
00602         const Command* cmd = hasCommandMap(it);
00603         if (!cmd) {
00604             _error = z::string("Invalid command: ") + ((!it.end())?*it:z::string(""));
00605             return 1;
00606         }
00607 
00608         _command = ref(cmd)._value;
00609 
00610         // parse all options
00611         while(!it.end()) {
00612             const z::string& str = *it;
00613             Map_t::found found = ref(cmd)._map.find(str);
00614             if(!found) {
00615                 if(str.at(0) == '-') {
00616                     // it can -x, --x or ---x (where <x> is any option)
00617                     _error = z::string("Invalid option: ") + str;
00618                     return 1;
00619                 }
00620                 break;
00621             }
00622 
00623             OptionBase* opt = *found;
00624             opt->handle(true, it);
00625             if(!it.end())
00626                 ++it;
00627         }
00628 
00629         // parse positional parameters
00630         for(List_t::iterator pit(ref(cmd)._list); !pit.end() && (!it.end()); ++pit) {
00631             OptionBase* opt = *pit;
00632             opt->handle(false, it);
00633             if(!it.end())
00634                 ++it;
00635         }
00636 
00637 
00638         if(ref(cmd)._posArg != 0) {
00639             // rest of arguments
00640             while(!it.end()) {
00641                 ref(cmd)._posArg->handle(false, it);
00642                 if(!it.end())
00643                     ++it;
00644             }
00645         }
00646 
00647         if(!it.end()) {
00648             _error = z::string("Unknown parameters");
00649             return 1;
00650         }
00651 
00652         return 0;
00653     }
00654 
00655     inline int CmdLine::parse(int argc, char* argv[]) {
00656         z::stringlist args;
00657         for(int i = 0; i < argc; ++i) {
00658             z::string arg(argv[i]);
00659             args.append(arg);
00660         }
00661         return parse(args);
00662     }
00663 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines