00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "commandline_options.hpp"
00017 #include "foreach.hpp"
00018 #include "serialization/string_utils.hpp"
00019 #include "util.hpp"
00020 #include "lua/llimits.h"
00021
00022 #include <boost/version.hpp>
00023
00024 namespace po = boost::program_options;
00025
00026
00027 class two_strings : public boost::tuple<std::string,std::string> {};
00028
00029 static void validate(boost::any& v, const std::vector<std::string>& values,
00030 two_strings*, int)
00031 {
00032 two_strings ret_val;
00033 if (values.size() != 2)
00034 #if BOOST_VERSION >= 104200
00035 throw po::validation_error(po::validation_error::invalid_option_value);
00036 #else
00037 throw po::validation_error("Invalid number of strings provided to option requiring exactly two of them.");
00038 #endif
00039 ret_val.get<0>() = values.at(0);
00040 ret_val.get<1>() = values.at(1);
00041 v = ret_val;
00042 }
00043
00044 commandline_options::commandline_options ( int argc, char** argv ) :
00045 bpp(),
00046 campaign(),
00047 campaign_difficulty(),
00048 campaign_scenario(),
00049 clock(false),
00050 config_path(false),
00051 config_dir(),
00052 data_dir(),
00053 debug(false),
00054 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00055 debug_dot_domain(),
00056 debug_dot_level(),
00057 #endif
00058 editor(),
00059 fps(false),
00060 fullscreen(false),
00061 gunzip(),
00062 gzip(),
00063 help(),
00064 language(),
00065 log(),
00066 load(),
00067 logdomains(),
00068 multiplayer(false),
00069 multiplayer_ai_config(),
00070 multiplayer_algorithm(),
00071 multiplayer_controller(),
00072 multiplayer_era(),
00073 multiplayer_exit_at_end(),
00074 multiplayer_label(),
00075 multiplayer_parm(),
00076 multiplayer_scenario(),
00077 multiplayer_side(),
00078 multiplayer_turns(),
00079 max_fps(),
00080 nocache(false),
00081 nodelay(false),
00082 nogui(false),
00083 nomusic(false),
00084 nosound(false),
00085 new_storyscreens(false),
00086 new_syntax(false),
00087 new_widgets(false),
00088 path(false),
00089 preprocess(false),
00090 preprocess_defines(),
00091 preprocess_input_macros(),
00092 preprocess_output_macros(),
00093 preprocess_path(),
00094 preprocess_target(),
00095 proxy(false),
00096 proxy_address(),
00097 proxy_password(),
00098 proxy_port(),
00099 proxy_user(),
00100 resolution(),
00101 rng_seed(),
00102 server(),
00103 username(),
00104 password(),
00105 screenshot(false),
00106 screenshot_map_file(),
00107 screenshot_output_file(),
00108 smallgui(false),
00109 strict_validation(false),
00110 test(),
00111 validcache(false),
00112 version(false),
00113 windowed(false),
00114 with_replay(false),
00115 argc_(argc),
00116 argv_(argv),
00117 all_(),
00118 visible_(),
00119 hidden_()
00120 {
00121
00122
00123 po::options_description general_opts("General options");
00124 general_opts.add_options()
00125 ("clock", "Adds the option to show a clock for testing the drawing timer.")
00126 ("config-dir", po::value<std::string>(), "sets the path of the user config directory to $HOME/<arg> or My Documents\\My Games\\<arg> for Windows. You can specify also an absolute path outside the $HOME or My Documents\\My Games directory.")
00127 ("config-path", "prints the path of the user config directory and exits.")
00128 ("data-dir", po::value<std::string>(), "overrides the data directory with the one specified.")
00129 ("debug,d", "enables additional command mode options in-game.")
00130 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00131 ("debug-dot-level", po::value<std::string>(), "sets the level of the debug dot files. <arg> should be a comma separated list of levels. These files are used for debugging the widgets especially the for the layout engine. When enabled the engine will produce dot files which can be converted to images with the dot tool. Available levels: size (generate the size info of the widget), state (generate the state info of the widget).")
00132 ("debug-dot-domain", po::value<std::string>(), "sets the domain of the debug dot files. <arg> should be a comma separated list of domains. See --debug-dot-level for more info. Available domains: show (generate the data when the dialog is about to be shown), layout (generate the data during the layout phase - might result in multiple files). The data can also be generated when the F12 is pressed in a dialog.")
00133 #endif
00134 ("editor,e", po::value<std::string>()->implicit_value(std::string()), "starts the in-game map editor directly. If file <arg> is specified, equivalent to -e --load <arg>.")
00135 ("gunzip", po::value<std::string>(), "decompresses a file (<arg>.gz) in gzip format and stores it without the .gz suffix. <arg>.gz will be removed.")
00136 ("gzip", po::value<std::string>(), "compresses a file (<arg>) in gzip format, stores it as <arg>.gz and removes <arg>.")
00137 ("help,h", "prints this message and exits.")
00138 ("language,L", po::value<std::string>(), "uses language <arg> (symbol) this session. Example: --language ang_GB@latin")
00139 ("load,l", po::value<std::string>(), "loads the save <arg> from the standard save game directory. When launching the map editor via -e, the map <arg> is loaded, relative to the current directory. If it is a directory, the editor will start with a load map dialog opened there.")
00140
00141
00142 ("nocache", "disables caching of game data.")
00143 ("nodelay", "runs the game without any delays.")
00144 ("nomusic", "runs the game without music.")
00145 ("nosound", "runs the game without sounds and music.")
00146 ("path", "prints the path to the data directory and exits.")
00147 ("rng-seed", po::value<unsigned int>(), "seeds the random number generator with number <arg>. Example: --rng-seed 0")
00148 ("screenshot", po::value<two_strings>()->multitoken(), "takes two arguments: <map> <output>. Saves a screenshot of <map> to <output> without initializing a screen. Editor must be compiled in for this to work.")
00149 ("server,s", po::value<std::string>()->implicit_value(std::string()), "connects to the host <arg> if specified or to the first host in your preferences.")
00150 ("username", po::value<std::string>(), "uses <username> when connecting to a server, ignoring other preferences.")
00151 ("password", po::value<std::string>(), "uses <password> when connecting to a server, ignoring other preferences.")
00152 ("strict-validation", "makes validation errors fatal")
00153 ("test,t", po::value<std::string>()->implicit_value(std::string()), "runs the game in a small test scenario. If specified, scenario <arg> will be used instead.")
00154 ("validcache", "assumes that the cache is valid. (dangerous)")
00155 ("version,v", "prints the game's version number and exits.")
00156 ("with-replay", "replays the file loaded with the --load option.")
00157 ;
00158
00159 po::options_description campaign_opts("Campaign options");
00160 campaign_opts.add_options()
00161 ("campaign,c", po::value<std::string>()->implicit_value(std::string()), "goes directly to the campaign with id <arg>. A selection menu will appear if no id was specified.")
00162 ("campaign-difficulty", po::value<int>(), "The difficulty of the specified campaign (1 to max). If none specified, the campaign difficulty selection widget will appear.")
00163 ("campaign-scenario", po::value<std::string>(),"The id of the scenario from the specified campaign. The default is the first scenario.")
00164 ;
00165
00166 po::options_description display_opts("Display options");
00167 display_opts.add_options()
00168 ("bpp", po::value<int>(), "sets BitsPerPixel value. Example: --bpp 32")
00169 ("fps", "displays the number of frames per second the game is currently running at, in a corner of the screen.")
00170 ("fullscreen,f", "runs the game in full screen mode.")
00171 ("max-fps", po::value<int>(), "the maximum fps the game tries to run at. Values should be between 1 and 1000, the default is 50.")
00172 ("new-widgets", "there is a new WIP widget toolkit this switch enables the new toolkit (VERY EXPERIMENTAL don't file bug reports since most are known). Parts of the library are deemed stable and will work without this switch.")
00173 ("resolution,r", po::value<std::string>(), "sets the screen resolution. <arg> should have format XxY. Example: --resolution 800x600")
00174 ("windowed,w", "runs the game in windowed mode.")
00175 ;
00176
00177 po::options_description logging_opts("Logging options");
00178 logging_opts.add_options()
00179 ("logdomains", po::value<std::string>()->implicit_value(std::string()), "lists defined log domains (only the ones containing <arg> filter if such is provided) and exits.")
00180 ("log-error", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'error'. <arg> should be given as comma separated list of domains, wildcards are allowed. Example: --log-error=network,gui/*,engine/enemies")
00181 ("log-warning", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'warning'. Similar to --log-error.")
00182 ("log-info", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'info'. Similar to --log-error.")
00183 ("log-debug", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'debug'. Similar to --log-error.")
00184 ;
00185
00186 po::options_description multiplayer_opts("Multiplayer options");
00187 multiplayer_opts.add_options()
00188 ("multiplayer,m", "Starts a multiplayer game. There are additional options that can be used as explained below:")
00189 ("ai-config", po::value<std::vector<std::string> >()->composing(), "selects a configuration file to load for this side. <arg> should have format side:value")
00190 ("algorithm", po::value<std::vector<std::string> >()->composing(), "selects a non-standard algorithm to be used by the AI controller for this side. <arg> should have format side:value")
00191 ("controller", po::value<std::vector<std::string> >()->composing(), "selects the controller for this side. <arg> should have format side:value")
00192 ("era", po::value<std::string>(), "selects the era to be played in by its id.")
00193 ("exit-at-end", "exit Wesnoth at the end of the scenario.")
00194 ("label", po::value<std::string>(), "sets the label for AIs.")
00195 ("nogui", "runs the game without the GUI.")
00196 ("parm", po::value<std::vector<std::string> >()->composing(), "sets additional parameters for this side. <arg> should have format side:name:value.")
00197 ("scenario", po::value<std::string>(), "selects a multiplayer scenario. The default scenario is \"multiplayer_The_Freelands\".")
00198 ("side", po::value<std::vector<std::string> >()->composing(), "selects a faction of the current era for this side by id. <arg> should have format side:value.")
00199 ("turns", po::value<std::string>(), "sets the number of turns. The default is \"50\".")
00200 ;
00201
00202 po::options_description preprocessor_opts("Preprocessor mode options");
00203 preprocessor_opts.add_options()
00204 ("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.")
00205 ("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")
00206 ("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.")
00207 ("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.")
00208 ;
00209
00210 po::options_description proxy_opts("Proxy options");
00211 proxy_opts.add_options()
00212 ("proxy", "enables usage of proxy for network connections.")
00213 ("proxy-address", po::value<std::string>(), "specifies address of the proxy.")
00214 ("proxy-port", po::value<std::string>(), "specifies port of the proxy.")
00215 ("proxy-user", po::value<std::string>(), "specifies username to log in to the proxy.")
00216 ("proxy-password", po::value<std::string>(), "specifies password to log in to the proxy.")
00217 ;
00218
00219 hidden_.add_options()
00220 ("new-storyscreens", "")
00221 ("smallgui", "")
00222 ;
00223 visible_.add(general_opts).add(campaign_opts).add(display_opts).add(logging_opts).add(multiplayer_opts).add(preprocessor_opts).add(proxy_opts);
00224
00225 all_.add(visible_).add(hidden_);
00226
00227 po::positional_options_description positional;
00228 positional.add("data-dir",1);
00229
00230 po::variables_map vm;
00231 const int parsing_style = po::command_line_style::default_style ^ po::command_line_style::allow_guessing;
00232 po::store(po::command_line_parser(argc_,argv_).options(all_).positional(positional).style(parsing_style).run(),vm);
00233
00234 if (vm.count("ai-config"))
00235 multiplayer_ai_config = parse_to_uint_string_tuples_(vm["ai-config"].as<std::vector<std::string> >());
00236 if (vm.count("algorithm"))
00237 multiplayer_algorithm = parse_to_uint_string_tuples_(vm["algorithm"].as<std::vector<std::string> >());
00238 if (vm.count("bpp"))
00239 bpp = vm["bpp"].as<int>();
00240 if (vm.count("campaign"))
00241 campaign = vm["campaign"].as<std::string>();
00242 if (vm.count("campaign-difficulty"))
00243 campaign_difficulty = vm["campaign-difficulty"].as<int>();
00244 if (vm.count("campaign-scenario"))
00245 campaign_scenario = vm["campaign-scenario"].as<std::string>();
00246 if (vm.count("clock"))
00247 clock = true;
00248 if (vm.count("config-dir"))
00249 config_dir = vm["config-dir"].as<std::string>();
00250 if (vm.count("config-path"))
00251 config_path = true;
00252 if (vm.count("controller"))
00253 multiplayer_controller = parse_to_uint_string_tuples_(vm["controller"].as<std::vector<std::string> >());
00254 if (vm.count("data-dir"))
00255 data_dir = vm["data-dir"].as<std::string>();
00256 if (vm.count("debug"))
00257 debug = true;
00258 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00259 if (vm.count("debug-dot-domain")) {
00260 debug_dot_domain = vm["debug-dot-domain"].as<std::string>();
00261 }
00262 if (vm.count("debug-dot-level")) {
00263 debug_dot_level = vm["debug-dot-level"].as<std::string>();
00264 }
00265 #endif
00266 if (vm.count("editor"))
00267 editor = vm["editor"].as<std::string>();
00268 if (vm.count("era"))
00269 multiplayer_era = vm["era"].as<std::string>();
00270 if (vm.count("exit-at-end"))
00271 multiplayer_exit_at_end = true;
00272 if (vm.count("fps"))
00273 fps = true;
00274 if (vm.count("fullscreen"))
00275 fullscreen = true;
00276 if (vm.count("gunzip"))
00277 gunzip = vm["gunzip"].as<std::string>();
00278 if (vm.count("gzip"))
00279 gzip = vm["gzip"].as<std::string>();
00280 if (vm.count("help"))
00281 help = true;
00282 if (vm.count("label"))
00283 multiplayer_label = vm["label"].as<std::string>();
00284 if (vm.count("language"))
00285 language = vm["language"].as<std::string>();
00286 if (vm.count("load"))
00287 load = vm["load"].as<std::string>();
00288 if (vm.count("log-error"))
00289 parse_log_domains_(vm["log-error"].as<std::string>(),0);
00290 if (vm.count("log-warning"))
00291 parse_log_domains_(vm["log-warning"].as<std::string>(),1);
00292 if (vm.count("log-info"))
00293 parse_log_domains_(vm["log-info"].as<std::string>(),2);
00294 if (vm.count("log-debug"))
00295 parse_log_domains_(vm["log-debug"].as<std::string>(),3);
00296 if (vm.count("logdomains"))
00297 logdomains = vm["logdomains"].as<std::string>();
00298 if (vm.count("max-fps"))
00299 max_fps = vm["max-fps"].as<int>();
00300 if (vm.count("multiplayer"))
00301 multiplayer = true;
00302 if (vm.count("new-storyscreens"))
00303 new_storyscreens = true;
00304 if (vm.count("new-syntax"))
00305 new_syntax = true;
00306 if (vm.count("new-widgets"))
00307 new_widgets = true;
00308 if (vm.count("nocache"))
00309 nocache = true;
00310 if (vm.count("nodelay"))
00311 nodelay = true;
00312 if (vm.count("nomusic"))
00313 nomusic = true;
00314 if (vm.count("nosound"))
00315 nosound = true;
00316 if (vm.count("nogui"))
00317 nogui = true;
00318 if (vm.count("parm"))
00319 multiplayer_parm = parse_to_uint_string_string_tuples_(vm["parm"].as<std::vector<std::string> >());
00320 if (vm.count("path"))
00321 path = true;
00322 if (vm.count("preprocess"))
00323 {
00324 preprocess = true;
00325 preprocess_path = vm["preprocess"].as<two_strings>().get<0>();
00326 preprocess_target = vm["preprocess"].as<two_strings>().get<1>();
00327 }
00328 if (vm.count("preprocess-defines"))
00329 preprocess_defines = utils::split(vm["preprocess-defines"].as<std::string>(), ',');
00330 if (vm.count("preprocess-input-macros"))
00331 preprocess_input_macros = vm["preprocess-input-macros"].as<std::string>();
00332 if (vm.count("preprocess-output-macros"))
00333 preprocess_output_macros = vm["preprocess-output-macros"].as<std::string>();
00334 if (vm.count("proxy"))
00335 proxy = true;
00336 if (vm.count("proxy-address"))
00337 proxy_address = vm["proxy-address"].as<std::string>();
00338 if (vm.count("proxy-password"))
00339 proxy_password = vm["proxy-password"].as<std::string>();
00340 if (vm.count("proxy-port"))
00341 proxy_port = vm["proxy-port"].as<std::string>();
00342 if (vm.count("proxy-user"))
00343 proxy_user = vm["proxy-user"].as<std::string>();
00344 if (vm.count("resolution"))
00345 parse_resolution_(vm["resolution"].as<std::string>());
00346 if (vm.count("rng-seed"))
00347 rng_seed = vm["rng-seed"].as<unsigned int>();
00348 if (vm.count("scenario"))
00349 multiplayer_scenario = vm["scenario"].as<std::string>();
00350 if (vm.count("screenshot"))
00351 {
00352 screenshot = true;
00353 screenshot_map_file = vm["screenshot"].as<two_strings>().get<0>();
00354 screenshot_output_file = vm["screenshot"].as<two_strings>().get<1>();
00355 }
00356 if (vm.count("server"))
00357 server = vm["server"].as<std::string>();
00358 if (vm.count("username"))
00359 username = vm["username"].as<std::string>();
00360 if (vm.count("password"))
00361 password = vm["password"].as<std::string>();
00362 if (vm.count("side"))
00363 multiplayer_side = parse_to_uint_string_tuples_(vm["side"].as<std::vector<std::string> >());
00364 if (vm.count("test"))
00365 test = vm["test"].as<std::string>();
00366 if (vm.count("turns"))
00367 multiplayer_turns = vm["turns"].as<std::string>();
00368 if (vm.count("smallgui"))
00369 smallgui = true;
00370 if (vm.count("strict-validation"))
00371 strict_validation = true;
00372 if (vm.count("validcache"))
00373 validcache = true;
00374 if (vm.count("version"))
00375 version = true;
00376 if (vm.count("windowed"))
00377 windowed = true;
00378 if (vm.count("with-replay"))
00379 with_replay = true;
00380 }
00381
00382 void commandline_options::parse_log_domains_(const std::string &domains_string, const int severity)
00383 {
00384 const std::vector<std::string> domains = utils::split(domains_string, ',');
00385 foreach (const std::string& domain, domains)
00386 {
00387 if (!log)
00388 log = std::vector<boost::tuple<int, std::string> >();
00389 log->push_back(boost::tuple<int, std::string>(severity,domain));
00390 }
00391 }
00392
00393 void commandline_options::parse_resolution_ ( const std::string& resolution_string )
00394 {
00395 const std::vector<std::string> tokens = utils::split(resolution_string, 'x');
00396 if (tokens.size() != 2)
00397 {}
00398 int xres = lexical_cast<int>(tokens[0]);
00399 int yres = lexical_cast<int>(tokens[1]);
00400 resolution = boost::tuple<int,int>(xres,yres);
00401 }
00402
00403 std::vector<boost::tuple<unsigned int,std::string> > commandline_options::parse_to_uint_string_tuples_(const std::vector<std::string> &strings, char separator)
00404 {
00405 std::vector<boost::tuple<unsigned int,std::string> > vec;
00406 boost::tuple<unsigned int,std::string> elem;
00407 foreach(const std::string &s, strings)
00408 {
00409 const std::vector<std::string> tokens = utils::split(s, separator);
00410 if (tokens.size()!=2)
00411 {
00412
00413 }
00414 elem.get<0>() = lexical_cast<unsigned int>(tokens[0]);
00415
00416 elem.get<1>() = tokens[1];
00417 vec.push_back(elem);
00418 }
00419 return vec;
00420 }
00421
00422 std::vector<boost::tuple<unsigned int,std::string,std::string> > commandline_options::parse_to_uint_string_string_tuples_(const std::vector<std::string> &strings, char separator)
00423 {
00424 std::vector<boost::tuple<unsigned int,std::string,std::string> > vec;
00425 boost::tuple<unsigned int,std::string,std::string> elem;
00426 foreach(const std::string &s, strings)
00427 {
00428 const std::vector<std::string> tokens = utils::split(s, separator);
00429 if (tokens.size()!=3)
00430 {
00431
00432 }
00433 elem.get<0>() = lexical_cast<unsigned int>(tokens[0]);
00434
00435 elem.get<1>() = tokens[1];
00436 elem.get<2>() = tokens[2];
00437 vec.push_back(elem);
00438 }
00439 return vec;
00440 }
00441
00442 std::ostream& operator<<(std::ostream &os, const commandline_options& cmdline_opts)
00443 {
00444 os << "Usage: " << cmdline_opts.argv_[0] << " [<options>] [<data-directory>]\n";
00445 os << cmdline_opts.visible_;
00446 return os;
00447 }