00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "global.hpp"
00023
00024 #include "config.hpp"
00025 #include "foreach.hpp"
00026 #include "log.hpp"
00027 #include "serialization/string_utils.hpp"
00028 #include "util.hpp"
00029 #include "utils/const_clone.tpp"
00030
00031 #include <cstdlib>
00032 #include <cstring>
00033 #include <deque>
00034 #include <boost/variant.hpp>
00035
00036 static lg::log_domain log_config("config");
00037 #define ERR_CF LOG_STREAM(err, log_config)
00038 #define DBG_CF LOG_STREAM(debug, log_config)
00039
00040 struct tconfig_implementation
00041 {
00042
00043
00044
00045
00046
00047
00048 template<class T>
00049 static typename utils::tconst_clone<config, T>::reference
00050 child(
00051 T config
00052 , const std::string& key
00053 , const std::string& parent)
00054 {
00055 config->check_valid();
00056
00057 assert(!parent.empty());
00058 assert(parent[0] == '[');
00059 assert(parent[parent.size() - 1] == ']');
00060
00061 if(config->has_child(key)) {
00062 return *(config->children.find(key)->second.front());
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 std::stringstream sstr;
00074 sstr << "Mandatory WML child »[" << key << "]« missing in »"
00075 << parent << "«. Please report this bug.";
00076
00077 throw config::error(sstr.str());
00078 }
00079 };
00080
00081
00082 config::attribute_value::attribute_value()
00083 : value()
00084 {
00085 }
00086
00087 config::attribute_value::~attribute_value()
00088 {
00089 }
00090
00091 config::attribute_value &config::attribute_value::operator=(const config::attribute_value &that)
00092 {
00093 value = that.value;
00094 return *this;
00095 }
00096
00097 config::attribute_value::attribute_value(const config::attribute_value &that)
00098 : value(that.value)
00099 {
00100 }
00101
00102 config::attribute_value &config::attribute_value::operator=(bool v)
00103 {
00104 value = v;
00105 return *this;
00106 }
00107
00108 config::attribute_value &config::attribute_value::operator=(int v)
00109 {
00110 value = double(v);
00111 return *this;
00112 }
00113
00114 config::attribute_value &config::attribute_value::operator=(size_t v)
00115 {
00116 value = double(v);
00117 return *this;
00118 }
00119
00120 config::attribute_value &config::attribute_value::operator=(long v)
00121 {
00122 value = double(v);
00123 return *this;
00124 }
00125 config::attribute_value &config::attribute_value::operator=(double v)
00126 {
00127 value = v;
00128 return *this;
00129 }
00130
00131 bool config::attribute_value::operator==(const config::attribute_value &other) const
00132 {
00133 return value == other.value;
00134 }
00135
00136 std::ostream &operator<<(std::ostream &os, const config::attribute_value &v)
00137 {
00138 return os << v.str();
00139 }
00140
00141 bool config::attribute_value::blank() const
00142 {
00143 return boost::get<const boost::blank>(&value);
00144 }
00145
00146 bool config::attribute_value::empty() const
00147 {
00148 if (boost::get<const boost::blank>(&value)) return true;
00149 if (const std::string *p = boost::get<const std::string>(&value)) return p->empty();
00150 return false;
00151 }
00152
00153 bool config::attribute_value::to_bool(bool def) const
00154 {
00155 if (const bool *p = boost::get<const bool>(&value)) return *p;
00156 return def;
00157 }
00158
00159 int config::attribute_value::to_int(int def) const
00160 {
00161 const double* i = boost::get<const double>(&value);
00162 if(i != NULL)
00163 {
00164 return int(*i);
00165 }
00166 return def;
00167 }
00168 long config::attribute_value::to_long(long def) const
00169 {
00170 const double* i = boost::get<const double>(&value);
00171 if (i != NULL)
00172 {
00173 return long(*i);
00174 }
00175 return def;
00176 }
00177 double config::attribute_value::to_double(double def) const
00178 {
00179 const double* d = boost::get<const double>(&value);;
00180 if(d != NULL)
00181 {
00182 return *d;;
00183 }
00184 return def;
00185 }
00186
00187 struct config_attribute_str_visitor : boost::static_visitor<std::string>
00188 {
00189 std::string operator()(boost::blank const &) const
00190 { return std::string(); }
00191 std::string operator()(bool b) const
00192 {
00193 static std::string s_yes("yes"), s_no("no");
00194 return b ? s_yes : s_no;
00195 }
00196 std::string operator()(double d) const
00197 {
00198 long i = static_cast<long>(d);
00199
00200 if (static_cast<double>(i) == d)
00201 return str_cast(i);
00202 else
00203 return str_cast(d);
00204 }
00205 std::string operator()(std::string const &s) const
00206 { return s; }
00207 std::string operator()(t_string const &s) const
00208 { return s.str(); }
00209 };
00210
00211 std::string config::attribute_value::str() const
00212 {
00213 return boost::apply_visitor(config_attribute_str_visitor(), value);
00214 }
00215
00216 t_string config::attribute_value::t_str() const
00217 {
00218 if (const t_string *p = boost::get<const t_string>(&value)) return *p;
00219 return str();
00220 }
00221
00222 config::attribute_value &config::attribute_value::operator=(const std::string &v)
00223 {
00224 if (v.empty()) { value = v; return *this; }
00225 if (v == "yes" || v == "true") return *this = true;
00226 if (v == "no" || v == "false") return *this = false;
00227 char *eptr;
00228 int i = strtol(v.c_str(), &eptr, 0);
00229 if (*eptr == '\0') return *this = i;
00230 double d = strtod(v.c_str(), &eptr);
00231 if (*eptr == '\0') return *this = d;
00232 value = v;
00233 return *this;
00234 }
00235
00236 config::attribute_value &config::attribute_value::operator=(const t_string &v)
00237 {
00238 if (!v.translatable()) return *this = v.str();
00239 value = v;
00240 return *this;
00241 }
00242
00243 config config::invalid;
00244
00245 const char* config::diff_track_attribute = "__diff_track";
00246
00247 void config::check_valid() const
00248 {
00249 if (!*this)
00250 throw error("Mandatory WML child missing yet untested for. Please report.");
00251 }
00252
00253 void config::check_valid(const config &cfg) const
00254 {
00255 if (!*this || !cfg)
00256 throw error("Mandatory WML child missing yet untested for. Please report.");
00257 }
00258
00259 config::config() : values(), children(), ordered_children()
00260 {
00261 }
00262
00263 config::config(const config& cfg) : values(cfg.values), children(), ordered_children()
00264 {
00265 append_children(cfg);
00266 }
00267
00268 config::config(const std::string& child) : values(), children(), ordered_children()
00269 {
00270 add_child(child);
00271 }
00272
00273 config::~config()
00274 {
00275 clear();
00276 }
00277
00278 config& config::operator=(const config& cfg)
00279 {
00280 if(this == &cfg) {
00281 return *this;
00282 }
00283
00284 clear();
00285 append_children(cfg);
00286 values.insert(cfg.values.begin(), cfg.values.end());
00287 return *this;
00288 }
00289
00290 #ifdef HAVE_CXX0X
00291 config::config(config &&cfg):
00292 values(std::move(cfg.values)),
00293 children(std::move(cfg.children)),
00294 ordered_children(std::move(cfg.ordered_children))
00295 {
00296 }
00297
00298 config &config::operator=(config &&cfg)
00299 {
00300 clear();
00301 swap(cfg);
00302 return *this;
00303 }
00304 #endif
00305
00306 bool config::has_attribute(const std::string &key) const
00307 {
00308 check_valid();
00309 return values.find(key) != values.end();
00310 }
00311
00312 bool config::has_old_attribute(const std::string &key, const std::string &old_key, const std::string& msg) const
00313 {
00314 check_valid();
00315 if (values.find(key) != values.end()) {
00316 return true;
00317 } else if (values.find(old_key) != values.end()) {
00318 if (!msg.empty())
00319 lg::wml_error << msg;
00320 return true;
00321 }
00322 return false;
00323 }
00324
00325
00326 void config::remove_attribute(const std::string &key)
00327 {
00328 check_valid();
00329 values.erase(key);
00330 }
00331
00332 void config::append_children(const config &cfg)
00333 {
00334 check_valid(cfg);
00335
00336 foreach (const any_child &value, cfg.all_children_range()) {
00337 add_child(value.key, value.cfg);
00338 }
00339 }
00340
00341 void config::append(const config &cfg)
00342 {
00343 append_children(cfg);
00344 foreach (const attribute &v, cfg.values) {
00345 values[v.first] = v.second;
00346 }
00347 }
00348
00349 void config::merge_children(const std::string& key)
00350 {
00351 check_valid();
00352
00353 if (child_count(key) < 2) return;
00354
00355 config merged_children;
00356 foreach (const config &cfg, child_range(key)) {
00357 merged_children.append(cfg);
00358 }
00359
00360 clear_children(key);
00361 add_child(key,merged_children);
00362 }
00363
00364 void config::merge_children_by_attribute(const std::string& key, const std::string& attribute)
00365 {
00366 check_valid();
00367
00368 if (child_count(key) < 2) return;
00369
00370 typedef std::map<std::string, config> config_map;
00371 config_map merged_children_map;
00372 foreach (const config &cfg, child_range(key)) {
00373 const std::string &value = cfg[attribute];
00374 config_map::iterator m = merged_children_map.find(value);
00375 if ( m!=merged_children_map.end() ) {
00376 m->second.append(cfg);
00377 } else {
00378 merged_children_map.insert(make_pair(value, cfg));
00379 }
00380 }
00381
00382 clear_children(key);
00383 foreach (const config_map::value_type &i, merged_children_map) {
00384 add_child(key,i.second);
00385 }
00386 }
00387
00388 config::child_itors config::child_range(const std::string& key)
00389 {
00390 check_valid();
00391
00392 child_map::iterator i = children.find(key);
00393 static child_list dummy;
00394 child_list *p = &dummy;
00395 if (i != children.end()) p = &i->second;
00396 return child_itors(child_iterator(p->begin()), child_iterator(p->end()));
00397 }
00398
00399 config::const_child_itors config::child_range(const std::string& key) const
00400 {
00401 check_valid();
00402
00403 child_map::const_iterator i = children.find(key);
00404 static child_list dummy;
00405 const child_list *p = &dummy;
00406 if (i != children.end()) p = &i->second;
00407 return const_child_itors(const_child_iterator(p->begin()), const_child_iterator(p->end()));
00408 }
00409
00410 unsigned config::child_count(const std::string &key) const
00411 {
00412 check_valid();
00413
00414 child_map::const_iterator i = children.find(key);
00415 if(i != children.end()) {
00416 return i->second.size();
00417 }
00418 return 0;
00419 }
00420
00421 bool config::has_child(const std::string &key) const
00422 {
00423 check_valid();
00424
00425 return children.find(key) != children.end();
00426 }
00427
00428 config &config::child(const std::string& key, int n)
00429 {
00430 check_valid();
00431
00432 const child_map::const_iterator i = children.find(key);
00433 if (i == children.end()) {
00434 DBG_CF << "The config object has no child named »"
00435 << key << "«.\n";
00436
00437 return invalid;
00438 }
00439
00440 if (n < 0) n = i->second.size() + n;
00441 if(size_t(n) < i->second.size()) {
00442 return *i->second[n];
00443 } else {
00444 DBG_CF << "The config object has only »" << i->second.size()
00445 << "« children named »" << key
00446 << "«; request for the index »" << n << "« can not be honoured.\n";
00447
00448 return invalid;
00449 }
00450 }
00451
00452 config& config::child(const std::string& key, const std::string& parent)
00453 {
00454 return tconfig_implementation::child(this, key, parent);
00455 }
00456
00457 const config& config::child(
00458 const std::string& key
00459 , const std::string& parent) const
00460 {
00461 return tconfig_implementation::child(this, key, parent);
00462 }
00463
00464 config config::child_or_empty(const std::string& key) const
00465 {
00466 check_valid();
00467
00468 child_map::const_iterator i = children.find(key);
00469 if (i != children.end() && !i->second.empty())
00470 return *i->second.front();
00471
00472 return config();
00473 }
00474
00475 config &config::child_or_add(const std::string &key)
00476 {
00477 child_map::const_iterator i = children.find(key);
00478 if (i != children.end() && !i->second.empty())
00479 return *i->second.front();
00480
00481 return add_child(key);
00482 }
00483
00484 config& config::add_child(const std::string& key)
00485 {
00486 check_valid();
00487
00488 child_list& v = children[key];
00489 v.push_back(new config());
00490 ordered_children.push_back(child_pos(children.find(key),v.size()-1));
00491 return *v.back();
00492 }
00493
00494 config& config::add_child(const std::string& key, const config& val)
00495 {
00496 check_valid(val);
00497
00498 child_list& v = children[key];
00499 v.push_back(new config(val));
00500 ordered_children.push_back(child_pos(children.find(key),v.size()-1));
00501 return *v.back();
00502 }
00503
00504 #ifdef HAVE_CXX0X
00505 config &config::add_child(const std::string &key, config &&val)
00506 {
00507 check_valid(val);
00508
00509 child_list &v = children[key];
00510 v.push_back(new config(std::move(val)));
00511 ordered_children.push_back(child_pos(children.find(key), v.size() - 1));
00512 return *v.back();
00513 }
00514 #endif
00515
00516 config &config::add_child_at(const std::string &key, const config &val, unsigned index)
00517 {
00518 check_valid(val);
00519
00520 child_list& v = children[key];
00521 if(index > v.size()) {
00522 throw error("illegal index to add child at");
00523 }
00524
00525 v.insert(v.begin()+index,new config(val));
00526
00527 bool inserted = false;
00528
00529 const child_pos value(children.find(key),index);
00530
00531 std::vector<child_pos>::iterator ord = ordered_children.begin();
00532 for(; ord != ordered_children.end(); ++ord) {
00533 if (ord->pos != value.pos) continue;
00534 if (!inserted && ord->index == index) {
00535 ord = ordered_children.insert(ord,value);
00536 inserted = true;
00537 } else if (ord->index >= index) {
00538 ord->index++;
00539 }
00540 }
00541
00542 if(!inserted) {
00543 ordered_children.push_back(value);
00544 }
00545
00546 return *v[index];
00547 }
00548
00549 namespace {
00550
00551 struct remove_ordered
00552 {
00553 remove_ordered(const config::child_map::iterator &iter) : iter_(iter) {}
00554
00555 bool operator()(const config::child_pos &pos) const
00556 { return pos.pos == iter_; }
00557 private:
00558 config::child_map::iterator iter_;
00559 };
00560
00561 }
00562
00563 void config::clear_children(const std::string& key)
00564 {
00565 check_valid();
00566
00567 child_map::iterator i = children.find(key);
00568 if (i == children.end()) return;
00569
00570 ordered_children.erase(std::remove_if(ordered_children.begin(),
00571 ordered_children.end(), remove_ordered(i)), ordered_children.end());
00572
00573 foreach (config *c, i->second) {
00574 delete c;
00575 }
00576
00577 children.erase(i);
00578 }
00579
00580 void config::splice_children(config &src, const std::string &key)
00581 {
00582 check_valid(src);
00583
00584 child_map::iterator i_src = src.children.find(key);
00585 if (i_src == src.children.end()) return;
00586
00587 src.ordered_children.erase(std::remove_if(src.ordered_children.begin(),
00588 src.ordered_children.end(), remove_ordered(i_src)),
00589 src.ordered_children.end());
00590
00591 child_list &dst = children[key];
00592 child_map::iterator i_dst = children.find(key);
00593 unsigned before = dst.size();
00594 dst.insert(dst.end(), i_src->second.begin(), i_src->second.end());
00595 src.children.erase(i_src);
00596
00597
00598 for (unsigned j = before; j < dst.size(); ++j) {
00599 ordered_children.push_back(child_pos(i_dst, j));
00600 }
00601 }
00602
00603 void config::recursive_clear_value(const std::string& key)
00604 {
00605 check_valid();
00606
00607 values.erase(key);
00608
00609 foreach (const any_child &value, all_children_range()) {
00610 const_cast<config *>(&value.cfg)->recursive_clear_value(key);
00611 }
00612 }
00613
00614 std::vector<config::child_pos>::iterator config::remove_child(
00615 const child_map::iterator &pos, unsigned index)
00616 {
00617
00618
00619 unsigned found = 0;
00620 foreach (child_pos &p, ordered_children)
00621 {
00622 if (p.pos != pos) continue;
00623 if (p.index == index)
00624 found = &p - &ordered_children.front();
00625 else if (p.index > index)
00626 --p.index;
00627 }
00628
00629
00630 delete pos->second[index];
00631 pos->second.erase(pos->second.begin() + index);
00632
00633
00634 return ordered_children.erase(ordered_children.begin() + found);
00635 }
00636
00637 config::all_children_iterator config::erase(const config::all_children_iterator& i)
00638 {
00639 return all_children_iterator(remove_child(i.i_->pos, i.i_->index));
00640 }
00641
00642 void config::remove_child(const std::string &key, unsigned index)
00643 {
00644 check_valid();
00645
00646 child_map::iterator i = children.find(key);
00647 if (i == children.end() || index >= i->second.size()) {
00648 ERR_CF << "Error: attempting to delete non-existing child: "
00649 << key << "[" << index << "]\n";
00650 return;
00651 }
00652
00653 remove_child(i, index);
00654 }
00655
00656 const config::attribute_value &config::operator[](const std::string &key) const
00657 {
00658 check_valid();
00659
00660 const attribute_map::const_iterator i = values.find(key);
00661 if (i != values.end()) return i->second;
00662 static const attribute_value empty_attribute;
00663 return empty_attribute;
00664 }
00665
00666 const config::attribute_value *config::get(const std::string &key) const
00667 {
00668 check_valid();
00669 attribute_map::const_iterator i = values.find(key);
00670 return i != values.end() ? &i->second : NULL;
00671 }
00672
00673 config::attribute_value &config::operator[](const std::string &key)
00674 {
00675 check_valid();
00676 return values[key];
00677 }
00678
00679 const config::attribute_value &config::get_old_attribute(const std::string &key, const std::string &old_key, const std::string &msg) const
00680 {
00681 check_valid();
00682
00683 attribute_map::const_iterator i = values.find(key);
00684 if (i != values.end())
00685 return i->second;
00686
00687 i = values.find(old_key);
00688 if (i != values.end()) {
00689 if (!msg.empty())
00690 lg::wml_error << msg;
00691 return i->second;
00692 }
00693
00694 static const attribute_value empty_attribute;
00695 return empty_attribute;
00696 }
00697
00698
00699 void config::merge_attributes(const config &cfg)
00700 {
00701 check_valid(cfg);
00702
00703 assert(this != &cfg);
00704 foreach (const attribute &v, cfg.values) {
00705
00706 std::string key = v.first;
00707 if (key.substr(0,7) == "add_to_") {
00708 std::string add_to = key.substr(7);
00709 values[add_to] = values[add_to].to_int() + v.second.to_int();
00710 } else
00711 values[v.first] = v.second;
00712 }
00713 }
00714
00715 config::const_attr_itors config::attribute_range() const
00716 {
00717 check_valid();
00718
00719 return const_attr_itors(const_attribute_iterator(values.begin()),
00720 const_attribute_iterator(values.end()));
00721 }
00722
00723 namespace {
00724
00725 struct config_has_value {
00726 config_has_value(const std::string& name, const std::string& value)
00727 : name_(name), value_()
00728 {
00729 value_ = value;
00730 }
00731
00732 bool operator()(const config* cfg) const { return (*cfg)[name_] == value_; }
00733
00734 private:
00735 std::string name_;
00736 config::attribute_value value_;
00737 };
00738
00739 }
00740
00741 config &config::find_child(const std::string &key, const std::string &name,
00742 const std::string &value)
00743 {
00744 check_valid();
00745
00746 const child_map::iterator i = children.find(key);
00747 if(i == children.end()) {
00748 DBG_CF << "Key »" << name << "« value »" << value
00749 << "« pair not found as child of key »" << key << "«.\n";
00750
00751 return invalid;
00752 }
00753
00754 const child_list::iterator j = std::find_if(i->second.begin(),
00755 i->second.end(),
00756 config_has_value(name,value));
00757 if(j != i->second.end()) {
00758 return **j;
00759 } else {
00760 DBG_CF << "Key »" << name << "« value »" << value
00761 << "« pair not found as child of key »" << key << "«.\n";
00762
00763 return invalid;
00764 }
00765 }
00766
00767 namespace {
00768
00769
00770
00771 struct config_clear_state
00772 {
00773 config_clear_state()
00774 : c(NULL)
00775 , mi()
00776 , vi(0)
00777 {
00778 }
00779
00780 config* c;
00781 config::child_map::iterator mi;
00782 size_t vi;
00783 };
00784 }
00785
00786 void config::clear()
00787 {
00788
00789
00790 if (!children.empty()) {
00791
00792
00793 config_clear_state init;
00794 init.c = this;
00795 init.mi = children.begin();
00796 init.vi = 0;
00797 std::deque<config_clear_state> l;
00798 l.push_back(init);
00799
00800 while (!l.empty()) {
00801 config_clear_state& state = l.back();
00802 if (state.mi != state.c->children.end()) {
00803 std::vector<config*>& v = state.mi->second;
00804 if (state.vi < v.size()) {
00805 config* c = v[state.vi];
00806 ++state.vi;
00807 if (c->children.empty()) {
00808 delete c;
00809 } else {
00810
00811 config_clear_state next;
00812 next.c = c;
00813 next.mi = c->children.begin();
00814 next.vi = 0;
00815 l.push_back(next);
00816 }
00817 } else {
00818 state.vi = 0;
00819 ++state.mi;
00820 }
00821 } else {
00822
00823
00824
00825 state.c->children.clear();
00826 if (state.c != this) delete state.c;
00827 l.pop_back();
00828 }
00829 }
00830 }
00831
00832 values.clear();
00833 ordered_children.clear();
00834 }
00835
00836 bool config::empty() const
00837 {
00838 check_valid();
00839
00840 return children.empty() && values.empty();
00841 }
00842
00843 config::all_children_iterator::reference config::all_children_iterator::operator*() const
00844 {
00845 return any_child(&i_->pos->first, i_->pos->second[i_->index]);
00846 }
00847
00848 config::all_children_iterator config::ordered_begin() const
00849 {
00850 return all_children_iterator(ordered_children.begin());
00851 }
00852
00853 config::all_children_iterator config::ordered_end() const
00854 {
00855 return all_children_iterator(ordered_children.end());
00856 }
00857
00858 config::all_children_itors config::all_children_range() const
00859 {
00860 return all_children_itors(
00861 all_children_iterator(ordered_children.begin()),
00862 all_children_iterator(ordered_children.end()));
00863 }
00864
00865 config config::get_diff(const config& c) const
00866 {
00867 check_valid(c);
00868
00869 config res;
00870 get_diff(c, res);
00871 return res;
00872 }
00873
00874 void config::get_diff(const config& c, config& res) const
00875 {
00876 check_valid(c);
00877 check_valid(res);
00878
00879 config* inserts = NULL;
00880
00881 attribute_map::const_iterator i;
00882 for(i = values.begin(); i != values.end(); ++i) {
00883 const attribute_map::const_iterator j = c.values.find(i->first);
00884 if(j == c.values.end() || (i->second != j->second && i->second != "")) {
00885 if(inserts == NULL) {
00886 inserts = &res.add_child("insert");
00887 }
00888
00889 (*inserts)[i->first] = i->second;
00890 }
00891 }
00892
00893 config* deletes = NULL;
00894
00895 for(i = c.values.begin(); i != c.values.end(); ++i) {
00896 const attribute_map::const_iterator itor = values.find(i->first);
00897 if(itor == values.end() || itor->second == "") {
00898 if(deletes == NULL) {
00899 deletes = &res.add_child("delete");
00900 }
00901
00902 (*deletes)[i->first] = "x";
00903 }
00904 }
00905
00906 std::vector<std::string> entities;
00907
00908 child_map::const_iterator ci;
00909 for(ci = children.begin(); ci != children.end(); ++ci) {
00910 entities.push_back(ci->first);
00911 }
00912
00913 for(ci = c.children.begin(); ci != c.children.end(); ++ci) {
00914 if(children.count(ci->first) == 0) {
00915 entities.push_back(ci->first);
00916 }
00917 }
00918
00919 for(std::vector<std::string>::const_iterator itor = entities.begin(); itor != entities.end(); ++itor) {
00920
00921 const child_map::const_iterator itor_a = children.find(*itor);
00922 const child_map::const_iterator itor_b = c.children.find(*itor);
00923
00924 static const child_list dummy;
00925
00926
00927 const child_list& a = itor_a != children.end() ? itor_a->second : dummy;
00928 const child_list& b = itor_b != c.children.end() ? itor_b->second : dummy;
00929
00930 size_t ndeletes = 0;
00931 size_t ai = 0, bi = 0;
00932 while(ai != a.size() || bi != b.size()) {
00933
00934 if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
00935 ++ai;
00936 ++bi;
00937 } else {
00938
00939
00940 std::stringstream buf;
00941
00942
00943
00944 if(b.size() - bi > a.size() - ai) {
00945 config& new_delete = res.add_child("delete_child");
00946 buf << bi - ndeletes;
00947 new_delete.values["index"] = buf.str();
00948 new_delete.add_child(*itor);
00949
00950 ++ndeletes;
00951 ++bi;
00952 }
00953
00954
00955
00956 else if(b.size() - bi < a.size() - ai) {
00957 config& new_insert = res.add_child("insert_child");
00958 buf << ai;
00959 new_insert.values["index"] = buf.str();
00960 new_insert.add_child(*itor,*a[ai]);
00961
00962 ++ai;
00963 }
00964
00965
00966
00967 else {
00968 config& new_change = res.add_child("change_child");
00969 buf << bi;
00970 new_change.values["index"] = buf.str();
00971 new_change.add_child(*itor,a[ai]->get_diff(*b[bi]));
00972
00973 ++ai;
00974 ++bi;
00975 }
00976 }
00977 }
00978 }
00979 }
00980
00981 void config::apply_diff(const config& diff, bool track )
00982 {
00983 check_valid(diff);
00984
00985 if (track) values[diff_track_attribute] = "modified";
00986
00987 if (const config &inserts = diff.child("insert")) {
00988 foreach (const attribute &v, inserts.attribute_range()) {
00989 values[v.first] = v.second;
00990 }
00991 }
00992
00993 if (const config &deletes = diff.child("delete")) {
00994 foreach (const attribute &v, deletes.attribute_range()) {
00995 values.erase(v.first);
00996 }
00997 }
00998
00999 foreach (const config &i, diff.child_range("change_child"))
01000 {
01001 const size_t index = lexical_cast<size_t>(i["index"].str());
01002 foreach (const any_child &item, i.all_children_range())
01003 {
01004 if (item.key.empty()) {
01005 continue;
01006 }
01007
01008 const child_map::iterator itor = children.find(item.key);
01009 if(itor == children.end() || index >= itor->second.size()) {
01010 throw error("error in diff: could not find element '" + item.key + "'");
01011 }
01012
01013 itor->second[index]->apply_diff(item.cfg, track);
01014 }
01015 }
01016
01017 foreach (const config &i, diff.child_range("insert_child"))
01018 {
01019 const size_t index = lexical_cast<size_t>(i["index"].str());
01020 foreach (const any_child &item, i.all_children_range()) {
01021 config& inserted = add_child_at(item.key, item.cfg, index);
01022 if (track) inserted[diff_track_attribute] = "new";
01023 }
01024 }
01025
01026 foreach (const config &i, diff.child_range("delete_child"))
01027 {
01028 const size_t index = lexical_cast<size_t>(i["index"].str());
01029 foreach (const any_child &item, i.all_children_range()) {
01030 if (!track) {
01031 remove_child(item.key, index);
01032 } else {
01033 const child_map::iterator itor = children.find(item.key);
01034 if(itor == children.end() || index >= itor->second.size()) {
01035 throw error("error in diff: could not find element '" + item.key + "'");
01036 }
01037 itor->second[index]->values[diff_track_attribute] = "deleted";
01038 }
01039 }
01040 }
01041 }
01042
01043 void config::clear_diff_track(const config& diff)
01044 {
01045 remove_attribute(diff_track_attribute);
01046 foreach (const config &i, diff.child_range("delete_child"))
01047 {
01048 const size_t index = lexical_cast<size_t>(i["index"].str());
01049 foreach (const any_child &item, i.all_children_range()) {
01050 remove_child(item.key, index);
01051 }
01052 }
01053
01054 foreach (const config &i, diff.child_range("change_child"))
01055 {
01056 const size_t index = lexical_cast<size_t>(i["index"].str());
01057 foreach (const any_child &item, i.all_children_range())
01058 {
01059 if (item.key.empty()) {
01060 continue;
01061 }
01062
01063 const child_map::iterator itor = children.find(item.key);
01064 if(itor == children.end() || index >= itor->second.size()) {
01065 throw error("error in diff: could not find element '" + item.key + "'");
01066 }
01067
01068 itor->second[index]->clear_diff_track(item.cfg);
01069 }
01070 }
01071 foreach (const any_child &value, all_children_range()) {
01072 const_cast<config *>(&value.cfg)->remove_attribute(diff_track_attribute);
01073 }
01074 }
01075
01076 void config::merge_with(const config& c)
01077 {
01078 check_valid(c);
01079
01080 std::map<std::string, unsigned> visitations;
01081
01082
01083 merge_attributes(c);
01084
01085
01086 all_children_iterator::Itor i, i_end = ordered_children.end();
01087 for(i = ordered_children.begin(); i != i_end; ++i) {
01088 const std::string& tag = i->pos->first;
01089 child_map::const_iterator j = c.children.find(tag);
01090 if (j != c.children.end()) {
01091 unsigned &visits = visitations[tag];
01092 if(visits < j->second.size()) {
01093 (i->pos->second[i->index])->merge_with(*j->second[visits++]);
01094 }
01095 }
01096 }
01097
01098
01099 for(child_map::const_iterator j = c.children.begin(); j != c.children.end(); ++j) {
01100 const std::string& tag = j->first;
01101 unsigned &visits = visitations[tag];
01102 while(visits < j->second.size()) {
01103 add_child(tag, *j->second[visits++]);
01104 }
01105 }
01106 }
01107
01108 bool config::matches(const config &filter) const
01109 {
01110 check_valid(filter);
01111
01112 foreach (const attribute &i, filter.attribute_range())
01113 {
01114 const attribute_value *v = get(i.first);
01115 if (!v || *v != i.second) return false;
01116 }
01117
01118 foreach (const any_child &i, filter.all_children_range())
01119 {
01120 if (i.key == "not") {
01121 if (matches(i.cfg)) return false;
01122 continue;
01123 }
01124 bool found = false;
01125 foreach (const config &j, child_range(i.key)) {
01126 if (j.matches(i.cfg)) {
01127 found = true;
01128 break;
01129 }
01130 }
01131 if(!found) return false;
01132 }
01133 return true;
01134 }
01135
01136 std::string config::debug() const
01137 {
01138 check_valid();
01139
01140 std::ostringstream outstream;
01141 outstream << *this;
01142 return outstream.str();
01143 }
01144
01145 std::ostream& operator << (std::ostream& outstream, const config& cfg)
01146 {
01147 static int i = 0;
01148 i++;
01149 foreach (const config::attribute &val, cfg.attribute_range()) {
01150 for (int j = 0; j < i-1; j++){ outstream << char(9); }
01151 outstream << val.first << " = " << val.second << '\n';
01152 }
01153 foreach (const config::any_child &child, cfg.all_children_range())
01154 {
01155 for (int j = 0; j < i - 1; ++j) outstream << char(9);
01156 outstream << "[" << child.key << "]\n";
01157 outstream << child.cfg;
01158 for (int j = 0; j < i - 1; ++j) outstream << char(9);
01159 outstream << "[/" << child.key << "]\n";
01160 }
01161 i--;
01162 return outstream;
01163 }
01164
01165 std::string config::hash() const
01166 {
01167 check_valid();
01168
01169 static const unsigned int hash_length = 128;
01170 static const char hash_string[] =
01171 "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
01172 char hash_str[hash_length + 1];
01173 std::string::const_iterator c;
01174
01175 unsigned int i;
01176 for(i = 0; i != hash_length; ++i) {
01177 hash_str[i] = 'a';
01178 }
01179 hash_str[hash_length] = 0;
01180
01181 i = 0;
01182 foreach (const attribute &val, values)
01183 {
01184 for (c = val.first.begin(); c != val.first.end(); ++c) {
01185 hash_str[i] ^= *c;
01186 if (++i == hash_length) i = 0;
01187 }
01188 std::string base_str = val.second.t_str().base_str();
01189 for (c = base_str.begin(); c != base_str.end(); ++c) {
01190 hash_str[i] ^= *c;
01191 if (++i == hash_length) i = 0;
01192 }
01193 }
01194
01195 foreach (const any_child &ch, all_children_range())
01196 {
01197 std::string child_hash = ch.cfg.hash();
01198 foreach (char c, child_hash) {
01199 hash_str[i] ^= c;
01200 ++i;
01201 if(i == hash_length) {
01202 i = 0;
01203 }
01204 }
01205 }
01206
01207 for(i = 0; i != hash_length; ++i) {
01208 hash_str[i] = hash_string[
01209 static_cast<unsigned>(hash_str[i]) % strlen(hash_string)];
01210 }
01211
01212 return std::string(hash_str);
01213 }
01214
01215 void config::swap(config& cfg)
01216 {
01217 check_valid(cfg);
01218
01219 values.swap(cfg.values);
01220 children.swap(cfg.children);
01221 ordered_children.swap(cfg.ordered_children);
01222 }
01223
01224 bool operator==(const config& a, const config& b)
01225 {
01226 a.check_valid(b);
01227
01228 if (a.values != b.values)
01229 return false;
01230
01231 config::all_children_itors x = a.all_children_range(), y = b.all_children_range();
01232 for (; x.first != x.second && y.first != y.second; ++x.first, ++y.first) {
01233 if (x.first->key != y.first->key || x.first->cfg != y.first->cfg) {
01234 return false;
01235 }
01236 }
01237
01238 return x.first == x.second && y.first == y.second;
01239 }