config.cpp

Go to the documentation of this file.
00001 /* $Id: config.cpp 54257 2012-05-20 09:56:20Z mordante $ */
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004    Copyright (C) 2005 - 2012 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY.
00013 
00014    See the COPYING file for more details.
00015 */
00016 
00017 /**
00018  * @file
00019  * Routines related to configuration-files / WML.
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      * Implementation for the wrappers for
00044      * [const] config& child(const std::string& key, const std::string& parent);
00045      *
00046      * @tparam T                  A pointer to the config.
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          * @todo Implement a proper wml_exception here.
00067          *
00068          * at the moment there seem to be dependency issues, which i don't want
00069          * to fix right now.
00070          */
00071 //      FAIL(missing_mandatory_wml_section(parent, key));
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     // key might be a reference to i_src->first, so it is no longer usable.
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     /* Find the position with the correct index and decrement all the
00618        indices in the ordering that are above this index. */
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     // Remove from the child map.
00630     delete pos->second[index];
00631     pos->second.erase(pos->second.begin() + index);
00632 
00633     // Erase from the ordering and return the next position.
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 } // end namespace
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      * Helper struct for iterative config clearing.
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; //the config being inspected
00781         config::child_map::iterator mi; //current child map entry
00782         size_t vi; //index into the child map item vector
00783     };
00784 }
00785 
00786 void config::clear()
00787 {
00788     // No validity check for this function.
00789 
00790     if (!children.empty()) {
00791         //start with this node, the first entry in the child map,
00792         //zeroeth element in that entry
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; //special case for a slight speed increase?
00809                     } else {
00810                         //descend to the next level
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                 //reached end of child map for this element - all child nodes
00823                 //have beed deleted, so it's safe to clear the map, delete the
00824                 //node and move up one level
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         // Get the two child lists. 'b' has to be modified to look like 'a'.
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             // If the two elements are the same, nothing needs to be done.
00934             if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
00935                 ++ai;
00936                 ++bi;
00937             } else {
00938                 // We have to work out what the most appropriate operation --
00939                 // delete, insert, or change is the best to get b[bi] looking like a[ai].
00940                 std::stringstream buf;
00941 
00942                 // If b has more elements than a, then we assume this element
00943                 // is an element that needs deleting.
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                 // If b has less elements than a, then we assume this element
00955                 // is an element that needs inserting.
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                 // Otherwise, they have the same number of elements,
00966                 // so try just changing this element to match.
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 /* = false */)
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     // Merge attributes first
01083     merge_attributes(c);
01084 
01085     // Now merge shared tags
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     // Now add any unvisited tags
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:32 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs