config.cpp

Go to the documentation of this file.
00001 /* $Id: config.cpp 26449 2008-05-07 17:57:47Z mordante $ */
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004    Copyright (C) 2005 - 2008 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 version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 //! @file config.cpp
00017 //! Routines related to configuration-files / WML.
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                 //decrement subsequent child indeces of the same key
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     // Remove from the ordering
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     // Decrement all indices in the ordering that are above this index,
00261     // since everything is getting shifted back by 1.
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     // Remove from the child map
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 } // end namespace
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         // Get the two child lists. 'b' has to be modified to look like 'a'.
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             // If the two elements are the same, nothing needs to be done.
00494             if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
00495                 ++ai;
00496                 ++bi;
00497             } else {
00498                 // We have to work out what the most appropriate operation --
00499                 // delete, insert, or change is the best to get b[bi] looking like a[ai].
00500                 std::stringstream buf;
00501 
00502                 // If b has more elements than a, then we assume this element
00503                 // is an element that needs deleting.
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                 // If b has less elements than a, then we assume this element
00515                 // is an element that needs inserting.
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                 // Otherwise, they have the same number of elements,
00526                 // so try just changing this element to match.
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     // Merge attributes first
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     // Now merge shared tags
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     // Now add any unvisited tags
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     // Merge not existing attributes first
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     // Now merge unshared tags
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     // First match values. all values should match.
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     // Now, match the kids
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 //#define TEST_CONFIG
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

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs