added --preprocess, --preprocess-defines and --preprocess-input-macros...

...to commandline_options
This commit is contained in:
Lukasz Dobrogowski 2011-06-09 09:52:42 +00:00
parent 508f710707
commit 6957c82245
3 changed files with 159 additions and 150 deletions

View File

@ -20,6 +20,19 @@
namespace po = boost::program_options;
class two_strings : public boost::tuple<std::string,std::string> {};
void validate(boost::any& v, const std::vector<std::string>& values,
two_strings*, int)
{
two_strings ret_val;
if (values.size() != 2)
throw po::validation_error(po::validation_error::invalid_option_value);
ret_val.get<0>() = values.at(0);
ret_val.get<1>() = values.at(1);
v = ret_val;
}
commandline_options::commandline_options ( int argc, char** argv ) :
bpp(),
campaign(),
@ -107,6 +120,9 @@ commandline_options::commandline_options ( int argc, char** argv ) :
("new-syntax", "enables the new campaign syntax parsing.")
("nocache", "disables caching of game data.")
("path", "prints the path to the data directory and exits.")
("preprocess,p", po::value<two_strings>()->multitoken(), "requires two arguments: <file/folder> <target directory>. Preprocesses a specified file/folder. The preprocessed file(s) will be written in the specified target directory: a plain cfg file and a processed cfg file.")
("preprocess-defines", po::value<std::string>(), "comma separated list of defines to be used by '--preprocess' command. If 'SKIP_CORE' is in the define list the data/core won't be preprocessed. Example: --preprocess-defines=FOO,BAR")
("preprocess-input-macros", po::value<std::string>(), "used only by the '--preprocess' command. Specifies source file <arg> that contains [preproc_define]s to be included before preprocessing.")
("preprocess-output-macros", po::value<std::string>()->implicit_value(std::string()), "used only by the '--preprocess' command. Will output all preprocessed macros in the target file <arg>. If the file is not specified the output will be file '_MACROS_.cfg' in the target directory of preprocess's command.")
("rng-seed", po::value<unsigned int>(), "seeds the random number generator with number <arg>. Example: --rng-seed 0")
("validcache", "assumes that the cache is valid. (dangerous)")
@ -135,7 +151,8 @@ commandline_options::commandline_options ( int argc, char** argv ) :
all_.add(visible_).add(hidden_);
po::variables_map vm;
po::store(po::parse_command_line(argc_,argv_,all_),vm);
const int parsing_style = po::command_line_style::default_style ^ po::command_line_style::allow_guessing;
po::store(po::parse_command_line(argc_,argv_,all_,parsing_style),vm);
if (vm.count("ai-config"))
multiplayer_ai_config = parse_to_int_string_tuples_(vm["ai-config"].as<std::vector<std::string> >());
@ -175,6 +192,16 @@ commandline_options::commandline_options ( int argc, char** argv ) :
nocache = true;
if (vm.count("path"))
path = true;
if (vm.count("preprocess"))
{
preprocess = true;
preprocess_path = vm["preprocess"].as<two_strings>().get<0>();
preprocess_target = vm["preprocess"].as<two_strings>().get<1>();
}
if (vm.count("preprocess-defines"))
preprocess_defines = utils::split(vm["preprocess-defines"].as<std::string>(), ',');
if (vm.count("preprocess-input-macros"))
preprocess_input_macros = vm["preprocess-input-macros"].as<std::string>();
if (vm.count("preprocess-output-macros"))
preprocess_output_macros = vm["preprocess-output-macros"].as<std::string>();
if (vm.count("rng-seed"))

View File

@ -167,6 +167,7 @@ static int process_command_args(int argc, char** argv, const commandline_options
game_config::wesnoth_program_dir = directory_name(program);
preprocess_options preproc;
// Options that don't change behaviour based on any others should be checked alphabetically below.
if(cmdline_opts.config_dir) {
set_preferences_dir(*cmdline_opts.config_dir);
}
@ -224,7 +225,31 @@ static int process_command_args(int argc, char** argv, const commandline_options
std::cout << game_config::path << "\n";
return 0;
}
if (cmdline_opts.preprocess_output_macros) {
if(cmdline_opts.preprocess_input_macros) {
std::string file = *cmdline_opts.preprocess_input_macros;
if (file_exists(file) == false)
{
std::cerr << "please specify an existing file. File "<< file <<" doesn't exist.\n";
return 1;
}
std::cerr << SDL_GetTicks() << " Reading cached defines from: " << file << "\n";
config cfg;
std::string error_log;
scoped_istream stream = istream_file(file);
read(cfg, *stream);
int read = 0;
// use static preproc_define::read_pair(config) to make a object
foreach (const config::any_child &value, cfg.all_children_range()) {
const preproc_map::value_type def = preproc_define::read_pair(value.cfg);
preproc.input_macros_[def.first] = def.second;
++read;
}
std::cerr << SDL_GetTicks() << " Read " << read << " defines.\n";
}
if(cmdline_opts.preprocess_output_macros) {
if (cmdline_opts.preprocess_output_macros->empty())
preproc.output_macros_path_ = "true";
else
@ -238,6 +263,100 @@ static int process_command_args(int argc, char** argv, const commandline_options
return 0;
}
// Options changing their behaviour dependant on some others should be checked below.
//TODO should be rewritten so that preprocess_input_macros and preprocess_output_macros are used inside, not before
if (cmdline_opts.preprocess) {
const std::string resourceToProcess(*cmdline_opts.preprocess_path);
const std::string targetDir(*cmdline_opts.preprocess_target);
Uint32 startTime = SDL_GetTicks();
// if the users add the SKIP_CORE define we won't preprocess data/core
bool skipCore = false;
bool skipTerrainGFX = false;
// the 'core_defines_map' is the one got from data/core macros
preproc_map defines_map(preproc.input_macros_);
std::string error_log;
if (cmdline_opts.preprocess_defines)
{
// add the specified defines
foreach (const std::string &define, *cmdline_opts.preprocess_defines)
{
if (define.empty()){
std::cerr << "empty define supplied\n";
continue;
}
LOG_PREPROC<<"adding define: "<< define<<'\n';
defines_map.insert(std::make_pair(define,
preproc_define(define)));
if (define == "SKIP_CORE")
{
std::cerr << "'SKIP_CORE' defined.\n";
skipCore = true;
}
else if (define == "NO_TERRAIN_GFX")
{
std::cerr << "'NO_TERRAIN_GFX' defined.\n";
skipTerrainGFX = true;
}
}
}
std::cerr << "added " << defines_map.size() << " defines.\n";
// preprocess core macros first if we don't skip the core
if (skipCore == false)
{
std::cerr << "preprocessing common macros from 'data/core' ...\n";
// process each folder explicitly to gain speed
preprocess_resource(game_config::path + "/data/core/macros",&defines_map);
if (skipTerrainGFX == false)
preprocess_resource(game_config::path + "/data/core/terrain-graphics",&defines_map);
std::cerr << "acquired " << (defines_map.size() - preproc.input_macros_.size())
<< " 'data/core' defines.\n";
}
else
std::cerr << "skipped 'data/core'\n";
// preprocess resource
std::cerr << "preprocessing specified resource: "
<< resourceToProcess << " ...\n";
preprocess_resource(resourceToProcess, &defines_map, true,true, targetDir);
std::cerr << "acquired " << (defines_map.size() - preproc.input_macros_.size())
<< " total defines.\n";
if (preproc.output_macros_path_ != "false")
{
std::string outputPath = targetDir + "/_MACROS_.cfg";
if (preproc.output_macros_path_ != "true")
outputPath = preproc.output_macros_path_;
std::cerr << "writing '" << outputPath << "' with "
<< defines_map.size() << " defines.\n";
scoped_ostream out = ostream_file(outputPath);
if (!out->fail())
{
config_writer writer(*out,false);
for(preproc_map::iterator itor = defines_map.begin();
itor != defines_map.end(); ++itor)
{
(*itor).second.write(writer, (*itor).first);
}
}
else
std::cerr << "couldn't open the file.\n";
}
std::cerr << "preprocessing finished. Took "<< SDL_GetTicks() - startTime << " ticks.\n";
return 0;
}
//parse arguments that shouldn't require a display device
int arg;
for(arg = 1; arg != argc; ++arg) {
@ -276,146 +395,6 @@ static int process_command_args(int argc, char** argv, const commandline_options
}
p = q;
}
} else if (val == "--preprocess-input-macros") {
if (arg + 1 < argc)
{
++arg;
std::string file = argv[arg];
if (file_exists(file) == false)
{
std::cerr << "please specify an existing file. File "<< file <<" doesn't exist.\n";
return 1;
}
std::cerr << SDL_GetTicks() << " Reading cached defines from: " << file << "\n";
config cfg;
std::string error_log;
scoped_istream stream = istream_file(file);
read(cfg, *stream);
int read = 0;
// use static preproc_define::read_pair(config) to make a object
foreach (const config::any_child &value, cfg.all_children_range()) {
const preproc_map::value_type def = preproc_define::read_pair(value.cfg);
preproc.input_macros_[def.first] = def.second;
++read;
}
std::cerr << SDL_GetTicks() << " Read " << read << " defines.\n";
}
else {
std::cerr << "please specify input macros file.\n";
return 2;
}
} else if (val.find("--preprocess") == 0 || val.find("-p") == 0){
if (arg + 2 < argc){
++arg;
const std::string resourceToProcess(argv[arg]);
++arg;
const std::string targetDir(argv[arg]);
Uint32 startTime = SDL_GetTicks();
// if the users add the SKIP_CORE define we won't preprocess data/core
bool skipCore = false;
bool skipTerrainGFX = false;
// the 'core_defines_map' is the one got from data/core macros
preproc_map defines_map(preproc.input_macros_);
std::string error_log;
// add the specified defines
size_t pos=std::string::npos;
if (val.find("--preprocess=") == 0)
pos = val.find("=");
else if (val.find("-p=") == 0)
pos = val.find("=");
// we have some defines specified
if (pos != std::string::npos)
{
std::string tmp_val = val.substr(pos+1);
while (pos != std::string::npos)
{
size_t tmpPos = val.find(',', pos+1);
tmp_val = val.substr(pos + 1,
tmpPos == std::string::npos ? tmpPos : tmpPos - (pos+1));
pos = tmpPos;
if (tmp_val.empty()){
std::cerr << "empty define supplied\n";
continue;
}
LOG_PREPROC<<"adding define: "<< tmp_val<<'\n';
defines_map.insert(std::make_pair(tmp_val,
preproc_define(tmp_val)));
if (tmp_val == "SKIP_CORE")
{
std::cerr << "'SKIP_CORE' defined.\n";
skipCore = true;
}
else if (tmp_val == "NO_TERRAIN_GFX")
{
std::cerr << "'NO_TERRAIN_GFX' defined.\n";
skipTerrainGFX = true;
}
}
std::cerr << "added " << defines_map.size() << " defines.\n";
}
// preprocess core macros first if we don't skip the core
if (skipCore == false)
{
std::cerr << "preprocessing common macros from 'data/core' ...\n";
// process each folder explicitly to gain speed
preprocess_resource(game_config::path + "/data/core/macros",&defines_map);
if (skipTerrainGFX == false)
preprocess_resource(game_config::path + "/data/core/terrain-graphics",&defines_map);
std::cerr << "acquired " << (defines_map.size() - preproc.input_macros_.size())
<< " 'data/core' defines.\n";
}
else
std::cerr << "skipped 'data/core'\n";
// preprocess resource
std::cerr << "preprocessing specified resource: "
<< resourceToProcess << " ...\n";
preprocess_resource(resourceToProcess, &defines_map, true,true, targetDir);
std::cerr << "acquired " << (defines_map.size() - preproc.input_macros_.size())
<< " total defines.\n";
if (preproc.output_macros_path_ != "false")
{
std::string outputPath = targetDir + "/_MACROS_.cfg";
if (preproc.output_macros_path_ != "true")
outputPath = preproc.output_macros_path_;
std::cerr << "writing '" << outputPath << "' with "
<< defines_map.size() << " defines.\n";
scoped_ostream out = ostream_file(outputPath);
if (!out->fail())
{
config_writer writer(*out,false);
for(preproc_map::iterator itor = defines_map.begin();
itor != defines_map.end(); ++itor)
{
(*itor).second.write(writer, (*itor).first);
}
}
else
std::cerr << "couldn't open the file.\n";
}
std::cerr << "preprocessing finished. Took "<< SDL_GetTicks() - startTime << " ticks.\n";
return 0;
}
else{
std::cerr << "Please specify a source file/folder and a target folder\n";
return 2;
}
}
}

View File

@ -195,6 +195,9 @@ BOOST_AUTO_TEST_CASE (test_full_options)
"--new-widgets",
"--nocache",
"--path",
"--preprocess", "preppathfoo", "preptargfoo",
"--preprocess-defines=DEFFOO,DEFBAR",
"--preprocess-input-macros=inmfoo",
"--preprocess-output-macros=outmfoo",
"--rng-seed=1234",
"--validcache",
@ -228,9 +231,9 @@ BOOST_AUTO_TEST_CASE (test_full_options)
BOOST_CHECK(co.logdomains && *co.logdomains == "filterfoo");
BOOST_CHECK(co.multiplayer);
BOOST_CHECK(co.multiplayer_ai_config);
BOOST_CHECK((*co.multiplayer_ai_config).size() == 2);
BOOST_CHECK((*co.multiplayer_ai_config)[0].get<0>() == 1 && (*co.multiplayer_ai_config)[0].get<1>() == "aifoo");
BOOST_CHECK((*co.multiplayer_ai_config)[1].get<0>() == 2 && (*co.multiplayer_ai_config)[1].get<1>() == "aibar");
BOOST_CHECK(co.multiplayer_ai_config->size() == 2);
BOOST_CHECK(co.multiplayer_ai_config->at(0).get<0>() == 1 && co.multiplayer_ai_config->at(0).get<1>() == "aifoo");
BOOST_CHECK(co.multiplayer_ai_config->at(1).get<0>() == 2 && co.multiplayer_ai_config->at(1).get<1>() == "aibar");
BOOST_CHECK(!co.multiplayer_algorithm);
BOOST_CHECK(!co.multiplayer_controller);
BOOST_CHECK(!co.multiplayer_era);
@ -248,12 +251,12 @@ BOOST_AUTO_TEST_CASE (test_full_options)
BOOST_CHECK(co.new_syntax);
BOOST_CHECK(co.new_widgets);
BOOST_CHECK(co.path);
BOOST_CHECK(!co.preprocess);
BOOST_CHECK(!co.preprocess_defines);
BOOST_CHECK(!co.preprocess_input_macros);
BOOST_CHECK(co.preprocess && co.preprocess_path && co.preprocess_target);
BOOST_CHECK(*co.preprocess_path == "preppathfoo" && *co.preprocess_target == "preptargfoo");
BOOST_CHECK(co.preprocess_defines && co.preprocess_defines->size() == 2);
BOOST_CHECK(co.preprocess_defines->at(0) == "DEFFOO" && co.preprocess_defines->at(1) == "DEFBAR");
BOOST_CHECK(co.preprocess_input_macros && *co.preprocess_input_macros == "inmfoo");
BOOST_CHECK(co.preprocess_output_macros && *co.preprocess_output_macros == "outmfoo");
BOOST_CHECK(!co.preprocess_path);
BOOST_CHECK(!co.preprocess_target);
BOOST_CHECK(!co.proxy);
BOOST_CHECK(!co.proxy_address);
BOOST_CHECK(!co.proxy_password);