Modified vconfig so that it is no longer forced...

...to return translatable strings after variable expansion.

In particular, the engine no longer tries to expand variables inside
plain numbers or booleans.
This commit is contained in:
Guillaume Melquiond 2010-08-19 22:07:53 +00:00
parent 79f2309489
commit ae7cc0a6d2
18 changed files with 79 additions and 89 deletions

View File

@ -42,6 +42,7 @@
typedef std::map<std::string, t_string> string_map; typedef std::map<std::string, t_string> string_map;
class config; class config;
class vconfig;
struct lua_State; struct lua_State;
bool operator==(const config &, const config &); bool operator==(const config &, const config &);
@ -202,6 +203,7 @@ public:
friend std::ostream& operator<<(std::ostream &os, const attribute_value &v); friend std::ostream& operator<<(std::ostream &os, const attribute_value &v);
friend void luaW_pushscalar(lua_State *, const attribute_value &); friend void luaW_pushscalar(lua_State *, const attribute_value &);
friend void write_key_val(std::ostream &, const std::string &, const attribute_value &, unsigned, std::string &); friend void write_key_val(std::ostream &, const std::string &, const attribute_value &, unsigned, std::string &);
friend class vconfig;
}; };
typedef std::map<std::string, attribute_value> attribute_map; typedef std::map<std::string, attribute_value> attribute_map;
@ -482,4 +484,11 @@ private:
std::vector<child_pos> ordered_children; std::vector<child_pos> ordered_children;
}; };
class variable_set
{
public:
virtual ~variable_set() {}
virtual config::attribute_value get_variable_const(const std::string &id) const = 0;
};
#endif #endif

View File

@ -30,15 +30,14 @@ class string_map_variable_set : public variable_set
public: public:
string_map_variable_set(const string_map& map) : map_(map) {}; string_map_variable_set(const string_map& map) : map_(map) {};
virtual t_string get_variable_const (const std::string& key) const virtual config::attribute_value get_variable_const(const std::string &key) const
{ {
config::attribute_value val;
const string_map::const_iterator itor = map_.find(key); const string_map::const_iterator itor = map_.find(key);
if (itor == map_.end()) { if (itor != map_.end())
return t_string(); val = itor->second;
} else { return val;
return itor->second; }
}
};
private: private:
const string_map& map_; const string_map& map_;

View File

@ -17,6 +17,7 @@
#define FORMULA_STRING_UTILS_HPP_INCLUDED #define FORMULA_STRING_UTILS_HPP_INCLUDED
#include "serialization/string_utils.hpp" #include "serialization/string_utils.hpp"
#include "config.hpp"
namespace utils { namespace utils {

View File

@ -408,20 +408,19 @@ namespace game_events {
foreach (const vconfig &values, variables) foreach (const vconfig &values, variables)
{ {
const std::string name = values["name"]; const std::string name = values["name"];
std::string value = resources::state_of_game->get_variable_const(name); config::attribute_value value = resources::state_of_game->get_variable_const(name);
double num_value = value.to_double();
const double num_value = atof(value.c_str());
#define TEST_STR_ATTR(name, test) do { \ #define TEST_STR_ATTR(name, test) do { \
if (values.has_attribute(name)) { \ if (values.has_attribute(name)) { \
std::string attr_str = values[name].str(); \ config::attribute_value attr_str = values[name]; \
if (!(test)) return false; \ if (!(test)) return false; \
} \ } \
} while (0) } while (0)
#define TEST_NUM_ATTR(name, test) do { \ #define TEST_NUM_ATTR(name, test) do { \
if (values.has_attribute(name)) { \ if (values.has_attribute(name)) { \
double attr_num = atof(values[name].c_str()); \ double attr_num = values[name].to_double(); \
if (!(test)) return false; \ if (!(test)) return false; \
} \ } \
} while (0) } while (0)
@ -434,11 +433,9 @@ namespace game_events {
TEST_NUM_ATTR("less_than", num_value < attr_num); TEST_NUM_ATTR("less_than", num_value < attr_num);
TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num); TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num);
TEST_NUM_ATTR("less_than_equal_to", num_value <= attr_num); TEST_NUM_ATTR("less_than_equal_to", num_value <= attr_num);
TEST_STR_ATTR("boolean_equals", TEST_STR_ATTR("boolean_equals", value == attr_str);
utils::string_bool(value) == utils::string_bool(attr_str)); TEST_STR_ATTR("boolean_not_equals", value != attr_str);
TEST_STR_ATTR("boolean_not_equals", TEST_STR_ATTR("contains", value.str().find(attr_str.str()) != std::string::npos);
utils::string_bool(value) != utils::string_bool(attr_str));
TEST_STR_ATTR("contains", value.find(attr_str) != std::string::npos);
#undef TEST_STR_ATTR #undef TEST_STR_ATTR
#undef TEST_NUM_ATTR #undef TEST_NUM_ATTR
@ -1805,7 +1802,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)
if (u != resources::units->end() && (filter.null() || game_events::unit_matches_filter(*u, filter))) if (u != resources::units->end() && (filter.null() || game_events::unit_matches_filter(*u, filter)))
{ {
text = cfg["description"]; text = cfg["description"].str();
u->add_modification("object", cfg.get_parsed_config()); u->add_modification("object", cfg.get_parsed_config());
@ -1815,7 +1812,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)
// Mark this item as used up. // Mark this item as used up.
used_items.insert(id); used_items.insert(id);
} else { } else {
text = cfg["cannot_use_message"]; text = cfg["cannot_use_message"].str();
command_type = "else"; command_type = "else";
} }
@ -2038,13 +2035,13 @@ WML_HANDLER_FUNCTION(set_menu_item, /*event_info*/, cfg)
mref = new wml_menu_item(id); mref = new wml_menu_item(id);
} }
if(cfg.has_attribute("image")) { if(cfg.has_attribute("image")) {
mref->image = cfg["image"]; mref->image = cfg["image"].str();
} }
if(cfg.has_attribute("description")) { if(cfg.has_attribute("description")) {
mref->description = cfg["description"]; mref->description = cfg["description"];
} }
if(cfg.has_attribute("needs_select")) { if(cfg.has_attribute("needs_select")) {
mref->needs_select = utils::string_bool(cfg["needs_select"], false); mref->needs_select = cfg["needs_select"].to_bool();
} }
if(cfg.has_child("show_if")) { if(cfg.has_child("show_if")) {
mref->show_if = cfg.child("show_if").get_config(); mref->show_if = cfg.child("show_if").get_config();
@ -2308,7 +2305,7 @@ WML_HANDLER_FUNCTION(endlevel, /*event_info*/, cfg)
end_level_data &data = resources::controller->get_end_level_data(); end_level_data &data = resources::controller->get_end_level_data();
std::string result = cfg["result"]; std::string result = cfg["result"];
data.custom_endlevel_music = cfg["music"]; data.custom_endlevel_music = cfg["music"].str();
data.carryover_report = utils::string_bool(cfg["carryover_report"], true); data.carryover_report = utils::string_bool(cfg["carryover_report"], true);
data.prescenario_save = utils::string_bool(cfg["save"], true); data.prescenario_save = utils::string_bool(cfg["save"], true);
data.linger_mode = utils::string_bool(cfg["linger_mode"], true) data.linger_mode = utils::string_bool(cfg["linger_mode"], true)
@ -2542,7 +2539,7 @@ std::string get_image(const vconfig& cfg, unit_map::iterator speaker)
image::locator locator(image); image::locator locator(image);
if(!locator.file_exists()) { if(!locator.file_exists()) {
image = cfg["image"]; image = cfg["image"].str();
} }
} }
return image; return image;

View File

@ -475,16 +475,17 @@ config::attribute_value &game_state::get_variable(const std::string& key)
return variable_info(key, true, variable_info::TYPE_SCALAR).as_scalar(); return variable_info(key, true, variable_info::TYPE_SCALAR).as_scalar();
} }
t_string game_state::get_variable_const(const std::string& key) const config::attribute_value game_state::get_variable_const(const std::string &key) const
{ {
variable_info to_get(key, false, variable_info::TYPE_SCALAR); variable_info to_get(key, false, variable_info::TYPE_SCALAR);
if(!to_get.is_valid) { if (!to_get.is_valid)
config::attribute_value &to_return = temporaries[key]; {
if (key.size() > 7 && key.substr(key.size()-7) == ".length") { config::attribute_value &to_return = temporaries[key];
// length is a special attribute, so guarantee its correctness if (key.size() > 7 && key.substr(key.size() - 7) == ".length") {
to_return = "0"; // length is a special attribute, so guarantee its correctness
} to_return = 0;
return to_return; }
return to_return;
} }
return to_get.as_scalar(); return to_get.as_scalar();
} }

View File

@ -103,7 +103,7 @@ public:
// Variable access // Variable access
config::attribute_value &get_variable(const std::string &varname); config::attribute_value &get_variable(const std::string &varname);
virtual t_string get_variable_const(const std::string& varname) const; virtual config::attribute_value get_variable_const(const std::string& varname) const;
config& get_variable_cfg(const std::string& varname); config& get_variable_cfg(const std::string& varname);
void set_variable(const std::string& varname, const t_string& value); void set_variable(const std::string& varname, const t_string& value);

View File

@ -20,6 +20,7 @@
#include "gui/widgets/helper.hpp" #include "gui/widgets/helper.hpp"
#include "serialization/string_utils.hpp" #include "serialization/string_utils.hpp"
#include "util.hpp" #include "util.hpp"
#include "tstring.hpp"
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>

View File

@ -79,7 +79,7 @@ public:
model(const vconfig &c) model(const vconfig &c)
: cfg(c), name(), stuff_list(),stuff_types_list(),inspect(),inspector_name() : cfg(c), name(), stuff_list(),stuff_types_list(),inspect(),inspector_name()
{ {
name = cfg["name"]; name = cfg["name"].str();
} }
vconfig cfg; vconfig cfg;

View File

@ -165,32 +165,6 @@ void luaW_pushscalar(lua_State *L, config::attribute_value const &v)
boost::apply_visitor(luaW_pushscalar_visitor(L), v.value); boost::apply_visitor(luaW_pushscalar_visitor(L), v.value);
} }
/**
* Converts a string into a Lua object pushed at the top of the stack.
* Boolean ("yes"/"no") and numbers are detected and typed accordingly.
*/
static void luaW_pushscalar(lua_State *L, t_string const &v)
{
if (!v.translatable())
{
char *pe;
char const *pb = v.c_str();
double d = strtod(v.c_str(), &pe);
if (pe != pb && *pe == '\0')
lua_pushnumber(L, d);
else if (v == "yes")
lua_pushboolean(L, true);
else if (v == "no")
lua_pushboolean(L, false);
else
lua_pushstring(L, pb);
}
else
{
luaW_pushtstring(L, v);
}
}
/** /**
* Returns true if the metatable of the object is the one found in the registry. * Returns true if the metatable of the object is the one found in the registry.
*/ */

View File

@ -335,7 +335,7 @@ std::string lineno_string(const std::string &lineno)
void preprocessor_streambuf::error(const std::string& error_type, int l) void preprocessor_streambuf::error(const std::string& error_type, int l)
{ {
utils::string_map i18n_symbols; string_map i18n_symbols;
std::string position, error; std::string position, error;
std::ostringstream pos; std::ostringstream pos;
pos << l << ' ' << location_; pos << l << ' ' << location_;

View File

@ -30,10 +30,6 @@ static lg::log_domain log_engine("engine");
#define ERR_GENERAL LOG_STREAM(err, lg::general) #define ERR_GENERAL LOG_STREAM(err, lg::general)
#define ERR_NG LOG_STREAM(err, log_engine) #define ERR_NG LOG_STREAM(err, log_engine)
variable_set::~variable_set()
{
}
namespace utils { namespace utils {
bool isnewline(const char c) bool isnewline(const char c)

View File

@ -24,18 +24,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/next_prior.hpp> #include <boost/next_prior.hpp>
#include "../tstring.hpp"
#include "SDL_types.h" #include "SDL_types.h"
class variable_set
{
public:
virtual ~variable_set();
virtual t_string get_variable_const(const std::string& id) const = 0;
};
/** The type we use to represent Unicode strings. */ /** The type we use to represent Unicode strings. */
typedef std::vector<wchar_t> wide_string; typedef std::vector<wchar_t> wide_string;
@ -44,6 +35,8 @@ typedef std::vector<Uint16> ucs2_string;
typedef std::vector<Uint32> ucs4_string; typedef std::vector<Uint32> ucs4_string;
typedef std::string utf8_string; typedef std::string utf8_string;
class t_string;
namespace utils { namespace utils {
const std::string unicode_minus = ""; const std::string unicode_minus = "";

View File

@ -142,19 +142,19 @@ void part::resolve_wml(const vconfig &cfg)
} }
if(cfg.has_attribute("background")) { if(cfg.has_attribute("background")) {
background_file_ = cfg["background"]; background_file_ = cfg["background"].str();
} }
if(cfg.has_attribute("scale_background")) { if(cfg.has_attribute("scale_background")) {
scale_background_ = utils::string_bool(cfg["scale_background"], true); scale_background_ = cfg["scale_background"].to_bool(true);
} }
if(cfg.has_attribute("show_title")) { if(cfg.has_attribute("show_title")) {
show_title_ = utils::string_bool(cfg["show_title"]); show_title_ = cfg["show_title"].to_bool();
} }
if(cfg.has_attribute("story")) { if(cfg.has_attribute("story")) {
text_ = cfg["story"]; text_ = cfg["story"].str();
} }
if(cfg.has_attribute("title")) { if(cfg.has_attribute("title")) {
text_title_ = cfg["title"]; text_title_ = cfg["title"].str();
if(!cfg.has_attribute("show_title")) { if(!cfg.has_attribute("show_title")) {
show_title_ = true; show_title_ = true;
} }
@ -166,10 +166,10 @@ void part::resolve_wml(const vconfig &cfg)
title_alignment_ = string_title_align(cfg["title_alignment"]); title_alignment_ = string_title_align(cfg["title_alignment"]);
} }
if(cfg.has_attribute("music")) { if(cfg.has_attribute("music")) {
music_ = cfg["music"]; music_ = cfg["music"].str();
} }
if(cfg.has_attribute("sound")) { if(cfg.has_attribute("sound")) {
sound_ = cfg["sound"]; sound_ = cfg["sound"].str();
} }
// Execution flow/branching/[image] // Execution flow/branching/[image]

View File

@ -21,6 +21,7 @@
#include "gui/auxiliary/log.hpp" #include "gui/auxiliary/log.hpp"
#include "font.hpp" #include "font.hpp"
#include "serialization/string_utils.hpp" #include "serialization/string_utils.hpp"
#include "tstring.hpp"
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>

View File

@ -1496,7 +1496,7 @@ bool unit::internal_matches_filter(const vconfig& cfg, const map_location& loc,
if (cfg.has_attribute("lua_function")) { if (cfg.has_attribute("lua_function")) {
bool b = resources::lua_kernel->run_filter bool b = resources::lua_kernel->run_filter
(cfg["lua_function"].c_str(), *this); (cfg["lua_function"].str().c_str(), *this);
if (!b) return false; if (!b) return false;
} }

View File

@ -557,7 +557,7 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m
if(cfg["red"].empty() && cfg["green"].empty() && cfg["blue"].empty()) { if(cfg["red"].empty() && cfg["green"].empty() && cfg["blue"].empty()) {
text_color = display::rgb(0xff,0xff,0xff); text_color = display::rgb(0xff,0xff,0xff);
} else { } else {
text_color = display::rgb(atoi(cfg["red"].c_str()),atoi(cfg["green"].c_str()),atoi(cfg["blue"].c_str())); text_color = display::rgb(cfg["red"], cfg["green"], cfg["blue"]);
} }
resources::screen->scroll_to_tile(u->get_location(), game_display::ONSCREEN, true, false); resources::screen->scroll_to_tile(u->get_location(), game_display::ONSCREEN, true, false);
vconfig t_filter = cfg.child("facing"); vconfig t_filter = cfg.child("facing");

View File

@ -32,6 +32,8 @@
#include "unit_map.hpp" #include "unit_map.hpp"
#include "team.hpp" #include "team.hpp"
#include <boost/variant.hpp>
static lg::log_domain log_engine("engine"); static lg::log_domain log_engine("engine");
#define LOG_NG LOG_STREAM(info, log_engine) #define LOG_NG LOG_STREAM(info, log_engine)
#define WRN_NG LOG_STREAM(warn, log_engine) #define WRN_NG LOG_STREAM(warn, log_engine)
@ -346,12 +348,27 @@ bool vconfig::has_child(const std::string& key) const
return false; return false;
} }
const t_string vconfig::expand(const std::string& key) const struct vconfig_expand_visitor : boost::static_visitor<void>
{ {
const t_string& val = (*cfg_)[key]; config::attribute_value &result;
if(repos != NULL) vconfig_expand_visitor(config::attribute_value &r): result(r) {}
return utils::interpolate_variables_into_tstring(val, *repos); template<typename T> void operator()(T const &) const {}
return t_string(val); void operator()(const std::string &s) const
{
result = utils::interpolate_variables_into_string(s, *repos);
}
void operator()(const t_string &s) const
{
result = utils::interpolate_variables_into_tstring(s, *repos);
}
};
config::attribute_value vconfig::expand(const std::string &key) const
{
config::attribute_value val = (*cfg_)[key];
if (repos)
boost::apply_visitor(vconfig_expand_visitor(val), val.value);
return val;
} }
vconfig::all_children_iterator::all_children_iterator(const Itor &i, const config *cache_key) vconfig::all_children_iterator::all_children_iterator(const Itor &i, const config *cache_key)

View File

@ -69,8 +69,9 @@ public:
* lifetime ends which causes UB. Instead use: * lifetime ends which causes UB. Instead use:
* const std::string temp = vcfg["foo"]; * const std::string temp = vcfg["foo"];
*/ */
const t_string operator[](const std::string& key) const { return expand(key); } const config::attribute_value operator[](const std::string &key) const
const t_string expand(const std::string&) const; /** < Synonym for operator[] */ { return expand(key); }
config::attribute_value expand(const std::string&) const; /** < Synonym for operator[] */
bool has_attribute(const std::string& key) const { return cfg_->has_attribute(key); } bool has_attribute(const std::string& key) const { return cfg_->has_attribute(key); }
bool empty() const { return (null() || cfg_->empty()); } bool empty() const { return (null() || cfg_->empty()); }