[complement-svn] SF.net SVN: complement: [1862] trunk/complement/explore
Status: Pre-Alpha
Brought to you by:
complement
From: <Dmi...@us...> - 2008-04-28 15:58:41
|
Revision: 1862 http://complement.svn.sourceforge.net/complement/?rev=1862&view=rev Author: DmitryOsmakov Date: 2008-04-28 08:58:14 -0700 (Mon, 28 Apr 2008) Log Message: ----------- added lib: Opts - new lib to work with command line options. Added Paths: ----------- trunk/complement/explore/include/misc/opts.h trunk/complement/explore/lib/misc/opts.cpp trunk/complement/explore/lib/misc/opts_usage.cpp Added: trunk/complement/explore/include/misc/opts.h =================================================================== --- trunk/complement/explore/include/misc/opts.h (rev 0) +++ trunk/complement/explore/include/misc/opts.h 2008-04-28 15:58:14 UTC (rev 1862) @@ -0,0 +1,254 @@ +#ifndef __OPTS_H__ +#define __OPTS_H__ + +#include <iostream> +#include <string> +#include <vector> +#include <sstream> +#include <typeinfo> +#include <cctype> + +using namespace std; + +class Value +{ +public: + void* ptr; + Value() { ptr = 0; } +}; + +class Opt +{ +public: + char shortname; + string longname; + string desc; + vector< string > args; + Value val; // must be vector + + bool has_arg; + bool is_set; +}; + +class Opts +{ +public: +// construct + Opts(const string& _brief = "",const string& _author = "",const string& _copyright = "") : brief(_brief) , author(_author) , copyright(_copyright) {}; + +// adding option + // 4 params + template <class T> + void add(char _shortname,const string& _longname,const string& _desc,T v); + + + // 3 params + template <class T> + void add(char _shortname,const string& desc,T v); + template <class T> + void add(const string& longname,const string& desc,T v); + + // 2 params + template <class T> + void add(char _shortname,T v); + template <class T> + void add(const string& _longname,T v); + + // 1 param - randomly generated names? + +// adding flag + void addf(char _shortname,const string& _longname,const string& _desc); + void addf(char _shortname,const string& _desc); + void addf(const string& _longname,const string& _desc); + +// getting option + template <class T> + T get(char _shortname,T& dest); + template <class T> + T get(const string& _longname,T& dest); + + bool is_set(char _shortname); + bool is_set(const string& _longname); + +// parse + void parse(int ac,char** av); + +// stuff + void help(ostream& out); + string get_pname() const; + string get_brief() const; + string get_author() const; + string get_copyright() const; + +// error handling + struct invalid_opt { string optname; invalid_opt(const string& _optname) : optname(_optname) {}; }; + struct missing_arg { string optname; missing_arg(const string& _optname) : optname(_optname) {}; }; + struct invalid_arg { string optname,argname; invalid_arg(const string& _optname,const string& _argname) : optname(_optname) , argname(_argname) {}; }; + +private: + // data + vector< Opt > storage; + vector< string > args; + + string pname; + string brief; + string author; + string copyright; + + bool isterm(const string& s); + bool is_opt_name(const string& s); + bool is_flag_group(const string& s); + bool is_substr(const string& small,const string& big); + int get_opt_index(string s); +}; + +template <class T> +void Opts::add(char _shortname,const string& _longname,const string& _desc,T v) +{ + Opt opt; + + //opt.val.tinfo = typeid(T); + opt.val.ptr = new T; + *(reinterpret_cast<T*>(opt.val.ptr)) = v; + + opt.shortname = _shortname; + opt.longname = _longname; + opt.desc = _desc; + + opt.has_arg = true; + opt.is_set = false; + + storage.push_back(opt); +} + +template <class T> +void Opts::add(char _shortname,const string& _desc,T v) +{ + Opt opt; + + //opt.val.tinfo = typeid(T); + opt.val.ptr = new T; + *(reinterpret_cast<T*>(opt.val.ptr)) = v; + + opt.shortname = _shortname; + opt.desc = _desc; + + opt.has_arg = true; + opt.is_set = false; + + storage.push_back(opt); +} + +template <class T> +void Opts::add(const string& _longname,const string& _desc,T v) +{ + Opt opt; + + //opt.val.tinfo = typeid(T); + opt.val.ptr = new T; + *(reinterpret_cast<T*>(opt.val.ptr)) = v; + + opt.longname = _longname; + opt.desc = _desc; + + opt.has_arg = true; + opt.is_set = false; + + storage.push_back(opt); +} + +template <class T> +void Opts::add(char _shortname,T v) +{ + Opt opt; + + //opt.val.tinfo = typeid(T); + opt.val.ptr = new T; + *(reinterpret_cast<T*>(opt.val.ptr)) = v; + + opt.shortname = _shortname; + + opt.has_arg = true; + opt.is_set = false; + + storage.push_back(opt); +} + +template <class T> +void Opts::add(const string& _longname,T v) +{ + Opt opt; + + //opt.val.tinfo = typeid(T); + opt.val.ptr = new T; + *(reinterpret_cast<T*>(opt.val.ptr)) = v; + + opt.longname = _longname; + + opt.has_arg = true; + opt.is_set = false; + + storage.push_back(opt); +} + +template <class T> +T Opts::get(char _shortname,T& res) +{ + int i; + for (i = 0;i < storage.size();i++) + if (storage[i].shortname == _shortname) + { + if (storage[i].is_set && storage[i].has_arg) + { + try + { + stringstream ss(storage[i].args[0]); + ss >> res; + } + catch(...) + { + throw invalid_arg(string("-") + string(1,_shortname),storage[i].args[0]); + } + } + else + { + res = *reinterpret_cast<T*>(storage[i].val.ptr); + } + break; + } + if (i == storage.size()) + throw invalid_opt(string("-") + string(1,_shortname)); + return res; +} + +template <class T> +T Opts::get(const string& _longname,T& res) +{ + int i; + for (i = 0;i < storage.size();i++) + if (storage[i].longname == _longname) + { + if (storage[i].is_set && storage[i].has_arg) + { + try + { + stringstream ss(storage[i].args[0]); + ss >> res; + } + catch(...) + { + throw invalid_arg(_longname,storage[i].args[0]); + } + } + else + { + res = *reinterpret_cast<T*>(storage[i].val.ptr); + } + break; + } + if (i == storage.size()) + throw invalid_opt(_longname); + return res; +} + +#endif Added: trunk/complement/explore/lib/misc/opts.cpp =================================================================== --- trunk/complement/explore/lib/misc/opts.cpp (rev 0) +++ trunk/complement/explore/lib/misc/opts.cpp 2008-04-28 15:58:14 UTC (rev 1862) @@ -0,0 +1,224 @@ +#include <vector> +#include <string> +#include <sstream> +#include <typeinfo> +#include "opts.h" + +using namespace std; + +string Opts::get_pname() const { return pname; } +string Opts::get_brief() const { return brief; } +string Opts::get_author() const { return author; } +string Opts::get_copyright() const { return copyright; } + +bool Opts::isterm(const string& s) +{ + return (s == "--"); +} + +bool Opts::is_opt_name(const string& s) +{ + return (s.size() > 0) && (s[0] == '-') && !is_flag_group(s); +} + +bool Opts::is_substr(const string& small,const string& big) +{ + if (small.size() > big.size()) + return false; + for (int i = 0;i < small.size();i++) + if (small[i] != big[i]) + return false; + + return true; +} + +bool Opts::is_flag_group(const string& s) +{ + if (s.size() > 2 && s[0] == '-') + { + for (int i = 1;i < s.size();i++) + if (!isalnum(s[i])) + return false; + return true; + } + else + return false; +} + +// this function assumes that is_opt_name(s) = true; +int Opts::get_opt_index(string s) +{ + if (s.size() == 2 && isalnum(s[1]) ) // is short name + { + int i; + for (i = 0;i < storage.size();i++) + if (storage[i].shortname == s[1]) + break; + return i; + } + + if (s.size() > 2 && s[1] == '-') + { + int i; + s = s.substr(2); + + // exact match + for (i = 0;i < storage.size();i++) + if (storage[i].longname == s) + return i; + + vector<int> matches; + for (i = 0;i < storage.size();i++) + if (is_substr(s,storage[i].longname)) + matches.push_back(i); + + if (matches.size() == 1) + return matches[0]; + else + return storage.size(); + } + + return storage.size(); +} + +void Opts::help(ostream& out) +{ + if (!brief.empty()) + out << brief << endl; + if (!author.empty()) + out << author << endl; + if (!copyright.empty()) + out << copyright << endl; + + out << "usage: " << endl; + out << pname << " [option ...] [optiongoup ...] [end operands ...]" << endl; + out << "available options:" << endl; + for (int i = 0;i < storage.size();i++) + out << "-" << storage[i].shortname << "\t[--" << storage[i].longname << "]\t-\t" << storage[i].desc << endl; +} + + +void Opts::addf(char _shortname,const string& _longname,const string& _desc) +{ + Opt opt; + opt.shortname = _shortname; + opt.longname = _longname; + opt.desc = _desc; + opt.has_arg = false; + opt.is_set = false; + storage.push_back(opt); +} + +void Opts::addf(char _shortname,const string& _desc) +{ + Opt opt; + opt.shortname = _shortname; + opt.desc = _desc; + opt.has_arg = false; + opt.is_set = false; + storage.push_back(opt); +} + +void Opts::addf(const string& _longname,const string& _desc) +{ + Opt opt; + opt.longname = _longname; + opt.desc = _desc; + opt.has_arg = false; + opt.is_set = false; + storage.push_back(opt); +} + +bool Opts::is_set(char _shortname) +{ + for (int i = 0;i < storage.size();i++) + if (storage[i].shortname == _shortname) + return storage[i].is_set; + return false; +} + +bool Opts::is_set(const string& _longname) +{ + for (int i = 0;i < storage.size();i++) + if (storage[i].longname == _longname) + return storage[i].is_set; + return false; +} + +void Opts::parse(int ac,char** av) +{ + pname = av[0]; + + int i = 1; + while (i < ac && !isterm(av[i])) + { + if (is_opt_name(av[i])) + { + string opt = av[i]; + string arg; + + int k = opt.find("="); + + if (k != string::npos) + { + arg = opt.substr(k + 1); + opt = opt.substr(0,k); + } + + int p = get_opt_index(opt); + + if (p == storage.size()) + throw invalid_opt(opt); + else + { + if (storage[p].has_arg) + { + if (!arg.empty()) + { + storage[p].is_set = true; + storage[p].args.push_back(arg); + } + else + if (i + 1 < ac) + { + storage[p].is_set = true; + storage[p].args.push_back(av[++i]); + } + else + throw missing_arg(opt); + } + else + { + storage[p].is_set = true; + if (!arg.empty()) + throw invalid_arg(opt,arg); + } + } + } + else + if (is_flag_group(av[i])) + { + string optgroup = av[i]; + for (int j = 1;j < optgroup.size();j++) + { + int p = get_opt_index(string("-") + optgroup[j]); + if (p == storage.size()) + throw invalid_opt( "-" + string(1,optgroup[j]) ); + else + { + storage[p].is_set = true; + if (storage[p].has_arg) + throw missing_arg( "-" + string(1,optgroup[j]) ); + } + } + } + else + args.push_back(av[i]); + i++; + } + + i += (i < ac && isterm(av[i])); + + while (i < ac) + args.push_back(av[i++]); +} Added: trunk/complement/explore/lib/misc/opts_usage.cpp =================================================================== --- trunk/complement/explore/lib/misc/opts_usage.cpp (rev 0) +++ trunk/complement/explore/lib/misc/opts_usage.cpp 2008-04-28 15:58:14 UTC (rev 1862) @@ -0,0 +1,79 @@ +#include <iostream> +#include <string> +#include "opts.h" + +using namespace std; + +struct point +{ + int x; + int y; + point(int _x = 0,int _y = 0) : x(_x) , y(_y) {}; +}; + +istream& operator>>(istream& t,point& p) +{ + t >> p.x >> p.y; + return t; +} + +ostream& operator<<(ostream& t,const point& p) +{ + t << p.x << ' ' << p.y; + return t; +} + +int main(int ac,char** av) +{ + Opts opts; + point p; + string name; + int port; + + opts.addf('h',"help","display help message"); + opts.addf('v',"verbose","verbose"); + opts.addf('j',"just","just do it"); + + opts.add('p',"port","port number",80); + opts.add('s',"point","start point",point(1,1)); + opts.add('n',"name","your name",string("maos")); + + try + { + opts.parse(ac,av); + } + catch(Opts::invalid_opt& t) + { + cout << "Invalid option: " << t.optname << endl; + return 1; + } + catch(Opts::invalid_arg& t) + { + cout << "Invalid argument: " << t.optname << ' ' << t.argname << endl; + return 1; + } + catch(Opts::missing_arg& t) + { + cout << "Missing argument: " << t.optname << endl; + return 1; + } + + if (opts.is_set('h')) + opts.help(cout); + + if (opts.is_set('v')) + cout << "Verbose mode is set" << endl; + else + cout << "Verbose mode is not set" << endl; + + if (opts.is_set("just")) + cout << "Just do it!" << endl; + else + cout << "Just don't do it!" << endl; + + cout << "port = " << opts.get('p',port) << endl; + cout << "point = " << opts.get('s',p) << endl; + cout << "name = " << opts.get('n',name) << endl; + + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |