| 1 | /* $Id$ $URL$ */ |
|---|
| 2 | #include "rconfig.h" |
|---|
| 3 | |
|---|
| 4 | #ifdef HAVE_BOOST |
|---|
| 5 | #include <boost/regex.hpp> |
|---|
| 6 | #include <boost/algorithm/string/trim.hpp> |
|---|
| 7 | #else |
|---|
| 8 | #include "rxstring/rxstring.h" |
|---|
| 9 | #endif |
|---|
| 10 | |
|---|
| 11 | /**\file rconfig.cpp |
|---|
| 12 | * Implementation of the Readable Configuration parser, and location of |
|---|
| 13 | * the configuration variable definitions (RConfig). This should be reusable, the |
|---|
| 14 | * parser is pretty simple -- just using a few regular expressions to match |
|---|
| 15 | * each line. |
|---|
| 16 | * \author Trent Apted <tapted@it.usyd.edu.au> |
|---|
| 17 | * $Revision$ |
|---|
| 18 | * $Date$ |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | #include <fstream> |
|---|
| 22 | #include <map> |
|---|
| 23 | |
|---|
| 24 | //#include <SDL.h> |
|---|
| 25 | #include <iostream> |
|---|
| 26 | #include <iomanip> |
|---|
| 27 | #include <sstream> |
|---|
| 28 | |
|---|
| 29 | #ifndef __GCC_ABI_VERSION |
|---|
| 30 | /** NDEMANGLE is defined if we can't demangle staff */ |
|---|
| 31 | #define NDEMANGLE |
|---|
| 32 | #endif |
|---|
| 33 | |
|---|
| 34 | #undef NDEMANGLE |
|---|
| 35 | |
|---|
| 36 | #ifndef NDEMANGLE |
|---|
| 37 | #include <cxxabi.h> |
|---|
| 38 | #endif |
|---|
| 39 | |
|---|
| 40 | /** Environment variable, provided by the OS */ |
|---|
| 41 | #ifdef __APPLE__ |
|---|
| 42 | #include <crt_externs.h> |
|---|
| 43 | #define environ (*_NSGetEnviron()) |
|---|
| 44 | #else |
|---|
| 45 | extern char** environ; |
|---|
| 46 | #endif |
|---|
| 47 | |
|---|
| 48 | namespace { |
|---|
| 49 | |
|---|
| 50 | #ifdef HAVE_BOOST |
|---|
| 51 | typedef boost::regex MyRegex; |
|---|
| 52 | typedef boost::smatch MyMatch; |
|---|
| 53 | typedef std::string RxString; |
|---|
| 54 | inline bool mymatch(const RxString& s, MyRegex& r, MyMatch& m) { |
|---|
| 55 | return regex_match(s, m, r); |
|---|
| 56 | } |
|---|
| 57 | inline void mytrim(RxString &s) { |
|---|
| 58 | boost::algorithm::trim(s); |
|---|
| 59 | } |
|---|
| 60 | #else |
|---|
| 61 | typedef RxString::Regex MyRegex; |
|---|
| 62 | typedef RxString::match_vec_type MyMatch; |
|---|
| 63 | inline bool mymatch(const RxString& s, MyRegex& r, MyMatch& m) { |
|---|
| 64 | return s.match(r, &m); |
|---|
| 65 | } |
|---|
| 66 | inline void mytrim(RxString &s) { |
|---|
| 67 | s.trim(); |
|---|
| 68 | } |
|---|
| 69 | #endif |
|---|
| 70 | |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | RCParser::RCParser(int aargc, char** aargv, char** eenvv) : |
|---|
| 74 | argc(aargc), argv(aargv), envv(eenvv ? eenvv : environ) |
|---|
| 75 | { |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | int RCParser::getArgc() const { |
|---|
| 79 | return argc; |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | char* const * RCParser::getArgv() const { |
|---|
| 83 | return argv; |
|---|
| 84 | } |
|---|
| 85 | |
|---|
| 86 | char* const * RCParser::getEnvv() const { |
|---|
| 87 | return envv; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | namespace RConfig { |
|---|
| 91 | |
|---|
| 92 | /** Demangle a type id name */ |
|---|
| 93 | const char* demangle (const char* typeid_name) { |
|---|
| 94 | #ifdef NDEMANGLE |
|---|
| 95 | return typeid_name; |
|---|
| 96 | #else |
|---|
| 97 | static char buf[1024]; |
|---|
| 98 | int status; |
|---|
| 99 | char *demangled = abi::__cxa_demangle(typeid_name, 0, 0, &status); |
|---|
| 100 | strncpy(buf, demangled, 1024); |
|---|
| 101 | free(demangled); |
|---|
| 102 | return buf; |
|---|
| 103 | #endif |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | /** Call demangle() after getting the typeid for a variable */ |
|---|
| 107 | #define DEMANGLE(_var) (demangle(typeid(_var).name())) |
|---|
| 108 | |
|---|
| 109 | class VarReader; |
|---|
| 110 | |
|---|
| 111 | namespace { |
|---|
| 112 | const bool IDEBUG = true; ///< Enable debugging |
|---|
| 113 | std::string *mrcfilename = 0; ///< Sentinel filename (default?) |
|---|
| 114 | typedef std::map<std::string, VarReader*> VARMAP; ///<Type for variable lookup table |
|---|
| 115 | VARMAP *varmap = 0; ///< Variable lookup table |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | /** |
|---|
| 119 | * A class for reading variables from a file. |
|---|
| 120 | */ |
|---|
| 121 | class VarReader { |
|---|
| 122 | protected: |
|---|
| 123 | const std::string name; ///< Name of the variable |
|---|
| 124 | public: |
|---|
| 125 | /** Create a var reader looking for things with \a nname */ |
|---|
| 126 | VarReader(const std::string nname) : name (nname) {} |
|---|
| 127 | /** Read in the variable from the string encountered in the config file */ |
|---|
| 128 | virtual bool readin(const RxString &val) = 0; |
|---|
| 129 | virtual bool readout(RxString &val) = 0; |
|---|
| 130 | /** Virtual destructor -- does nothing */ |
|---|
| 131 | virtual ~VarReader() {} |
|---|
| 132 | }; |
|---|
| 133 | |
|---|
| 134 | /** |
|---|
| 135 | * Template class that uses RxString::converTo for reading variables |
|---|
| 136 | */ |
|---|
| 137 | template <class T> |
|---|
| 138 | class VarReaderT : public VarReader { |
|---|
| 139 | protected: |
|---|
| 140 | const char* override; ///< Message to print if/when we override \a ref |
|---|
| 141 | T &ref; ///< Where to write the variable |
|---|
| 142 | public: |
|---|
| 143 | /** Create a templatized VarReader, reading into \a rref */ |
|---|
| 144 | VarReaderT (T &rref, const std::string& nname, const char* ooverride = "Overriding default"); |
|---|
| 145 | virtual bool readin(const RxString &val); |
|---|
| 146 | virtual bool readout(RxString &val); |
|---|
| 147 | }; |
|---|
| 148 | |
|---|
| 149 | /** |
|---|
| 150 | * Instantiate a VarReader based on the variable type |
|---|
| 151 | */ |
|---|
| 152 | template <class T> |
|---|
| 153 | VarReader* make_varreader(T &ref, const std::string &name) { |
|---|
| 154 | return new VarReaderT<T>(ref, name); |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | /** |
|---|
| 158 | * A VarReader for reading in collection configuration variables, |
|---|
| 159 | * defers each instance to the regular VarReader |
|---|
| 160 | */ |
|---|
| 161 | template <class T> |
|---|
| 162 | class VarReaderV : public VarReader { |
|---|
| 163 | protected: |
|---|
| 164 | std::vector<T> &ref; ///< The vector reference |
|---|
| 165 | T temp; ///< tempory var, into which we read before pushing back |
|---|
| 166 | VarReader *vr; ///< The reader for each element |
|---|
| 167 | public: |
|---|
| 168 | /** Create a vectorized var reader for \a rref */ |
|---|
| 169 | VarReaderV (std::vector<T> &rref, const std::string& nname); |
|---|
| 170 | /** Virtual destructor -- deletes \a vr */ |
|---|
| 171 | virtual ~VarReaderV() {delete vr;} |
|---|
| 172 | virtual bool readin(const RxString &val); |
|---|
| 173 | virtual bool readout(RxString &val); |
|---|
| 174 | }; |
|---|
| 175 | |
|---|
| 176 | /** |
|---|
| 177 | * Instantiate a VarReaderV based on a vector value type |
|---|
| 178 | */ |
|---|
| 179 | template <class T> |
|---|
| 180 | VarReader* make_varreaderv(std::vector<T> &ref, const std::string &name) { |
|---|
| 181 | std::string localname(name); |
|---|
| 182 | return new VarReaderV<T>(ref, localname); |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | /** Add a VarReaderT to the map of variables we want to look for */ |
|---|
| 186 | template <class T> |
|---|
| 187 | static void addvar(const char* cname, T& var, const char* context) { |
|---|
| 188 | std::string name(cname); |
|---|
| 189 | if (IDEBUG) { |
|---|
| 190 | std::cerr.setf(std::ios_base::left, std::ios_base::adjustfield); |
|---|
| 191 | std::cerr |
|---|
| 192 | << "(cfg) " << std::setw(15) << DEMANGLE(T) |
|---|
| 193 | << ' ' << std::setw(30) << name |
|---|
| 194 | << " = " << std::setw(20) << var; |
|---|
| 195 | if (context) |
|---|
| 196 | std::cerr << " (" << context << ")"; |
|---|
| 197 | std::cerr << std::endl; |
|---|
| 198 | |
|---|
| 199 | } |
|---|
| 200 | varmap->insert(VARMAP::value_type(name, make_varreader(var, name))); |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | template <class T> |
|---|
| 204 | static void addvar_uninitialised(const char* cname, T& var, const char* initval, const char* context) { |
|---|
| 205 | std::string name(cname); |
|---|
| 206 | if (IDEBUG) { |
|---|
| 207 | std::cerr.setf(std::ios_base::left, std::ios_base::adjustfield); |
|---|
| 208 | std::cerr |
|---|
| 209 | << "(cfg) " << std::setw(15) << DEMANGLE(T) |
|---|
| 210 | << ' ' << std::setw(30) << name |
|---|
| 211 | << " = " << std::setw(20) << initval; |
|---|
| 212 | if (context) |
|---|
| 213 | std::cerr << " (" << context << ")"; |
|---|
| 214 | std::cerr << std::endl; |
|---|
| 215 | |
|---|
| 216 | } |
|---|
| 217 | varmap->insert(VARMAP::value_type(name, make_varreader(var, name))); |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | /** Add a VarReaderV to the map of variables we want to look for */ |
|---|
| 221 | template <class T> |
|---|
| 222 | static void addvecvar(const char* cname, std::vector<T>& var, const char* context) { |
|---|
| 223 | std::string name(cname); |
|---|
| 224 | if (IDEBUG) { |
|---|
| 225 | std::cerr.setf(std::ios_base::left, std::ios_base::adjustfield); |
|---|
| 226 | std::cerr |
|---|
| 227 | << "(cfg) " << std::setw(15) << DEMANGLE(T) |
|---|
| 228 | << ' ' << std::setw(30) << name |
|---|
| 229 | << " = <vector>"; |
|---|
| 230 | if (context) |
|---|
| 231 | std::cerr << " (" << context << ")"; |
|---|
| 232 | std::cerr << std::endl; |
|---|
| 233 | } |
|---|
| 234 | varmap->insert(VARMAP::value_type(cname, make_varreaderv(var, name))); |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | /** Insert a variable reader for \a varname into the variable lookup table, |
|---|
| 238 | * where the configuration name is identical to the variable. |
|---|
| 239 | */ |
|---|
| 240 | #define WILLPARSE(varname) addvar( #varname , varname, "legacy rconfig.cpp" ) |
|---|
| 241 | |
|---|
| 242 | /** Insert a variable reader for \a varname that appears in the config |
|---|
| 243 | * file as \a match |
|---|
| 244 | */ |
|---|
| 245 | #define WILLPARSEN(varname, match) addvar( match , varname, "legacy rconfig.cpp" ) |
|---|
| 246 | |
|---|
| 247 | /** Insert a vector variable reader for \a varname that appears in the |
|---|
| 248 | * config file as \a match |
|---|
| 249 | */ |
|---|
| 250 | #define WILLPARSEV(varname, match) addvecvar( match , varname, "legacy rconfig.cpp" ) |
|---|
| 251 | |
|---|
| 252 | /** |
|---|
| 253 | * Initialise the variable lookup table |
|---|
| 254 | */ |
|---|
| 255 | int rcfile_init() { |
|---|
| 256 | varmap = new VARMAP(); |
|---|
| 257 | mrcfilename = new std::string("rcfile"); |
|---|
| 258 | return varmap->size(); |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | /** Cleanup thunks */ |
|---|
| 262 | void rcfile_cleanup() { |
|---|
| 263 | if (!varmap) |
|---|
| 264 | return; |
|---|
| 265 | const VARMAP::iterator e = varmap->end(); |
|---|
| 266 | for (VARMAP::iterator it = varmap->begin(); it != e ; ++it) |
|---|
| 267 | delete it->second; |
|---|
| 268 | delete varmap; |
|---|
| 269 | varmap = 0; |
|---|
| 270 | delete mrcfilename; |
|---|
| 271 | mrcfilename = 0; |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | int Init::count = 0; |
|---|
| 275 | Init::Init() { |
|---|
| 276 | if (count++ == 0) { |
|---|
| 277 | rcfile_init(); |
|---|
| 278 | } |
|---|
| 279 | } |
|---|
| 280 | Init::~Init() { |
|---|
| 281 | if (--count == 0) { |
|---|
| 282 | rcfile_cleanup(); |
|---|
| 283 | } |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | void rcfile_tell(const char* name, bool &ref, const char* context) { |
|---|
| 287 | addvar(name, ref, context); |
|---|
| 288 | } |
|---|
| 289 | void rcfile_tell(const char* name, int &ref, const char* context) { |
|---|
| 290 | addvar(name, ref, context); |
|---|
| 291 | } |
|---|
| 292 | void rcfile_tell(const char* name, float &ref, const char* context) { |
|---|
| 293 | addvar(name, ref, context); |
|---|
| 294 | } |
|---|
| 295 | void rcfile_tell(const char* name, double &ref, const char* context) { |
|---|
| 296 | addvar(name, ref, context); |
|---|
| 297 | } |
|---|
| 298 | void rcfile_tell(const char* name, unsigned &ref, const char* context) { |
|---|
| 299 | addvar(name, ref, context); |
|---|
| 300 | } |
|---|
| 301 | void rcfile_tell(const char* name, std::string &ref, const char* context) { |
|---|
| 302 | addvar(name, ref, context); |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | void rcfile_tellstr(const char* name, std::string &ref, const char* defval, const char* context) { |
|---|
| 306 | addvar_uninitialised(name, ref, defval, context); |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | /* |
|---|
| 310 | void rcfile_tell(const char* name, std::vector<bool> &ref) { |
|---|
| 311 | addvecvar(name, ref); |
|---|
| 312 | }*/ |
|---|
| 313 | void rcfile_tell(const char* name, std::vector<int> &ref, const char* context) { |
|---|
| 314 | addvecvar(name, ref, context); |
|---|
| 315 | } |
|---|
| 316 | void rcfile_tell(const char* name, std::vector<float> &ref, const char* context) { |
|---|
| 317 | addvecvar(name, ref, context); |
|---|
| 318 | } |
|---|
| 319 | void rcfile_tell(const char* name, std::vector<double> &ref, const char* context) { |
|---|
| 320 | addvecvar(name, ref, context); |
|---|
| 321 | } |
|---|
| 322 | void rcfile_tell(const char* name, std::vector<unsigned> &ref, const char* context) { |
|---|
| 323 | addvecvar(name, ref, context); |
|---|
| 324 | } |
|---|
| 325 | void rcfile_tell(const char* name, std::vector<std::string> &ref, const char* context) { |
|---|
| 326 | addvecvar(name, ref, context); |
|---|
| 327 | } |
|---|
| 328 | |
|---|
| 329 | /** Suck out a quoted string from \a str */ |
|---|
| 330 | static RxString getquote(const RxString &str) { |
|---|
| 331 | size_t i; |
|---|
| 332 | bool bs = false; |
|---|
| 333 | RxString ret; |
|---|
| 334 | for (i = 0; i < str.size() && str[i] != '"'; ++i) |
|---|
| 335 | ; |
|---|
| 336 | for (i = i + 1; i < str.size() && (bs || str[i] != '"'); ++i) { |
|---|
| 337 | if (bs) |
|---|
| 338 | ret += '\\'; |
|---|
| 339 | bs = str[i] == '\\'; |
|---|
| 340 | if (!bs) |
|---|
| 341 | ret += str[i]; |
|---|
| 342 | } |
|---|
| 343 | return ret; |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | namespace { |
|---|
| 347 | /** Parse a single line from the RCFile */ |
|---|
| 348 | bool rcfile_xparseline(const RxString& line, bool suppress_unknown = false) { |
|---|
| 349 | static MyRegex line_regex("^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=[[:space:]]*(.*)"); |
|---|
| 350 | static MyRegex comment_regex("[^#]+"); |
|---|
| 351 | MyMatch matches; |
|---|
| 352 | MyMatch rhs; |
|---|
| 353 | if (mymatch(line, line_regex, matches)) { |
|---|
| 354 | RxString val = matches[2]; |
|---|
| 355 | RxString key = matches[1]; |
|---|
| 356 | mytrim(val); |
|---|
| 357 | if (val[0] == '"') { |
|---|
| 358 | val = getquote(val); |
|---|
| 359 | } else if (mymatch(val, comment_regex, rhs)) { |
|---|
| 360 | val = rhs[0]; |
|---|
| 361 | } else { |
|---|
| 362 | return false; |
|---|
| 363 | } |
|---|
| 364 | VARMAP::iterator it = varmap->find(key.c_str()); |
|---|
| 365 | if (it != varmap->end()) { |
|---|
| 366 | it->second->readin(val); |
|---|
| 367 | return true; |
|---|
| 368 | } else if (!suppress_unknown) { |
|---|
| 369 | fprintf(stderr, "Unknown CFG param: %s\n", key.c_str()); |
|---|
| 370 | } |
|---|
| 371 | } |
|---|
| 372 | return false; |
|---|
| 373 | } |
|---|
| 374 | } |
|---|
| 375 | |
|---|
| 376 | |
|---|
| 377 | void rcfile_getnames(std::vector<std::string> & names) { |
|---|
| 378 | VARMAP::const_iterator it = varmap->begin(); |
|---|
| 379 | const VARMAP::const_iterator end = varmap->end(); |
|---|
| 380 | for (; it != end; ++it) |
|---|
| 381 | names.push_back(it->first); |
|---|
| 382 | } |
|---|
| 383 | |
|---|
| 384 | bool rcfile_parseline(const std::string& line) { |
|---|
| 385 | return rcfile_xparseline(line); |
|---|
| 386 | } |
|---|
| 387 | |
|---|
| 388 | bool rcfile_getvalue(std::string& val, const std::string& name) { |
|---|
| 389 | VARMAP::const_iterator it = varmap->find(name); |
|---|
| 390 | if (it != varmap->end()) |
|---|
| 391 | return it->second->readout(val); |
|---|
| 392 | return false; |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | int rcfile_parse(const char* file) { |
|---|
| 396 | *mrcfilename = file; |
|---|
| 397 | unsigned ctr = 0; |
|---|
| 398 | std::ifstream in(file); |
|---|
| 399 | if (in) { |
|---|
| 400 | while (in) { |
|---|
| 401 | RxString line; |
|---|
| 402 | getline(in, line); |
|---|
| 403 | if (rcfile_xparseline(line/*, varmap*/)) |
|---|
| 404 | ctr++; |
|---|
| 405 | } |
|---|
| 406 | } else { |
|---|
| 407 | fprintf(stderr, "Couldn't open %s for reading\n", file); |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | ctr = 0; |
|---|
| 411 | if (environ) { |
|---|
| 412 | for (char** envarg = environ; *envarg; ++envarg) |
|---|
| 413 | if (rcfile_xparseline(*envarg, true)) |
|---|
| 414 | ctr++; |
|---|
| 415 | } |
|---|
| 416 | return 0; |
|---|
| 417 | } |
|---|
| 418 | |
|---|
| 419 | template <class T> |
|---|
| 420 | VarReaderT<T>::VarReaderT (T &rref, const std::string& nname, const char* ooverride) |
|---|
| 421 | : |
|---|
| 422 | VarReader(nname), override(ooverride), ref (rref) { |
|---|
| 423 | } |
|---|
| 424 | |
|---|
| 425 | template <class T> |
|---|
| 426 | bool VarReaderT<T>::readin(const RxString &val) { |
|---|
| 427 | std::istringstream iss(val); |
|---|
| 428 | if (!(iss >> ref)) { |
|---|
| 429 | fprintf(stderr, "Bad format in %s for %s (%s)\n", mrcfilename->c_str(), name.c_str(), val.c_str()); |
|---|
| 430 | return false; |
|---|
| 431 | } else { |
|---|
| 432 | fprintf(stderr, "%s %s to %s\n", override, name.c_str(), val.c_str()); |
|---|
| 433 | } |
|---|
| 434 | return true; |
|---|
| 435 | } |
|---|
| 436 | |
|---|
| 437 | template <class T> |
|---|
| 438 | bool VarReaderT<T>::readout(RxString &val) { |
|---|
| 439 | std::ostringstream oss; |
|---|
| 440 | if (oss << ref) { |
|---|
| 441 | val = oss.str(); |
|---|
| 442 | } |
|---|
| 443 | return oss; |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | template <> |
|---|
| 447 | bool VarReaderT<std::string>::readin(const RxString &val) { |
|---|
| 448 | fprintf(stderr, "%s %s to %s\n", override, name.c_str(), val.c_str()); |
|---|
| 449 | ref = val; |
|---|
| 450 | return true; |
|---|
| 451 | } |
|---|
| 452 | |
|---|
| 453 | template <> |
|---|
| 454 | bool VarReaderT<std::string>::readout(RxString &val) { |
|---|
| 455 | val = "\""; |
|---|
| 456 | val += ref; |
|---|
| 457 | val += "\""; |
|---|
| 458 | return true; |
|---|
| 459 | } |
|---|
| 460 | |
|---|
| 461 | template <class T> |
|---|
| 462 | VarReaderV<T>::VarReaderV (std::vector<T> &rref, const std::string& nname) |
|---|
| 463 | : |
|---|
| 464 | VarReader(nname), ref(rref), vr(new VarReaderT<T>(temp, nname + "[i]", "Adding another")) |
|---|
| 465 | { |
|---|
| 466 | |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | template <class T> |
|---|
| 470 | bool VarReaderV<T>::readin(const RxString &val) { |
|---|
| 471 | if (vr->readin(val)) { |
|---|
| 472 | ref.push_back(temp); |
|---|
| 473 | return true; |
|---|
| 474 | } |
|---|
| 475 | return false; |
|---|
| 476 | } |
|---|
| 477 | |
|---|
| 478 | template <class T> |
|---|
| 479 | bool VarReaderV<T>::readout(RxString &val) { |
|---|
| 480 | val = "<vector>"; |
|---|
| 481 | return true; |
|---|
| 482 | } |
|---|
| 483 | |
|---|
| 484 | /** |
|---|
| 485 | * Template specialisation for strings (no formatting) |
|---|
| 486 | */ |
|---|
| 487 | /* |
|---|
| 488 | template<> |
|---|
| 489 | class VarReaderT<std::string> : public VarReader { |
|---|
| 490 | protected: |
|---|
| 491 | const char* override; |
|---|
| 492 | std::string &ref; |
|---|
| 493 | public: |
|---|
| 494 | VarReaderT (std::string &rref, const std::string& nname, const char* ooverride = "Overriding default") |
|---|
| 495 | : |
|---|
| 496 | VarReader(nname), override(ooverride), ref(rref) {} |
|---|
| 497 | virtual bool readin(const RxString &val) { |
|---|
| 498 | fprintf(stderr, "%s %s to %s\n", override, name.c_str(), val.c_str()); |
|---|
| 499 | ref = val; |
|---|
| 500 | return true; |
|---|
| 501 | } |
|---|
| 502 | }; |
|---|
| 503 | */ |
|---|
| 504 | |
|---|
| 505 | |
|---|
| 506 | #ifdef OLDCRUD |
|---|
| 507 | |
|---|
| 508 | /** Parse a primitive type into \a varname */ |
|---|
| 509 | #define PARSE_PRIMITIVE(varname) else if (strcmp(matches[1].c_str(), #varname) == 0) { \ |
|---|
| 510 | if(!val.convertTo(varname)) { \ |
|---|
| 511 | fprintf(stderr, "Bad format in %s for %s (%s)\n", file, #varname, val.c_str()); \ |
|---|
| 512 | } else { \ |
|---|
| 513 | fprintf(stderr, "Overriding default %s to %s\n", #varname, val.c_str()); \ |
|---|
| 514 | } \ |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | /** Parse a string into \a varname */ |
|---|
| 518 | #define PARSE_STRING(varname) else if (strcmp(matches[1].c_str(), #varname) == 0) { \ |
|---|
| 519 | fprintf(stderr, "Overriding default %s to %s\n", #varname, val.c_str()); \ |
|---|
| 520 | varname = val; \ |
|---|
| 521 | } |
|---|
| 522 | |
|---|
| 523 | |
|---|
| 524 | /** The old rcfile reader with quadratic scalability */ |
|---|
| 525 | static int oldrcfile_parse(const char* file) { /*FOLD00*/ |
|---|
| 526 | *mrcfilename = file; |
|---|
| 527 | rcfile_init(); |
|---|
| 528 | std::ifstream in(file); |
|---|
| 529 | if (!in) { |
|---|
| 530 | fprintf(stderr, "Couldn't open %s for reading\n", file); |
|---|
| 531 | return 1; |
|---|
| 532 | } |
|---|
| 533 | //in.setf(std::ios_base::boolalpha); //doesn't work... |
|---|
| 534 | while (in) { |
|---|
| 535 | RxString line; |
|---|
| 536 | RxString::match_vec_type matches; |
|---|
| 537 | line.append_line(in); |
|---|
| 538 | if (line.match("^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=[[:space:]]*(.*)", |
|---|
| 539 | &matches)) { |
|---|
| 540 | RxString::match_vec_type rhs; |
|---|
| 541 | RxString val; |
|---|
| 542 | matches[2].trim(); |
|---|
| 543 | if (matches[2][0] == '"') { |
|---|
| 544 | val = getquote(matches[2]); |
|---|
| 545 | } else if (matches[2].match("[^#]+", &rhs)) { |
|---|
| 546 | val = rhs[0]; |
|---|
| 547 | } else { |
|---|
| 548 | continue; |
|---|
| 549 | } |
|---|
| 550 | if (false) { |
|---|
| 551 | } |
|---|
| 552 | /* BEGIN: This is where you put all the variables to look for */ |
|---|
| 553 | PARSE_PRIMITIVE(DEPTH_DELTA) |
|---|
| 554 | PARSE_PRIMITIVE(IMAGE_TRANSPARENCY) |
|---|
| 555 | PARSE_PRIMITIVE(CORNER_PROP) |
|---|
| 556 | PARSE_PRIMITIVE(TRY_FULLSCREEN) |
|---|
| 557 | PARSE_PRIMITIVE(DEFAULT_WRITE_DWELL) |
|---|
| 558 | PARSE_PRIMITIVE(TARGET_SCREEN_WIDTH) |
|---|
| 559 | PARSE_PRIMITIVE(TARGET_SCREEN_HEIGHT) |
|---|
| 560 | PARSE_PRIMITIVE(TARGET_SCREEN_BPP) |
|---|
| 561 | PARSE_PRIMITIVE(SCREEN_NUM_USERS) |
|---|
| 562 | PARSE_PRIMITIVE(TARGET_ANISOTROPIC) |
|---|
| 563 | PARSE_PRIMITIVE(TARGET_FSAA) |
|---|
| 564 | PARSE_PRIMITIVE(RENDER_NICEST) |
|---|
| 565 | PARSE_PRIMITIVE(COPY_SEPARATION_SQ) |
|---|
| 566 | PARSE_PRIMITIVE(DWELL_AREA_SQ) |
|---|
| 567 | PARSE_PRIMITIVE(JUMP_DISTANCE_SQ) |
|---|
| 568 | PARSE_PRIMITIVE(IGNORE_JUMPS) |
|---|
| 569 | PARSE_PRIMITIVE(MENU_DWELL_TIME) |
|---|
| 570 | PARSE_PRIMITIVE(COPY_GESTURE) |
|---|
| 571 | PARSE_PRIMITIVE(MOUSE_DEBUG) |
|---|
| 572 | PARSE_PRIMITIVE(MIN_REDRAW) |
|---|
| 573 | PARSE_PRIMITIVE(SHOW_FPS) |
|---|
| 574 | PARSE_PRIMITIVE(SHOW_EPS) |
|---|
| 575 | PARSE_PRIMITIVE(SHOW_NUMIMAGES) |
|---|
| 576 | PARSE_PRIMITIVE(SHOW_TIMESINCE) |
|---|
| 577 | PARSE_PRIMITIVE(SHOW_MEM) |
|---|
| 578 | PARSE_PRIMITIVE(SHOW_ANIM) |
|---|
| 579 | PARSE_PRIMITIVE(HIDE_CURSOR) |
|---|
| 580 | PARSE_PRIMITIVE(ANIMATIONS) |
|---|
| 581 | PARSE_PRIMITIVE(ANIMATION_LOAD_TIME) |
|---|
| 582 | PARSE_PRIMITIVE(WORMHOLE_MAX) |
|---|
| 583 | PARSE_PRIMITIVE(MIN_SCALE_FOR_DRAW) |
|---|
| 584 | PARSE_PRIMITIVE(FIELD_OF_VIEW_Y) |
|---|
| 585 | PARSE_PRIMITIVE(HARD_TEXTURE_LIMIT) |
|---|
| 586 | PARSE_PRIMITIVE(CAPTURE_FRAME) |
|---|
| 587 | PARSE_PRIMITIVE(ANOTO_FRAME) |
|---|
| 588 | PARSE_PRIMITIVE(JPEG_QUALITY) |
|---|
| 589 | PARSE_PRIMITIVE(ALWAYS_UPSCALE) |
|---|
| 590 | PARSE_PRIMITIVE(SINCELOCK_MAX) |
|---|
| 591 | PARSE_PRIMITIVE(SWANKY_BLACKHOLE) |
|---|
| 592 | PARSE_PRIMITIVE(CLEARSCREEN_BUG) |
|---|
| 593 | PARSE_PRIMITIVE(MANUAL_ASPECT) |
|---|
| 594 | |
|---|
| 595 | PARSE_PRIMITIVE(DO_MOMENTUM) |
|---|
| 596 | PARSE_PRIMITIVE(DEFAULT_COEFF) |
|---|
| 597 | PARSE_PRIMITIVE(GRAVITY) |
|---|
| 598 | PARSE_PRIMITIVE(VELOCITY_WINDOW) |
|---|
| 599 | PARSE_PRIMITIVE(ESCAPE_VELOCITY) |
|---|
| 600 | PARSE_PRIMITIVE(BLACKHOLE_TRAPDIST) |
|---|
| 601 | PARSE_PRIMITIVE(BLACKHOLE_ACCEL) |
|---|
| 602 | PARSE_PRIMITIVE(FLIPPER_THRESHOLD) |
|---|
| 603 | PARSE_PRIMITIVE(TEST_FLIPPING) |
|---|
| 604 | |
|---|
| 605 | PARSE_PRIMITIVE(SOCKET_ENABLED) |
|---|
| 606 | PARSE_PRIMITIVE(LISTEN_TIMEOUTMS) |
|---|
| 607 | PARSE_PRIMITIVE(IMAGE_SERVER_PORT) |
|---|
| 608 | PARSE_PRIMITIVE(COMMAND_SERVER_PORT) |
|---|
| 609 | PARSE_PRIMITIVE(DATAWALL_PORT) |
|---|
| 610 | PARSE_PRIMITIVE(MAGICMIRROR_PORT) |
|---|
| 611 | PARSE_PRIMITIVE(MAGICMIRROR_SEND) |
|---|
| 612 | PARSE_PRIMITIVE(AUDIOBOX_PORT) |
|---|
| 613 | PARSE_PRIMITIVE(ENABLE_AUDIOBOX) |
|---|
| 614 | PARSE_PRIMITIVE(LMB_ONLY) |
|---|
| 615 | PARSE_PRIMITIVE(SAVE_VIDEO) |
|---|
| 616 | PARSE_PRIMITIVE(MENU_SYSTEM) |
|---|
| 617 | |
|---|
| 618 | PARSE_PRIMITIVE(MENU_RADIUS) |
|---|
| 619 | PARSE_PRIMITIVE(WRITING_WIDTH) |
|---|
| 620 | PARSE_PRIMITIVE(WRITING_PWIDTH) |
|---|
| 621 | PARSE_PRIMITIVE(STIPPLE_WRITING) |
|---|
| 622 | PARSE_PRIMITIVE(DO_WRITING) |
|---|
| 623 | PARSE_PRIMITIVE(FLIP_WIDGETS) |
|---|
| 624 | |
|---|
| 625 | PARSE_PRIMITIVE(LOAD_X) |
|---|
| 626 | PARSE_PRIMITIVE(LOAD_Y) |
|---|
| 627 | PARSE_PRIMITIVE(LOAD_Z) |
|---|
| 628 | PARSE_PRIMITIVE(LOAD_STARTSCALE) |
|---|
| 629 | PARSE_PRIMITIVE(LOAD_FULLSCALE) |
|---|
| 630 | PARSE_PRIMITIVE(DATAWALL) |
|---|
| 631 | PARSE_PRIMITIVE(STEREO) |
|---|
| 632 | PARSE_PRIMITIVE(CAMERA_FACTOR) |
|---|
| 633 | PARSE_PRIMITIVE(DATAWALL_SEND) |
|---|
| 634 | PARSE_PRIMITIVE(STEREO_IOD) |
|---|
| 635 | PARSE_PRIMITIVE(FUSION_DISTANCE) |
|---|
| 636 | PARSE_PRIMITIVE(AUDIO_TRACKS) |
|---|
| 637 | PARSE_PRIMITIVE(X700_SELECT_BUG) |
|---|
| 638 | PARSE_PRIMITIVE(ENVMENU_DWELLRANGE) |
|---|
| 639 | PARSE_PRIMITIVE(BH_DELETE_SPEED) |
|---|
| 640 | PARSE_PRIMITIVE(PERSONAL_SPACE_COPY) |
|---|
| 641 | PARSE_PRIMITIVE(PSCOPY_RESIST_DIST) |
|---|
| 642 | PARSE_PRIMITIVE(CIRCLE_SCALE) |
|---|
| 643 | PARSE_PRIMITIVE(CIRCLE_SEGMENTS) |
|---|
| 644 | PARSE_PRIMITIVE(AUDIO_CIRCLES) |
|---|
| 645 | PARSE_PRIMITIVE(BLACK_SCREEN) |
|---|
| 646 | |
|---|
| 647 | |
|---|
| 648 | /* This is how you'd do a string variable */ |
|---|
| 649 | PARSE_STRING(INITIAL_IMAGE_DIRECTORY) |
|---|
| 650 | PARSE_STRING(BLACKHOLE_FILE) |
|---|
| 651 | PARSE_STRING(FRAME_FILE) |
|---|
| 652 | PARSE_STRING(ANOTOFRAME_FILE) |
|---|
| 653 | PARSE_STRING(AUDIOBOX_SERVER) |
|---|
| 654 | PARSE_STRING(DATAWALL_SERVER) |
|---|
| 655 | PARSE_STRING(MAGICMIRROR_SERVER) |
|---|
| 656 | PARSE_STRING(FRAME_SOUNDFILE) |
|---|
| 657 | PARSE_STRING(RECORD_SOUNDFILE) |
|---|
| 658 | |
|---|
| 659 | /* This is how you'd do a collection variable */ |
|---|
| 660 | else if (matches[1] == "FILE") { |
|---|
| 661 | INITIAL_FILES.push_back(val); |
|---|
| 662 | } else if (matches[1] == "RFB_HOST") { |
|---|
| 663 | REMOTE_FRAMEBUFFERS.push_back(val); |
|---|
| 664 | } else if (matches[1] == "RFB_PORT") { |
|---|
| 665 | int p; val.convertTo(p); |
|---|
| 666 | RFB_PORTS.push_back(p); |
|---|
| 667 | } else if (matches[1] == "RFB_PASS") { |
|---|
| 668 | RFB_PASSWORDS.push_back(val); |
|---|
| 669 | } |
|---|
| 670 | /* END: variable parsing */ |
|---|
| 671 | else { |
|---|
| 672 | fprintf(stderr, "Unknown CFG param: %s\n", matches[1].c_str()); |
|---|
| 673 | } |
|---|
| 674 | } |
|---|
| 675 | } |
|---|
| 676 | return 0; |
|---|
| 677 | } /*FOLD00*/ |
|---|
| 678 | |
|---|
| 679 | #endif |
|---|
| 680 | |
|---|
| 681 | } |
|---|