variable.cpp

Go to the documentation of this file.
00001 /* $Id: variable.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004    Copyright (C) 2005 - 2012 by Philippe Plantier <ayin@anathas.org>
00005 
00006    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY.
00014 
00015    See the COPYING file for more details.
00016 */
00017 
00018 /**
00019  *  @file
00020  *  Manage WML-variables.
00021  */
00022 
00023 #include "global.hpp"
00024 
00025 #include "variable.hpp"
00026 
00027 #include "foreach.hpp"
00028 #include "formula_string_utils.hpp"
00029 #include "gamestatus.hpp"
00030 #include "log.hpp"
00031 #include "resources.hpp"
00032 #include "unit.hpp"
00033 #include "unit_map.hpp"
00034 #include "team.hpp"
00035 
00036 #include <boost/variant.hpp>
00037 
00038 static lg::log_domain log_engine("engine");
00039 #define LOG_NG LOG_STREAM(info, log_engine)
00040 #define WRN_NG LOG_STREAM(warn, log_engine)
00041 #define ERR_NG LOG_STREAM(err, log_engine)
00042 
00043 namespace
00044 {
00045     /**
00046      * @todo FIXME: the variable repository should be
00047      * a class of variable.hpp, and not the game_state.
00048      */
00049     #define repos (resources::state_of_game)
00050 
00051     // keeps track of insert_tag variables used by get_parsed_config
00052     std::set<std::string> vconfig_recursion;
00053 
00054     /**
00055      * config_cache is a map to track temp storage of inserted tags on the heap.
00056      * If an event is spawned from a variable or any ActionWML from a volatile
00057      * source is to be executed safely then its memory should be managed by vconfig
00058      */
00059     std::map<config const *, int> config_cache;
00060 
00061     // map by hash for equivalent inserted tags already in the cache
00062     std::map<std::string const *, config const *> hash_to_cache;
00063 
00064     // map to remember config hashes that have already been calculated
00065     std::map<config const *, std::string const *> config_hashes;
00066 
00067     config empty_config;
00068 
00069     struct compare_str_ptr {
00070         bool operator()(const std::string* s1, const std::string* s2) const
00071         {
00072             return (*s1) < (*s2);
00073         }
00074     };
00075 
00076     class hash_memory_manager {
00077     public:
00078         hash_memory_manager() :
00079             mem_()
00080         {
00081         }
00082 
00083         const std::string *find(const std::string& str) const {
00084             std::set<std::string const*, compare_str_ptr>::const_iterator itor = mem_.lower_bound(&str);
00085             if(itor == mem_.end() || **itor != str) {
00086                 return NULL;
00087             }
00088             return *itor;
00089         }
00090         void insert(const std::string *newhash) {
00091             mem_.insert(newhash);
00092         }
00093         void clear() {
00094             hash_to_cache.clear();
00095             config_hashes.clear();
00096             std::set<std::string const*, compare_str_ptr>::iterator mem_it,
00097                 mem_end = mem_.end();
00098             for(mem_it = mem_.begin(); mem_it != mem_end; ++mem_it) {
00099                 delete *mem_it;
00100             }
00101             mem_.clear();
00102         }
00103         ~hash_memory_manager() {
00104             clear();
00105         }
00106     private:
00107         std::set<std::string const*, compare_str_ptr> mem_;
00108     };
00109     hash_memory_manager hash_memory;
00110 }
00111 
00112 static const std::string* get_hash_of(const config* cp) {
00113     //first see if the memory of a constant config hash exists
00114     std::map<config const *, std::string const *>::iterator ch_it = config_hashes.find(cp);
00115     if(ch_it != config_hashes.end()) {
00116         return ch_it->second;
00117     }
00118     //next see if an equivalent hash string has been memorized
00119     const std::string & temp_hash = cp->hash();
00120     std::string const* find_hash = hash_memory.find(temp_hash);
00121     if(find_hash != NULL) {
00122         return find_hash;
00123     }
00124     //finally, we just allocate a new hash string to memory
00125     std::string* new_hash = new std::string(temp_hash);
00126     hash_memory.insert(new_hash);
00127     //do not insert into config_hashes (may be a variable config)
00128     return new_hash;
00129 }
00130 
00131 static void increment_config_usage(const config*& key) {
00132     if(key == NULL) return;
00133     std::map<config const *, int>::iterator this_usage =  config_cache.find(key);
00134     if(this_usage != config_cache.end()) {
00135         ++this_usage->second;
00136         return;
00137     }
00138     const std::string *hash = get_hash_of(key);
00139     const config *& cfg_store = hash_to_cache[hash];
00140     if(cfg_store == NULL || (key != cfg_store && *key != *cfg_store)) {
00141         // this is a new volatile config: allocate some memory & update key
00142         key = new config(*key);
00143         // remember this cache to prevent an equivalent one from being created
00144         cfg_store = key;
00145         // since the config is now constant, we can safely memorize the hash
00146         config_hashes[key] = hash;
00147     } else {
00148         // swap the key with an equivalent or equal one in the cache
00149         key = cfg_store;
00150     }
00151     ++(config_cache[key]);
00152 }
00153 
00154 static void decrement_config_usage(const config* key) {
00155     if(key == NULL) return;
00156     std::map<config const *, int>::iterator this_usage = config_cache.find(key);
00157     assert(this_usage != config_cache.end());
00158     if(--(this_usage->second) == 0) {
00159         config_cache.erase(this_usage);
00160         if(config_cache.empty()) {
00161             hash_memory.clear();
00162         } else {
00163             if(!hash_to_cache.empty()) {
00164                 hash_to_cache.erase(get_hash_of(key));
00165             }
00166             config_hashes.erase(key);
00167         }
00168         delete key;
00169     }
00170 }
00171 
00172 vconfig::vconfig() :
00173     cfg_(NULL), cache_key_(NULL)
00174 {
00175 }
00176 
00177 vconfig::vconfig(const config* cfg, const config * cache_key) :
00178     cfg_(cfg), cache_key_(cache_key)
00179 {
00180     increment_config_usage(cache_key_);
00181     if(cache_key_ != cache_key) {
00182         //location of volatile cfg has moved
00183         cfg_ = cache_key_;
00184     }
00185 }
00186 
00187 vconfig::vconfig(const config &cfg, bool is_volatile) :
00188     cfg_(&cfg), cache_key_(&cfg)
00189 {
00190     if(is_volatile) {
00191         increment_config_usage(cache_key_);
00192         if (cache_key_ != &cfg) {
00193             //location of volatile cfg has moved
00194             cfg_ = cache_key_;
00195         }
00196     } else {
00197         cache_key_ = NULL;
00198     }
00199 }
00200 
00201 vconfig::vconfig(const vconfig& v) :
00202     cfg_(v.cfg_), cache_key_(v.cache_key_)
00203 {
00204     increment_config_usage(cache_key_);
00205 }
00206 
00207 vconfig::~vconfig()
00208 {
00209     decrement_config_usage(cache_key_);
00210 }
00211 
00212 vconfig vconfig::empty_vconfig()
00213 {
00214     return vconfig(config(), true);
00215 }
00216 
00217 vconfig vconfig::unconstructed_vconfig()
00218 {
00219     return vconfig();
00220 }
00221 
00222 vconfig& vconfig::operator=(const vconfig& cfg)
00223 {
00224     const config* prev_key = cache_key_;
00225     cfg_ = cfg.cfg_;
00226     cache_key_ = cfg.cache_key_;
00227     increment_config_usage(cache_key_);
00228     decrement_config_usage(prev_key);
00229     return *this;
00230 }
00231 
00232 const config vconfig::get_parsed_config() const
00233 {
00234     config res;
00235 
00236     foreach (const config::attribute &i, cfg_->attribute_range()) {
00237         res[i.first] = expand(i.first);
00238     }
00239 
00240     foreach (const config::any_child &child, cfg_->all_children_range())
00241     {
00242         if (child.key == "insert_tag") {
00243             vconfig insert_cfg(child.cfg);
00244             const t_string& name = insert_cfg["name"];
00245             const t_string& vname = insert_cfg["variable"];
00246             if(!vconfig_recursion.insert(vname).second) {
00247                 throw recursion_error("vconfig::get_parsed_config() infinite recursion detected, aborting");
00248             }
00249             try {
00250                 variable_info vinfo(vname, false, variable_info::TYPE_CONTAINER);
00251                 if(!vinfo.is_valid) {
00252                     res.add_child(name); //add empty tag
00253                 } else if(vinfo.explicit_index) {
00254                     res.add_child(name, vconfig(vinfo.as_container()).get_parsed_config());
00255                 } else {
00256                     variable_info::array_range range = vinfo.as_array();
00257                     if(range.first == range.second) {
00258                         res.add_child(name); //add empty tag
00259                     }
00260                     while(range.first != range.second) {
00261                         res.add_child(name, vconfig(*range.first++).get_parsed_config());
00262                     }
00263                 }
00264                 vconfig_recursion.erase(vname);
00265             } catch(recursion_error &err) {
00266                 vconfig_recursion.erase(vname);
00267                 WRN_NG << err.message << std::endl;
00268                 if(vconfig_recursion.empty()) {
00269                     res.add_child("insert_tag", insert_cfg.get_config());
00270                 } else {
00271                     // throw to the top [insert_tag] which started the recursion
00272                     throw;
00273                 }
00274             }
00275         } else {
00276             res.add_child(child.key, vconfig(child.cfg).get_parsed_config());
00277         }
00278     }
00279     return res;
00280 }
00281 
00282 vconfig::child_list vconfig::get_children(const std::string& key) const
00283 {
00284     vconfig::child_list res;
00285 
00286     foreach (const config::any_child &child, cfg_->all_children_range())
00287     {
00288         if (child.key == key) {
00289             res.push_back(vconfig(&child.cfg, cache_key_));
00290         } else if (child.key == "insert_tag") {
00291             vconfig insert_cfg(child.cfg);
00292             if(insert_cfg["name"] == key) {
00293                 variable_info vinfo(insert_cfg["variable"], false, variable_info::TYPE_CONTAINER);
00294                 if(!vinfo.is_valid) {
00295                     //push back an empty tag
00296                     res.push_back(vconfig(empty_config));
00297                 } else if(vinfo.explicit_index) {
00298                     config * cp = &(vinfo.as_container());
00299                     res.push_back(vconfig(cp, cp));
00300                 } else {
00301                     variable_info::array_range range = vinfo.as_array();
00302                     if(range.first == range.second) {
00303                         //push back an empty tag
00304                         res.push_back(vconfig(empty_config));
00305                     }
00306                     while(range.first != range.second) {
00307                         config *cp = &*range.first++;
00308                         res.push_back(vconfig(cp, cp));
00309                     }
00310                 }
00311             }
00312         }
00313     }
00314     return res;
00315 }
00316 
00317 vconfig vconfig::child(const std::string& key) const
00318 {
00319     if (const config &natural = cfg_->child(key)) {
00320         return vconfig(&natural, cache_key_);
00321     }
00322     foreach (const config &ins, cfg_->child_range("insert_tag"))
00323     {
00324         vconfig insert_cfg(ins);
00325         if(insert_cfg["name"] == key) {
00326             variable_info vinfo(insert_cfg["variable"], false, variable_info::TYPE_CONTAINER);
00327             if(!vinfo.is_valid) {
00328                 return vconfig(empty_config);
00329             }
00330             config * cp = &(vinfo.as_container());
00331             return vconfig(cp, cp);
00332         }
00333     }
00334     return unconstructed_vconfig();
00335 }
00336 
00337 bool vconfig::has_child(const std::string& key) const
00338 {
00339     if (cfg_->child(key)) {
00340         return true;
00341     }
00342     foreach (const config &ins, cfg_->child_range("insert_tag"))
00343     {
00344         vconfig insert_cfg(ins);
00345         if(insert_cfg["name"] == key) {
00346             return true;
00347         }
00348     }
00349     return false;
00350 }
00351 
00352 struct vconfig_expand_visitor : boost::static_visitor<void>
00353 {
00354     config::attribute_value &result;
00355     vconfig_expand_visitor(config::attribute_value &r): result(r) {}
00356     template<typename T> void operator()(T const &) const {}
00357     void operator()(const std::string &s) const
00358     {
00359         result = utils::interpolate_variables_into_string(s, *repos);
00360     }
00361     void operator()(const t_string &s) const
00362     {
00363         result = utils::interpolate_variables_into_tstring(s, *repos);
00364     }
00365 };
00366 
00367 config::attribute_value vconfig::expand(const std::string &key) const
00368 {
00369     config::attribute_value val = (*cfg_)[key];
00370     if (repos)
00371         boost::apply_visitor(vconfig_expand_visitor(val), val.value);
00372     return val;
00373 }
00374 
00375 vconfig::all_children_iterator::all_children_iterator(const Itor &i, const config *cache_key)
00376 : i_(i), inner_index_(0), cache_key_(cache_key)
00377 {
00378 }
00379 
00380 vconfig::all_children_iterator& vconfig::all_children_iterator::operator++()
00381 {
00382     if (inner_index_ >= 0 && i_->key == "insert_tag")
00383     {
00384         variable_info vinfo(vconfig(i_->cfg)["variable"], false, variable_info::TYPE_CONTAINER);
00385         if(vinfo.is_valid && !vinfo.explicit_index) {
00386             variable_info::array_range range = vinfo.as_array();
00387             if (++inner_index_ < std::distance(range.first, range.second)) {
00388                 return *this;
00389             }
00390             inner_index_ = 0;
00391         }
00392     }
00393     ++i_;
00394     return *this;
00395 }
00396 
00397 vconfig::all_children_iterator vconfig::all_children_iterator::operator++(int)
00398 {
00399     vconfig::all_children_iterator i = *this;
00400     this->operator++();
00401     return i;
00402 }
00403 
00404 vconfig::all_children_iterator::reference vconfig::all_children_iterator::operator*() const
00405 {
00406     return value_type(get_key(), get_child());
00407 }
00408 
00409 vconfig::all_children_iterator::pointer vconfig::all_children_iterator::operator->() const
00410 {
00411     pointer_proxy p = { value_type(get_key(), get_child()) };
00412     return p;
00413 }
00414 
00415 
00416 std::string vconfig::all_children_iterator::get_key() const
00417 {
00418     const std::string &key = i_->key;
00419     if (inner_index_ >= 0 && key == "insert_tag") {
00420         return vconfig(i_->cfg)["name"];
00421     }
00422     return key;
00423 }
00424 
00425 vconfig vconfig::all_children_iterator::get_child() const
00426 {
00427     if (inner_index_ >= 0 && i_->key == "insert_tag")
00428     {
00429         config * cp;
00430         variable_info vinfo(vconfig(i_->cfg)["variable"], false, variable_info::TYPE_CONTAINER);
00431         if(!vinfo.is_valid) {
00432             return vconfig(empty_config);
00433         } else if(inner_index_ == 0) {
00434             cp = &(vinfo.as_container());
00435             return vconfig(cp, cp);
00436         }
00437         variable_info::array_range r = vinfo.as_array();
00438         std::advance(r.first, inner_index_);
00439         cp = &*r.first;
00440         return vconfig(cp, cp);
00441     }
00442     return vconfig(&i_->cfg, cache_key_);
00443 }
00444 
00445 bool vconfig::all_children_iterator::operator==(const all_children_iterator &i) const
00446 {
00447     return i_ == i.i_ && inner_index_ == i.inner_index_;
00448 }
00449 
00450 vconfig::all_children_iterator vconfig::ordered_begin() const
00451 {
00452     return all_children_iterator(cfg_->ordered_begin(), cache_key_);
00453 }
00454 
00455 vconfig::all_children_iterator vconfig::ordered_end() const
00456 {
00457     return all_children_iterator(cfg_->ordered_end(), cache_key_);
00458 }
00459 
00460 namespace variable
00461 {
00462     manager::~manager()
00463     {
00464         hash_memory.clear();
00465     }
00466 }
00467 
00468 scoped_wml_variable::scoped_wml_variable(const std::string& var_name) :
00469     previous_val_(),
00470     var_name_(var_name),
00471     activated_(false)
00472 {
00473     repos->scoped_variables.push_back(this);
00474 }
00475 
00476 config &scoped_wml_variable::store(const config &var_value)
00477 {
00478     foreach (const config &i, repos->get_variables().child_range(var_name_)) {
00479         previous_val_.add_child(var_name_, i);
00480     }
00481     repos->clear_variable_cfg(var_name_);
00482     config &res = repos->add_variable_cfg(var_name_, var_value);
00483     LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been auto-stored.\n";
00484     activated_ = true;
00485     return res;
00486 }
00487 
00488 scoped_wml_variable::~scoped_wml_variable()
00489 {
00490     if(activated_) {
00491         repos->clear_variable_cfg(var_name_);
00492         foreach (const config &i, previous_val_.child_range(var_name_)) {
00493             repos->add_variable_cfg(var_name_, i);
00494         }
00495         LOG_NG << "scoped_wml_variable: var_name \"" << var_name_ << "\" has been reverted.\n";
00496     }
00497     assert(repos->scoped_variables.back() == this);
00498     repos->scoped_variables.pop_back();
00499 }
00500 
00501 void scoped_xy_unit::activate()
00502 {
00503     map_location loc = map_location(x_, y_);
00504     unit_map::const_iterator itor = umap_.find(loc);
00505     if(itor != umap_.end()) {
00506         config &tmp_cfg = store();
00507         itor->write(tmp_cfg);
00508         tmp_cfg["x"] = x_ + 1;
00509         tmp_cfg["y"] = y_ + 1;
00510         LOG_NG << "auto-storing $" << name() << " at (" << loc << ")\n";
00511     } else {
00512         ERR_NG << "failed to auto-store $" << name() << " at (" << loc << ")\n";
00513     }
00514 }
00515 
00516 void scoped_weapon_info::activate()
00517 {
00518     if (data_) {
00519         store(data_);
00520     }
00521 }
00522 
00523 void scoped_recall_unit::activate()
00524 {
00525     const std::vector<team>& teams = teams_manager::get_teams();
00526     std::vector<team>::const_iterator team_it;
00527     for (team_it = teams.begin(); team_it != teams.end(); ++team_it) {
00528         if (team_it->save_id() == player_ )
00529             break;
00530     }
00531 
00532     if(team_it != teams.end()) {
00533         if(team_it->recall_list().size() > recall_index_) {
00534             config &tmp_cfg = store();
00535             team_it->recall_list()[recall_index_].write(tmp_cfg);
00536             tmp_cfg["x"] = "recall";
00537             tmp_cfg["y"] = "recall";
00538             LOG_NG << "auto-storing $" << name() << " for player: " << player_
00539                 << " at recall index: " << recall_index_ << '\n';
00540         } else {
00541             ERR_NG << "failed to auto-store $" << name() << " for player: " << player_
00542                 << " at recall index: " << recall_index_ << '\n';
00543         }
00544     } else {
00545         ERR_NG << "failed to auto-store $" << name() << " for player: " << player_ << '\n';
00546     }
00547 }
00548 
00549 namespace {
00550 bool recursive_activation = false;
00551 
00552 /** Turns on any auto-stored variables */
00553 void activate_scope_variable(std::string var_name)
00554 {
00555     if(recursive_activation)
00556         return;
00557     const std::string::iterator itor = std::find(var_name.begin(),var_name.end(),'.');
00558     if(itor != var_name.end()) {
00559         var_name.erase(itor, var_name.end());
00560     }
00561     std::vector<scoped_wml_variable*>::reverse_iterator rit;
00562     for(rit = repos->scoped_variables.rbegin(); rit != repos->scoped_variables.rend(); ++rit) {
00563         if((**rit).name() == var_name) {
00564             recursive_activation = true;
00565             if(!(**rit).activated()) {
00566                 (**rit).activate();
00567             }
00568             recursive_activation = false;
00569             break;
00570         }
00571     }
00572 }
00573 } // end anonymous namespace
00574 
00575 variable_info::variable_info(const std::string& varname,
00576         bool force_valid, TYPE validation_type) :
00577     vartype(validation_type),
00578     is_valid(false),
00579     key(),
00580     explicit_index(false),
00581     index(0),
00582     vars(NULL)
00583 {
00584     assert(repos != NULL);
00585     activate_scope_variable(varname);
00586 
00587     vars = &repos->variables_;
00588     key = varname;
00589     std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
00590     int dot_index = key.find('.');
00591 
00592     bool force_length = false;
00593     // example varname = "unit_store.modifications.trait[0]"
00594     while(itor != key.end()) { // subvar access
00595         std::string element=key.substr(0,dot_index);
00596         key = key.substr(dot_index+1);
00597 
00598         size_t inner_index = 0;
00599         const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
00600         const bool inner_explicit_index = index_start != element.end();
00601         if(inner_explicit_index) {
00602             const std::string::iterator index_end = std::find(index_start,element.end(),']');
00603             const std::string index_str(index_start+1,index_end);
00604             inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
00605             if(inner_index > game_config::max_loop) {
00606                 ERR_NG << "variable_info: index greater than " << game_config::max_loop
00607                        << ", truncated\n";
00608                 inner_index = game_config::max_loop;
00609             }
00610             element = std::string(element.begin(),index_start);
00611         }
00612 
00613         size_t size = vars->child_count(element);
00614         if(size <= inner_index) {
00615             if(force_valid) {
00616                 // Add elements to the array until the requested size is attained
00617                 if(inner_explicit_index || key != "length") {
00618                     for(; size <= inner_index; ++size) {
00619                         vars->add_child(element);
00620                     }
00621                 }
00622             } else if(inner_explicit_index) {
00623                 WRN_NG << "variable_info: invalid WML array index, "
00624                     << varname << std::endl;
00625                 return;
00626             } else if(varname.length() >= 7 && varname.substr(varname.length()-7) == ".length") {
00627                 // require '.' to avoid matching suffixes -> requires varname over key to always find length
00628                 // return length 0 for non-existent WML array (handled below)
00629                 force_length = true;
00630             } else {
00631                 WRN_NG << "variable_info: retrieving member of non-existent WML container, "
00632                 << varname << std::endl;
00633                 return;
00634             }
00635         }
00636         if((!inner_explicit_index && key == "length") || force_length) {
00637             switch(vartype) {
00638             case variable_info::TYPE_ARRAY:
00639             case variable_info::TYPE_CONTAINER:
00640                 WRN_NG << "variable_info: using reserved WML variable as wrong type, "
00641                     << varname << std::endl;
00642                 is_valid = force_valid || repos->temporaries_.child(varname);
00643                 break;
00644             case variable_info::TYPE_SCALAR:
00645             default:
00646                 // Store the length of the array as a temporary variable
00647                 repos->temporaries_[varname] = int(size);
00648                 is_valid = true;
00649                 break;
00650             }
00651             key = varname;
00652             vars = &repos->temporaries_;
00653             return;
00654         }
00655 
00656         vars = &vars->child(element, inner_index);
00657         itor = std::find(key.begin(),key.end(),'.');
00658         dot_index = key.find('.');
00659     } // end subvar access
00660 
00661     const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
00662     explicit_index = index_start != key.end();
00663     if(explicit_index) {
00664         const std::string::iterator index_end = std::find(index_start,key.end(),']');
00665         const std::string index_str(index_start+1,index_end);
00666         index = static_cast<size_t>(lexical_cast_default<int>(index_str));
00667         if(index > game_config::max_loop) {
00668             ERR_NG << "variable_info: index greater than " << game_config::max_loop
00669                    << ", truncated\n";
00670             index = game_config::max_loop;
00671         }
00672         key = std::string(key.begin(),index_start);
00673         size_t size = vars->child_count(key);
00674         if(size <= index) {
00675             if(!force_valid) {
00676                 WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
00677                 return;
00678             }
00679             for(; size <= index; ++size) {
00680                 vars->add_child(key);
00681             }
00682         }
00683         switch(vartype) {
00684         case variable_info::TYPE_ARRAY:
00685             vars = &vars->child(key, index);
00686             key = "__array";
00687             is_valid = force_valid || vars->child(key);
00688             break;
00689         case variable_info::TYPE_SCALAR:
00690             vars = &vars->child(key, index);
00691             key = "__value";
00692             is_valid = force_valid || vars->has_attribute(key);
00693             break;
00694         case variable_info::TYPE_CONTAINER:
00695         case variable_info::TYPE_UNSPECIFIED:
00696         default:
00697             is_valid = true;
00698             return;
00699         }
00700         if (force_valid) {
00701             WRN_NG << "variable_info: using explicitly indexed "
00702                 "container as wrong WML type, " << varname << '\n';
00703         }
00704         explicit_index = false;
00705         index = 0;
00706     } else {
00707         // Final variable is not an explicit index [...]
00708         switch(vartype) {
00709         case variable_info::TYPE_ARRAY:
00710         case variable_info::TYPE_CONTAINER:
00711             is_valid = force_valid || vars->child(key);
00712             break;
00713         case variable_info::TYPE_SCALAR:
00714             is_valid = force_valid || vars->has_attribute(key);
00715             break;
00716         case variable_info::TYPE_UNSPECIFIED:
00717         default:
00718             is_valid = true;
00719             break;
00720         }
00721     }
00722 }
00723 
00724 config::attribute_value &variable_info::as_scalar()
00725 {
00726     assert(is_valid);
00727     return (*vars)[key];
00728 }
00729 
00730 config& variable_info::as_container() {
00731     assert(is_valid);
00732     if(explicit_index) {
00733         // Empty data for explicit index was already created if it was needed
00734         return vars->child(key, index);
00735     }
00736     if (config &temp = vars->child(key)) {
00737         // The container exists, index not specified, return index 0
00738         return temp;
00739     }
00740     // Add empty data for the new variable, since it does not exist yet
00741     return vars->add_child(key);
00742 }
00743 
00744 variable_info::array_range variable_info::as_array() {
00745     assert(is_valid);
00746     return vars->child_range(key);
00747 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:14 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs