The Battle for Wesnoth  1.19.25+dev
commandline_options.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2025
3  by Lukasz Dobrogowski <lukasz.dobrogowski@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "commandline_options.hpp"
17 
18 #include "config.hpp"
19 #include "formatter.hpp"
20 #include "lexical_cast.hpp"
21 #include "serialization/string_utils.hpp" // for split
22 
23 #include <boost/any.hpp> // for any
24 #include <boost/program_options/cmdline.hpp>
25 #include <boost/program_options/errors.hpp> // for validation_error, etc
26 #include <boost/program_options/parsers.hpp>
27 #include <boost/program_options/positional_options.hpp>
28 #include <boost/program_options/value_semantic.hpp> // for value, etc
29 #include <boost/program_options/variables_map.hpp> // for variables_map, etc
30 
31 #include <array>
32 #include <string>
33 
34 #ifndef _WIN32
35 # include <unistd.h> // for isatty
36 #endif
37 
38 namespace po = boost::program_options;
39 
40 class two_strings : public std::pair<std::string,std::string> {};
41 
42 static void validate(boost::any& v, const std::vector<std::string>& values,
43  two_strings*, int)
44 {
45  two_strings ret_val;
46  if(values.size() != 2) {
47  throw po::validation_error(po::validation_error::invalid_option_value);
48  }
49  ret_val.first = values[0];
50  ret_val.second = values[1];
51  v = ret_val;
52 }
53 
55  : error(formatter() << "Invalid resolution \"" << resolution
56  << "\" (WIDTHxHEIGHT expected)")
57 {
58 }
59 
61  const std::string& expected_format)
62  : error(formatter() << "Invalid value set \"" << str
63  << "\" (" << expected_format << " expected)")
64 {
65 }
66 
67 
68 #define IMPLY_TERMINAL " Implies --no-log-to-file"
69 
70 
71 commandline_options::commandline_options(const std::vector<std::string>& args)
72  : campaign()
73  , campaign_difficulty()
74  , campaign_scenario()
75  , campaign_skip_story(false)
76  , clock(false)
77  , core_id()
78  , print_data_path(false)
79  , data_dir()
80  , debug(false)
81  , debug_lua(false)
82  , strict_lua(false)
83  , allow_insecure(false)
84  , addon_server_info(false)
85 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
86  , debug_dot_domain()
87  , debug_dot_level()
88 #endif
89  , editor()
90  , fps(false)
91  , fullscreen(false)
92  , help()
93  , language()
94  , log()
95  , load()
96  , logdomains()
97  , log_precise_timestamps(false)
98  , multiplayer(false)
99  , multiplayer_ai_config()
100  , multiplayer_algorithm()
101  , multiplayer_controller()
102  , multiplayer_era()
103  , multiplayer_exit_at_end()
104  , multiplayer_ignore_map_settings()
105  , multiplayer_label()
106  , multiplayer_parm()
107  , multiplayer_repeat()
108  , multiplayer_scenario()
109  , multiplayer_side()
110  , multiplayer_turns()
111  , max_fps()
112  , noaddons(false)
113  , nocache(false)
114  , nogui(false)
115  , nobanner(false)
116  , nomusic(false)
117  , no_simd(false)
118  , nosound(false)
119  , new_widgets(false)
120  , preprocess(false)
121  , preprocess_defines()
122  , preprocess_input_macros()
123  , preprocess_output_macros()
124  , preprocess_path()
125  , preprocess_target()
126  , resolution()
127  , rng_seed()
128  , server()
129  , username()
130  , password()
131  , render_image()
132  , render_image_dst()
133  , generate_spritesheet()
134  , screenshot(false)
135  , screenshot_map_file()
136  , screenshot_output_file()
137  , plugin_file()
138  , script_unsafe_mode(false)
139  , strict_validation(false)
140  , test()
141  , unit_test()
142  , headless_unit_test(false)
143  , noreplaycheck(false)
144  , mptest(false)
145  , print_usercache_path(false)
146  , usercache_dir()
147  , print_userdata_path(false)
148  , userdata_dir()
149  , validcache(false)
150  , validate_core(false)
151  , validate_addon()
152  , validate_schema()
153  , validate_wml()
154  , validate_with()
155  , do_diff()
156  , do_patch()
157  , diff_left()
158  , diff_right()
159  , version(false)
160  , simple_version(false)
161  , report(false)
162  , windowed(false)
163  , with_replay(false)
164 #ifdef _WIN32
165  , no_console(false)
166 #endif
167  , no_log_sanitize(false)
168  , log_to_file(false)
169  , no_log_to_file(
170 #ifdef _WIN32
171  false
172 #else
173  isatty(STDOUT_FILENO) // default to no log file if stdout is a tty
174 #endif
175  )
176  , translation_percent()
177  , args_(args.begin() + 1, args.end())
178  , args0_(*args.begin())
179  , all_()
180  , visible_()
181  , hidden_()
182 {
183  // When adding items don't forget to update doc/man/wesnoth.6
184  // Options are sorted alphabetically by --long-option.
185  po::options_description general_opts("General options");
186  general_opts.add_options()
187  ("all-translations", "Show all translations, even incomplete ones.")
188  ("clock", "Adds the option to show a clock for testing the drawing timer.")
189  ("core", po::value<std::string>(), "Overrides the loaded core with the one whose id is specified.")
190  ("data-dir", po::value<std::string>(), "Overrides the data directory with the one specified. The data directory is the one that contains subdirectories 'data', 'fonts', 'images' and others.")
191  ("data-path", "prints the path of the data directory and exits." IMPLY_TERMINAL)
192  ("debug,d", "enables additional command mode options in-game.")
193  ("debug-lua", "enables some Lua debugging mechanisms")
194  ("strict-lua", "disallow deprecated Lua API calls")
195  ("allow-insecure", "Allows sending a plaintext password over an unencrypted connection. Should only ever be used for local testing.")
196  ("addon-server-info", "Shows a button on the add-ons manager to query the add-ons server for various information.")
197 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
198  ("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).")
199  ("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.")
200 #endif
201  ("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>.")
202  ("help,h", "prints this message and exits." IMPLY_TERMINAL)
203  ("language,L", po::value<std::string>(), "uses language <arg> (symbol) this session. Example: --language ang_GB@latin")
204  ("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.")
205  ("noaddons", "disables the loading of all add-ons.")
206  ("nocache", "disables caching of game data.")
207  ("nomusic", "runs the game without music.")
208  ("no-simd", "disables SIMD hardware acceleration.")
209  ("nosound", "runs the game without sounds and music.")
210  ("password", po::value<std::string>(), "uses <password> when connecting to a server, ignoring other preferences.")
211  ("plugin", po::value<std::string>(), "load a script which defines a wesnoth plugin. Lua file should return a function which will be run as a coroutine and periodically woken up with updates.")
212  ("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." IMPLY_TERMINAL)
213  ("generate-spritesheet", po::value<std::string>(), "generates a spritesheet from all png images in the given path, recursively (one sheet per directory)")
214  ("report,R", "initializes game directories, prints build information suitable for use in bug reports, and exits." IMPLY_TERMINAL)
215  ("rng-seed", po::value<unsigned int>(), "seeds the random number generator with number <arg>. Example: --rng-seed 0")
216  ("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." IMPLY_TERMINAL)
217  ("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.")
218  ("strict-validation", "makes validation errors fatal")
219  ("translations-over", po::value<unsigned int>(), "Specify the standard for determining whether a translation is complete.")
220  ("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.")
221  ("usercache-dir", po::value<std::string>(), "sets the path of the cache 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/.cache/wesnoth on X11 and to the userdata-dir on other systems.")
222  ("usercache-path", "prints the path of the cache directory and exits.")
223  ("userdata-dir", po::value<std::string>(), "sets the path of the userdata directory. You can use ~ to denote $HOME or My Documents\\My Games on Windows.")
224  ("userdata-path", "prints the path of the userdata directory and exits." IMPLY_TERMINAL)
225  ("username", po::value<std::string>(), "uses <username> when connecting to a server, ignoring other preferences.")
226  ("validcache", "assumes that the cache is valid. (dangerous)")
227  ("version,v", "prints the game's version number and exits." IMPLY_TERMINAL)
228  ("simple-version", "prints the game's version number and nothing else." IMPLY_TERMINAL)
229  ("with-replay", "replays the file loaded with the --load option.")
230  ;
231 
232  po::options_description campaign_opts("Campaign options");
233  campaign_opts.add_options()
234  ("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.")
235  ("campaign-difficulty", po::value<int>(), "The difficulty of the specified campaign (1 to max). If none specified, the campaign difficulty selection widget will appear.")
236  ("campaign-scenario", po::value<std::string>(),"The id of the scenario from the specified campaign. The default is the first scenario.")
237  ("campaign-skip-story", "Skip [story] tags of the specified campaign.")
238  ;
239 
240  po::options_description display_opts("Display options");
241  display_opts.add_options()
242  ("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.")
243  ("fullscreen,f", "runs the game in full screen mode.")
244  ("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.")
245  ("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.")
246  ("resolution,r", po::value<std::string>(), "sets the screen resolution. <arg> should have format XxY. Example: --resolution 800x600")
247  ("windowed,w", "runs the game in windowed mode.")
248  ;
249 
250  po::options_description logging_opts("Logging options");
251  logging_opts.add_options()
252  ("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." IMPLY_TERMINAL)
253  ("log-error", po::value<std::vector<std::string>>()->composing(), "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")
254  ("log-warning", po::value<std::vector<std::string>>()->composing(), "sets the severity level of the specified log domain(s) to 'warning'. Similar to --log-error.")
255  ("log-info", po::value<std::vector<std::string>>()->composing(), "sets the severity level of the specified log domain(s) to 'info'. Similar to --log-error.")
256  ("log-debug", po::value<std::vector<std::string>>()->composing(), "sets the severity level of the specified log domain(s) to 'debug'. Similar to --log-error.")
257  ("log-none", po::value<std::vector<std::string>>()->composing(), "sets the severity level of the specified log domain(s) to 'none'. Similar to --log-error.")
258  ("log-precise", "shows the timestamps in log output with more precision.")
259  ("no-log-to-file", "log output is written only to standard error rather than to a file. The environment variable WESNOTH_NO_LOG_FILE can also be set as an alternative.")
260  ("log-to-file", "log output is written to the log file instead of standard error. Cancels the effect of --no-log-to-file whether implicit or explicit.")
261  ("no-log-sanitize", "disables the anonymization that's normally applied when logging, for example replacing usernames with USER.")
262 #ifdef _WIN32
263  ("wnoconsole", "For Windows, when used with --no-log-to-file, results in output being written to cerr/cout instead of CONOUT. Otherwise, does nothing.")
264 #endif
265  ;
266 
267  po::options_description multiplayer_opts("Multiplayer options");
268  multiplayer_opts.add_options()
269  ("multiplayer,m", "Starts a multiplayer game. There are additional options that can be used as explained below:")
270  ("ai-config", po::value<std::vector<std::string>>()->composing(), "selects a configuration file to load for this side. <arg> should have format side:value")
271  ("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")
272  ("controller", po::value<std::vector<std::string>>()->composing(), "selects the controller for this side. <arg> should have format side:value")
273  ("era", po::value<std::string>(), "selects the era to be played in by its id.")
274  ("exit-at-end", "exit Wesnoth at the end of the scenario.")
275  ("ignore-map-settings", "do not use map settings.")
276  ("label", po::value<std::string>(), "sets the label for AIs.") // TODO: is the description precise? this option was undocumented before.
277  ("multiplayer-repeat", po::value<unsigned int>(), "repeats a multiplayer game after it is finished <arg> times.")
278  ("nogui", "runs the game without the GUI." IMPLY_TERMINAL)
279  ("parm", po::value<std::vector<std::string>>()->composing(), "sets additional parameters for this side. <arg> should have format side:name:value.")
280  ("scenario", po::value<std::string>(), "selects a multiplayer scenario. The default scenario is \"multiplayer_The_Freelands\".")
281  ("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.")
282  ("turns", po::value<std::string>(), "sets the number of turns. By default no turn limit is set.")
283  ;
284 
285  po::options_description testing_opts("Testing options");
286  testing_opts.add_options()
287  ("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.")
288  ("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." IMPLY_TERMINAL)
289  ("showgui", "don't run headlessly (for debugging a failing test)")
290  ("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.")
291  ("nobanner", "suppress startup banner.")
292  ("noreplaycheck", "don't try to validate replay of unit test.")
293  ("mp-test", "load the test mp scenarios.")
294  ;
295 
296  po::options_description parsing_opts("WML parsing options");
297  parsing_opts.add_options()
298  ("use-schema,S", po::value<std::string>(), "specify a schema to validate WML against (defaults to the core schema).")
299  ("validate,V", po::value<std::string>(), "validate a specified WML file against a schema." IMPLY_TERMINAL)
300  ("validate-addon", po::value<std::string>()->value_name("addon_id"), "validate the specified addon's WML against the schema. Requires the user to play the campaign (in the GUI) to trigger the validation.")
301  ("validate-core", "validate the core WML against the schema.")
302  ("validate-schema", po::value<std::string>(), "validate a specified WML schema." IMPLY_TERMINAL)
303  ("diff,D", po::value<two_strings>()->multitoken(), "diff two preprocessed WML documents." IMPLY_TERMINAL)
304  ("output,o", po::value<std::string>(), "output to specified file")
305  ("patch,P", po::value<two_strings>()->multitoken(), "apply a patch to a preprocessed WML document." IMPLY_TERMINAL)
306  ("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." IMPLY_TERMINAL)
307  ("preprocess-string", po::value<std::string>(), "preprocesses the given string." IMPLY_TERMINAL)
308  ("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")
309  ("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.")
310  ("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.")
311  ;
312 
313  //hidden_.add_options()
314  // ("example-hidden-option", "")
315  // ;
316  visible_.add(general_opts).add(campaign_opts).add(display_opts).add(logging_opts).add(multiplayer_opts).add(testing_opts).add(parsing_opts);
317 
318  all_.add(visible_).add(hidden_);
319 
320  po::positional_options_description positional;
321  positional.add("data-dir",1);
322 
323  po::variables_map vm;
324  const int parsing_style = po::command_line_style::default_style ^ po::command_line_style::allow_guessing;
325 
326  const auto parsed_options = po::command_line_parser(args_)
327  .options(all_)
328  .positional(positional)
329  .style(parsing_style)
330  .run();
331 
332  po::store(parsed_options, vm);
333 
334  if(vm.count("ai-config"))
335  multiplayer_ai_config = parse_to_uint_string_tuples_(vm["ai-config"].as<std::vector<std::string>>());
336  if(vm.count("algorithm"))
337  multiplayer_algorithm = parse_to_uint_string_tuples_(vm["algorithm"].as<std::vector<std::string>>());
338  if(vm.count("campaign"))
339  campaign = vm["campaign"].as<std::string>();
340  if(vm.count("campaign-difficulty"))
341  campaign_difficulty = vm["campaign-difficulty"].as<int>();
342  if(vm.count("campaign-scenario"))
343  campaign_scenario = vm["campaign-scenario"].as<std::string>();
344  if(vm.count("campaign-skip-story"))
345  campaign_skip_story = true;
346  if(vm.count("clock"))
347  clock = true;
348  if(vm.count("core"))
349  core_id = vm["core"].as<std::string>();
350  if(vm.count("controller"))
351  multiplayer_controller = parse_to_uint_string_tuples_(vm["controller"].as<std::vector<std::string>>());
352  if(vm.count("data-dir"))
353  data_dir = vm["data-dir"].as<std::string>();
354  if(vm.count("data-path"))
355  print_data_path = true;
356  if(vm.count("debug"))
357  debug = true;
358  if(vm.count("debug-lua"))
359  debug_lua = true;
360  if(vm.count("strict-lua"))
361  strict_lua = true;
362  if(vm.count("allow-insecure"))
363  allow_insecure = true;
364  if(vm.count("addon-server-info"))
365  addon_server_info = true;
366 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
367  if(vm.count("debug-dot-domain")) {
368  debug_dot_domain = vm["debug-dot-domain"].as<std::string>();
369  }
370  if(vm.count("debug-dot-level")) {
371  debug_dot_level = vm["debug-dot-level"].as<std::string>();
372  }
373 #endif
374  if(vm.count("editor"))
375  editor = vm["editor"].as<std::string>();
376  if(vm.count("era"))
377  multiplayer_era = vm["era"].as<std::string>();
378  if(vm.count("exit-at-end"))
380  if(vm.count("fps"))
381  fps = true;
382  if(vm.count("fullscreen"))
383  fullscreen = true;
384  if(vm.count("help"))
385  help = true;
386  if(vm.count("ignore-map-settings"))
388  if(vm.count("label"))
389  multiplayer_label = vm["label"].as<std::string>();
390  if(vm.count("language"))
391  language = vm["language"].as<std::string>();
392  if(vm.count("load"))
393  load = vm["load"].as<std::string>();
394  if(vm.count("logdomains"))
395  logdomains = vm["logdomains"].as<std::string>();
396  if(vm.count("log-precise"))
397  log_precise_timestamps = true;
398  if(vm.count("log-strict"))
399  parse_log_strictness(vm["log-strict"].as<std::string>());
400  if(vm.count("max-fps"))
401  max_fps = vm["max-fps"].as<int>();
402  if(vm.count("mp-test"))
403  mptest = true;
404  if(vm.count("multiplayer"))
405  multiplayer = true;
406  if(vm.count("multiplayer-repeat"))
407  multiplayer_repeat = vm["multiplayer-repeat"].as<unsigned int>();
408  if(vm.count("new-widgets"))
409  new_widgets = true;
410  if(vm.count("noaddons"))
411  noaddons = true;
412  if(vm.count("nocache"))
413  nocache = true;
414  if(vm.count("nomusic"))
415  nomusic = true;
416  if(vm.count("noreplaycheck"))
417  noreplaycheck = true;
418  if(vm.count("no-simd"))
419  no_simd = true;
420  if(vm.count("nosound"))
421  nosound = true;
422  if(vm.count("nogui"))
423  nogui = true;
424  if(vm.count("nobanner"))
425  nobanner = true;
426  if(vm.count("parm"))
427  multiplayer_parm = parse_to_uint_string_string_tuples_(vm["parm"].as<std::vector<std::string>>());
428  if(vm.count("preprocess"))
429  {
430  preprocess = true;
431  preprocess_path = vm["preprocess"].as<two_strings>().first;
432  preprocess_target = vm["preprocess"].as<two_strings>().second;
433  }
434  if(vm.count("preprocess-string"))
435  {
436  preprocess_source_string = vm["preprocess-string"].as<std::string>();
437  }
438  if(vm.count("diff"))
439  {
440  do_diff = true;
441  diff_left = vm["diff"].as<two_strings>().first;
442  diff_right = vm["diff"].as<two_strings>().second;
443  }
444  if(vm.count("patch"))
445  {
446  do_patch = true;
447  diff_left = vm["patch"].as<two_strings>().first;
448  diff_right = vm["patch"].as<two_strings>().second;
449  }
450  if(vm.count("output"))
451  {
452  output_file = vm["output"].as<std::string>();
453  }
454  if(vm.count("preprocess-defines"))
455  preprocess_defines = utils::split(vm["preprocess-defines"].as<std::string>(), ',');
456  if(vm.count("preprocess-input-macros"))
457  preprocess_input_macros = vm["preprocess-input-macros"].as<std::string>();
458  if(vm.count("preprocess-output-macros"))
459  preprocess_output_macros = vm["preprocess-output-macros"].as<std::string>();
460  if(vm.count("resolution"))
461  parse_resolution_(vm["resolution"].as<std::string>());
462  if(vm.count("rng-seed"))
463  rng_seed = vm["rng-seed"].as<unsigned int>();
464  if(vm.count("scenario"))
465  multiplayer_scenario = vm["scenario"].as<std::string>();
466  if(vm.count("render-image"))
467  {
468  render_image = vm["render-image"].as<two_strings>().first;
469  render_image_dst = vm["render-image"].as<two_strings>().second;
470  }
471  if(vm.count("generate-spritesheet"))
472  generate_spritesheet = vm["generate-spritesheet"].as<std::string>();
473  if(vm.count("screenshot"))
474  {
475  screenshot = true;
476  screenshot_map_file = vm["screenshot"].as<two_strings>().first;
477  screenshot_output_file = vm["screenshot"].as<two_strings>().second;
478  }
479  if(vm.count("unsafe-scripts"))
480  script_unsafe_mode = true;
481  if(vm.count("plugin"))
482  plugin_file = vm["plugin"].as<std::string>();
483  if(vm.count("server"))
484  server = vm["server"].as<std::string>();
485  if(vm.count("username"))
486  username = vm["username"].as<std::string>();
487  if(vm.count("password"))
488  password = vm["password"].as<std::string>();
489  if(vm.count("report"))
490  report = true;
491  if(vm.count("side"))
492  multiplayer_side = parse_to_uint_string_tuples_(vm["side"].as<std::vector<std::string>>());
493  if(vm.count("test"))
494  test = vm["test"].as<std::string>();
495  if(vm.count("unit"))
496  {
497  unit_test = vm["unit"].as<std::vector<std::string>>();
498  headless_unit_test = true;
499  }
500  if(vm.count("showgui"))
501  headless_unit_test = false;
502  if(vm.count("noreplaycheck"))
503  noreplaycheck = true;
504  if(vm.count("turns"))
505  multiplayer_turns = vm["turns"].as<std::string>();
506  if(vm.count("strict-validation"))
507  strict_validation = true;
508  if(vm.count("usercache-dir"))
509  usercache_dir = vm["usercache-dir"].as<std::string>();
510  if(vm.count("usercache-path"))
511  print_usercache_path = true;
512  if(vm.count("userdata-dir"))
513  userdata_dir = vm["userdata-dir"].as<std::string>();
514  if(vm.count("userdata-path"))
515  print_userdata_path = true;
516  if(vm.count("validcache"))
517  validcache = true;
518  // If you add a new validate-* option, remember the any_validation_option() function
519  if(vm.count("validate"))
520  validate_wml = vm["validate"].as<std::string>();
521  if(vm.count("validate-core"))
522  validate_core = true;
523  if(vm.count("validate-addon"))
524  validate_addon = vm["validate-addon"].as<std::string>();
525  if(vm.count("validate-schema"))
526  validate_schema = vm["validate-schema"].as<std::string>();
527  // If you add a new validate-* option, remember the any_validation_option() function
528  if(vm.count("use-schema"))
529  validate_with = vm["use-schema"].as<std::string>();
530  if(vm.count("version"))
531  version = true;
532  if(vm.count("simple-version"))
533  {
534  simple_version = true;
535  nobanner = true;
536  }
537  if(vm.count("windowed"))
538  windowed = true;
539  if(vm.count("with-replay"))
540  with_replay = true;
541 #ifdef _WIN32
542  if(vm.count("wnoconsole"))
543  no_console = true;
544 #endif
545  if(vm.count("no-log-sanitize"))
546  no_log_sanitize = true;
547  if(vm.count("log-to-file"))
548  log_to_file = true;
549  if(vm.count("no-log-to-file"))
550  no_log_to_file = true;
551  if(vm.count("all-translations"))
553  else if(vm.count("translations-over"))
554  translation_percent = std::clamp<unsigned int>(vm["translations-over"].as<unsigned int>(), 0, 100);
555 
556  // Parse log domain severity following the command line order.
557  for (const auto& option : parsed_options.options) {
558  if (!option.value.empty()) {
559  if (option.string_key == "log-error") {
560  parse_log_domains_(option.value.front(),lg::err().get_severity());
561  } else if (option.string_key == "log-warning") {
562  parse_log_domains_(option.value.front(),lg::warn().get_severity());
563  } else if (option.string_key == "log-info") {
564  parse_log_domains_(option.value.front(),lg::info().get_severity());
565  } else if (option.string_key == "log-debug") {
566  parse_log_domains_(option.value.front(),lg::debug().get_severity());
567  } else if (option.string_key == "log-none") {
568  parse_log_domains_(option.value.front(),lg::severity::LG_NONE);
569  }
570  }
571  }
572 }
573 
574 void commandline_options::parse_log_domains_(const std::string &domains_string, const lg::severity severity)
575 {
576  if(std::vector<std::string> domains = utils::split(domains_string, ','); !domains.empty()) {
577  if(!log) {
578  log.emplace();
579  }
580  for(auto&& domain : domains) {
581  log->emplace_back(severity, std::move(domain));
582  }
583  }
584 }
585 
587  static const std::array<const lg::logger*, 4> loggers {{&lg::err(), &lg::warn(), &lg::info(), &lg::debug()}};
588  for(const lg::logger * l : loggers ) {
589  if(severity == l->get_name()) {
591  return;
592  }
593  }
594  PLAIN_LOG << "Unrecognized argument to --log-strict : " << severity << " . \nDisabling strict mode logging.";
596 }
597 
598 void commandline_options::parse_resolution_ (const std::string& resolution_string)
599 {
600  const std::vector<std::string> tokens = utils::split(resolution_string, 'x');
601  if(tokens.size() != 2) {
602  throw bad_commandline_resolution(resolution_string);
603  }
604 
605  int xres, yres;
606 
607  try {
608  xres = std::stoi(tokens[0]);
609  yres = std::stoi(tokens[1]);
610  } catch(const std::invalid_argument &) {
611  throw bad_commandline_resolution(resolution_string);
612  }
613 
614  resolution = std::pair(xres, yres);
615 }
616 
617 std::vector<std::pair<unsigned int,std::string>> commandline_options::parse_to_uint_string_tuples_(const std::vector<std::string> &strings, char separator)
618 {
619  std::vector<std::pair<unsigned int,std::string>> vec;
620 
621  using namespace std::literals;
622  const std::string expected_format
623  = "UINT"s + separator + "STRING";
624 
625  for(const std::string &s : strings) {
626  std::vector<std::string> tokens = utils::split(s, separator);
627  if(tokens.size() != 2) {
628  throw bad_commandline_tuple(s, expected_format);
629  }
630 
631  unsigned int temp;
632  try {
633  temp = lexical_cast<unsigned int>(tokens[0]);
634  } catch (const bad_lexical_cast &) {
635  throw bad_commandline_tuple(s, expected_format);
636  }
637 
638  vec.emplace_back(temp, std::move(tokens[1]));
639  }
640  return vec;
641 }
642 
643 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)
644 {
645  std::vector<std::tuple<unsigned int,std::string,std::string>> vec;
646 
647  using namespace std::literals;
648  const std::string expected_format
649  = "UINT"s + separator + "STRING" + separator + "STRING";
650 
651  for(const std::string &s : strings) {
652  const std::vector<std::string> tokens = utils::split(s, separator);
653  if(tokens.size() != 3) {
654  throw bad_commandline_tuple(s, expected_format);
655  }
656 
657  unsigned int temp;
658  try {
659  temp = lexical_cast<unsigned int>(tokens[0]);
660  } catch (const bad_lexical_cast &) {
661  throw bad_commandline_tuple(s, expected_format);
662  }
663 
664  vec.emplace_back(temp, tokens[1], tokens[2]);
665  }
666  return vec;
667 }
668 
669 std::ostream& operator<<(std::ostream &os, const commandline_options& cmdline_opts)
670 {
671  os << "Usage: " << cmdline_opts.args0_ << " [<options>] [<data-directory>]\n";
672  os << cmdline_opts.visible_;
673  return os;
674 }
675 
677  config ret;
678  if(server) {
679  ret["server"] = *server;
680  }
681  if(username) {
682  ret["username"] = *username;
683  }
684  if(password) {
685  ret["password"] = *password;
686  }
687  return ret;
688 }
689 
691 {
693 }
#define debug(x)
bad_commandline_resolution(const std::string &resolution)
bad_commandline_tuple(const std::string &str, const std::string &expected_format)
bool nogui
True if –nogui was given on the command line.
utils::optional< std::vector< std::pair< unsigned int, std::string > > > multiplayer_side
Non-empty if –side was given on the command line.
bool print_userdata_path
True if –userdata-path was given on the command line.
utils::optional< std::pair< int, int > > resolution
Pair of AxB values specified after –resolution.
utils::optional< std::string > validate_wml
Non-empty if –validate was given on the command line.
bool simple_version
True if –simple-version was given on the command line.
bool report
True if –report was given on the command line.
boost::program_options::options_description hidden_
bool headless_unit_test
True if –unit is used and –showgui is not present.
utils::optional< std::string > screenshot_map_file
Map file to make a screenshot of.
utils::optional< std::string > multiplayer_scenario
Non-empty if –scenario was given on the command line.
utils::optional< std::string > test
Non-empty if –test was given on the command line.
bool no_log_sanitize
True if –no-log-sanitize was given on the command line.
bool windowed
True if –windowed was given on the command line.
bool strict_lua
True if –strict-lua was given in the commandline.
utils::optional< std::string > language
Non-empty if –language was given on the command line.
bool print_usercache_path
True if –usercache-path was given on the command line.
std::vector< std::pair< unsigned int, std::string > > parse_to_uint_string_tuples_(const std::vector< std::string > &strings, char separator=':')
A helper function splitting vector of strings of format unsigned int:string to vector of tuples (unsi...
utils::optional< std::vector< std::string > > preprocess_defines
Defines that were given to the –preprocess option.
bool noreplaycheck
True if –noreplaycheck was given on the command line.
utils::optional< std::string > screenshot_output_file
Output file to put screenshot in.
void parse_log_domains_(const std::string &domains_string, const lg::severity severity)
utils::optional< std::string > usercache_dir
Non-empty if –usercache-dir was given on the command line.
bool no_simd
True if –no-simd was given on the command line.
utils::optional< int > max_fps
Max FPS specified by –max-fps option.
utils::optional< std::string > core_id
Non-empty if –core was given on the command line.
bool multiplayer_exit_at_end
True if –exit-at-and was given on the command line.
utils::optional< std::string > validate_addon
Non-empty if –validate-addon was given on the command line.
utils::optional< int > campaign_difficulty
Non-empty if –campaign-difficulty was given on the command line.
utils::optional< unsigned int > multiplayer_repeat
Repeats specified by –multiplayer-repeat option.
utils::optional< std::string > validate_schema
Non-empty if –validate-schema was given on the command line.
bool debug
True if –debug was given on the command line.
bool mptest
True if –mp-test was given on the command line.
void parse_log_strictness(const std::string &severity)
bool nosound
True if –nosound was given on the command line.
bool multiplayer
True if –multiplayer was given on the command line.
utils::optional< std::string > server
Non-empty if –server was given on the command line.
bool script_unsafe_mode
Whether to load the "package" package for the scripting environment.
utils::optional< std::string > userdata_dir
Non-empty if –userdata-dir was given on the command line.
std::vector< std::string > args_
utils::optional< unsigned int > translation_percent
Non-empty if –all-translations or –translations-over is given on the command line.
utils::optional< std::string > plugin_file
File to load a lua plugin script from.
bool nobanner
True if –nobanner was given on the command line.
utils::optional< std::vector< std::pair< lg::severity, std::string > > > log
Contains parsed arguments of –log-* (e.g.
bool validcache
True if –validcache was given on the command line.
utils::optional< std::string > generate_spritesheet
Path of which to generate a spritesheet.
std::vector< std::tuple< unsigned int, std::string, std::string > > parse_to_uint_string_string_tuples_(const std::vector< std::string > &strings, char separator=':')
A helper function splitting vector of strings of format unsigned int:string:string to vector of tuple...
bool nomusic
True if –nomusic was given on the command line.
bool clock
True if –clock was given on the command line.
utils::optional< std::string > render_image_dst
Output file to put rendered image path in.
utils::optional< std::string > render_image
Image path to render.
boost::program_options::options_description visible_
utils::optional< std::string > campaign
Non-empty if –campaign was given on the command line.
utils::optional< std::string > logdomains
Non-empty if –logdomains was given on the command line.
bool new_widgets
True if –new-widgets was given on the command line.
utils::optional< std::string > preprocess_input_macros
Non-empty if –preprocess-input-macros was given on the command line.
bool preprocess
True if –preprocess was given on the command line.
utils::optional< unsigned int > rng_seed
RNG seed specified by –rng-seed option.
std::string diff_left
Files for diffing or patching.
utils::optional< std::vector< std::pair< unsigned int, std::string > > > multiplayer_ai_config
Non-empty if –ai-config was given on the command line.
bool version
True if –version was given on the command line.
utils::optional< std::string > multiplayer_label
Non-empty if –label was given on the command line.
bool allow_insecure
True if –allow-insecure was given in the commandline.
void parse_resolution_(const std::string &resolution_string)
utils::optional< std::string > multiplayer_era
Non-empty if –era was given on the command line.
utils::optional< std::string > validate_with
Non-empty if –use-schema was given on the command line.
bool noaddons
True if –noaddons was given on the command line.
bool fps
True if –fps was given on the command line.
utils::optional< std::string > output_file
Output filename for WML diff or preprocessing.
utils::optional< std::string > multiplayer_turns
Non-empty if –turns was given on the command line.
commandline_options(const std::vector< std::string > &args)
utils::optional< std::string > data_dir
Non-empty if –data-dir was given on the command line.
utils::optional< std::string > username
Non-empty if –username was given on the command line.
utils::optional< std::string > preprocess_target
Target (output) path that was given to the –preprocess option.
bool campaign_skip_story
True if –skip-story was given on the command line.
bool with_replay
True if –with-replay was given on the command line.
bool screenshot
True if –screenshot was given on the command line.
bool log_to_file
True if –log-to-file was given on the command line.
bool debug_lua
True if –debug-lua was given in the commandline.
std::vector< std::string > unit_test
Non-empty if –unit was given on the command line.
bool log_precise_timestamps
True if –log-precise was given on the command line.
utils::optional< std::string > preprocess_source_string
String to preprocess.
bool no_log_to_file
True if –no-log-to-file was given on the command line.
bool multiplayer_ignore_map_settings
True if –ignore-map-settings was given at the command line.
utils::optional< std::string > password
Non-empty if –password was given on the command line.
utils::optional< std::string > preprocess_output_macros
Non-empty if –preprocess-output-macros was given on the command line.
bool fullscreen
True if –fullscreen was given on the command line.
friend std::ostream & operator<<(std::ostream &os, const commandline_options &cmdline_opts)
To be used for printing help to the commandline.
bool any_validation_option() const
True if the –validate or any of the –validate-* options are given.
utils::optional< std::vector< std::pair< unsigned int, std::string > > > multiplayer_controller
Non-empty if –controller was given on the command line.
bool strict_validation
True if –strict-validation was given on the command line.
bool validate_core
True if –validate-core was given on the command line.
utils::optional< std::vector< std::pair< unsigned int, std::string > > > multiplayer_algorithm
Non-empty if –algorithm was given on the command line.
utils::optional< std::string > preprocess_path
Path to parse that was given to the –preprocess option.
bool nocache
True if –nocache was given on the command line.
utils::optional< std::vector< std::tuple< unsigned int, std::string, std::string > > > multiplayer_parm
Non-empty if –parm was given on the command line.
boost::program_options::options_description all_
bool print_data_path
True if –data-path was given on the command line.
utils::optional< std::string > campaign_scenario
Non-empty if –campaign-scenario was given on the command line.
utils::optional< std::string > load
Non-empty if –load was given on the command line.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
std::ostringstream wrapper.
Definition: formatter.hpp:40
severity get_severity() const
Definition: log.hpp:219
#define IMPLY_TERMINAL
static void validate(boost::any &v, const std::vector< std::string > &values, two_strings *, int)
Definitions for the interface to Wesnoth Markup Language (WML).
New lexcical_cast header.
#define PLAIN_LOG
Definition: log.hpp:296
Manage the empty-palette in the editor.
Definition: action.cpp:31
bool addon_server_info
Definition: game_config.cpp:79
bool allow_insecure
Definition: game_config.cpp:78
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
Definition: tips.cpp:37
bool new_widgets
Do we wish to use the new library or not.
Definition: settings.cpp:23
logger & err()
Definition: log.cpp:339
severity
Definition: log.hpp:82
logger & debug()
Definition: log.cpp:357
logger & warn()
Definition: log.cpp:345
static domain_map * domains
Definition: log.cpp:334
logger & info()
Definition: log.cpp:351
void set_strict_severity(severity severity)
Definition: log.cpp:420
constexpr auto values
Definition: ranges.hpp:46
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
Definition: charconv.hpp:156
std::vector< std::string > split(const config_attribute_value &val)
Thrown when a lexical_cast fails.
static map_location::direction s