The Battle for Wesnoth  1.19.13+dev
wesnoth.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
3  by David White <dave@whitevine.net>
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 "addon/manager.hpp"
17 #include "build_info.hpp"
18 #include "commandline_argv.hpp"
19 #include "commandline_options.hpp" // for commandline_options, etc
20 #include "config.hpp" // for config, config::error, etc
21 #include "cursor.hpp" // for set, CURSOR_TYPE::NORMAL, etc
22 #include "events.hpp"
23 #include "filesystem.hpp" // for filesystem::file_exists, filesystem::io_exception, etc
24 #include "floating_label.hpp"
25 #include "font/error.hpp" // for error
26 #include "font/font_config.hpp" // for load_font_config, etc
27 #include "formula/formula.hpp" // for formula_error
28 #include "game_config.hpp" // for path, debug, debug_lua, etc
29 #include "game_config_manager.hpp" // for game_config_manager, etc
30 #include "game_end_exceptions.hpp"
31 #include "game_launcher.hpp" // for game_launcher, etc
32 #include "gettext.hpp"
33 #include "gui/core/event/handler.hpp" // for tmanager
35 #include "gui/dialogs/message.hpp" // for show_error_message
37 #include "gui/dialogs/title_screen.hpp" // for title_screen, etc
38 #include "gui/gui.hpp" // for init
39 #include "log.hpp" // for LOG_STREAM, general, logger, etc
44 #include "sdl/exception.hpp" // for exception
45 #include "serialization/binary_or_text.hpp" // for config_writer
46 #include "serialization/chrono.hpp"
47 #include "serialization/parser.hpp" // for read
48 #include "serialization/preprocessor.hpp" // for preproc_define, etc
49 #include "serialization/schema_validator.hpp" // for strict_validation_enabled and schema_validator
50 #include "sound.hpp" // for commit_music_changes, etc
51 #include "utils/optimer.hpp"
52 #include "formula/string_utils.hpp" // VGETTEXT
53 #include <functional>
54 #include "game_version.hpp" // for version_info
55 #include "video.hpp" // for video::error and video::quit
56 #include "wesconfig.h" // for PACKAGE
57 #include "wml_exception.hpp" // for wml_exception
58 
60 #ifdef _WIN32
61 #include "log_windows.hpp"
62 
63 #include <float.h>
64 #endif // _WIN32
65 
66 #ifndef _MSC_VER
67 #include <fenv.h>
68 #endif // _MSC_VER
69 
70 #include <SDL2/SDL.h> // for SDL_Init, SDL_INIT_TIMER
71 
72 #include <boost/program_options/errors.hpp> // for error
73 #include <boost/algorithm/string/predicate.hpp> // for checking cmdline options
74 #include "utils/optional_fwd.hpp"
75 
76 #include <cerrno> // for ENOMEM
77 #include <clocale> // for setlocale, LC_ALL, etc
78 #include <cstdio> // for remove, fprintf, stderr
79 #include <cstdlib> // for srand, exit
80 #include <exception> // for exception
81 #include <vector>
82 #include <iostream>
83 
84 //#define NO_CATCH_AT_GAME_END
85 
86 #ifdef _WIN32
87 
88 #ifdef INADDR_ANY
89 #undef INADDR_ANY
90 #endif
91 
92 #ifdef INADDR_BROADCAST
93 #undef INADDR_BROADCAST
94 #endif
95 
96 #ifdef INADDR_NONE
97 #undef INADDR_NONE
98 #endif
99 
100 #include <windows.h>
101 
102 #endif // _WIN32
103 
104 #ifdef __ANDROID__
105 #define main SDL_main
106 #endif
107 
108 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
109 #include "gui/widgets/debug.hpp"
110 #endif
111 
112 // this file acts as a launcher for various gui2 dialogs
113 // so this reduces some boilerplate.
114 using namespace gui2::dialogs;
115 
116 static lg::log_domain log_config("config");
117 #define LOG_CONFIG LOG_STREAM(info, log_config)
118 
119 #define LOG_GENERAL LOG_STREAM(info, lg::general())
120 
121 static lg::log_domain log_preprocessor("preprocessor");
122 #define LOG_PREPROC LOG_STREAM(info, log_preprocessor)
123 
124 // this is needed to allow identical functionality with clean refactoring
125 // play_game only returns on an error, all returns within play_game can
126 // be replaced with this
127 static void safe_exit(int res)
128 {
129  LOG_GENERAL << "exiting with code " << res;
130  exit(res);
131 }
132 
133 static void handle_preprocess_string(const commandline_options& cmdline_opts)
134 {
135  preproc_map defines_map;
136 
137  if(cmdline_opts.preprocess_input_macros) {
138  std::string file = *cmdline_opts.preprocess_input_macros;
139  if(!filesystem::file_exists(file)) {
140  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
141  return;
142  }
143 
144  PLAIN_LOG << "Reading cached defines from: " << file;
145 
146  config cfg;
147 
148  try {
149  cfg = io::read(*filesystem::istream_file(file));
150  } catch(const config::error& e) {
151  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
152  }
153 
154  int read = 0;
155 
156  // use static preproc_define::read_pair(config) to make a object
157  for(const auto [_, cfg] : cfg.all_children_view()) {
158  const preproc_map::value_type def = preproc_define::read_pair(cfg);
159  defines_map[def.first] = def.second;
160  ++read;
161  }
162 
163  PLAIN_LOG << "Read " << read << " defines.";
164  }
165 
166  if(cmdline_opts.preprocess_defines) {
167  // add the specified defines
168  for(const std::string& define : *cmdline_opts.preprocess_defines) {
169  if(define.empty()) {
170  PLAIN_LOG << "empty define supplied";
171  continue;
172  }
173 
174  LOG_PREPROC << "adding define: " << define;
175  defines_map.emplace(define, preproc_define(define));
176  }
177  }
178 
179  // add the WESNOTH_VERSION define
180  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
181 
182  // preprocess resource
183  PLAIN_LOG << "preprocessing specified string: " << *cmdline_opts.preprocess_source_string;
184  const utils::ms_optimer timer(
185  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
186  std::cout << preprocess_string(*cmdline_opts.preprocess_source_string, &defines_map) << std::endl;
187  PLAIN_LOG << "added " << defines_map.size() << " defines.";
188 }
189 
190 static void handle_preprocess_command(const commandline_options& cmdline_opts)
191 {
192  preproc_map input_macros;
193 
194  if(cmdline_opts.preprocess_input_macros) {
195  std::string file = *cmdline_opts.preprocess_input_macros;
196  if(filesystem::file_exists(file) == false) {
197  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
198  return;
199  }
200 
201  PLAIN_LOG << "Reading cached defines from: " << file;
202 
203  config cfg;
204 
205  try {
206  cfg = io::read(*filesystem::istream_file(file));
207  } catch(const config::error& e) {
208  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
209  }
210 
211  int read = 0;
212 
213  // use static preproc_define::read_pair(config) to make a object
214  for(const auto [_, cfg] : cfg.all_children_view()) {
215  const preproc_map::value_type def = preproc_define::read_pair(cfg);
216  input_macros[def.first] = def.second;
217  ++read;
218  }
219 
220  PLAIN_LOG << "Read " << read << " defines.";
221  }
222 
223  const std::string resourceToProcess(*cmdline_opts.preprocess_path);
224  const std::string targetDir(*cmdline_opts.preprocess_target);
225 
226  const utils::ms_optimer timer(
227  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
228 
229  // If the users add the SKIP_CORE define we won't preprocess data/core
230  bool skipCore = false;
231  bool skipTerrainGFX = false;
232 
233  // The 'core_defines_map' is the one got from data/core macros
234  preproc_map defines_map(input_macros);
235 
236  if(cmdline_opts.preprocess_defines) {
237  // add the specified defines
238  for(const std::string& define : *cmdline_opts.preprocess_defines) {
239  if(define.empty()) {
240  PLAIN_LOG << "empty define supplied";
241  continue;
242  }
243 
244  LOG_PREPROC << "adding define: " << define;
245  defines_map.emplace(define, preproc_define(define));
246 
247  if(define == "SKIP_CORE") {
248  PLAIN_LOG << "'SKIP_CORE' defined.";
249  skipCore = true;
250  } else if(define == "NO_TERRAIN_GFX") {
251  PLAIN_LOG << "'NO_TERRAIN_GFX' defined.";
252  skipTerrainGFX = true;
253  }
254  }
255  }
256 
257  // add the WESNOTH_VERSION define
258  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
259 
260  PLAIN_LOG << "added " << defines_map.size() << " defines.";
261 
262  // preprocess core macros first if we don't skip the core
263  if(skipCore == false) {
264  PLAIN_LOG << "preprocessing common macros from 'data/core' ...";
265 
266  // process each folder explicitly to gain speed
267  preprocess_resource(game_config::path + "/data/core/macros", &defines_map);
268 
269  if(skipTerrainGFX == false) {
270  preprocess_resource(game_config::path + "/data/core/terrain-graphics", &defines_map);
271  }
272 
273  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " 'data/core' defines.";
274  } else {
275  PLAIN_LOG << "skipped 'data/core'";
276  }
277 
278  // preprocess resource
279  PLAIN_LOG << "preprocessing specified resource: " << resourceToProcess << " ...";
280 
281  preprocess_resource(resourceToProcess, &defines_map, true, true, targetDir);
282  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " total defines.";
283 
284  if(cmdline_opts.preprocess_output_macros) {
285  std::string outputFileName = "_MACROS_.cfg";
286  if(!cmdline_opts.preprocess_output_macros->empty()) {
287  outputFileName = *cmdline_opts.preprocess_output_macros;
288  }
289 
290  std::string outputPath = targetDir + "/" + outputFileName;
291 
292  PLAIN_LOG << "writing '" << outputPath << "' with " << defines_map.size() << " defines.";
293 
295  if(!out->fail()) {
296  config_writer writer(*out, false);
297 
298  for(auto& define_pair : defines_map) {
299  define_pair.second.write(writer, define_pair.first);
300  }
301  } else {
302  PLAIN_LOG << "couldn't open the file.";
303  }
304  }
305 }
306 
307 static int handle_validate_command(const std::string& file, abstract_validator& validator, const std::vector<std::string>& defines) {
308  preproc_map defines_map;
309  // add the WESNOTH_VERSION define
310  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
311  defines_map["SCHEMA_VALIDATION"] = preproc_define();
312  for(const std::string& define : defines) {
313  if(define.empty()) {
314  PLAIN_LOG << "empty define supplied";
315  continue;
316  }
317 
318  LOG_PREPROC << "adding define: " << define;
319  defines_map.emplace(define, preproc_define(define));
320  }
321  PLAIN_LOG << "Validating " << file << " against schema " << validator.name_;
323  io::read(*preprocess_file(file, &defines_map), &validator);
324  if(lg::broke_strict()) {
325  std::cout << "validation failed\n";
326  } else {
327  std::cout << "validation succeeded\n";
328  }
329  return lg::broke_strict();
330 }
331 
332 /** Process commandline-arguments */
333 static int process_command_args(commandline_options& cmdline_opts)
334 {
335  // Options that output info unaffected by other options and return.
336  if(cmdline_opts.help) {
337  std::cout << cmdline_opts;
338  return 0;
339  }
340 
341  if(cmdline_opts.logdomains) {
342  std::cout << lg::list_log_domains(*cmdline_opts.logdomains);
343  return 0;
344  }
345 
346  if(cmdline_opts.version) {
347  std::cout << "Battle for Wesnoth" << " " << game_config::wesnoth_version.str() << "\n\n";
348  std::cout << "Library versions:\n" << game_config::library_versions_report() << '\n';
349  std::cout << "Optional features:\n" << game_config::optional_features_report();
350  return 0;
351  }
352 
353  if(cmdline_opts.simple_version) {
354  std::cout << game_config::wesnoth_version.str() << "\n";
355  return 0;
356  }
357 
358  // Options that don't change behavior based on any others should be checked alphabetically below.
359 
360  if(cmdline_opts.no_log_sanitize) {
361  lg::set_log_sanitize(false);
362  }
363 
364  if(cmdline_opts.usercache_dir) {
366  }
367 
368  if(cmdline_opts.userdata_dir) {
370  }
371 
372  // earliest possible point to ensure the userdata directory is known
374  filesystem::set_user_data_dir(std::string());
375  }
376 
377  // userdata is initialized, so initialize logging to file if enabled
378  // If true, output will be redirected to file, else output be written to console.
379  // On Windows, if Wesnoth was not started from a console, one will be allocated.
380  if(cmdline_opts.log_to_file
381  || (!cmdline_opts.no_log_to_file
382  && !getenv("WESNOTH_NO_LOG_FILE")
383  // command line options that imply not redirecting output to a log file
384  && !cmdline_opts.data_path
385  && !cmdline_opts.userdata_path
386  && !cmdline_opts.usercache_path
387  && !cmdline_opts.report
388  && !cmdline_opts.do_diff
389  && !cmdline_opts.do_patch
390  && !cmdline_opts.preprocess
391  && !cmdline_opts.render_image
392  && !cmdline_opts.screenshot
393  && !cmdline_opts.nogui
394  && !cmdline_opts.headless_unit_test
395  && !cmdline_opts.validate_schema
396  && !cmdline_opts.validate_wml
397  )
398  )
399  {
401  }
402 #ifdef _WIN32
403  // This forces a Windows console to be attached to the process even
404  // if Wesnoth is an IMAGE_SUBSYSTEM_WINDOWS_GUI executable because it
405  // turns Wesnoth into a CLI application. (unless --wnoconsole is given)
406  else if(!cmdline_opts.no_console) {
408  }
409 #endif
410 
411  if(cmdline_opts.log) {
412  for(const auto& log_pair : *cmdline_opts.log) {
413  const std::string log_domain = log_pair.second;
414  const lg::severity severity = log_pair.first;
415  if(!lg::set_log_domain_severity(log_domain, severity)) {
416  PLAIN_LOG << "unknown log domain: " << log_domain;
417  return 2;
418  }
419  }
420  }
421 
422  if(!cmdline_opts.nobanner) {
423  const auto now = std::chrono::system_clock::now();
424  PLAIN_LOG << "Battle for Wesnoth v" << game_config::revision << " " << game_config::build_arch();
425  PLAIN_LOG << "Started on " << chrono::format_local_timestamp(now, "%a %b %d %T %Y") << '\n';
426  }
427 
428  if(cmdline_opts.usercache_path) {
429  std::cout << filesystem::get_cache_dir();
430  return 0;
431  }
432 
433  if(cmdline_opts.userdata_path) {
434  std::cout << filesystem::get_user_data_dir();
435  return 0;
436  }
437 
438  if(cmdline_opts.data_dir) {
439  game_config::path = filesystem::normalize_path(*cmdline_opts.data_dir, true, true);
440  if(!cmdline_opts.nobanner) {
441  PLAIN_LOG << "Overriding data directory with '" << game_config::path << "'";
442  }
443  } else {
444  // if a pre-defined path does not exist this will empty it
445 #ifdef __ANDROID__
446  game_config::path = SDL_AndroidGetExternalStoragePath() + std::string("/gamedata");
447 #endif
449  if(game_config::path.empty()) {
450  if(std::string exe_dir = filesystem::get_exe_dir(); !exe_dir.empty()) {
451  if(std::string auto_dir = filesystem::autodetect_game_data_dir(std::move(exe_dir)); !auto_dir.empty()) {
452  if(!cmdline_opts.nobanner) {
453  PLAIN_LOG << "Automatically found a possible data directory at: " << auto_dir;
454  }
455  game_config::path = filesystem::normalize_path(auto_dir, true, true);
456  }
457  } else {
458  PLAIN_LOG << "Cannot find game data directory. Specify one with --data-dir";
459  return 1;
460  }
461  }
462  }
463 
465  PLAIN_LOG << "Could not find game data directory '" << game_config::path << "'";
466  return 1;
467  }
468 
469  if(cmdline_opts.data_path) {
470  std::cout << game_config::path;
471  return 0;
472  }
473 
474  if(cmdline_opts.debug_lua) {
475  game_config::debug_lua = true;
476  }
477 
478  if(cmdline_opts.allow_insecure) {
480  }
481 
482  if(cmdline_opts.addon_server_info) {
484  }
485 
486  if(cmdline_opts.strict_lua) {
488  }
489 
490  if(cmdline_opts.log_precise_timestamps) {
492  }
493 
494  if(cmdline_opts.rng_seed) {
495  srand(*cmdline_opts.rng_seed);
496  }
497 
498  if(cmdline_opts.render_image) {
499  SDL_setenv("SDL_VIDEODRIVER", "dummy", 1);
500  }
501 
502  if(cmdline_opts.strict_validation) {
504  }
505 
506  if(cmdline_opts.report) {
507  std::cout << "\n========= BUILD INFORMATION =========\n\n" << game_config::full_build_report();
508  return 0;
509  }
510 
511  if(cmdline_opts.validate_schema) {
513  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
514  return handle_validate_command(*cmdline_opts.validate_schema, validator, {});
515  }
516 
517  if(cmdline_opts.do_diff) {
518  std::ifstream in_left(cmdline_opts.diff_left);
519  std::ifstream in_right(cmdline_opts.diff_right);
520  config left = io::read(in_left);
521  config right = io::read(in_right);
522  std::ostream* os = &std::cout;
523  if(cmdline_opts.output_file) {
524  os = new std::ofstream(*cmdline_opts.output_file);
525  }
527  out.write(right.get_diff(left));
528  if(os != &std::cout) delete os;
529  return 0;
530  }
531 
532  if(cmdline_opts.do_patch) {
533  std::ifstream in_base(cmdline_opts.diff_left);
534  std::ifstream in_diff(cmdline_opts.diff_right);
535  config base = io::read(in_base);
536  config diff = io::read(in_diff);
537  base.apply_diff(diff);
538  std::ostream* os = &std::cout;
539  if(cmdline_opts.output_file) {
540  os = new std::ofstream(*cmdline_opts.output_file);
541  }
543  out.write(base);
544  if(os != &std::cout) delete os;
545  return 0;
546  }
547 
548  if(cmdline_opts.generate_spritesheet) {
549  PLAIN_LOG << "sheet path " << *cmdline_opts.generate_spritesheet;
551  return 0;
552  }
553 
554  // Options changing their behavior dependent on some others should be checked below.
555 
556  if(cmdline_opts.preprocess) {
557  handle_preprocess_command(cmdline_opts);
558  return 0;
559  }
560 
561  if(cmdline_opts.preprocess_source_string.has_value()) {
562  handle_preprocess_string(cmdline_opts);
563  return 0;
564  }
565 
566  if(cmdline_opts.validate_wml) {
567  std::string schema_path;
568  if(cmdline_opts.validate_with) {
569  schema_path = *cmdline_opts.validate_with;
570  if(!filesystem::file_exists(schema_path)) {
571  if(auto check = filesystem::get_wml_location(schema_path)) {
572  schema_path = check.value();
573  } else {
574  PLAIN_LOG << "Could not find schema file: " << schema_path;
575  }
576  } else {
577  schema_path = filesystem::normalize_path(schema_path);
578  }
579  } else {
580  schema_path = filesystem::get_wml_location("schema/game_config.cfg").value();
581  }
583  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
584  return handle_validate_command(*cmdline_opts.validate_wml, validator,
585  cmdline_opts.preprocess_defines.value_or<decltype(cmdline_opts.preprocess_defines)::value_type>({}));
586  }
587 
588  if(cmdline_opts.preprocess_defines || cmdline_opts.preprocess_input_macros || cmdline_opts.preprocess_path) {
589  // It would be good if this was supported for running tests too, possibly for other uses.
590  // For the moment show an error message instead of leaving the user wondering why it doesn't work.
591  PLAIN_LOG << "That --preprocess-* option is only supported when using --preprocess or --validate.";
592  return 2;
593  }
594 
595  // Not the most intuitive solution, but I wanted to leave current semantics for now
596  return -1;
597 }
598 
599 /**
600  * I would prefer to setup locale first so that early error
601  * messages can get localized, but we need the game_launcher
602  * initialized to have filesystem::get_intl_dir() to work. Note: setlocale()
603  * does not take GUI language setting into account.
604  */
605 static void init_locale()
606 {
607 #if defined _WIN32 || defined __APPLE__
608  setlocale(LC_ALL, "English");
609 #else
610  std::setlocale(LC_ALL, "C");
611 #endif
612 
613  const std::string& intl_dir = filesystem::get_intl_dir();
614 
615  translation::bind_textdomain(PACKAGE, intl_dir.c_str(), "UTF-8");
616  translation::bind_textdomain(PACKAGE "-lib", intl_dir.c_str(), "UTF-8");
618 }
619 
620 /**
621  * Print an alert and instructions to stderr about early initialization errors.
622  *
623  * This is provided as an aid for users dealing with potential data dir
624  * configuration issues. The first code to read core WML *has* the
625  * responsibility to call this function in the event of a problem, to inform
626  * the user of the most likely possible cause and suggest a course of action
627  * to solve the issue.
628  */
630 {
631  // NOTE: wrap output to 80 columns.
632  PLAIN_LOG << '\n'
633  << "An error at this point during initialization usually indicates that the data\n"
634  << "directory above was not correctly set or detected. Try passing the correct path\n"
635  << "in the command line with the --data-dir switch or as the only argument.";
636 }
637 
638 /**
639  * Handles the lua script command line arguments if present.
640  * This function will only run once.
641  */
643 {
644  static bool first_time = true;
645 
646  if(!first_time) {
647  return;
648  }
649 
650  first_time = false;
651 
652  if(!game->init_lua_script()) {
653  // PLAIN_LOG << "error when loading lua scripts at startup";
654  // PLAIN_LOG << "could not load lua script: " << *cmdline_opts.script_file;
655  }
656 }
657 
658 #ifdef _MSC_VER
659 static void check_fpu()
660 {
661  uint32_t f_control;
662 
663  if(_controlfp_s(&f_control, 0, 0) == 0) {
664  uint32_t unused;
665  uint32_t rounding_mode = f_control & _MCW_RC;
666 
667  if(rounding_mode != _RC_NEAR) {
668  PLAIN_LOG << "Floating point rounding mode is currently '"
669  << ((rounding_mode == _RC_CHOP)
670  ? "chop"
671  : (rounding_mode == _RC_UP)
672  ? "up"
673  : (rounding_mode == _RC_DOWN)
674  ? "down"
675  : (rounding_mode == _RC_NEAR) ? "near" : "unknown")
676  << "' setting to 'near'";
677 
678  if(_controlfp_s(&unused, _RC_NEAR, _MCW_RC)) {
679  PLAIN_LOG << "failed to set floating point rounding type to 'near'";
680  }
681  }
682 
683 #ifndef _M_AMD64
684  uint32_t precision_mode = f_control & _MCW_PC;
685  if(precision_mode != _PC_53) {
686  PLAIN_LOG << "Floating point precision mode is currently '"
687  << ((precision_mode == _PC_53)
688  ? "double"
689  : (precision_mode == _PC_24)
690  ? "single"
691  : (precision_mode == _PC_64) ? "double extended" : "unknown")
692  << "' setting to 'double'";
693 
694  if(_controlfp_s(&unused, _PC_53, _MCW_PC)) {
695  PLAIN_LOG << "failed to set floating point precision type to 'double'";
696  }
697  }
698 #endif
699 
700  } else {
701  PLAIN_LOG << "_controlfp_s failed.";
702  }
703 }
704 #else
705 static void check_fpu()
706 {
707  switch(fegetround()) {
708  case FE_TONEAREST:
709  break;
710  case FE_DOWNWARD:
711  STREAMING_LOG << "Floating point precision mode is currently 'downward'";
712  goto reset_fpu;
713  case FE_TOWARDZERO:
714  STREAMING_LOG << "Floating point precision mode is currently 'toward-zero'";
715  goto reset_fpu;
716  case FE_UPWARD:
717  STREAMING_LOG << "Floating point precision mode is currently 'upward'";
718  goto reset_fpu;
719  default:
720  STREAMING_LOG << "Floating point precision mode is currently 'unknown'";
721  goto reset_fpu;
722  reset_fpu:
723  STREAMING_LOG << " - setting to 'nearest'\n";
724  fesetround(FE_TONEAREST);
725  break;
726  }
727 }
728 #endif
729 
730 /**
731  * Setups the game environment and enters
732  * the titlescreen or game loops.
733  */
734 static int do_gameloop(commandline_options& cmdline_opts)
735 {
736  srand(std::time(nullptr));
737 
738  const auto game = std::make_unique<game_launcher>(cmdline_opts);
739 
740  init_locale();
741 
742  bool res;
743 
744  // Do initialize fonts before reading the game config, to have game
745  // config error messages displayed. fonts will be re-initialized later
746  // when the language is read from the game config.
747  res = font::load_font_config();
748  if(res == false) {
749  PLAIN_LOG << "could not initialize fonts";
750  // The most common symptom of a bogus data dir path -- warn the user.
752  return 1;
753  }
754 
755  res = game->init_language();
756  if(res == false) {
757  PLAIN_LOG << "could not initialize the language";
758  return 1;
759  }
760 
761  res = game->init_video();
762  if(res == false) {
763  PLAIN_LOG << "could not initialize display";
764  return 1;
765  }
766 
767  check_fpu();
768  const cursor::manager cursor_manager;
770 
771 #if(defined(_X11) && !defined(__APPLE__)) || defined(_WIN32)
772  SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
773 #endif
774 
775  gui2::init();
776  gui2::switch_theme(prefs::get().gui2_theme());
777  const gui2::event::manager gui_event_manager;
778 
779  // if the log directory is not writable, then this is the error condition so show the error message.
780  // if the log directory is writable, then there's no issue.
781  // if the optional isn't set, then logging to file has been disabled, so there's no issue.
782  if(!lg::log_dir_writable().value_or(true)) {
783  utils::string_map symbols;
784  symbols["logdir"] = filesystem::get_logs_dir();
785  std::string msg = VGETTEXT("Unable to create log files in directory $logdir. This is often caused by incorrect folder permissions, anti-virus software restricting folder access, or using OneDrive to manage your My Documents folder.", symbols);
786  gui2::show_message(_("Logging Failure"), msg, message::ok_button);
787  }
788 
789  game_config_manager config_manager(cmdline_opts);
790 
794  }
795 
796  loading_screen::display([&res, &config_manager, &cmdline_opts]() {
799 
800  if(res == false) {
801  PLAIN_LOG << "could not initialize game config";
802  return;
803  }
804 
806 
807  res = font::load_font_config();
808  if(res == false) {
809  PLAIN_LOG << "could not re-initialize fonts for the current language";
810  return;
811  }
812 
813  if(!game_config::no_addons && !cmdline_opts.noaddons) {
815 
817  }
818  });
819 
820  if(res == false) {
821  return 1;
822  }
823 
824  plugins_manager plugins_man(new application_lua_kernel);
825 
826  const plugins_context::reg_vec callbacks {
827  {"play_multiplayer", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::CONNECT)},
828  {"play_local", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::LOCAL)},
829  {"play_campaign", std::bind(&game_launcher::play_campaign, game.get())},
830  };
831 
832  const plugins_context::areg_vec accessors {
833  {"command_line", std::bind(&commandline_options::to_config, &cmdline_opts)},
834  };
835 
836  plugins_context plugins("titlescreen", callbacks, accessors);
837 
838  plugins.set_callback("exit", [](const config& cfg) { safe_exit(cfg["code"].to_int(0)); }, false);
839 
840  while(true) {
841  if(!game->has_load_data()) {
842  auto cfg = config_manager.game_config().optional_child("titlescreen_music");
843  if(cfg) {
844  for(const config& i : cfg->child_range("music")) {
846  }
847 
848  config title_music_config;
849  title_music_config["name"] = game_config::title_music;
850  title_music_config["append"] = true;
851  title_music_config["immediate"] = true;
852  sound::play_music_config(title_music_config);
853  } else {
856  }
857  }
858 
859  handle_lua_script_args(&*game, cmdline_opts);
860 
861  plugins.play_slice();
862  plugins.play_slice();
863 
864  if(!cmdline_opts.unit_test.empty()) {
865  return static_cast<int>(game->unit_test());
866  }
867 
868  if(game->play_test() == false) {
869  return 0;
870  }
871 
872  if(game->play_screenshot_mode() == false) {
873  return 0;
874  }
875 
876  if(game->play_render_image_mode() == false) {
877  return 0;
878  }
879 
880  // Start directly a campaign
881  if(game->goto_campaign() == false) {
882  if(game->jump_to_campaign_id().empty())
883  continue; // Go to main menu
884  else
885  return 1; // we got an error starting the campaign from command line
886  }
887 
888  // Start directly a multiplayer
889  // Eventually with a specified server
890  if(game->goto_multiplayer() == false) {
891  continue; // Go to main menu
892  }
893 
894  // Start directly a commandline multiplayer game
895  if(game->play_multiplayer_commandline() == false) {
896  return 0;
897  }
898 
899  if(game->goto_editor() == false) {
900  return 0;
901  }
902 
903  const font::floating_label_context label_manager;
904 
906 
907  // If loading a game, skip the titlescreen entirely
908  if(game->has_load_data() && game->load_game()) {
910  continue;
911  }
912 
913  int retval;
914  { // scope to not keep the title screen alive all game
915  title_screen dlg(*game);
916 
917  // Allows re-layout on resize.
918  // Since RELOAD_UI is not checked here, it causes
919  // the dialog to be closed and reshown with changes.
921  dlg.show();
922  }
923  retval = dlg.get_retval();
924  }
925 
926  switch(retval) {
928  LOG_GENERAL << "quitting game...";
929  return 0;
931  game->play_multiplayer(game_launcher::mp_mode::CONNECT);
932  break;
934  game->play_multiplayer(game_launcher::mp_mode::HOST);
935  break;
937  game->play_multiplayer(game_launcher::mp_mode::LOCAL);
938  break;
940  loading_screen::display([&config_manager]() {
941  config_manager.reload_changed_game_config();
942  gui2::init();
943  gui2::switch_theme(prefs::get().gui2_theme());
944  });
945  break;
947  game->start_editor();
948  break;
951  break;
953  break;
955  gui2::switch_theme(prefs::get().gui2_theme());
956  break;
957  }
958  }
959 }
960 
961 #ifdef _WIN32
962 #define error_exit(res) \
963  do { \
964  if(lg::using_own_console()) { \
965  std::cerr << "Press enter to continue..." << std::endl; \
966  std::cin.get(); \
967  } \
968  return res; \
969  } while(false)
970 #else
971 #define error_exit(res) return res
972 #endif
973 
974 #ifdef __APPLE__
975 extern "C" int wesnoth_main(int argc, char** argv);
976 int wesnoth_main(int argc, char** argv)
977 #else
978 int main(int argc, char** argv)
979 #endif
980 {
982  auto args = read_argv(argc, argv);
983  assert(!args.empty());
984 
985 #ifdef _WIN32
986  _putenv("PANGOCAIRO_BACKEND=fontconfig");
987  _putenv("FONTCONFIG_PATH=fonts");
988 #endif
989 #ifdef __APPLE__
990  // Using setenv with overwrite disabled so we can override this in the
991  // original process environment for research/testing purposes.
992  setenv("PANGOCAIRO_BACKEND", "fontconfig", 0);
993 #endif
994 #ifdef __ANDROID__
995  setenv("PANGOCAIRO_BACKEND", "fontconfig", 0);
996  setenv("SDL_HINT_AUDIODRIVER", "android", 0);
997 #endif
998 
999  try {
1000  commandline_options cmdline_opts = commandline_options(args);
1001  int finished = process_command_args(cmdline_opts);
1002 
1003  if(finished != -1) {
1004 #ifdef _WIN32
1005  if(lg::using_own_console()) {
1006  std::cerr << "Press enter to continue..." << std::endl;
1007  std::cin.get();
1008  }
1009 #endif
1010  safe_exit(finished);
1011  }
1012 
1013  SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
1014  // Is there a reason not to just use SDL_INIT_EVERYTHING?
1015  if(SDL_Init(SDL_INIT_TIMER) < 0) {
1016  PLAIN_LOG << "Couldn't initialize SDL: " << SDL_GetError();
1017  return (1);
1018  }
1019  atexit(SDL_Quit);
1020 
1021  // Mac's touchpad generates touch events too.
1022  // Ignore them until Macs have a touchscreen: https://forums.libsdl.org/viewtopic.php?p=45758
1023 #if defined(__APPLE__) && !defined(__IPHONEOS__)
1024  SDL_EventState(SDL_FINGERMOTION, SDL_DISABLE);
1025  SDL_EventState(SDL_FINGERDOWN, SDL_DISABLE);
1026  SDL_EventState(SDL_FINGERUP, SDL_DISABLE);
1027 #endif
1028 
1029  // declare this here so that it will always be at the front of the event queue.
1030  events::event_context global_context;
1031 
1032 #ifndef __ANDROID__
1033  SDL_StartTextInput();
1034 #endif
1035  const int res = do_gameloop(cmdline_opts);
1036  safe_exit(res);
1037  } catch(const boost::program_options::error& e) {
1038  // logging hasn't been initialized by this point
1039  std::cerr << "Error in command line: " << e.what() << std::endl;
1040  std::string error = "Error parsing command line arguments: ";
1041  error += e.what();
1042  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", error.c_str(), nullptr);
1043  error_exit(2);
1044  } catch(const video::error& e) {
1045  PLAIN_LOG << "Video system error: " << e.what();
1046  error_exit(1);
1047  } catch(const font::error& e) {
1048  PLAIN_LOG << "Could not initialize fonts.\n\n" << e.what() << "\n\nExiting.";
1049  error_exit(1);
1050  } catch(const config::error& e) {
1051  PLAIN_LOG << e.message;
1052  error_exit(1);
1053  } catch(const video::quit&) {
1054  // just means the game should quit
1055  } catch(const return_to_play_side_exception&) {
1056  PLAIN_LOG << "caught return_to_play_side_exception, please report this bug (quitting)";
1057  } catch(const quit_game_exception&) {
1058  PLAIN_LOG << "caught quit_game_exception (quitting)";
1059  } catch(const wml_exception& e) {
1060  PLAIN_LOG << "WML exception:\nUser message: " << e.user_message << "\nDev message: " << e.dev_message;
1061  error_exit(1);
1062  } catch(const wfl::formula_error& e) {
1063  PLAIN_LOG << e.what() << "\n\nGame will be aborted.";
1064  error_exit(1);
1065  } catch(const sdl::exception& e) {
1066  PLAIN_LOG << e.what();
1067  error_exit(1);
1068  } catch(const game::error& e) {
1069  PLAIN_LOG << "Game error: " << e.what();
1070  error_exit(1);
1071  } catch(const std::bad_alloc&) {
1072  PLAIN_LOG << "Ran out of memory. Aborted.";
1073  error_exit(ENOMEM);
1074 #if !defined(NO_CATCH_AT_GAME_END)
1075  } catch(const std::exception& e) {
1076  // Try to catch unexpected exceptions.
1077  PLAIN_LOG << "Caught general '" << typeid(e).name() << "' exception:\n" << e.what();
1078  error_exit(1);
1079  } catch(const std::string& e) {
1080  PLAIN_LOG << "Caught a string thrown as an exception:\n" << e;
1081  error_exit(1);
1082  } catch(const char* e) {
1083  PLAIN_LOG << "Caught a string thrown as an exception:\n" << e;
1084  error_exit(1);
1085  } catch(...) {
1086  // Ensure that even when we terminate with `throw 42`, the exception
1087  // is caught and all destructors are actually called. (Apparently,
1088  // some compilers will simply terminate without calling destructors if
1089  // the exception isn't caught.)
1090  PLAIN_LOG << "Caught general exception " << utils::get_unknown_exception_type() << ". Terminating.";
1091  error_exit(1);
1092 #endif
1093  }
1094 
1095  return 0;
1096 } // end main
int wesnoth_main(int argc, char **argv)
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on's version information structs.
Definition: manager.cpp:381
Used in parsing config file.
Definition: validator.hpp:38
bool nogui
True if –nogui was given on the command line.
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.
bool headless_unit_test
True if –unit is used and –showgui is not present.
bool no_log_sanitize
True if –no-log-sanitize was given on the command line.
bool strict_lua
True if –strict-lua was given in the commandline.
utils::optional< std::vector< std::string > > preprocess_defines
Defines that were given to the –preprocess option.
utils::optional< std::string > usercache_dir
Non-empty if –usercache-dir was given on the command line.
utils::optional< std::string > validate_schema
Non-empty if –validate-schema was given on the command line.
utils::optional< std::string > userdata_dir
Non-empty if –userdata-dir was given on the command line.
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.
utils::optional< std::string > generate_spritesheet
Path of which to generate a spritesheet.
utils::optional< std::string > render_image
Image path to render.
utils::optional< std::string > logdomains
Non-empty if –logdomains 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.
bool data_path
True if –data-path was given on the command line.
bool version
True if –version was given on the command line.
bool allow_insecure
True if –allow-insecure was given in the commandline.
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.
utils::optional< std::string > output_file
Output filename for WML diff or preprocessing.
utils::optional< std::string > data_dir
Non-empty if –data-dir was given on the command line.
utils::optional< std::string > preprocess_target
Target (output) path that was given to the –preprocess option.
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 userdata_path
True if –userdata-path 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.
utils::optional< std::string > preprocess_output_macros
Non-empty if –preprocess-output-macros was given on the command line.
bool strict_validation
True if –strict-validation was given on the command line.
utils::optional< std::string > preprocess_path
Path to parse that was given to the –preprocess option.
bool help
True if –help was given on the command line.
bool usercache_path
True if –usercache-path was given on the command line.
Class for writing a config out to a file in pieces.
void write(const config &cfg)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:796
child_itors child_range(config_key_type key)
Definition: config.cpp:268
void apply_diff(const config &diff, bool track=false)
A function to apply a diff config onto this config object.
Definition: config.cpp:1022
config get_diff(const config &c) const
A function to get the differences between this object, and 'c', as another config object.
Definition: config.cpp:906
@ NO_FORCE_RELOAD
Don't reload if the previous defines equal the new defines.
bool init_game_config(FORCE_RELOAD_CONFIG force_reload)
const game_config_view & game_config() const
optional_const_config optional_child(config_key_type key) const
bool play_multiplayer(mp_mode mode)
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
static void display(const std::function< void()> &f)
@ ok_button
Shows an ok button.
Definition: message.hpp:73
bool show(const unsigned auto_close_time=0)
Shows the window.
This class implements the title screen.
int get_retval()
Definition: window.hpp:402
void play_slice()
Definition: context.cpp:103
std::vector< Reg > reg_vec
Definition: context.hpp:40
std::vector< aReg > areg_vec
Definition: context.hpp:41
void set_callback(const std::string &name, callback_function)
Definition: context.cpp:53
static prefs & get()
Exception used to escape form the ai or ui code to playsingle_controller::play_side.
Realization of serialization/validator.hpp abstract validator.
std::string str() const
Serializes the version number into string form.
Type that can be thrown as an exception to quit to desktop.
Definition: video.hpp:323
std::vector< std::string > read_argv([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:1032
Contains the exception interfaces used to signal completion of a scenario, campaign or turn.
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition: gettext.hpp:97
Standard logging facilities (interface).
#define STREAMING_LOG
Definition: log.hpp:297
#define PLAIN_LOG
Definition: log.hpp:296
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
Definition: chrono.hpp:62
@ WAIT
Definition: cursor.hpp:28
@ NORMAL
Definition: cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:178
void set_main_thread()
Definition: events.cpp:471
std::string get_cache_dir()
Definition: filesystem.cpp:882
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
std::string get_user_data_dir()
Definition: filesystem.cpp:872
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:341
std::string get_exe_dir()
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
Returns a translated path to the actual file or directory, if it exists.
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::string autodetect_game_data_dir(std::string exe_dir)
Try to autodetect the location of the game data dir.
void set_cache_dir(const std::string &newcachedir)
Definition: filesystem.cpp:835
std::string get_logs_dir()
Definition: filesystem.cpp:877
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:54
bool is_userdata_initialized()
Definition: filesystem.cpp:624
std::string get_intl_dir()
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
void set_user_data_dir(std::string newprefdir)
Definition: filesystem.cpp:737
bool load_font_config()
Definition: font_config.cpp:78
std::string path
Definition: filesystem.cpp:106
bool addon_server_info
Definition: game_config.cpp:79
std::string full_build_report()
Produce a bug report-style info dump.
Definition: build_info.cpp:666
std::string library_versions_report()
Produce a plain-text report of library versions suitable for stdout/stderr.
Definition: build_info.cpp:656
const version_info wesnoth_version(VERSION)
bool allow_insecure
Definition: game_config.cpp:78
std::string title_music
std::string build_arch()
Obtain the processor architecture for this build.
Definition: build_info.cpp:316
std::string optional_features_report()
Produce a plain-text report of features suitable for stdout/stderr.
Definition: build_info.cpp:661
const std::string revision
bool check_migration
Definition: filesystem.cpp:114
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:112
void switch_theme(const std::string &theme_id)
Set and activate the given gui2 theme.
Definition: gui.cpp:153
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:148
retval
Default window/dialog return values.
Definition: retval.hpp:30
void build_spritesheet_from(const std::string &entry_point)
config read(std::istream &in, abstract_validator *validator)
Definition: parser.cpp:600
bool using_own_console()
Returns true if a console was allocated by the Wesnoth process.
severity
Definition: log.hpp:82
std::string list_log_domains(const std::string &filter)
Definition: log.cpp:410
bool broke_strict()
Definition: log.cpp:430
void set_log_to_file()
Do the initial redirection to a log file if the logs directory is writable.
Definition: log.cpp:266
void set_log_sanitize(bool sanitize)
toggle log sanitization
Definition: log.cpp:434
utils::optional< bool > log_dir_writable()
Returns the result set by check_log_dir_writable().
Definition: log.cpp:312
void do_console_redirect()
Allocates a console if needed and redirects output to CONOUT.
void precise_timestamps(bool pt)
Definition: log.cpp:337
bool set_log_domain_severity(const std::string &name, severity severity)
Definition: log.cpp:379
void set_strict_severity(severity severity)
Definition: log.cpp:420
void empty_playlist()
Definition: sound.cpp:609
void play_music_config(const config &music_node, bool allow_interrupt_current_track, int i)
Definition: sound.cpp:712
void stop_music()
Definition: sound.cpp:554
void bind_textdomain(const char *domain, const char *directory, const char *)
Definition: gettext.cpp:479
void set_default_textdomain(const char *domain)
Definition: gettext.cpp:487
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
std::map< std::string, t_string > string_map
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
std::string preprocess_string(const std::string &contents, preproc_map *defines, const std::string &textdomain)
Function to use the WML preprocessor on a string.
void preprocess_resource(const std::string &res_name, preproc_map *defines_map, bool write_cfg, bool write_plain_cfg, const std::string &parent_directory)
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
std::map< std::string, struct preproc_define > preproc_map
One of the realizations of serialization/validator.hpp abstract validator.
Contains a basic exception class for SDL operations.
structure which will hide all current floating labels, and cause floating labels instantiated after i...
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
static preproc_map::value_type read_pair(const config &)
Reports time elapsed at the end of an object scope.
Definition: optimer.hpp:37
An error specifically indicating video subsystem problems.
Definition: video.hpp:316
Helper class, don't construct this directly.
bool strict_validation_enabled
Definition: validator.cpp:21
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
#define PACKAGE
Definition: wesconfig.h:23
static lg::log_domain log_preprocessor("preprocessor")
static void handle_preprocess_string(const commandline_options &cmdline_opts)
Definition: wesnoth.cpp:133
static void safe_exit(int res)
Definition: wesnoth.cpp:127
static int do_gameloop(commandline_options &cmdline_opts)
Setups the game environment and enters the titlescreen or game loops.
Definition: wesnoth.cpp:734
static int handle_validate_command(const std::string &file, abstract_validator &validator, const std::vector< std::string > &defines)
Definition: wesnoth.cpp:307
int main(int argc, char **argv)
Definition: wesnoth.cpp:978
static int process_command_args(commandline_options &cmdline_opts)
Process commandline-arguments.
Definition: wesnoth.cpp:333
static void handle_preprocess_command(const commandline_options &cmdline_opts)
Definition: wesnoth.cpp:190
static void check_fpu()
Definition: wesnoth.cpp:705
#define LOG_PREPROC
Definition: wesnoth.cpp:122
static void init_locale()
I would prefer to setup locale first so that early error messages can get localized,...
Definition: wesnoth.cpp:605
static void handle_lua_script_args(game_launcher *game, commandline_options &)
Handles the lua script command line arguments if present.
Definition: wesnoth.cpp:642
#define error_exit(res)
Definition: wesnoth.cpp:971
static void warn_early_init_failure()
Print an alert and instructions to stderr about early initialization errors.
Definition: wesnoth.cpp:629
#define LOG_GENERAL
Definition: wesnoth.cpp:119
static lg::log_domain log_config("config")
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define e