Skip to content

Commit

Permalink
failed conversion of enums results in error dialog, in debug mode
Browse files Browse the repository at this point in the history
The make_enum macro header now includes wml_exception.hpp, and
game_config. We use the FAIL macro to launch a transient
twml_exception dialog when an enum is casted from an illegal
string value. This means that when enums in our C++ classes are
initialized using lexical_cast<enum_type> (cfg["attribute"]),
we will automatically give error reports for bad values.
  • Loading branch information
cbeck88 committed May 25, 2014
1 parent 12fad6e commit 986a872
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
26 changes: 23 additions & 3 deletions src/make_enum.hpp
Expand Up @@ -68,13 +68,25 @@ MAKE_ENUM_STREAM_OPS2(bar , another)
* foo::enumname_to_string(foo::enumname); //no throw
*
* The stream ops define
* std::ostream & operator<< (std::ostream &, foo::enumname)
* std::istream & operator>> (std::istream &, foo::enumname &)
* std::ostream & operator<< (std::ostream &, foo::enumname) //no throw. asserts false if enum has an illegal value.
* std::istream & operator>> (std::istream &, foo::enumname &) //throws twml_exception including line number and arguments, IF game_config::debug is true.
* //doesn't throw except in that case, and correctly sets istream state to failing always.
* //this is generally a recoverable exception that only shows a temporary dialog box,
* //and is caught at many places in the gui code. you may safely catch it and ignore it,
* //and then proceeding, or use a wrapper like lexical_cast_default which will assign the
* //default value and proceed after the dialog passes.
*
* In case of a bad string -> enum conversion from istream output,
* the istream will have its fail bit set.
* This means that lexical_casts will throw a bad_lexical_cast,
* in the similar scenario.
* in the similar scenario. (but, that exception won't have any
* details about the error.)
*
* It is recommended to use this type either the built-in wesnoth
* lexical_cast or lexical_cast default.
*
* HOWEVER, if you DON'T want twml_exceptions to be thrown in any
* circumstance, then use the string_to_enumname functions instead.
*
* To get lexical_cast, you must separately include util.hpp
*
Expand All @@ -87,7 +99,9 @@ MAKE_ENUM_STREAM_OPS2(bar , another)
#ifndef MAKE_ENUM_HPP
#define MAKE_ENUM_HPP

#include "game_config.hpp"
#include "global.hpp"
#include "wml_exception.hpp"

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
Expand Down Expand Up @@ -189,6 +203,9 @@ inline std::istream& operator>> (std::istream & is, NAME & val) \
val = CAT2(string_to_, NAME) ( temp ); \
} catch (bad_enum_cast & e) { \
is.setstate(std::ios::failbit); \
if (game_config::debug) { \
FAIL( e.what() ); \
} \
} \
return is; \
} \
Expand All @@ -210,6 +227,9 @@ inline std::istream& operator>> (std::istream & is, NAMESPACE::NAME & val) \
val = CAT2(NAMESPACE::string_to_,NAME) ( temp ); \
} catch (bad_enum_cast & e) {\
is.setstate(std::ios::failbit); \
if (game_config::debug) { \
FAIL( e.what() ); \
} \
} \
return is; \
} \
Expand Down
4 changes: 2 additions & 2 deletions src/team.cpp
Expand Up @@ -131,7 +131,7 @@ void team::team_info::read(const config &cfg)
allow_player = cfg["allow_player"].to_bool(true);
chose_random = cfg["chose_random"].to_bool(false);
no_leader = cfg["no_leader"].to_bool();
defeat_condition = team::string_to_DEFEAT_CONDITION_default(cfg["defeat_condition"], team::NO_LEADER);
defeat_condition = lexical_cast_default<team::DEFEAT_CONDITION>(cfg["defeat_condition"], team::NO_LEADER);
hidden = cfg["hidden"].to_bool();
no_turn_confirmation = cfg["suppress_end_turn_confirmation"].to_bool();
side = cfg["side"].to_int(1);
Expand Down Expand Up @@ -258,7 +258,7 @@ void team::team_info::write(config& cfg) const
cfg["allow_player"] = allow_player;
cfg["chose_random"] = chose_random;
cfg["no_leader"] = no_leader;
cfg["defeat_condition"] = team::DEFEAT_CONDITION_to_string(defeat_condition);
cfg["defeat_condition"] = lexical_cast<std::string>(defeat_condition);
cfg["hidden"] = hidden;
cfg["suppress_end_turn_confirmation"] = no_turn_confirmation;
cfg["scroll_to_leader"] = scroll_to_leader;
Expand Down
2 changes: 1 addition & 1 deletion src/team.hpp
Expand Up @@ -277,7 +277,7 @@ class team : public savegame::savegame_config
DEFEAT_CONDITION defeat_condition() const { return info_.defeat_condition; }
void set_defeat_condition(DEFEAT_CONDITION value) { info_.defeat_condition = value; }
///sets the defeat condition if @param value is a valid defeat condition, otherwise nothing happes.
void set_defeat_condition_string(const std::string& value) { info_.defeat_condition = string_to_DEFEAT_CONDITION_default(value, info_.defeat_condition); }
void set_defeat_condition_string(const std::string& value) { info_.defeat_condition = lexical_cast_default<team::DEFEAT_CONDITION>(value, info_.defeat_condition); }
void have_leader(bool value=true) { info_.no_leader = !value; }
bool hidden() const { return info_.hidden; }
void set_hidden(bool value) { info_.hidden=value; }
Expand Down

0 comments on commit 986a872

Please sign in to comment.