Zen
A cross-platform functional programming language
|
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 }