Made the WML parser able to continue parsing when it detects an error.

Made the "refresh_game_cfg" error-tolerant.
This commit is contained in:
Philippe Plantier 2005-03-29 21:01:30 +00:00
parent 38691814f9
commit b9c9a81cd6
3 changed files with 127 additions and 102 deletions

View file

@ -225,88 +225,6 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
namespace {
//this function reads the game configuration, searching for valid cached copies first
void read_game_cfg(preproc_map& defines, std::vector<line_source>& line_src, config& cfg, bool use_cache)
{
log_scope("read_game_cfg");
if(defines.size() < 4) {
bool is_valid = true;
std::stringstream str;
str << "-v" << game_config::version;
for(preproc_map::const_iterator i = defines.begin(); i != defines.end(); ++i) {
if(i->second.value != "" || i->second.arguments.empty() == false) {
is_valid = false;
break;
}
str << "-" << i->first;
}
std::string localename = get_locale().localename;
str << "-lang_" << (localename.empty() ? "default" : localename);
if(is_valid) {
const std::string& cache = get_cache_dir();
if(cache != "") {
const std::string fname = cache + "/game.cfg-cache" + str.str();
const std::string fname_checksum = fname + ".checksum";
file_tree_checksum dir_checksum;
if(use_cache) {
try {
if(file_exists(fname_checksum)) {
config checksum_cfg;
scoped_istream stream = istream_file(fname_checksum);
read(checksum_cfg, *stream);
dir_checksum = file_tree_checksum(checksum_cfg);
}
} catch(config::error&) {
std::cerr << "cache checksum is corrupt\n";
} catch(io_exception&) {
std::cerr << "error reading cache checksum\n";
}
}
if(use_cache && file_exists(fname) && file_create_time(fname) > data_tree_checksum().modified && dir_checksum == data_tree_checksum()) {
std::cerr << "found valid cache at '" << fname << "' using it\n";
log_scope("read cache");
try {
scoped_istream stream = istream_file(fname);
read_compressed(cfg, *stream);
return;
} catch(config::error&) {
std::cerr << "cache is corrupt. Loading from files\n";
} catch(io_exception&) {
std::cerr << "error reading cache. Loading from files\n";
}
}
std::cerr << "no valid cache found. Writing cache to '" << fname << "'\n";
//read the file and then write to the cache
scoped_istream stream = preprocess_file("data/game.cfg", &defines, &line_src);
read(cfg, *stream, &line_src);
try {
scoped_ostream cache = ostream_file(fname);
write_compressed(*cache, cfg);
config checksum_cfg;
data_tree_checksum().write(checksum_cfg);
scoped_ostream checksum = ostream_file(fname_checksum);
write(*checksum, checksum_cfg);
} catch(io_exception&) {
std::cerr << "could not write to cache '" << fname << "'\n";
}
return;
}
}
}
std::cerr << "caching cannot be done. Reading file\n";
scoped_istream stream = preprocess_file("data/game.cfg", &defines, &line_src);
read(cfg, *stream, &line_src);
}
bool less_campaigns_rank(const config* a, const config* b) {
return lexical_cast_default<int>((*a)["rank"],1000) <
@ -341,6 +259,7 @@ private:
game_controller(const game_controller&);
void operator=(const game_controller&);
void read_game_cfg(preproc_map& defines, std::vector<line_source>& line_src, config& cfg, bool use_cache);
void refresh_game_cfg();
void download_campaigns();
@ -1396,6 +1315,97 @@ bool game_controller::change_language()
return false;
}
//this function reads the game configuration, searching for valid cached copies first
void game_controller::read_game_cfg(preproc_map& defines, std::vector<line_source>& line_src, config& cfg, bool use_cache)
{
log_scope("read_game_cfg");
if(defines.size() < 4) {
bool is_valid = true;
std::stringstream str;
str << "-v" << game_config::version;
for(preproc_map::const_iterator i = defines.begin(); i != defines.end(); ++i) {
if(i->second.value != "" || i->second.arguments.empty() == false) {
is_valid = false;
break;
}
str << "-" << i->first;
}
std::string localename = get_locale().localename;
str << "-lang_" << (localename.empty() ? "default" : localename);
if(is_valid) {
const std::string& cache = get_cache_dir();
if(cache != "") {
const std::string fname = cache + "/game.cfg-cache" + str.str();
const std::string fname_checksum = fname + ".checksum";
file_tree_checksum dir_checksum;
if(use_cache) {
try {
if(file_exists(fname_checksum)) {
config checksum_cfg;
scoped_istream stream = istream_file(fname_checksum);
read(checksum_cfg, *stream);
dir_checksum = file_tree_checksum(checksum_cfg);
}
} catch(config::error&) {
std::cerr << "cache checksum is corrupt\n";
} catch(io_exception&) {
std::cerr << "error reading cache checksum\n";
}
}
if(use_cache && file_exists(fname) && file_create_time(fname) > data_tree_checksum().modified && dir_checksum == data_tree_checksum()) {
std::cerr << "found valid cache at '" << fname << "' using it\n";
log_scope("read cache");
try {
scoped_istream stream = istream_file(fname);
read_compressed(cfg, *stream);
return;
} catch(config::error&) {
std::cerr << "cache is corrupt. Loading from files\n";
} catch(io_exception&) {
std::cerr << "error reading cache. Loading from files\n";
}
}
std::cerr << "no valid cache found. Writing cache to '" << fname << "'\n";
//read the file and then write to the cache
scoped_istream stream = preprocess_file("data/game.cfg", &defines, &line_src);
std::string error_log;
read(cfg, *stream, &line_src, &error_log);
if(!error_log.empty()) {
gui::show_error_message(disp(),
_("Error loading game configuration files: '") +
error_log);
}
try {
scoped_ostream cache = ostream_file(fname);
write_compressed(*cache, cfg);
config checksum_cfg;
data_tree_checksum().write(checksum_cfg);
scoped_ostream checksum = ostream_file(fname_checksum);
write(*checksum, checksum_cfg);
} catch(io_exception&) {
std::cerr << "could not write to cache '" << fname << "'\n";
}
return;
}
}
}
std::cerr << "caching cannot be done. Reading file\n";
scoped_istream stream = preprocess_file("data/game.cfg", &defines, &line_src);
read(cfg, *stream, &line_src);
}
void game_controller::refresh_game_cfg()
{
try {

View file

@ -58,7 +58,7 @@ class parser
{
public:
parser(config& cfg, std::istream& in, std::vector<line_source> const* line_sources);
void operator() ();
void operator() (std::string* error_log=NULL);
private:
void parse_element();
@ -97,29 +97,42 @@ parser::parser(config &cfg, std::istream &in, std::vector<line_source> const *li
{
}
void parser::operator()()
void parser::operator()(std::string* error_log)
{
cfg_.clear();
elements.push(element(&cfg_, "", 0, PACKAGE));
tok_.textdomain() = PACKAGE;
do {
tok_.next_token();
try {
tok_.next_token();
switch(tok_.current_token().type) {
case token::LF:
continue;
case '[':
parse_element();
break;
case token::STRING:
parse_variable();
break;
default:
error(_("Unexpected characters at line start"));
break;
case token::END:
break;
switch(tok_.current_token().type) {
case token::LF:
continue;
case '[':
parse_element();
break;
case token::STRING:
parse_variable();
break;
default:
error(_("Unexpected characters at line start"));
break;
case token::END:
break;
}
} catch(config::error& e) {
if(error_log == NULL)
throw;
// On error, dump tokens to the next LF
while(tok_.current_token().type != token::LF &&
tok_.current_token().type != token::END) {
tok_.next_token();
}
*error_log += e.message + '\n';
}
} while (tok_.current_token().type != token::END);
@ -323,9 +336,10 @@ void parser::error(const std::string& error_type)
} // end anon namespace
void read(config &cfg, std::istream &data_in, std::vector< line_source > const *line_sources)
void read(config &cfg, std::istream &data_in, std::vector< line_source > const *line_sources,
std::string* error_log)
{
parser(cfg, data_in, line_sources)();
parser(cfg, data_in, line_sources)(error_log);
}
static char const *AttributeEquals = "=";

View file

@ -23,7 +23,8 @@ struct line_source;
line_source get_line_source(std::vector< line_source > const &line_src, int line);
//read data in, clobbering existing data.
void read(config &cfg, std::istream &in, std::vector< line_source > const *lines = 0); //throws config::error
void read(config &cfg, std::istream &in, std::vector< line_source > const *lines = 0,
std::string* error_log=NULL); //throws config::error
void write(std::ostream &out, config const &cfg);