00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef ARCHON_UTILITIES_OPTIONS_H
00021 #define ARCHON_UTILITIES_OPTIONS_H
00022
00023 #include <string>
00024 #include <vector>
00025
00026 #include <archon/util/exception.H>
00027 #include <archon/util/term.H>
00028 #include <archon/util/logger.H>
00029
00030 namespace Archon
00031 {
00032 namespace Utilities
00033 {
00034 using namespace std;
00035
00036 struct Options
00037 {
00038 struct DefinitionException: virtual Exception
00039 {
00040 DefinitionException(string l, string m): Exception(l, m) {}
00041 };
00042
00046 struct FileAccessException: virtual Exception
00047 {
00048 FileAccessException(string l, string m): Exception(l, m) {}
00049 };
00050
00051 Options(bool treatNegativeNumbersAsOptions = false,
00052 Logger *logger = Logger::get());
00053 ~Options();
00054
00055 enum WantArg
00056 {
00057 wantArg_never,
00058 wantArg_optional,
00059 wantArg_always
00060 };
00061
00062 template<typename T> struct Parser
00063 {
00064 static T parse(const char *) throw(ParseException);
00065 static string format(T);
00066 };
00067
00071 template<typename T> struct Unrestricted
00072 {
00073 void check(const T &) const throw(ParseException) {}
00074 };
00075
00079 template<typename T> struct Range
00080 {
00081 T from, to;
00082 Range(T from, T to): from(from), to(to) {}
00083 void check(const T &v) const throw(ParseException)
00084 {
00085 if(v < from || v >= to)
00086 ARCHON_THROW1(ParseException, "Out of range");
00087 }
00088 };
00089
00090 template<typename T> static Range<T> range(T from, T to)
00091 {
00092 return Range<T>(from, to);
00093 }
00094
00134 template<typename T, typename D>
00135 void addConfig(string shortName, string longName,
00136 T &var, T val, string description,
00137 WantArg wantArg, D domainChecker)
00138 throw(DefinitionException)
00139 {
00140 verify(shortName, longName);
00141 defs.push_back(new DefVar<T, D>(false, shortName, longName, var, val,
00142 wantArg, domainChecker, description));
00143 }
00144
00152 template<typename T>
00153 void addConfig(string shortName, string longName,
00154 T &var, T val, string description,
00155 WantArg wantArg = wantArg_never)
00156 throw(DefinitionException)
00157 {
00158 verify(shortName, longName);
00159 defs.push_back(new DefVar<T, Unrestricted<T> >
00160 (false, shortName, longName, var, val,
00161 wantArg, Unrestricted<T>(), description));
00162 }
00163
00170 template<typename T, typename D>
00171 void addSwitch(string shortName, string longName,
00172 T &var, T val, string description,
00173 WantArg wantArg, D domainChecker)
00174 throw(DefinitionException)
00175 {
00176 verify(shortName, longName);
00177 defs.push_back(new DefVar<T, D>(true, shortName, longName, var, val,
00178 wantArg, domainChecker, description));
00179 }
00180
00187 template<typename T>
00188 void addSwitch(string shortName, string longName,
00189 T &var, T val, string description,
00190 WantArg wantArg = wantArg_never)
00191 throw(DefinitionException)
00192 {
00193 verify(shortName, longName);
00194 defs.push_back(new DefVar<T, Unrestricted<T> >
00195 (true, shortName, longName, var, val,
00196 wantArg, Unrestricted<T>(), description));
00197 }
00198
00203 struct IntByInt
00204 {
00205 int x, y;
00206
00207 bool operator==(const IntByInt &o) const { return x == o.x && y == o.y; }
00208 };
00209
00225 bool processCommandLine(int &argc, const char *argv[],
00226 bool switchesOnly = false);
00227
00233 bool processConfigFile(string path)
00234 throw(FileAccessException);
00235
00242 void saveConfigFile(string path)
00243 throw(FileAccessException);
00244
00248 string list(unsigned width = Term::getWidth());
00249
00250 private:
00251 struct Def
00252 {
00253 bool switchOnly;
00254 string shortName;
00255 string longName;
00256 string description;
00257 WantArg wantArg;
00258
00259 Def(bool switchOnly, string shortName, string longName,
00260 string description, WantArg wantArg):
00261 switchOnly(switchOnly), shortName(shortName), longName(longName),
00262 description(description), wantArg(wantArg) {}
00263
00267 virtual ~Def() {}
00268
00272 virtual void execute(Options *o, const char *arg) const
00273 throw(ParseException) = 0;
00274 };
00275
00276 struct DefVarBase: public Def
00277 {
00278 DefVarBase(bool switchOnly, string shortName, string longName,
00279 string description, WantArg wantArg):
00280 Def(switchOnly, shortName, longName, description, wantArg) {}
00281 virtual ~DefVarBase() {}
00282 virtual string getValue() const = 0;
00283 virtual bool isDefaultSet() const = 0;
00284 };
00285
00286 template<typename T, typename D>
00287 struct DefVar: public DefVarBase
00288 {
00289 T &var;
00290 T val;
00291 D domainChecker;
00292
00293 DefVar(bool switchOnly, string shortName, string longName,
00294 T &var, T val, WantArg wantArg, D d, string description):
00295 DefVarBase(switchOnly, shortName, longName, description, wantArg),
00296 var(var), val(val), domainChecker(d) {}
00297
00298 virtual ~DefVar() {}
00299
00300 void execute(Options *o, const char *arg) const throw(ParseException)
00301 {
00302 if(!arg)
00303 {
00304 var = val;
00305 return;
00306 }
00307
00308 T v = Parser<T>::parse(arg);
00309 domainChecker.check(v);
00310 var = v;
00311 }
00312
00313 virtual string getValue() const
00314 {
00315 return Parser<T>::format(var);
00316 }
00317
00318 virtual bool isDefaultSet() const
00319 {
00320 return var == val;
00321 }
00322 };
00323
00324 enum ArgType
00325 {
00326 argType_normal,
00327 argType_shortOption,
00328 argType_longOption
00329 };
00330
00331 ArgType examineArg(string);
00332
00333 private:
00334 bool treatNegativeNumbersAsOptions;
00335 Logger *logger;
00336 vector<const Def *> defs;
00337
00338 void verify(string shortName, string longName)
00339 throw(DefinitionException);
00340 };
00341 }
00342 }
00343
00344 #endif // ARCHON_UTILITIES_OPTIONS_H