1 /*
2 Copyright (C) 2011 - 2018 by Lukasz Dobrogowski <lukasz.dobrogowski@gmail.com>
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any lfooater version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13 */
14
15 #include "commandline_options.hpp"
16
17 #include "config.hpp"
18 #include "formatter.hpp"
19 #include "lexical_cast.hpp"
20 #include "log.hpp" // for logger, set_strict_severity, etc
21 #include "serialization/string_utils.hpp" // for split
22 #include "utils/general.hpp" // for clamp
23
24 #include <boost/any.hpp> // for any
25 #include <boost/program_options/cmdline.hpp>
26 #include <boost/program_options/errors.hpp> // for validation_error, etc
27 #include <boost/program_options/parsers.hpp>
28 #include <boost/program_options/positional_options.hpp>
29 #include <boost/program_options/value_semantic.hpp> // for value, etc
30 #include <boost/program_options/variables_map.hpp> // for variables_map, etc
31 #include <iostream> // for operator<<, basic_ostream, etc
32
33 namespace po = boost::program_options;
34
35 class two_strings : public std::pair<std::string,std::string> {};
36
validate(boost::any & v,const std::vector<std::string> & values,two_strings *,int)37 static void validate(boost::any& v, const std::vector<std::string>& values,
38 two_strings*, int)
39 {
40 two_strings ret_val;
41 if (values.size() != 2) {
42 throw po::validation_error(po::validation_error::invalid_option_value);
43 }
44 ret_val.first = values.at(0);
45 ret_val.second = values.at(1);
46 v = ret_val;
47 }
48
bad_commandline_resolution(const std::string & resolution)49 bad_commandline_resolution::bad_commandline_resolution(const std::string& resolution)
50 : error(formatter() << "Invalid resolution \"" << resolution
51 << "\" (WIDTHxHEIGHT expected)")
52 {
53 }
54
bad_commandline_tuple(const std::string & str,const std::string & expected_format)55 bad_commandline_tuple::bad_commandline_tuple(const std::string& str,
56 const std::string& expected_format)
57 : error(formatter() << "Invalid value set \"" << str
58 << "\" (" << expected_format << " expected)")
59 {
60 }
61
commandline_options(const std::vector<std::string> & args)62 commandline_options::commandline_options (const std::vector<std::string>& args) :
63 bunzip2(),
64 bzip2(),
65 campaign(),
66 campaign_difficulty(),
67 campaign_scenario(),
68 campaign_skip_story(false),
69 clock(false),
70 data_path(false),
71 data_dir(),
72 debug(false),
73 debug_lua(false),
74 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
75 debug_dot_domain(),
76 debug_dot_level(),
77 #endif
78 editor(),
79 fps(false),
80 fullscreen(false),
81 gunzip(),
82 gzip(),
83 help(),
84 language(),
85 log(),
86 load(),
87 logdomains(),
88 log_precise_timestamps(false),
89 multiplayer(false),
90 multiplayer_ai_config(),
91 multiplayer_algorithm(),
92 multiplayer_controller(),
93 multiplayer_era(),
94 multiplayer_exit_at_end(),
95 multiplayer_ignore_map_settings(),
96 multiplayer_label(),
97 multiplayer_parm(),
98 multiplayer_repeat(),
99 multiplayer_scenario(),
100 multiplayer_side(),
101 multiplayer_turns(),
102 max_fps(),
103 noaddons(false),
104 nocache(false),
105 nodelay(false),
106 nogui(false),
107 nomusic(false),
108 nosound(false),
109 new_widgets(false),
110 preprocess(false),
111 preprocess_defines(),
112 preprocess_input_macros(),
113 preprocess_output_macros(),
114 preprocess_path(),
115 preprocess_target(),
116 resolution(),
117 rng_seed(),
118 server(),
119 username(),
120 password(),
121 screenshot(false),
122 screenshot_map_file(),
123 screenshot_output_file(),
124 script_unsafe_mode(false),
125 strict_validation(false),
126 test(),
127 unit_test(),
128 headless_unit_test(false),
129 noreplaycheck(false),
130 mptest(false),
131 userconfig_path(false),
132 userconfig_dir(),
133 userdata_path(false),
134 userdata_dir(),
135 validcache(false),
136 version(false),
137 report(false),
138 windowed(false),
139 with_replay(false),
140 args_(args.begin() + 1 , args.end()),
141 args0_(*args.begin()),
142 all_(),
143 visible_(),
144 hidden_()
145 {
146 // When adding items don't forget to update doc/man/wesnoth.6
147 // Options are sorted alphabetically by --long-option.
148 po::options_description general_opts("General options");
149 general_opts.add_options()
150 ("all-translations", "Show all translations, even incomplete ones.")
151 ("bunzip2", po::value<std::string>(), "decompresses a file (<arg>.bz2) in bzip2 format and stores it without the .bz2 suffix. <arg>.bz2 will be removed.")
152 ("bzip2", po::value<std::string>(), "compresses a file (<arg>) in bzip2 format, stores it as <arg>.bz2 and removes <arg>.")
153 ("clock", "Adds the option to show a clock for testing the drawing timer.")
154 ("config-dir", po::value<std::string>(), "sets the path of the userdata 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. DEPRECATED: use userdata-dir instead.")
155 ("config-path", "prints the path of the userdata directory and exits. DEPRECATED: use userdata-path instead.")
156 ("core", po::value<std::string>(), "overrides the loaded core with the one whose id is specified.")
157 ("data-dir", po::value<std::string>(), "overrides the data directory with the one specified.")
158 ("data-path", "prints the path of the data directory and exits.")
159 ("debug,d", "enables additional command mode options in-game.")
160 ("debug-lua", "enables some Lua debugging mechanisms")
161 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
162 ("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).")
163 ("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.")
164 #endif
165 ("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>.")
166 ("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.")
167 ("gzip", po::value<std::string>(), "compresses a file (<arg>) in gzip format, stores it as <arg>.gz and removes <arg>.")
168 ("help,h", "prints this message and exits.")
169 ("language,L", po::value<std::string>(), "uses language <arg> (symbol) this session. Example: --language ang_GB@latin")
170 ("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.")
171 ("noaddons", "disables the loading of all add-ons.")
172 ("nocache", "disables caching of game data.")
173 ("nodelay", "runs the game without any delays.")
174 ("nomusic", "runs the game without music.")
175 ("nosound", "runs the game without sounds and music.")
176 ("password", po::value<std::string>(), "uses <password> when connecting to a server, ignoring other preferences.")
177 ("plugin", po::value<std::string>(), "(experimental) load a script which defines a wesnoth plugin. similar to --script below, but Lua file should return a function which will be run as a coroutine and periodically woken up with updates.")
178 ("render-image", po::value<two_strings>()->multitoken(), "takes two arguments: <image> <output>. Like screenshot, but instead of a map, takes a valid Wesnoth 'image path string' with image path functions, and writes it to a .png file."
179 #ifdef _WIN32
180 " Implies --wconsole."
181 #endif // _WIN32
182 )
183 ("report,R", "initializes game directories, prints build information suitable for use in bug reports, and exits."
184 #ifdef _WIN32
185 " Implies --wconsole."
186 #endif // _WIN32
187 )
188 ("rng-seed", po::value<unsigned int>(), "seeds the random number generator with number <arg>. Example: --rng-seed 0")
189 ("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."
190 #ifdef _WIN32
191 " Implies --wconsole."
192 #endif // _WIN32
193 )
194 ("script", po::value<std::string>(), "(experimental) file containing a Lua script to control the client")
195 ("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.")
196 ("strict-validation", "makes validation errors fatal")
197 ("translations-over", po::value<unsigned int>(), "Specify the standard for determining whether a translation is complete.")
198 ("unsafe-scripts", "makes the \'package\' package available to Lua scripts, so that they can load arbitrary packages. Do not do this with untrusted scripts! This action gives ua the same permissions as the Wesnoth executable.")
199 ("userconfig-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. Defaults to $HOME/.config/wesnoth on X11 and to the userdata-dir on other systems.")
200 ("userconfig-path", "prints the path of the user config directory and exits.")
201 ("userdata-dir", po::value<std::string>(), "sets the path of the userdata 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.")
202 ("userdata-path", "prints the path of the userdata directory and exits.")
203 ("username", po::value<std::string>(), "uses <username> when connecting to a server, ignoring other preferences.")
204 ("validcache", "assumes that the cache is valid. (dangerous)")
205 ("version,v", "prints the game's version number and exits.")
206 ("with-replay", "replays the file loaded with the --load option.")
207 #ifdef _WIN32
208 ("wconsole", "attaches a console window on startup (Windows only). Implied by any option that prints something and exits.")
209 #endif // _WIN32
210 ;
211
212 po::options_description campaign_opts("Campaign options");
213 campaign_opts.add_options()
214 ("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.")
215 ("campaign-difficulty", po::value<int>(), "The difficulty of the specified campaign (1 to max). If none specified, the campaign difficulty selection widget will appear.")
216 ("campaign-scenario", po::value<std::string>(),"The id of the scenario from the specified campaign. The default is the first scenario.")
217 ("campaign-skip-story", "Skip [story] tags of the specified campaign.")
218 ;
219
220 po::options_description display_opts("Display options");
221 display_opts.add_options()
222 ("fps", "displays the number of frames per second the game is currently running at, in a corner of the screen. Min/avg/max don't take the FPS limiter into account, act does.")
223 ("fullscreen,f", "runs the game in full screen mode.")
224 ("max-fps", po::value<int>(), "the maximum fps the game tries to run at. Values should be between 1 and 1000, the default is the display's refresh rate.")
225 ("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.")
226 ("resolution,r", po::value<std::string>(), "sets the screen resolution. <arg> should have format XxY. Example: --resolution 800x600")
227 ("windowed,w", "runs the game in windowed mode.")
228 ;
229
230 po::options_description logging_opts("Logging options");
231 logging_opts.add_options()
232 ("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.")
233 ("log-error", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'error'. <arg> should be given as a comma-separated list of domains, wildcards are allowed. Example: --log-error=network,gui/*,engine/enemies")
234 ("log-warning", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'warning'. Similar to --log-error.")
235 ("log-info", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'info'. Similar to --log-error.")
236 ("log-debug", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'debug'. Similar to --log-error.")
237 ("log-none", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'none'. Similar to --log-error.")
238 ("log-precise", "shows the timestamps in log output with more precision.")
239 ;
240
241 po::options_description multiplayer_opts("Multiplayer options");
242 multiplayer_opts.add_options()
243 ("multiplayer,m", "Starts a multiplayer game. There are additional options that can be used as explained below:")
244 ("ai-config", po::value<std::vector<std::string>>()->composing(), "selects a configuration file to load for this side. <arg> should have format side:value")
245 ("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")
246 ("controller", po::value<std::vector<std::string>>()->composing(), "selects the controller for this side. <arg> should have format side:value")
247 ("era", po::value<std::string>(), "selects the era to be played in by its id.")
248 ("exit-at-end", "exit Wesnoth at the end of the scenario.")
249 ("ignore-map-settings", "do not use map settings.")
250 ("label", po::value<std::string>(), "sets the label for AIs.") //TODO is the description precise? this option was undocumented before.
251 ("multiplayer-repeat", po::value<unsigned int>(), "repeats a multiplayer game after it is finished <arg> times.")
252 ("nogui", "runs the game without the GUI.")
253 ("parm", po::value<std::vector<std::string>>()->composing(), "sets additional parameters for this side. <arg> should have format side:name:value.")
254 ("scenario", po::value<std::string>(), "selects a multiplayer scenario. The default scenario is \"multiplayer_The_Freelands\".")
255 ("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.")
256 ("turns", po::value<std::string>(), "sets the number of turns. By default no turn limit is set.")
257 ;
258
259 po::options_description testing_opts("Testing options");
260 testing_opts.add_options()
261 ("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.")
262 ("unit,u", po::value<std::vector<std::string>>(), "runs a unit test scenario. The GUI is not shown and the exit code of the program reflects the victory / defeat conditions of the scenario.\n\t0 - PASS\n\t1 - FAIL\n\t3 - FAIL (INVALID REPLAY)\n\t4 - FAIL (ERRORED REPLAY)\n\t5 - FAIL (BROKE STRICT)\n\t6 - FAIL (WML EXCEPTION)\n\tMultiple tests can be run by giving this option multiple times, in this case the test run will stop immediately after any test which doesn't PASS and the return code will be the status of the test that caused the stop.")
263 ("showgui", "don't run headlessly (for debugging a failing test)")
264 ("log-strict", po::value<std::string>(), "sets the strict level of the logger. any messages sent to log domains of this level or more severe will cause the unit test to fail regardless of the victory result.")
265 ("noreplaycheck", "don't try to validate replay of unit test.")
266 ("mp-test", "load the test mp scenarios.")
267 ;
268
269 po::options_description preprocessor_opts("Preprocessor mode options");
270 preprocessor_opts.add_options()
271 ("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.")
272 ("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")
273 ("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.")
274 ("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.")
275 ;
276
277 //hidden_.add_options()
278 // ("example-hidden-option", "")
279 // ;
280 visible_.add(general_opts).add(campaign_opts).add(display_opts).add(logging_opts).add(multiplayer_opts).add(testing_opts).add(preprocessor_opts);
281
282 all_.add(visible_).add(hidden_);
283
284 po::positional_options_description positional;
285 positional.add("data-dir",1);
286
287 po::variables_map vm;
288 const int parsing_style = po::command_line_style::default_style ^ po::command_line_style::allow_guessing;
289 po::store(po::command_line_parser(args_).options(all_).positional(positional).style(parsing_style).run(),vm);
290
291 if (vm.count("ai-config"))
292 multiplayer_ai_config = parse_to_uint_string_tuples_(vm["ai-config"].as<std::vector<std::string>>());
293 if (vm.count("algorithm"))
294 multiplayer_algorithm = parse_to_uint_string_tuples_(vm["algorithm"].as<std::vector<std::string>>());
295 if (vm.count("bunzip2"))
296 bunzip2 = vm["bunzip2"].as<std::string>();
297 if (vm.count("bzip2"))
298 bzip2 = vm["bzip2"].as<std::string>();
299 if (vm.count("campaign"))
300 campaign = vm["campaign"].as<std::string>();
301 if (vm.count("campaign-difficulty"))
302 campaign_difficulty = vm["campaign-difficulty"].as<int>();
303 if (vm.count("campaign-scenario"))
304 campaign_scenario = vm["campaign-scenario"].as<std::string>();
305 if (vm.count("campaign-skip-story"))
306 campaign_skip_story = true;
307 if (vm.count("clock"))
308 clock = true;
309 if (vm.count("core"))
310 core_id = vm["core"].as<std::string>();
311 if (vm.count("config-dir"))
312 userdata_dir = vm["config-dir"].as<std::string>(); //TODO: complain and remove
313 if (vm.count("config-path"))
314 userdata_path = true; //TODO: complain and remove
315 if (vm.count("controller"))
316 multiplayer_controller = parse_to_uint_string_tuples_(vm["controller"].as<std::vector<std::string>>());
317 if (vm.count("data-dir"))
318 data_dir = vm["data-dir"].as<std::string>();
319 if (vm.count("data-path"))
320 data_path = true;
321 if (vm.count("debug"))
322 debug = true;
323 if (vm.count("debug-lua"))
324 debug_lua = true;
325 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
326 if (vm.count("debug-dot-domain")) {
327 debug_dot_domain = vm["debug-dot-domain"].as<std::string>();
328 }
329 if (vm.count("debug-dot-level")) {
330 debug_dot_level = vm["debug-dot-level"].as<std::string>();
331 }
332 #endif
333 if (vm.count("editor"))
334 editor = vm["editor"].as<std::string>();
335 if (vm.count("era"))
336 multiplayer_era = vm["era"].as<std::string>();
337 if (vm.count("exit-at-end"))
338 multiplayer_exit_at_end = true;
339 if (vm.count("fps"))
340 fps = true;
341 if (vm.count("fullscreen"))
342 fullscreen = true;
343 if (vm.count("gunzip"))
344 gunzip = vm["gunzip"].as<std::string>();
345 if (vm.count("gzip"))
346 gzip = vm["gzip"].as<std::string>();
347 if (vm.count("help"))
348 help = true;
349 if (vm.count("ignore-map-settings"))
350 multiplayer_ignore_map_settings = true;
351 if (vm.count("label"))
352 multiplayer_label = vm["label"].as<std::string>();
353 if (vm.count("language"))
354 language = vm["language"].as<std::string>();
355 if (vm.count("load"))
356 load = vm["load"].as<std::string>();
357 if (vm.count("log-error"))
358 parse_log_domains_(vm["log-error"].as<std::string>(),lg::err().get_severity());
359 if (vm.count("log-warning"))
360 parse_log_domains_(vm["log-warning"].as<std::string>(),lg::warn().get_severity());
361 if (vm.count("log-info"))
362 parse_log_domains_(vm["log-info"].as<std::string>(),lg::info().get_severity());
363 if (vm.count("log-debug"))
364 parse_log_domains_(vm["log-debug"].as<std::string>(),lg::debug().get_severity());
365 if (vm.count("log-none"))
366 parse_log_domains_(vm["log-none"].as<std::string>(),-1);
367 if (vm.count("logdomains"))
368 logdomains = vm["logdomains"].as<std::string>();
369 if (vm.count("log-precise"))
370 log_precise_timestamps = true;
371 if (vm.count("log-strict"))
372 parse_log_strictness(vm["log-strict"].as<std::string>());
373 if (vm.count("max-fps"))
374 max_fps = vm["max-fps"].as<int>();
375 if (vm.count("mp-test"))
376 mptest = true;
377 if (vm.count("multiplayer"))
378 multiplayer = true;
379 if (vm.count("multiplayer-repeat"))
380 multiplayer_repeat = vm["multiplayer-repeat"].as<unsigned int>();
381 if (vm.count("new-widgets"))
382 new_widgets = true;
383 if (vm.count("noaddons"))
384 noaddons = true;
385 if (vm.count("nocache"))
386 nocache = true;
387 if (vm.count("nodelay"))
388 nodelay = true;
389 if (vm.count("nomusic"))
390 nomusic = true;
391 if (vm.count("noreplaycheck"))
392 noreplaycheck = true;
393 if (vm.count("nosound"))
394 nosound = true;
395 if (vm.count("nogui"))
396 nogui = true;
397 if (vm.count("parm"))
398 multiplayer_parm = parse_to_uint_string_string_tuples_(vm["parm"].as<std::vector<std::string>>());
399 if (vm.count("preprocess"))
400 {
401 preprocess = true;
402 preprocess_path = vm["preprocess"].as<two_strings>().first;
403 preprocess_target = vm["preprocess"].as<two_strings>().second;
404 }
405 if (vm.count("preprocess-defines"))
406 preprocess_defines = utils::split(vm["preprocess-defines"].as<std::string>(), ',');
407 if (vm.count("preprocess-input-macros"))
408 preprocess_input_macros = vm["preprocess-input-macros"].as<std::string>();
409 if (vm.count("preprocess-output-macros"))
410 preprocess_output_macros = vm["preprocess-output-macros"].as<std::string>();
411 if (vm.count("resolution"))
412 parse_resolution_(vm["resolution"].as<std::string>());
413 if (vm.count("rng-seed"))
414 rng_seed = vm["rng-seed"].as<unsigned int>();
415 if (vm.count("scenario"))
416 multiplayer_scenario = vm["scenario"].as<std::string>();
417 if (vm.count("render-image"))
418 {
419 render_image = vm["render-image"].as<two_strings>().first;
420 render_image_dst = vm["render-image"].as<two_strings>().second;
421 }
422 if (vm.count("screenshot"))
423 {
424 screenshot = true;
425 screenshot_map_file = vm["screenshot"].as<two_strings>().first;
426 screenshot_output_file = vm["screenshot"].as<two_strings>().second;
427 }
428 if (vm.count("script"))
429 script_file = vm["script"].as<std::string>();
430 if (vm.count("unsafe-scripts"))
431 script_unsafe_mode = true;
432 if (vm.count("plugin"))
433 plugin_file = vm["plugin"].as<std::string>();
434 if (vm.count("server"))
435 server = vm["server"].as<std::string>();
436 if (vm.count("username"))
437 username = vm["username"].as<std::string>();
438 if (vm.count("password"))
439 password = vm["password"].as<std::string>();
440 if (vm.count("report"))
441 report = true;
442 if (vm.count("side"))
443 multiplayer_side = parse_to_uint_string_tuples_(vm["side"].as<std::vector<std::string>>());
444 if (vm.count("test"))
445 test = vm["test"].as<std::string>();
446 if (vm.count("unit"))
447 {
448 unit_test = vm["unit"].as<std::vector<std::string>>();
449 headless_unit_test = true;
450 }
451 if (vm.count("showgui"))
452 headless_unit_test = false;
453 if (vm.count("noreplaycheck"))
454 noreplaycheck = true;
455 if (vm.count("turns"))
456 multiplayer_turns = vm["turns"].as<std::string>();
457 if (vm.count("strict-validation"))
458 strict_validation = true;
459 if (vm.count("userconfig-dir"))
460 userconfig_dir = vm["userconfig-dir"].as<std::string>();
461 if (vm.count("userconfig-path"))
462 userconfig_path = true;
463 if (vm.count("userdata-dir"))
464 userdata_dir = vm["userdata-dir"].as<std::string>();
465 if (vm.count("userdata-path"))
466 userdata_path = true;
467 if (vm.count("validcache"))
468 validcache = true;
469 if (vm.count("version"))
470 version = true;
471 if (vm.count("windowed"))
472 windowed = true;
473 if (vm.count("with-replay"))
474 with_replay = true;
475 if(vm.count("all-translations"))
476 translation_percent = 0;
477 else if(vm.count("translations-over"))
478 translation_percent = utils::clamp<unsigned int>(vm["translations-over"].as<unsigned int>(), 0, 100);
479 }
480
parse_log_domains_(const std::string & domains_string,const int severity)481 void commandline_options::parse_log_domains_(const std::string &domains_string, const int severity)
482 {
483 const std::vector<std::string> domains = utils::split(domains_string, ',');
484 for (const std::string& domain : domains)
485 {
486 if (!log)
487 log = std::vector<std::pair<int, std::string>>();
488 log->emplace_back(severity, domain);
489 }
490 }
491
parse_log_strictness(const std::string & severity)492 void commandline_options::parse_log_strictness (const std::string & severity ) {
493 static lg::logger const *loggers[] { &lg::err(), &lg::warn(), &lg::info(), &lg::debug() };
494 for (const lg::logger * l : loggers ) {
495 if (severity == l->get_name()) {
496 lg::set_strict_severity(*l);
497 return ;
498 }
499 }
500 std::cerr << "Unrecognized argument to --log-strict : " << severity << " . \nDisabling strict mode logging." << std::endl;
501 lg::set_strict_severity(-1);
502 }
503
parse_resolution_(const std::string & resolution_string)504 void commandline_options::parse_resolution_ ( const std::string& resolution_string )
505 {
506 const std::vector<std::string> tokens = utils::split(resolution_string, 'x');
507 if (tokens.size() != 2) {
508 throw bad_commandline_resolution(resolution_string);
509 }
510
511 int xres, yres;
512
513 try {
514 xres = std::stoi(tokens[0]);
515 yres = std::stoi(tokens[1]);
516 } catch(const std::invalid_argument &) {
517 throw bad_commandline_resolution(resolution_string);
518 }
519
520 resolution = std::make_pair(xres, yres);
521 }
522
parse_to_uint_string_tuples_(const std::vector<std::string> & strings,char separator)523 std::vector<std::pair<unsigned int,std::string>> commandline_options::parse_to_uint_string_tuples_(const std::vector<std::string> &strings, char separator)
524 {
525 std::vector<std::pair<unsigned int,std::string>> vec;
526 const std::string& expected_format
527 = std::string() + "UINT" + separator + "STRING";
528
529 for (const std::string &s : strings)
530 {
531 const std::vector<std::string> tokens = utils::split(s, separator);
532 if(tokens.size() != 2) {
533 throw bad_commandline_tuple(s, expected_format);
534 }
535
536 unsigned int temp;
537 try {
538 temp = lexical_cast<unsigned int>(tokens[0]);
539 } catch (const bad_lexical_cast &) {
540 throw bad_commandline_tuple(s, expected_format);
541 }
542
543 vec.emplace_back(temp, tokens[1]);
544 }
545 return vec;
546 }
547
parse_to_uint_string_string_tuples_(const std::vector<std::string> & strings,char separator)548 std::vector<std::tuple<unsigned int,std::string,std::string>> commandline_options::parse_to_uint_string_string_tuples_(const std::vector<std::string> &strings, char separator)
549 {
550 std::vector<std::tuple<unsigned int,std::string,std::string>> vec;
551 const std::string& expected_format
552 = std::string() + "UINT" + separator + "STRING" + separator + "STRING";
553
554 for (const std::string &s : strings)
555 {
556 const std::vector<std::string> tokens = utils::split(s, separator);
557 if(tokens.size() != 3) {
558 throw bad_commandline_tuple(s, expected_format);
559 }
560
561 unsigned int temp;
562 try {
563 temp = lexical_cast<unsigned int>(tokens[0]);
564 } catch (const bad_lexical_cast &) {
565 throw bad_commandline_tuple(s, expected_format);
566 }
567
568 vec.emplace_back(temp, tokens[1], tokens[2]);
569 }
570 return vec;
571 }
572
operator <<(std::ostream & os,const commandline_options & cmdline_opts)573 std::ostream& operator<<(std::ostream &os, const commandline_options& cmdline_opts)
574 {
575 os << "Usage: " << cmdline_opts.args0_ << " [<options>] [<data-directory>]\n";
576 os << cmdline_opts.visible_;
577 return os;
578 }
579
to_config() const580 config commandline_options::to_config() const {
581 config ret;
582 if (server) {
583 ret["server"] = *server;
584 }
585 if (username) {
586 ret["username"] = *username;
587 }
588 if (password) {
589 ret["password"] = *password;
590 }
591 return ret;
592 }
593