00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <iostream>
00030 #include <sstream>
00031
00032 #include "configuration.h"
00033
00034
00035 using namespace natfw;
00036
00037
00038
00039 class parse_error : public std::exception {
00040 public:
00041 parse_error(const std::string &msg) throw () : msg(msg) { }
00042 virtual ~parse_error() throw () { }
00043
00044 std::string get_msg() const throw () { return msg; }
00045
00046 private:
00047 std::string msg;
00048 };
00049
00050
00054 configuration::configuration(config_entry rules[]) {
00055 for (unsigned i=0; rules[i].type != config_entry::T_END; i++)
00056 values[ rules[i].key ] = rules[i];
00057 }
00058
00059
00068 void configuration::load(const std::string &filename) throw (config_error) {
00069
00070 std::ifstream in(filename.c_str());
00071
00072 if ( ! in )
00073 throw config_error("cannot open file `" + filename + "'");
00074
00075 try {
00076 this->load(in);
00077 }
00078 catch ( config_error &e ) {
00079 in.close();
00080 throw;
00081 }
00082 catch ( ... ) {
00083 in.close();
00084 throw config_error("unknown exception thrown");
00085 }
00086
00087 in.close();
00088 }
00089
00090
00099 void configuration::load(std::istream &in_stream) throw (config_error) {
00100 using namespace std;
00101
00102 for (int line = 1; in_stream; line++) {
00103 string buf;
00104 string key;
00105
00106 getline(in_stream, buf);
00107
00108 stringstream in(buf);
00109
00110
00111 strip_leading_space(in);
00112
00113
00114 if ( in.peek() == -1 || in.peek() == '#' )
00115 continue;
00116
00117
00118 in >> key;
00119 if ( key == "")
00120 throw config_error("parse error", line);
00121
00122 if ( values.find(key) == values.end() )
00123 throw config_error("invalid key `" + key + "'", line);
00124
00125
00126 strip_leading_space(in);
00127
00128 char c = in.get();
00129 if ( c != '=' )
00130 throw config_error("parse error", line);
00131
00132
00133 strip_leading_space(in);
00134
00135
00136 if ( in.peek() == -1 )
00137 continue;
00138
00139 try {
00140 parse_and_assign(key, in);
00141 }
00142 catch ( parse_error &e ) {
00143 throw config_error(e.get_msg(), line);
00144 }
00145 }
00146
00147 if ( ! in_stream.eof() )
00148 throw config_error("stream error");
00149
00150
00151 for ( c_iter i = values.begin(); i != values.end(); i++ ) {
00152 const config_entry &e = i->second;
00153
00154 if ( e.required && ! e.defined )
00155 throw config_error(
00156 "key `" + e.key + "' required but not set");
00157 }
00158 }
00159
00160
00169 void configuration::dump(std::ostream &out) throw (config_error) {
00170 using namespace std;
00171
00172 out << "# Configuration dump" << endl;
00173
00174 for ( c_iter i = values.begin(); i != values.end(); i++ ) {
00175 const config_entry &e = i->second;
00176
00177 out << e.key << " = ";
00178
00179 if ( ! e.defined ) {
00180 out << endl;
00181 continue;
00182 }
00183
00184 switch ( e.type ) {
00185 case config_entry::T_BOOL:
00186 out << e.bool_value << endl;
00187 break;
00188 case config_entry::T_INT:
00189 out << e.int_value << endl;
00190 break;
00191 case config_entry::T_FLOAT:
00192 out << e.float_value << endl;
00193 break;
00194 case config_entry::T_STR:
00195 write_string(out, e.str_value);
00196 out << endl;
00197 break;
00198 case config_entry::T_IPv4:
00199 out << e.ipv4_value << endl;
00200 break;
00201 case config_entry::T_IPv6:
00202 out << e.ipv6_value << endl;
00203 break;
00204 case config_entry::T_IPv4_LIST:
00205 case config_entry::T_IPv6_LIST:
00206 dump_address_list(out, e.address_list);
00207 out << endl;
00208 break;
00209 default:
00210 assert( false );
00211 }
00212 }
00213 }
00214
00215
00216 void configuration::dump_address_list(std::ostream &out,
00217 const std::list<hostaddress> &addresses) const {
00218
00219 typedef std::list<hostaddress>::const_iterator addr_iter;
00220
00221 for ( addr_iter i = addresses.begin(); i != addresses.end(); i++ )
00222 out << *i << " ";
00223 }
00224
00225
00232 bool configuration::is_defined(const std::string &key) const throw () {
00233 c_iter i = values.find(key);
00234
00235 if ( values.find(key) == values.end() )
00236 return false;
00237 else
00238 return i->second.defined;
00239 }
00240
00241
00248 std::string configuration::get_string(const std::string &key) const throw () {
00249 c_iter i = values.find(key);
00250 assert( i != values.end() );
00251 assert( i->second.type == config_entry::T_STR );
00252
00253 return i->second.str_value;
00254 }
00255
00256
00263 bool configuration::get_bool(const std::string &key) const throw () {
00264 c_iter i = values.find(key);
00265 assert( i != values.end() );
00266 assert( i->second.type == config_entry::T_BOOL );
00267
00268 return i->second.bool_value;
00269 }
00270
00271
00278 int configuration::get_int(const std::string &key) const throw () {
00279 c_iter i = values.find(key);
00280 assert( i != values.end() );
00281 assert( i->second.type == config_entry::T_INT );
00282
00283 return i->second.int_value;
00284 }
00285
00286
00293 float configuration::get_float(const std::string &key) const throw () {
00294 c_iter i = values.find(key);
00295 assert( i != values.end() );
00296 assert( i->second.type == config_entry::T_FLOAT );
00297
00298 return i->second.float_value;
00299 }
00300
00301
00308 hostaddress configuration::get_ipv4_address(
00309 const std::string &key) const throw () {
00310
00311 c_iter i = values.find(key);
00312 assert( i != values.end() );
00313 assert( i->second.type == config_entry::T_IPv4 );
00314
00315 return i->second.ipv4_value;
00316 }
00317
00318
00325 hostaddress configuration::get_ipv6_address(
00326 const std::string &key) const throw () {
00327
00328 c_iter i = values.find(key);
00329 assert( i != values.end() );
00330 assert( i->second.type == config_entry::T_IPv6 );
00331
00332 return i->second.ipv6_value;
00333 }
00334
00335
00342 std::list<hostaddress> configuration::get_ipv4_address_list(
00343 const std::string &key) const throw () {
00344
00345 c_iter i = values.find(key);
00346 assert( i != values.end() );
00347 assert( i->second.type == config_entry::T_IPv4_LIST );
00348
00349 return i->second.address_list;
00350 }
00351
00352
00359 std::list<hostaddress> configuration::get_ipv6_address_list(
00360 const std::string &key) const throw () {
00361
00362 c_iter i = values.find(key);
00363 assert( i != values.end() );
00364 assert( i->second.type == config_entry::T_IPv6_LIST );
00365
00366 return i->second.address_list;
00367 }
00368
00369
00370 void configuration::strip_leading_space(std::istream &in) const {
00371 while ( in && ( in.peek() == ' ' || in.peek() == '\t' ) )
00372 in.get();
00373 }
00374
00375
00376
00377 void configuration::parse_and_assign(const std::string &key, std::istream &in) {
00378
00379 switch ( values[key].type ) {
00380 case config_entry::T_BOOL:
00381 values[key].bool_value = parse_bool(in);
00382 break;
00383 case config_entry::T_INT:
00384 values[key].int_value = parse_int(in);
00385 break;
00386 case config_entry::T_FLOAT:
00387 values[key].float_value = parse_float(in);
00388 break;
00389 case config_entry::T_STR:
00390 values[key].str_value = parse_string(in);
00391 break;
00392 case config_entry::T_IPv4:
00393 values[key].ipv4_value = parse_ipv4_address(in);
00394 break;
00395 case config_entry::T_IPv6:
00396 values[key].ipv6_value = parse_ipv6_address(in);
00397 break;
00398 case config_entry::T_IPv4_LIST:
00399 values[key].address_list = parse_ipv4_address_list(in);
00400 break;
00401 case config_entry::T_IPv6_LIST:
00402 values[key].address_list = parse_ipv6_address_list(in);
00403 break;
00404 default:
00405 assert( false );
00406 throw parse_error("invalid value");
00407 }
00408
00409
00410 values[key].defined = true;
00411 }
00412
00413
00414
00415 void configuration::write_string(
00416 std::ostream &out, const std::string &str) const {
00417
00418 std::stringstream stream(str);
00419
00420 out << '"';
00421
00422 char c;
00423 while ( stream.get(c) ) {
00424 switch ( c ) {
00425 case '\\':
00426 case '"': out << '\\' << c; break;
00427 default: out << c;
00428 }
00429 }
00430
00431 out << '"';
00432 }
00433
00434
00435
00436 std::string configuration::parse_string(std::istream &in) const {
00437
00438 if ( in.get() != '"' )
00439 throw parse_error("string doesn't start with a quotation mark");
00440
00441 bool escape = false;
00442 std::string tmp;
00443 char c;
00444
00445 while ( in.get(c) ) {
00446 if ( escape ) {
00447 if ( c == '\\' || c == '"' )
00448 tmp += c;
00449 else
00450 throw parse_error("invalid escape sequence");
00451
00452 escape = false;
00453 }
00454 else {
00455 if ( c == '"' )
00456 break;
00457 else if ( c == '\\' )
00458 escape = true;
00459 else
00460 tmp += c;
00461 }
00462 }
00463
00464
00465 if ( c != '"' )
00466 throw parse_error("unterminated string");
00467
00468 skip_rest_of_line(in);
00469
00470 return tmp;
00471 }
00472
00473
00474 hostaddress configuration::parse_ipv4_address(std::istream &in) const {
00475 std::string word;
00476 in >> word;
00477
00478 bool success;
00479 hostaddress addr(word.c_str(), &success);
00480
00481 if ( success || ! addr.is_ipv4() )
00482 return addr;
00483 else
00484 throw parse_error("invalid IPv4 address");
00485
00486 skip_rest_of_line(in);
00487
00488 return addr;
00489 }
00490
00491
00492 hostaddress configuration::parse_ipv6_address(std::istream &in) const {
00493 std::string word;
00494 in >> word;
00495
00496 bool success;
00497 hostaddress addr(word.c_str(), &success);
00498
00499 if ( success || ! addr.is_ipv6() )
00500 return addr;
00501 else
00502 throw parse_error("invalid IPv6 address");
00503
00504 skip_rest_of_line(in);
00505
00506 return addr;
00507 }
00508
00509 std::list<hostaddress> configuration::parse_ipv4_address_list(
00510 std::istream &in) const {
00511
00512 std::list<hostaddress> result;
00513
00514 std::string tmp;
00515 while ( in >> tmp ) {
00516 bool success;
00517 hostaddress addr(tmp.c_str(), &success);
00518
00519 if ( success && addr.is_ipv4() )
00520 result.push_back(addr);
00521 else
00522 throw parse_error("invalid IPv4 address `" + tmp + "'");
00523 }
00524
00525 return result;
00526 }
00527
00528 std::list<hostaddress> configuration::parse_ipv6_address_list(
00529 std::istream &in) const {
00530
00531 std::list<hostaddress> result;
00532
00533 std::string tmp;
00534 while ( in >> tmp ) {
00535 bool success;
00536 hostaddress addr(tmp.c_str(), &success);
00537
00538 if ( success && addr.is_ipv6() )
00539 result.push_back(addr);
00540 else
00541 throw parse_error("invalid IPv6 address `" + tmp + "'");
00542 }
00543
00544 return result;
00545 }
00546
00547 int configuration::parse_int(std::istream &in) const {
00548 int tmp = -1;
00549
00550 in >> tmp;
00551
00552 if ( ! in.good() && ! in.eof() )
00553 throw parse_error("parsing integer failed");
00554
00555 skip_rest_of_line(in);
00556
00557 return tmp;
00558 }
00559
00560
00561 float configuration::parse_float(std::istream &in) const {
00562 float tmp = 0.0;
00563
00564 in >> tmp;
00565
00566 if ( ! in.good() && ! in.eof() )
00567 throw parse_error("parsing float failed");
00568
00569 skip_rest_of_line(in);
00570
00571 return tmp;
00572 }
00573
00574
00575 bool configuration::parse_bool(std::istream &in) const {
00576 std::string tmp;
00577 bool value;
00578
00579 in >> tmp;
00580
00581 if ( tmp == "true" )
00582 value = true;
00583 else if ( tmp == "false" )
00584 value = false;
00585 else
00586 throw parse_error("parsing boolean failed");
00587
00588 skip_rest_of_line(in);
00589
00590 return value;
00591 }
00592
00593
00594
00595 void configuration::skip_rest_of_line(std::istream &in) const {
00596 char c;
00597 while ( in.get(c) ) {
00598 if ( c != ' ' && c != '\t' )
00599 throw parse_error("junk after value");
00600 }
00601 }
00602
00603
00604