|
ORTS
|
00001 #ifndef Options_H 00002 #define Options_H 00003 00004 /** @file Options.H 00005 Command line options. 00006 00007 $Id: Options.H 5817 2007-09-12 23:59:14Z sorsten $ 00008 $Source$ 00009 */ 00010 00011 // This is an ORTS file (c) Michael Buro, licensed under the GPL 00012 00013 #include "Global.H" 00014 00015 //=================================================================== 00016 00017 /** Base class for command line option. */ 00018 class Opt { 00019 00020 public: 00021 00022 std::string remark; 00023 bool param; 00024 00025 /** Parse option value from string. 00026 @return true on error 00027 */ 00028 virtual bool from_string(const std::string &s) = 0; 00029 virtual std::string to_string() const = 0; 00030 virtual std::string get_type_name() const = 0; 00031 00032 Opt() : param(true) {} 00033 virtual ~Opt() {} 00034 }; 00035 00036 //=================================================================== 00037 00038 /** Command line option. */ 00039 template <class T> class OptT : public Opt 00040 { 00041 public: 00042 00043 T value; 00044 00045 OptT(T v) { value = v; } 00046 00047 std::string to_string() const; 00048 bool from_string(const std::string &s); 00049 std::string get_type_name() const; 00050 00051 static std::string type_name; 00052 }; 00053 00054 //=================================================================== 00055 00056 /** Command line option parser. */ 00057 class Options { 00058 00059 public: 00060 00061 typedef std::map<std::string, Opt*> OMap; 00062 typedef OMap::iterator OMapIt; 00063 typedef OMap::const_iterator OMapCIt; 00064 00065 protected: 00066 00067 static Vector<std::string> heading_name; 00068 static Vector<OMap> options; 00069 static OMap s_omap; 00070 00071 OMap *omap; 00072 00073 template <class T> struct Type { 00074 static std::string name; 00075 }; 00076 00077 public: 00078 00079 /** Add an option that takes a parameter. */ 00080 00081 template <class T> 00082 void put(const char *skey, T v, const char *remark=0) 00083 { 00084 std::string key(skey); 00085 OMapIt oit = s_omap.find(key); 00086 00087 if (oit == s_omap.end()) { 00088 00089 if (!remark) { 00090 errstr << "remark missing: " << skey << std::endl; 00091 ERR(""); 00092 } 00093 00094 // new entry 00095 OptT<T> *o = new OptT<T>(v); 00096 o->remark = std::string(remark); 00097 s_omap[key] = o; 00098 (*omap)[key] = o; 00099 return; 00100 } 00101 00102 // entry found, check type 00103 00104 OptT<T> *o = dynamic_cast<OptT<T>*>(oit->second); 00105 00106 if (!o) { 00107 errstr << "different type for option " << skey << " - " << remark << std::endl; 00108 abort(); exit(20); 00109 } 00110 00111 // when redefining skey, type and value have to match 00112 00113 if (remark && o->value != v) { 00114 OptT<T> temp(v); 00115 errstr << "different value for option " << skey << ": was " << o->to_string() << ", now: " << temp.to_string() << std::endl; 00116 abort(); exit(20); 00117 } 00118 00119 o->value = v; // overwrite 00120 } 00121 00122 //------------------------------------------------------------------- 00123 00124 /** Add a flag - does not take any parameters. */ 00125 00126 void put(const char *skey, const char *remark=0) 00127 { 00128 std::string key(skey); 00129 OMapIt oit = s_omap.find(key); 00130 00131 if (oit == s_omap.end()) { 00132 00133 if (!remark) { 00134 errstr << "remark missing: " << skey << std::endl; 00135 ERR(""); 00136 } 00137 00138 // new entry 00139 OptT<bool> *o = new OptT<bool>(false); 00140 o->remark = std::string(remark); 00141 s_omap[key] = o; 00142 (*omap)[key] = o; 00143 o->param = false; 00144 return; 00145 } 00146 00147 // entry found, check type 00148 00149 OptT<bool> *o = dynamic_cast<OptT<bool>*>(oit->second); 00150 00151 if (!o) { 00152 errstr << "different type for option " << skey << " - " << remark << std::endl; 00153 ERR(""); 00154 } 00155 00156 // when redefining skey, type and value have to match 00157 00158 if (remark && o->value != false) { 00159 errstr << "different value for option " << skey << ": was " << o->value << ", now: " << false << std::endl; 00160 ERR(""); 00161 } 00162 00163 o->value = false; // overwrite 00164 } 00165 00166 //------------------------------------------------------------------- 00167 00168 /** Get value of option. 00169 @param key Name of the option to extract. 00170 @param v Location to store the retrieved value. 00171 @param bReportErr 00172 If true, then function reports errors (ERR iff illegal). 00173 If false, the function returns true on errors. 00174 This is useful in cases where we would like to fail silently or 00175 report/handle the error in the calling code. 00176 */ 00177 template <class T> 00178 static bool get(const std::string &key, T &v, bool bReportErr = true) 00179 { 00180 OMapCIt oit = s_omap.find(key); 00181 00182 if (oit == s_omap.end()) { 00183 // not found 00184 if (bReportErr) { 00185 errstr << "option not found: " << key << std::endl; 00186 ERR(""); 00187 } 00188 return true; 00189 } 00190 00191 OptT<T> *o = dynamic_cast<OptT<T>*>(oit->second); 00192 if (!o) { 00193 // illegal type 00194 if (bReportErr) { 00195 errstr << "illegal value type for option " << key << ": expected " 00196 << oit->second->get_type_name() << ", got " << Type<T>::name << std::endl; 00197 ERR(""); 00198 } 00199 return true; 00200 } 00201 00202 v = o->value; 00203 return false; 00204 } 00205 00206 //------------------------------------------------------------------- 00207 00208 template <class T> 00209 static bool set(const std::string &key, T v, bool bReportErr = true) 00210 { 00211 OMapCIt oit = s_omap.find(key); 00212 00213 if (oit == s_omap.end()) { 00214 // not found 00215 if (bReportErr) { 00216 errstr << "option not found: " << key << std::endl; 00217 ERR(""); 00218 } 00219 return true; 00220 } 00221 00222 OptT<T> *o = dynamic_cast<OptT<T>*>(oit->second); 00223 if (!o) { 00224 // illegal type 00225 if (bReportErr) { 00226 errstr << "illegal value type for option " << key << ": expected " 00227 << oit->second->get_type_name() << ", got " << Type<T>::name << std::endl; 00228 ERR(""); 00229 } 00230 return true; 00231 } 00232 00233 o->value = v; 00234 return false; 00235 } 00236 00237 // write options to stream 00238 static void write(std::ostream &os); 00239 00240 // clears all options 00241 static void reset(); 00242 00243 // @return false iff OK 00244 static bool process(sint4 argc, char **argv, std::ostream &oserr, const char *remark=0); 00245 // return non-options in rest (useful for mandatory parameters) 00246 static bool process2(sint4 argc, char **argv, std::ostream &oserr, Vector<std::string> &rest); 00247 static bool process(const std::string& args , std::ostream &oserr, const char *remark); 00248 00249 Options(std::string heading=""); 00250 virtual ~Options(); 00251 00252 private: 00253 00254 // prevent copying and assigning (not implemented yet) 00255 Options(const Options &) {} 00256 // Options &operator=(const Options &) {} 00257 }; 00258 00259 //=================================================================== 00260 00261 REGISTER_TYPEOF(20, Options::OMap::iterator); 00262 REGISTER_TYPEOF(21, Options::OMap::const_iterator); 00263 REGISTER_TYPEOF(22, Vector<Options::OMap>::iterator); 00264 REGISTER_TYPEOF(23, Vector<Options::OMap>::const_iterator); 00265 00266 #endif