options.H

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
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,    // Do not accept an option-argument.
00058         wantArg_optional, // Use option-argument if present.
00059         wantArg_always    // Require option-argument.
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;  // eg. --version
00255         string longName;   // eg. -v
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

Generated on Sun Jul 30 22:55:41 2006 for Archon by  doxygen 1.4.4