00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "global.hpp"
00020
00021 #include <algorithm>
00022 #include <sstream>
00023 #include <string.h>
00024 #include <ostream>
00025 #include "config.hpp"
00026 #include "gettext.hpp"
00027 #include "log.hpp"
00028 #include "util.hpp"
00029
00030 #define ERR_CF LOG_STREAM(err, config)
00031
00032 config::config() : values(), children(), ordered_children()
00033 {
00034 }
00035
00036 config::config(const config& cfg) : values(), children(), ordered_children()
00037 {
00038 append(cfg);
00039 }
00040
00041 config::config(const std::string& child) : values(), children(), ordered_children()
00042 {
00043 add_child(child);
00044 }
00045
00046 config::~config()
00047 {
00048 clear();
00049 }
00050
00051 config& config::operator=(const config& cfg)
00052 {
00053 if(this == &cfg) {
00054 return *this;
00055 }
00056
00057 clear();
00058
00059 append(cfg);
00060
00061 return *this;
00062 }
00063
00064 void config::append(const config& cfg)
00065 {
00066 for(all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i) {
00067 const std::pair<const std::string*,const config*>& value = *i;
00068 add_child(*value.first,*value.second);
00069 }
00070
00071 for(string_map::const_iterator j = cfg.values.begin(); j != cfg.values.end(); ++j) {
00072 values[j->first] = j->second;
00073 }
00074 }
00075
00076 void config::merge_children(const std::string& key)
00077 {
00078 config merged_children;
00079 const child_list& children = get_children(key);
00080 if(children.size() < 2) {
00081 return;
00082 }
00083
00084 for(child_list::const_iterator i = children.begin(); i != children.end(); ++i) {
00085 merged_children.append(**i);
00086 }
00087
00088 clear_children(key);
00089 add_child(key,merged_children);
00090 }
00091
00092 config::child_itors config::child_range(const std::string& key)
00093 {
00094 child_map::iterator i = children.find(key);
00095 if(i != children.end()) {
00096 return child_itors(i->second.begin(),i->second.end());
00097 } else {
00098 static std::vector<config*> dummy;
00099 return child_itors(dummy.begin(),dummy.end());
00100 }
00101 }
00102
00103 config::const_child_itors config::child_range(const std::string& key) const
00104 {
00105 child_map::const_iterator i = children.find(key);
00106 if(i != children.end()) {
00107 return const_child_itors(i->second.begin(),i->second.end());
00108 } else {
00109 static const std::vector<config*> dummy;
00110 return const_child_itors(dummy.begin(),dummy.end());
00111 }
00112 }
00113
00114 const config::child_list& config::get_children(const std::string& key) const
00115 {
00116 const child_map::const_iterator i = children.find(key);
00117 if(i != children.end()) {
00118 return i->second;
00119 } else {
00120 static const child_list dummy;
00121 return dummy;
00122 }
00123 }
00124
00125 const config::child_map& config::all_children() const { return children; }
00126
00127 config* config::child(const std::string& key)
00128 {
00129 const child_map::const_iterator i = children.find(key);
00130 if(i != children.end() && i->second.empty() == false) {
00131 return i->second.front();
00132 } else {
00133 return NULL;
00134 }
00135 }
00136
00137 const config* config::child(const std::string& key) const
00138 {
00139 const child_map::const_iterator i = children.find(key);
00140 if(i != children.end() && i->second.empty() == false) {
00141 return i->second.front();
00142 } else {
00143 return NULL;
00144 }
00145 }
00146
00147 config& config::add_child(const std::string& key)
00148 {
00149 child_list& v = children[key];
00150 v.push_back(new config());
00151 ordered_children.push_back(child_pos(children.find(key),v.size()-1));
00152 return *v.back();
00153 }
00154
00155 config& config::add_child(const std::string& key, const config& val)
00156 {
00157 child_list& v = children[key];
00158 v.push_back(new config(val));
00159 ordered_children.push_back(child_pos(children.find(key),v.size()-1));
00160 return *v.back();
00161 }
00162
00163 config& config::add_child_at(const std::string& key, const config& val, size_t index)
00164 {
00165 child_list& v = children[key];
00166 if(index > v.size()) {
00167 throw error("illegal index to add child at");
00168 }
00169
00170 v.insert(v.begin()+index,new config(val));
00171
00172 bool inserted = false;
00173
00174 const child_pos value(children.find(key),index);
00175
00176 std::vector<child_pos>::iterator ord = ordered_children.begin();
00177 for(; ord != ordered_children.end(); ++ord) {
00178 if(!inserted && ord->index == index && ord->pos->first == key) {
00179 ord = ordered_children.insert(ord,value);
00180 inserted = true;
00181 } else if(ord->index >= index && ord->pos->first == key) {
00182 ord->index++;
00183 }
00184 }
00185
00186 if(!inserted) {
00187 ordered_children.push_back(value);
00188 }
00189
00190 return *v[index];
00191 }
00192
00193 namespace {
00194
00195 struct remove_ordered {
00196 remove_ordered(const std::string& key) : key_(key) {}
00197
00198 bool operator()(const config::child_pos& pos) const { return pos.pos->first == key_; }
00199 private:
00200 std::string key_;
00201 };
00202
00203 }
00204
00205 void config::clear_children(const std::string& key)
00206 {
00207 ordered_children.erase(std::remove_if(ordered_children.begin(),ordered_children.end(),remove_ordered(key)),ordered_children.end());
00208
00209 child_map::iterator i = children.find(key);
00210 if (i != children.end()) {
00211 for (child_iterator c = i->second.begin(); c != i->second.end(); c++) {
00212 delete *c;
00213 }
00214 children.erase(i);
00215 }
00216 }
00217
00218 void config::recursive_clear_value(const std::string& key)
00219 {
00220 values.erase(key);
00221
00222 for (all_children_iterator it = ordered_begin(); it != ordered_end(); ++it)
00223 {
00224 const_cast<config*>(it->second)->recursive_clear_value(key);
00225 }
00226 }
00227
00228 config::all_children_iterator config::erase(const config::all_children_iterator& i)
00229 {
00230 config* found_config = NULL;
00231 std::vector<child_pos>::iterator erase_pos, j, j_end = ordered_children.end();
00232 for(j = ordered_children.begin(); j != j_end; ++j) {
00233 if(i.get_key() == j->pos->first) {
00234 if(i.get_index() == j->index) {
00235 erase_pos = j;
00236 found_config = *(j->pos->second.begin() + j->index);
00237 } else if(i.get_index() < j->index) {
00238
00239 j->index--;
00240 }
00241 }
00242 }
00243 child_list& vec = children[i.get_key()];
00244 if(!found_config || erase_pos->index >= vec.size()) {
00245 ERR_CF << "Error: attempting to delete non-existing child: "
00246 << i.get_key() << "[" << i.get_index() << "]\n";
00247 return ordered_end();
00248 }
00249 delete found_config;
00250 vec.erase(vec.begin()+i.get_index());
00251 return all_children_iterator(ordered_children.erase(erase_pos));
00252 }
00253
00254 void config::remove_child(const std::string& key, size_t index)
00255 {
00256
00257 const child_pos pos(children.find(key),index);
00258 ordered_children.erase(std::remove(ordered_children.begin(),ordered_children.end(),pos),ordered_children.end());
00259
00260
00261
00262 for(std::vector<child_pos>::iterator i = ordered_children.begin(); i != ordered_children.end(); ++i) {
00263 if(i->pos->first == key && i->index > index) {
00264 i->index--;
00265 }
00266 }
00267
00268
00269 child_list& v = children[key];
00270 if(index >= v.size()) {
00271 ERR_CF << "Error: attempting to delete non-existing child: "
00272 << key << "[" << index << "]\n";
00273 return;
00274 }
00275 config* const res = v[index];
00276 v.erase(v.begin()+index);
00277 delete res;
00278 }
00279
00280 t_string& config::operator[](const std::string& key)
00281 {
00282 return values[key];
00283 }
00284
00285 const t_string& config::operator[](const std::string& key) const
00286 {
00287 return get_attribute(key);
00288 }
00289
00290 const t_string& config::get_attribute(const std::string& key) const
00291 {
00292 const string_map::const_iterator i = values.find(key);
00293 if(i != values.end()) {
00294 return i->second;
00295 } else {
00296 static const t_string empty_string;
00297 return empty_string;
00298 }
00299 }
00300
00301 namespace {
00302
00303 struct config_has_value {
00304 config_has_value(const std::string& name, const std::string& value)
00305 : name_(name), value_(value)
00306 {}
00307
00308 bool operator()(const config* cfg) const { return (*cfg)[name_] == value_; }
00309
00310 private:
00311 const std::string name_, value_;
00312 };
00313
00314 }
00315
00316 config* config::find_child(const std::string& key,
00317 const std::string& name,
00318 const t_string& value)
00319 {
00320 const child_map::iterator i = children.find(key);
00321 if(i == children.end())
00322 return NULL;
00323
00324 const child_list::iterator j = std::find_if(i->second.begin(),
00325 i->second.end(),
00326 config_has_value(name,value));
00327 if(j != i->second.end())
00328 return *j;
00329 else
00330 return NULL;
00331 }
00332
00333 const config* config::find_child(const std::string& key,
00334 const std::string& name,
00335 const t_string& value) const
00336 {
00337 const child_map::const_iterator i = children.find(key);
00338 if(i == children.end())
00339 return NULL;
00340
00341 const child_list::const_iterator j = std::find_if(
00342 i->second.begin(),
00343 i->second.end(),
00344 config_has_value(name,value));
00345 if(j != i->second.end())
00346 return *j;
00347 else
00348 return NULL;
00349 }
00350
00351 void config::clear()
00352 {
00353 for(std::map<std::string,std::vector<config*> >::iterator i = children.begin(); i != children.end(); ++i) {
00354 std::vector<config*>& v = i->second;
00355 for(std::vector<config*>::iterator j = v.begin(); j != v.end(); ++j)
00356 delete *j;
00357 }
00358
00359 children.clear();
00360 values.clear();
00361 ordered_children.clear();
00362 }
00363
00364 bool config::empty() const
00365 {
00366 return children.empty() && values.empty();
00367 }
00368
00369 config::all_children_iterator::all_children_iterator(config::all_children_iterator::Itor i) : i_(i)
00370 {}
00371
00372 config::all_children_iterator& config::all_children_iterator::operator++()
00373 {
00374 ++i_;
00375 return *this;
00376 }
00377
00378 config::all_children_iterator config::all_children_iterator::operator++(int)
00379 {
00380 config::all_children_iterator i = *this;
00381 ++i_;
00382 return i;
00383 }
00384
00385 std::pair<const std::string*,const config*> config::all_children_iterator::operator*() const
00386 {
00387 return std::pair<const std::string*,const config*>(&(i_->pos->first),i_->pos->second[i_->index]);
00388 }
00389
00390 config::all_children_iterator::pointer config::all_children_iterator::operator->() const
00391 {
00392 return pointer(new std::pair<const std::string*,const config*>(&(i_->pos->first),i_->pos->second[i_->index]));
00393 }
00394
00395 const std::string& config::all_children_iterator::get_key() const
00396 {
00397 return i_->pos->first;
00398 }
00399
00400 const config& config::all_children_iterator::get_child() const
00401 {
00402 return *(i_->pos->second[i_->index]);
00403 }
00404
00405 size_t config::all_children_iterator::get_index() const
00406 {
00407 return i_->index;
00408 }
00409
00410 bool config::all_children_iterator::operator==(all_children_iterator i) const
00411 {
00412 return i_ == i.i_;
00413 }
00414
00415 bool config::all_children_iterator::operator!=(all_children_iterator i) const
00416 {
00417 return i_ != i.i_;
00418 }
00419
00420 config::all_children_iterator config::ordered_begin() const
00421 {
00422 return all_children_iterator(ordered_children.begin());
00423 }
00424
00425 config::all_children_iterator config::ordered_end() const
00426 {
00427 return all_children_iterator(ordered_children.end());
00428 }
00429
00430 config config::get_diff(const config& c) const
00431 {
00432 config res;
00433 get_diff(c, res);
00434 return res;
00435 }
00436
00437 void config::get_diff(const config& c, config& res) const
00438 {
00439 config* inserts = NULL;
00440
00441 string_map::const_iterator i;
00442 for(i = values.begin(); i != values.end(); ++i) {
00443 const string_map::const_iterator j = c.values.find(i->first);
00444 if(j == c.values.end() || (i->second != j->second && i->second != "")) {
00445 if(inserts == NULL) {
00446 inserts = &res.add_child("insert");
00447 }
00448
00449 (*inserts)[i->first] = i->second;
00450 }
00451 }
00452
00453 config* deletes = NULL;
00454
00455 for(i = c.values.begin(); i != c.values.end(); ++i) {
00456 const string_map::const_iterator itor = values.find(i->first);
00457 if(itor == values.end() || itor->second == "") {
00458 if(deletes == NULL) {
00459 deletes = &res.add_child("delete");
00460 }
00461
00462 (*deletes)[i->first] = "x";
00463 }
00464 }
00465
00466 std::vector<std::string> entities;
00467
00468 child_map::const_iterator ci;
00469 for(ci = children.begin(); ci != children.end(); ++ci) {
00470 entities.push_back(ci->first);
00471 }
00472
00473 for(ci = c.children.begin(); ci != c.children.end(); ++ci) {
00474 if(children.count(ci->first) == 0) {
00475 entities.push_back(ci->first);
00476 }
00477 }
00478
00479 for(std::vector<std::string>::const_iterator itor = entities.begin(); itor != entities.end(); ++itor) {
00480
00481 const child_map::const_iterator itor_a = children.find(*itor);
00482 const child_map::const_iterator itor_b = c.children.find(*itor);
00483
00484 static const child_list dummy;
00485
00486
00487 const child_list& a = itor_a != children.end() ? itor_a->second : dummy;
00488 const child_list& b = itor_b != c.children.end() ? itor_b->second : dummy;
00489
00490 size_t ndeletes = 0;
00491 size_t ai = 0, bi = 0;
00492 while(ai != a.size() || bi != b.size()) {
00493
00494 if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
00495 ++ai;
00496 ++bi;
00497 } else {
00498
00499
00500 std::stringstream buf;
00501
00502
00503
00504 if(b.size() - bi > a.size() - ai) {
00505 config& new_delete = res.add_child("delete_child");
00506 buf << bi - ndeletes;
00507 new_delete.values["index"] = buf.str();
00508 new_delete.add_child(*itor);
00509
00510 ++ndeletes;
00511 ++bi;
00512 }
00513
00514
00515
00516 else if(b.size() - bi < a.size() - ai) {
00517 config& new_insert = res.add_child("insert_child");
00518 buf << ai;
00519 new_insert.values["index"] = buf.str();
00520 new_insert.add_child(*itor,*a[ai]);
00521
00522 ++ai;
00523 }
00524
00525
00526
00527 else {
00528 config& new_change = res.add_child("change_child");
00529 buf << bi;
00530 new_change.values["index"] = buf.str();
00531 new_change.add_child(*itor,a[ai]->get_diff(*b[bi]));
00532
00533 ++ai;
00534 ++bi;
00535 }
00536 }
00537 }
00538 }
00539 }
00540
00541 void config::apply_diff(const config& diff)
00542 {
00543 const config* const inserts = diff.child("insert");
00544 if(inserts != NULL) {
00545 for(string_map::const_iterator i = inserts->values.begin(); i != inserts->values.end(); ++i) {
00546 values[i->first] = i->second;
00547 }
00548 }
00549
00550 const config* const deletes = diff.child("delete");
00551 if(deletes != NULL) {
00552 for(string_map::const_iterator i = deletes->values.begin(); i != deletes->values.end(); ++i) {
00553 values.erase(i->first);
00554 }
00555 }
00556
00557 const child_list& child_changes = diff.get_children("change_child");
00558 child_list::const_iterator i;
00559 for(i = child_changes.begin(); i != child_changes.end(); ++i) {
00560 const size_t index = lexical_cast<size_t>((**i)["index"].str());
00561 for(all_children_iterator j = (*i)->ordered_begin(); j != (*i)->ordered_end(); ++j) {
00562 const std::pair<const std::string*,const config*> item = *j;
00563
00564 if(item.first->empty()) {
00565 continue;
00566 }
00567
00568 const child_map::iterator itor = children.find(*item.first);
00569 if(itor == children.end() || index >= itor->second.size()) {
00570 throw error("error in diff: could not find element '" + *item.first + "'");
00571 }
00572
00573 itor->second[index]->apply_diff(*item.second);
00574 }
00575 }
00576
00577 const child_list& child_inserts = diff.get_children("insert_child");
00578 for(i = child_inserts.begin(); i != child_inserts.end(); ++i) {
00579 const size_t index = lexical_cast<size_t>((**i)["index"].str());
00580 for(all_children_iterator j = (*i)->ordered_begin(); j != (*i)->ordered_end(); ++j) {
00581 const std::pair<const std::string*,const config*> item = *j;
00582 add_child_at(*item.first,*item.second,index);
00583 }
00584 }
00585
00586 const child_list& child_deletes = diff.get_children("delete_child");
00587 for(i = child_deletes.begin(); i != child_deletes.end(); ++i) {
00588 const size_t index = lexical_cast<size_t>((**i)["index"].str());
00589 for(all_children_iterator j = (*i)->ordered_begin(); j != (*i)->ordered_end(); ++j) {
00590 const std::pair<const std::string*,const config*> item = *j;
00591
00592 remove_child(*item.first,index);
00593 }
00594 }
00595 }
00596
00597 void config::merge_with(const config& c)
00598 {
00599 std::map<std::string, unsigned> visitations;
00600
00601
00602 string_map::const_iterator attrib_it, attrib_end = c.values.end();
00603 for(attrib_it = c.values.begin(); attrib_it != attrib_end; ++attrib_it) {
00604 values[attrib_it->first] = attrib_it->second;
00605 }
00606
00607
00608 all_children_iterator::Itor i, i_end = ordered_children.end();
00609 for(i = ordered_children.begin(); i != i_end; ++i) {
00610 const std::string& tag = i->pos->first;
00611 child_map::const_iterator j = c.children.find(tag);
00612 if (j != c.children.end()) {
00613 unsigned &visits = visitations[tag];
00614 if(visits < j->second.size()) {
00615 (i->pos->second[i->index])->merge_with(*j->second[visits++]);
00616 }
00617 }
00618 }
00619
00620
00621 for(child_map::const_iterator j = c.children.begin(); j != c.children.end(); ++j) {
00622 const std::string& tag = j->first;
00623 unsigned &visits = visitations[tag];
00624 while(visits < j->second.size()) {
00625 add_child(tag, *j->second[visits++]);
00626 }
00627 }
00628 }
00629
00630 void config::merge_and_keep(const config& c)
00631 {
00632
00633 string_map::const_iterator attrib_it, attrib_end = c.values.end();
00634 for(attrib_it = c.values.begin(); attrib_it != attrib_end; ++attrib_it) {
00635 if (values[attrib_it->first] == "")
00636 values[attrib_it->first] = attrib_it->second;
00637 }
00638
00639
00640 for(child_map::const_iterator i = c.children.begin(); i != c.children.end(); ++i) {
00641 const std::string& tag = i->first;
00642 child_map::const_iterator j = children.find(tag);
00643 if (j == children.end()) {
00644 for (size_t count=0; count < i->second.size(); count++)
00645 add_child(tag, *i->second[count]);
00646 }
00647 }
00648 }
00649
00650 bool config::matches(const config &filter) const
00651 {
00652
00653 for(string_map::const_iterator j = filter.values.begin(); j != filter.values.end(); ++j) {
00654 if(!this->values.count(j->first)) return false;
00655 const t_string& test_val = this->values.find(j->first)->second;
00656 if(test_val != j->second) {
00657 const std::string& boolcheck = j->second.base_str();
00658 if(boolcheck == "yes" || boolcheck == "true" || boolcheck == "on") {
00659 if(!utils::string_bool(test_val.base_str(), false)) {
00660 return false;
00661 }
00662 } else if(boolcheck == "no" || boolcheck == "false" || boolcheck == "off") {
00663 if(utils::string_bool(test_val.base_str(), true)) {
00664 return false;
00665 }
00666 } else {
00667 return false;
00668 }
00669 }
00670 }
00671
00672
00673 for(all_children_iterator i2 = filter.ordered_begin(); i2 != filter.ordered_end(); ++i2) {
00674 if(*(*i2).first == "not") continue;
00675 child_list interesting_children = get_children(*(*i2).first);
00676 bool found = false;
00677 for(child_list::iterator j2 = interesting_children.begin(); j2 != interesting_children.end(); ++j2) {
00678 if((*j2)->matches(*(*i2).second)) {
00679 found = true;
00680 }
00681 }
00682 if(!found) return false;
00683 }
00684 child_list negative_children = filter.get_children("not");
00685 for(child_list::iterator j3 = negative_children.begin() ; j3 != negative_children.end() ; j3++) {
00686 if(matches(**j3)) return false;
00687 }
00688 return true;
00689 }
00690
00691 void config::prune() {
00692 string_map::iterator val = values.begin();
00693 while(val != values.end()) {
00694 if(val->second.empty()) {
00695 values.erase(val++);
00696 } else {
00697 ++val;
00698 }
00699 }
00700
00701 for(child_map::const_iterator list = children.begin(); list != children.end(); ++list) {
00702 for(child_list::const_iterator child = list->second.begin(); child != list->second.end(); ++child) {
00703 (*child)->prune();
00704 }
00705 }
00706 }
00707
00708 void config::reset_translation() const
00709 {
00710 for(string_map::const_iterator val = values.begin(); val != values.end(); ++val) {
00711 val->second.reset_translation();
00712 }
00713
00714 for(child_map::const_iterator list = children.begin(); list != children.end(); ++list) {
00715 for(child_list::const_iterator child = list->second.begin();
00716 child != list->second.end(); ++child) {
00717 (*child)->reset_translation();
00718 }
00719 }
00720 }
00721
00722 std::string config::debug() const
00723 {
00724 std::ostringstream outstream;
00725 outstream << *this;
00726 return outstream.str();
00727 }
00728
00729 std::ostream& operator << (std::ostream& outstream, const config& cfg) {
00730 static int i = 0;
00731 i++;
00732 for(string_map::const_iterator val = cfg.values.begin(); val != cfg.values.end(); ++val) {
00733 for (int j = 0; j < i-1; j++){ outstream << char(9); }
00734 outstream << val->first << " = " << val->second << "\n";
00735 }
00736 for(config::all_children_iterator list = cfg.ordered_begin(); list != cfg.ordered_end(); ++list) {
00737 { for (int j = 0; j < i-1; j++){ outstream << char(9); } }
00738 outstream << "[" << *(*list).first << "]\n";
00739 outstream << *(*list).second;
00740 { for (int j = 0; j < i-1; j++){ outstream << char(9); } }
00741 outstream << "[/" << *(*list).first << "]\n";
00742 }
00743 i--;
00744 return outstream;
00745 }
00746
00747 std::string config::hash() const
00748 {
00749 static const unsigned int hash_length = 128;
00750 static const char hash_string[] =
00751 "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
00752 char hash_str[hash_length + 1];
00753 std::string::const_iterator c;
00754
00755 unsigned int i;
00756 for(i = 0; i != hash_length; ++i) {
00757 hash_str[i] = 'a';
00758 }
00759 hash_str[hash_length] = 0;
00760
00761 i = 0;
00762 for(string_map::const_iterator val = values.begin(); val != values.end(); ++val) {
00763 if(val->first.size() && val->second.size()) {
00764 for(c = val->first.begin(); c != val->first.end(); ++c) {
00765 if(utils::portable_isspace(*c)) {
00766 continue;
00767 }
00768 hash_str[i] ^= *c;
00769 ++i;
00770 if(i == hash_length) {
00771 i = 0;
00772 }
00773 }
00774 const std::string &base_str = val->second.base_str();
00775 for(c = base_str.begin(); c != base_str.end(); ++c) {
00776 if(utils::portable_isspace(*c)) {
00777 continue;
00778 }
00779 hash_str[i] ^= *c;
00780 ++i;
00781 if(i == hash_length) {
00782 i = 0;
00783 }
00784 }
00785 }
00786 }
00787 for(child_map::const_iterator list = children.begin(); list != children.end(); ++list) {
00788 for(child_list::const_iterator child = list->second.begin(); child != list->second.end(); ++child) {
00789 std::string child_hash = (*child)->hash();
00790 for(c = child_hash.begin(); c != child_hash.end(); ++c) {
00791 hash_str[i] ^= *c;
00792 ++i;
00793 if(i == hash_length) {
00794 i = 0;
00795 }
00796 }
00797 }
00798 }
00799
00800 for(i = 0; i != hash_length; ++i) {
00801 hash_str[i] = hash_string[
00802 static_cast<unsigned>(hash_str[i]) % strlen(hash_string)];
00803 }
00804
00805 return std::string(hash_str);
00806 }
00807
00808 void config::swap(config& cfg)
00809 {
00810 values.swap(cfg.values);
00811 children.swap(cfg.children);
00812 ordered_children.swap(cfg.ordered_children);
00813 }
00814
00815 bool operator==(const config& a, const config& b)
00816 {
00817 if (a.values != b.values)
00818 return false;
00819
00820 config::all_children_iterator x = a.ordered_begin(), y = b.ordered_begin();
00821 while(x != a.ordered_end() && y != b.ordered_end()) {
00822 const std::pair<const std::string*,const config*> val1 = *x;
00823 const std::pair<const std::string*,const config*> val2 = *y;
00824
00825 if(*val1.first != *val2.first || *val1.second != *val2.second) {
00826 return false;
00827 }
00828
00829 ++x;
00830 ++y;
00831 }
00832
00833 return x == a.ordered_end() && y == b.ordered_end();
00834 }
00835
00836 bool operator!=(const config& a, const config& b)
00837 {
00838 return !operator==(a,b);
00839 }
00840
00841
00842
00843 #ifdef TEST_CONFIG
00844
00845 int main()
00846 {
00847 config cfg(read_file("testconfig"));
00848 std::cout << cfg.write() << std::endl;
00849 }
00850
00851 #endif