The Battle for Wesnoth  1.19.9+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/parser.hpp" // for read
47 #include "serialization/preprocessor.hpp" // for preproc_define, etc
48 #include "serialization/schema_validator.hpp" // for strict_validation_enabled and schema_validator
49 #include "sound.hpp" // for commit_music_changes, etc
50 #include "utils/optimer.hpp"
51 #include "formula/string_utils.hpp" // VGETTEXT
52 #include <functional>
53 #include "game_version.hpp" // for version_info
54 #include "video.hpp" // for video::error and video::quit
55 #include "wesconfig.h" // for PACKAGE
56 #include "widgets/button.hpp" // for button
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 <ctime> // for time, ctime, std::time_t
81 #include <exception> // for exception
82 #include <vector>
83 #include <iostream>
84 
85 //#define NO_CATCH_AT_GAME_END
86 
87 #ifdef _WIN32
88 
89 #ifdef INADDR_ANY
90 #undef INADDR_ANY
91 #endif
92 
93 #ifdef INADDR_BROADCAST
94 #undef INADDR_BROADCAST
95 #endif
96 
97 #ifdef INADDR_NONE
98 #undef INADDR_NONE
99 #endif
100 
101 #include <windows.h>
102 
103 #endif // _WIN32
104 
105 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
106 #include "gui/widgets/debug.hpp"
107 #endif
108 
109 // this file acts as a launcher for various gui2 dialogs
110 // so this reduces some boilerplate.
111 using namespace gui2::dialogs;
112 
113 static lg::log_domain log_config("config");
114 #define LOG_CONFIG LOG_STREAM(info, log_config)
115 
116 #define LOG_GENERAL LOG_STREAM(info, lg::general())
117 
118 static lg::log_domain log_preprocessor("preprocessor");
119 #define LOG_PREPROC LOG_STREAM(info, log_preprocessor)
120 
121 // this is needed to allow identical functionality with clean refactoring
122 // play_game only returns on an error, all returns within play_game can
123 // be replaced with this
124 static void safe_exit(int res)
125 {
126  LOG_GENERAL << "exiting with code " << res;
127  exit(res);
128 }
129 
130 static void handle_preprocess_string(const commandline_options& cmdline_opts)
131 {
132  preproc_map defines_map;
133 
134  if(cmdline_opts.preprocess_input_macros) {
135  std::string file = *cmdline_opts.preprocess_input_macros;
136  if(!filesystem::file_exists(file)) {
137  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
138  return;
139  }
140 
141  PLAIN_LOG << "Reading cached defines from: " << file;
142 
143  config cfg;
144 
145  try {
147  read(cfg, *stream);
148  } catch(const config::error& e) {
149  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
150  }
151 
152  int read = 0;
153 
154  // use static preproc_define::read_pair(config) to make a object
155  for(const auto [_, cfg] : cfg.all_children_view()) {
156  const preproc_map::value_type def = preproc_define::read_pair(cfg);
157  defines_map[def.first] = def.second;
158  ++read;
159  }
160 
161  PLAIN_LOG << "Read " << read << " defines.";
162  }
163 
164  if(cmdline_opts.preprocess_defines) {
165  // add the specified defines
166  for(const std::string& define : *cmdline_opts.preprocess_defines) {
167  if(define.empty()) {
168  PLAIN_LOG << "empty define supplied";
169  continue;
170  }
171 
172  LOG_PREPROC << "adding define: " << define;
173  defines_map.emplace(define, preproc_define(define));
174  }
175  }
176 
177  // add the WESNOTH_VERSION define
178  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
179 
180  // preprocess resource
181  PLAIN_LOG << "preprocessing specified string: " << *cmdline_opts.preprocess_source_string;
182  const utils::ms_optimer timer(
183  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
184  std::cout << preprocess_string(*cmdline_opts.preprocess_source_string, &defines_map) << std::endl;
185  PLAIN_LOG << "added " << defines_map.size() << " defines.";
186 }
187 
188 static void handle_preprocess_command(const commandline_options& cmdline_opts)
189 {
190  preproc_map input_macros;
191 
192  if(cmdline_opts.preprocess_input_macros) {
193  std::string file = *cmdline_opts.preprocess_input_macros;
194  if(filesystem::file_exists(file) == false) {
195  PLAIN_LOG << "please specify an existing file. File " << file << " doesn't exist.";
196  return;
197  }
198 
199  PLAIN_LOG << "Reading cached defines from: " << file;
200 
201  config cfg;
202 
203  try {
205  read(cfg, *stream);
206  } catch(const config::error& e) {
207  PLAIN_LOG << "Caught a config error while parsing file '" << file << "':\n" << e.message;
208  }
209 
210  int read = 0;
211 
212  // use static preproc_define::read_pair(config) to make a object
213  for(const auto [_, cfg] : cfg.all_children_view()) {
214  const preproc_map::value_type def = preproc_define::read_pair(cfg);
215  input_macros[def.first] = def.second;
216  ++read;
217  }
218 
219  PLAIN_LOG << "Read " << read << " defines.";
220  }
221 
222  const std::string resourceToProcess(*cmdline_opts.preprocess_path);
223  const std::string targetDir(*cmdline_opts.preprocess_target);
224 
225  const utils::ms_optimer timer(
226  [](const auto& timer) { PLAIN_LOG << "preprocessing finished. Took " << timer << " ticks."; });
227 
228  // If the users add the SKIP_CORE define we won't preprocess data/core
229  bool skipCore = false;
230  bool skipTerrainGFX = false;
231 
232  // The 'core_defines_map' is the one got from data/core macros
233  preproc_map defines_map(input_macros);
234 
235  if(cmdline_opts.preprocess_defines) {
236  // add the specified defines
237  for(const std::string& define : *cmdline_opts.preprocess_defines) {
238  if(define.empty()) {
239  PLAIN_LOG << "empty define supplied";
240  continue;
241  }
242 
243  LOG_PREPROC << "adding define: " << define;
244  defines_map.emplace(define, preproc_define(define));
245 
246  if(define == "SKIP_CORE") {
247  PLAIN_LOG << "'SKIP_CORE' defined.";
248  skipCore = true;
249  } else if(define == "NO_TERRAIN_GFX") {
250  PLAIN_LOG << "'NO_TERRAIN_GFX' defined.";
251  skipTerrainGFX = true;
252  }
253  }
254  }
255 
256  // add the WESNOTH_VERSION define
257  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
258 
259  PLAIN_LOG << "added " << defines_map.size() << " defines.";
260 
261  // preprocess core macros first if we don't skip the core
262  if(skipCore == false) {
263  PLAIN_LOG << "preprocessing common macros from 'data/core' ...";
264 
265  // process each folder explicitly to gain speed
266  preprocess_resource(game_config::path + "/data/core/macros", &defines_map);
267 
268  if(skipTerrainGFX == false) {
269  preprocess_resource(game_config::path + "/data/core/terrain-graphics", &defines_map);
270  }
271 
272  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " 'data/core' defines.";
273  } else {
274  PLAIN_LOG << "skipped 'data/core'";
275  }
276 
277  // preprocess resource
278  PLAIN_LOG << "preprocessing specified resource: " << resourceToProcess << " ...";
279 
280  preprocess_resource(resourceToProcess, &defines_map, true, true, targetDir);
281  PLAIN_LOG << "acquired " << (defines_map.size() - input_macros.size()) << " total defines.";
282 
283  if(cmdline_opts.preprocess_output_macros) {
284  std::string outputFileName = "_MACROS_.cfg";
285  if(!cmdline_opts.preprocess_output_macros->empty()) {
286  outputFileName = *cmdline_opts.preprocess_output_macros;
287  }
288 
289  std::string outputPath = targetDir + "/" + outputFileName;
290 
291  PLAIN_LOG << "writing '" << outputPath << "' with " << defines_map.size() << " defines.";
292 
294  if(!out->fail()) {
295  config_writer writer(*out, false);
296 
297  for(auto& define_pair : defines_map) {
298  define_pair.second.write(writer, define_pair.first);
299  }
300  } else {
301  PLAIN_LOG << "couldn't open the file.";
302  }
303  }
304 }
305 
306 static int handle_validate_command(const std::string& file, abstract_validator& validator, const std::vector<std::string>& defines) {
307  preproc_map defines_map;
308  // add the WESNOTH_VERSION define
309  defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
310  defines_map["SCHEMA_VALIDATION"] = preproc_define();
311  for(const std::string& define : defines) {
312  if(define.empty()) {
313  PLAIN_LOG << "empty define supplied";
314  continue;
315  }
316 
317  LOG_PREPROC << "adding define: " << define;
318  defines_map.emplace(define, preproc_define(define));
319  }
320  PLAIN_LOG << "Validating " << file << " against schema " << validator.name_;
322  filesystem::scoped_istream stream = preprocess_file(file, &defines_map);
323  config result;
324  read(result, *stream, &validator);
325  if(lg::broke_strict()) {
326  std::cout << "validation failed\n";
327  } else {
328  std::cout << "validation succeeded\n";
329  }
330  return lg::broke_strict();
331 }
332 
333 /** Process commandline-arguments */
334 static int process_command_args(commandline_options& cmdline_opts)
335 {
336  // Options that don't change behavior based on any others should be checked alphabetically below.
337 
338  if(cmdline_opts.no_log_sanitize) {
339  lg::set_log_sanitize(false);
340  }
341 
342  if(cmdline_opts.usercache_dir) {
344  }
345 
346  if(cmdline_opts.userdata_dir) {
348  }
349 
350  // earliest possible point to ensure the userdata directory is known
352  filesystem::set_user_data_dir(std::string());
353  }
354 
355  // userdata is initialized, so initialize logging to file if enabled
356  // If true, output will be redirected to file, else output be written to console.
357  // On Windows, if Wesnoth was not started from a console, one will be allocated.
358  if(cmdline_opts.log_to_file
359  || (!cmdline_opts.no_log_to_file
360  && !getenv("WESNOTH_NO_LOG_FILE")
361  // command line options that imply not redirecting output to a log file
362  && !cmdline_opts.data_path
363  && !cmdline_opts.userdata_path
364  && !cmdline_opts.usercache_path
365  && !cmdline_opts.version
366  && !cmdline_opts.simple_version
367  && !cmdline_opts.logdomains
368  && !cmdline_opts.help
369  && !cmdline_opts.report
370  && !cmdline_opts.do_diff
371  && !cmdline_opts.do_patch
372  && !cmdline_opts.preprocess
373  && !cmdline_opts.render_image
374  && !cmdline_opts.screenshot
375  && !cmdline_opts.nogui
376  && !cmdline_opts.headless_unit_test
377  && !cmdline_opts.validate_schema
378  && !cmdline_opts.validate_wml
379  )
380  )
381  {
383  }
384 #ifdef _WIN32
385  // This forces a Windows console to be attached to the process even
386  // if Wesnoth is an IMAGE_SUBSYSTEM_WINDOWS_GUI executable because it
387  // turns Wesnoth into a CLI application. (unless --wnoconsole is given)
388  else if(!cmdline_opts.no_console) {
390  }
391 #endif
392 
393  if(cmdline_opts.log) {
394  for(const auto& log_pair : *cmdline_opts.log) {
395  const std::string log_domain = log_pair.second;
396  const lg::severity severity = log_pair.first;
397  if(!lg::set_log_domain_severity(log_domain, severity)) {
398  PLAIN_LOG << "unknown log domain: " << log_domain;
399  return 2;
400  }
401  }
402  }
403 
404  if(!cmdline_opts.nobanner) {
405  PLAIN_LOG << "Battle for Wesnoth v" << game_config::revision << " " << game_config::build_arch();
406  const std::time_t t = std::time(nullptr);
407  PLAIN_LOG << "Started on " << ctime(&t);
408  }
409 
410  if(cmdline_opts.usercache_path) {
411  std::cout << filesystem::get_cache_dir();
412  return 0;
413  }
414 
415  if(cmdline_opts.userdata_path) {
416  std::cout << filesystem::get_user_data_dir();
417  return 0;
418  }
419 
420  if(cmdline_opts.data_dir) {
421  game_config::path = filesystem::normalize_path(*cmdline_opts.data_dir, true, true);
422  if(!cmdline_opts.nobanner) {
423  PLAIN_LOG << "Overriding data directory with '" << game_config::path << "'";
424  }
425  } else {
426  // if a pre-defined path does not exist this will empty it
428  if(game_config::path.empty()) {
429  if(std::string exe_dir = filesystem::get_exe_dir(); !exe_dir.empty()) {
430  if(std::string auto_dir = filesystem::autodetect_game_data_dir(std::move(exe_dir)); !auto_dir.empty()) {
431  if(!cmdline_opts.nobanner) {
432  PLAIN_LOG << "Automatically found a possible data directory at: " << auto_dir;
433  }
434  game_config::path = filesystem::normalize_path(auto_dir, true, true);
435  }
436  } else {
437  PLAIN_LOG << "Cannot find game data directory. Specify one with --data-dir";
438  return 1;
439  }
440  }
441  }
442 
444  PLAIN_LOG << "Could not find game data directory '" << game_config::path << "'";
445  return 1;
446  }
447 
448  if(cmdline_opts.data_path) {
449  std::cout << game_config::path;
450  return 0;
451  }
452 
453  if(cmdline_opts.debug_lua) {
454  game_config::debug_lua = true;
455  }
456 
457  if(cmdline_opts.allow_insecure) {
459  }
460 
461  if(cmdline_opts.addon_server_info) {
463  }
464 
465  if(cmdline_opts.strict_lua) {
467  }
468 
469  if(cmdline_opts.help) {
470  std::cout << cmdline_opts;
471  return 0;
472  }
473 
474  if(cmdline_opts.logdomains) {
475  std::cout << lg::list_log_domains(*cmdline_opts.logdomains);
476  return 0;
477  }
478 
479  if(cmdline_opts.log_precise_timestamps) {
481  }
482 
483  if(cmdline_opts.rng_seed) {
484  srand(*cmdline_opts.rng_seed);
485  }
486 
487  if(cmdline_opts.render_image) {
488  SDL_setenv("SDL_VIDEODRIVER", "dummy", 1);
489  }
490 
491  if(cmdline_opts.strict_validation) {
493  }
494 
495  if(cmdline_opts.version) {
496  std::cout << "Battle for Wesnoth" << " " << game_config::wesnoth_version.str() << "\n\n";
497  std::cout << "Library versions:\n" << game_config::library_versions_report() << '\n';
498  std::cout << "Optional features:\n" << game_config::optional_features_report();
499 
500  return 0;
501  }
502 
503  if(cmdline_opts.simple_version) {
504  std::cout << game_config::wesnoth_version.str() << "\n";
505 
506  return 0;
507  }
508 
509  if(cmdline_opts.report) {
510  std::cout << "\n========= BUILD INFORMATION =========\n\n" << game_config::full_build_report();
511  return 0;
512  }
513 
514  if(cmdline_opts.validate_schema) {
516  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
517  return handle_validate_command(*cmdline_opts.validate_schema, validator, {});
518  }
519 
520  if(cmdline_opts.do_diff) {
521  config left, right;
522  std::ifstream in_left(cmdline_opts.diff_left);
523  std::ifstream in_right(cmdline_opts.diff_right);
524  read(left, in_left);
525  read(right, in_right);
526  std::ostream* os = &std::cout;
527  if(cmdline_opts.output_file) {
528  os = new std::ofstream(*cmdline_opts.output_file);
529  }
531  out.write(right.get_diff(left));
532  if(os != &std::cout) delete os;
533  return 0;
534  }
535 
536  if(cmdline_opts.do_patch) {
537  config base, diff;
538  std::ifstream in_base(cmdline_opts.diff_left);
539  std::ifstream in_diff(cmdline_opts.diff_right);
540  read(base, in_base);
541  read(diff, in_diff);
542  base.apply_diff(diff);
543  std::ostream* os = &std::cout;
544  if(cmdline_opts.output_file) {
545  os = new std::ofstream(*cmdline_opts.output_file);
546  }
548  out.write(base);
549  if(os != &std::cout) delete os;
550  return 0;
551  }
552 
553  if(cmdline_opts.generate_spritesheet) {
554  PLAIN_LOG << "sheet path " << *cmdline_opts.generate_spritesheet;
556  return 0;
557  }
558 
559  // Options changing their behavior dependent on some others should be checked below.
560 
561  if(cmdline_opts.preprocess) {
562  handle_preprocess_command(cmdline_opts);
563  return 0;
564  }
565 
566  if(cmdline_opts.preprocess_source_string.has_value()) {
567  handle_preprocess_string(cmdline_opts);
568  return 0;
569  }
570 
571  if(cmdline_opts.validate_wml) {
572  std::string schema_path;
573  if(cmdline_opts.validate_with) {
574  schema_path = *cmdline_opts.validate_with;
575  if(!filesystem::file_exists(schema_path)) {
576  if(auto check = filesystem::get_wml_location(schema_path)) {
577  schema_path = check.value();
578  } else {
579  PLAIN_LOG << "Could not find schema file: " << schema_path;
580  }
581  } else {
582  schema_path = filesystem::normalize_path(schema_path);
583  }
584  } else {
585  schema_path = filesystem::get_wml_location("schema/game_config.cfg").value();
586  }
588  validator.set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
589  return handle_validate_command(*cmdline_opts.validate_wml, validator,
590  cmdline_opts.preprocess_defines.value_or<decltype(cmdline_opts.preprocess_defines)::value_type>({}));
591  }
592 
593  if(cmdline_opts.preprocess_defines || cmdline_opts.preprocess_input_macros || cmdline_opts.preprocess_path) {
594  // It would be good if this was supported for running tests too, possibly for other uses.
595  // For the moment show an error message instead of leaving the user wondering why it doesn't work.
596  PLAIN_LOG << "That --preprocess-* option is only supported when using --preprocess or --validate.";
597  return 2;
598  }
599 
600  // Not the most intuitive solution, but I wanted to leave current semantics for now
601  return -1;
602 }
603 
604 /**
605  * I would prefer to setup locale first so that early error
606  * messages can get localized, but we need the game_launcher
607  * initialized to have filesystem::get_intl_dir() to work. Note: setlocale()
608  * does not take GUI language setting into account.
609  */
610 static void init_locale()
611 {
612 #if defined _WIN32 || defined __APPLE__
613  setlocale(LC_ALL, "English");
614 #else
615  std::setlocale(LC_ALL, "C");
616 #endif
617 
618  const std::string& intl_dir = filesystem::get_intl_dir();
619 
620  translation::bind_textdomain(PACKAGE, intl_dir.c_str(), "UTF-8");
621  translation::bind_textdomain(PACKAGE "-lib", intl_dir.c_str(), "UTF-8");
623 }
624 
625 /**
626  * Print an alert and instructions to stderr about early initialization errors.
627  *
628  * This is provided as an aid for users dealing with potential data dir
629  * configuration issues. The first code to read core WML *has* the
630  * responsibility to call this function in the event of a problem, to inform
631  * the user of the most likely possible cause and suggest a course of action
632  * to solve the issue.
633  */
635 {
636  // NOTE: wrap output to 80 columns.
637  PLAIN_LOG << '\n'
638  << "An error at this point during initialization usually indicates that the data\n"
639  << "directory above was not correctly set or detected. Try passing the correct path\n"
640  << "in the command line with the --data-dir switch or as the only argument.";
641 }
642 
643 /**
644  * Handles the lua script command line arguments if present.
645  * This function will only run once.
646  */
648 {
649  static bool first_time = true;
650 
651  if(!first_time) {
652  return;
653  }
654 
655  first_time = false;
656 
657  if(!game->init_lua_script()) {
658  // PLAIN_LOG << "error when loading lua scripts at startup";
659  // PLAIN_LOG << "could not load lua script: " << *cmdline_opts.script_file;
660  }
661 }
662 
663 #ifdef _MSC_VER
664 static void check_fpu()
665 {
666  uint32_t f_control;
667 
668  if(_controlfp_s(&f_control, 0, 0) == 0) {
669  uint32_t unused;
670  uint32_t rounding_mode = f_control & _MCW_RC;
671 
672  if(rounding_mode != _RC_NEAR) {
673  PLAIN_LOG << "Floating point rounding mode is currently '"
674  << ((rounding_mode == _RC_CHOP)
675  ? "chop"
676  : (rounding_mode == _RC_UP)
677  ? "up"
678  : (rounding_mode == _RC_DOWN)
679  ? "down"
680  : (rounding_mode == _RC_NEAR) ? "near" : "unknown")
681  << "' setting to 'near'";
682 
683  if(_controlfp_s(&unused, _RC_NEAR, _MCW_RC)) {
684  PLAIN_LOG << "failed to set floating point rounding type to 'near'";
685  }
686  }
687 
688 #ifndef _M_AMD64
689  uint32_t precision_mode = f_control & _MCW_PC;
690  if(precision_mode != _PC_53) {
691  PLAIN_LOG << "Floating point precision mode is currently '"
692  << ((precision_mode == _PC_53)
693  ? "double"
694  : (precision_mode == _PC_24)
695  ? "single"
696  : (precision_mode == _PC_64) ? "double extended" : "unknown")
697  << "' setting to 'double'";
698 
699  if(_controlfp_s(&unused, _PC_53, _MCW_PC)) {
700  PLAIN_LOG << "failed to set floating point precision type to 'double'";
701  }
702  }
703 #endif
704 
705  } else {
706  PLAIN_LOG << "_controlfp_s failed.";
707  }
708 }
709 #else
710 static void check_fpu()
711 {
712  switch(fegetround()) {
713  case FE_TONEAREST:
714  break;
715  case FE_DOWNWARD:
716  STREAMING_LOG << "Floating point precision mode is currently 'downward'";
717  goto reset_fpu;
718  case FE_TOWARDZERO:
719  STREAMING_LOG << "Floating point precision mode is currently 'toward-zero'";
720  goto reset_fpu;
721  case FE_UPWARD:
722  STREAMING_LOG << "Floating point precision mode is currently 'upward'";
723  goto reset_fpu;
724  default:
725  STREAMING_LOG << "Floating point precision mode is currently 'unknown'";
726  goto reset_fpu;
727  reset_fpu:
728  STREAMING_LOG << " - setting to 'nearest'\n";
729  fesetround(FE_TONEAREST);
730  break;
731  }
732 }
733 #endif
734 
735 /**
736  * Setups the game environment and enters
737  * the titlescreen or game loops.
738  */
739 static int do_gameloop(commandline_options& cmdline_opts)
740 {
741  srand(std::time(nullptr));
742 
743  const auto game = std::make_unique<game_launcher>(cmdline_opts);
744 
745  init_locale();
746 
747  bool res;
748 
749  // Do initialize fonts before reading the game config, to have game
750  // config error messages displayed. fonts will be re-initialized later
751  // when the language is read from the game config.
752  res = font::load_font_config();
753  if(res == false) {
754  PLAIN_LOG << "could not initialize fonts";
755  // The most common symptom of a bogus data dir path -- warn the user.
757  return 1;
758  }
759 
760  res = game->init_language();
761  if(res == false) {
762  PLAIN_LOG << "could not initialize the language";
763  return 1;
764  }
765 
766  res = game->init_video();
767  if(res == false) {
768  PLAIN_LOG << "could not initialize display";
769  return 1;
770  }
771 
772  check_fpu();
773  const cursor::manager cursor_manager;
775 
776 #if(defined(_X11) && !defined(__APPLE__)) || defined(_WIN32)
777  SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
778 #endif
779 
780  gui2::init();
781  gui2::switch_theme(prefs::get().gui2_theme());
782  const gui2::event::manager gui_event_manager;
783 
784  // if the log directory is not writable, then this is the error condition so show the error message.
785  // if the log directory is writable, then there's no issue.
786  // if the optional isn't set, then logging to file has been disabled, so there's no issue.
787  if(!lg::log_dir_writable().value_or(true)) {
788  utils::string_map symbols;
789  symbols["logdir"] = filesystem::get_logs_dir();
790  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);
791  gui2::show_message(_("Logging Failure"), msg, message::ok_button);
792  }
793 
794  game_config_manager config_manager(cmdline_opts);
795 
799  }
800 
801  loading_screen::display([&res, &config_manager, &cmdline_opts]() {
804 
805  if(res == false) {
806  PLAIN_LOG << "could not initialize game config";
807  return;
808  }
809 
811 
812  res = font::load_font_config();
813  if(res == false) {
814  PLAIN_LOG << "could not re-initialize fonts for the current language";
815  return;
816  }
817 
818  if(!game_config::no_addons && !cmdline_opts.noaddons) {
820 
822  }
823  });
824 
825  if(res == false) {
826  return 1;
827  }
828 
829  plugins_manager plugins_man(new application_lua_kernel);
830 
831  const plugins_context::reg_vec callbacks {
832  {"play_multiplayer", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::CONNECT)},
833  {"play_local", std::bind(&game_launcher::play_multiplayer, game.get(), game_launcher::mp_mode::LOCAL)},
834  {"play_campaign", std::bind(&game_launcher::play_campaign, game.get())},
835  };
836 
837  const plugins_context::areg_vec accessors {
838  {"command_line", std::bind(&commandline_options::to_config, &cmdline_opts)},
839  };
840 
841  plugins_context plugins("titlescreen", callbacks, accessors);
842 
843  plugins.set_callback("exit", [](const config& cfg) { safe_exit(cfg["code"].to_int(0)); }, false);
844 
845  while(true) {
846  if(!game->has_load_data()) {
847  auto cfg = config_manager.game_config().optional_child("titlescreen_music");
848  if(cfg) {
849  for(const config& i : cfg->child_range("music")) {
851  }
852 
853  config title_music_config;
854  title_music_config["name"] = game_config::title_music;
855  title_music_config["append"] = true;
856  title_music_config["immediate"] = true;
857  sound::play_music_config(title_music_config);
858  } else {
861  }
862  }
863 
864  handle_lua_script_args(&*game, cmdline_opts);
865 
866  plugins.play_slice();
867  plugins.play_slice();
868 
869  if(!cmdline_opts.unit_test.empty()) {
870  return static_cast<int>(game->unit_test());
871  }
872 
873  if(game->play_test() == false) {
874  return 0;
875  }
876 
877  if(game->play_screenshot_mode() == false) {
878  return 0;
879  }
880 
881  if(game->play_render_image_mode() == false) {
882  return 0;
883  }
884 
885  // Start directly a campaign
886  if(game->goto_campaign() == false) {
887  if(game->jump_to_campaign_id().empty())
888  continue; // Go to main menu
889  else
890  return 1; // we got an error starting the campaign from command line
891  }
892 
893  // Start directly a multiplayer
894  // Eventually with a specified server
895  if(game->goto_multiplayer() == false) {
896  continue; // Go to main menu
897  }
898 
899  // Start directly a commandline multiplayer game
900  if(game->play_multiplayer_commandline() == false) {
901  return 0;
902  }
903 
904  if(game->goto_editor() == false) {
905  return 0;
906  }
907 
908  const font::floating_label_context label_manager;
909 
911 
912  // If loading a game, skip the titlescreen entirely
913  if(game->has_load_data() && game->load_game()) {
915  continue;
916  }
917 
918  int retval;
919  { // scope to not keep the title screen alive all game
920  title_screen dlg(*game);
921 
922  // Allows re-layout on resize.
923  // Since RELOAD_UI is not checked here, it causes
924  // the dialog to be closed and reshown with changes.
926  dlg.show();
927  }
928  retval = dlg.get_retval();
929  }
930 
931  switch(retval) {
933  LOG_GENERAL << "quitting game...";
934  return 0;
936  game->play_multiplayer(game_launcher::mp_mode::CONNECT);
937  break;
939  game->play_multiplayer(game_launcher::mp_mode::HOST);
940  break;
942  game->play_multiplayer(game_launcher::mp_mode::LOCAL);
943  break;
945  loading_screen::display([&config_manager]() {
946  config_manager.reload_changed_game_config();
947  gui2::init();
948  gui2::switch_theme(prefs::get().gui2_theme());
949  });
950  break;
952  game->start_editor();
953  break;
956  break;
958  break;
960  gui2::switch_theme(prefs::get().gui2_theme());
961  break;
962  }
963  }
964 }
965 
966 #ifdef _WIN32
967 #define error_exit(res) \
968  do { \
969  if(lg::using_own_console()) { \
970  std::cerr << "Press enter to continue..." << std::endl; \
971  std::cin.get(); \
972  } \
973  return res; \
974  } while(false)
975 #else
976 #define error_exit(res) return res
977 #endif
978 
979 #ifdef __APPLE__
980 extern "C" int wesnoth_main(int argc, char** argv);
981 int wesnoth_main(int argc, char** argv)
982 #else
983 int main(int argc, char** argv)
984 #endif
985 {
987  auto args = read_argv(argc, argv);
988  assert(!args.empty());
989 
990 #ifdef _WIN32
991  _putenv("PANGOCAIRO_BACKEND=fontconfig");
992  _putenv("FONTCONFIG_PATH=fonts");
993 #endif
994 #ifdef __APPLE__
995  // Using setenv with overwrite disabled so we can override this in the
996  // original process environment for research/testing purposes.
997  setenv("PANGOCAIRO_BACKEND", "fontconfig", 0);
998 #endif
999 
1000  try {
1001  commandline_options cmdline_opts = commandline_options(args);
1002  int finished = process_command_args(cmdline_opts);
1003 
1004  if(finished != -1) {
1005 #ifdef _WIN32
1006  if(lg::using_own_console()) {
1007  std::cerr << "Press enter to continue..." << std::endl;
1008  std::cin.get();
1009  }
1010 #endif
1011  safe_exit(finished);
1012  }
1013 
1014  SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
1015  // Is there a reason not to just use SDL_INIT_EVERYTHING?
1016  if(SDL_Init(SDL_INIT_TIMER) < 0) {
1017  PLAIN_LOG << "Couldn't initialize SDL: " << SDL_GetError();
1018  return (1);
1019  }
1020  atexit(SDL_Quit);
1021 
1022  // Mac's touchpad generates touch events too.
1023  // Ignore them until Macs have a touchscreen: https://forums.libsdl.org/viewtopic.php?p=45758
1024 #if defined(__APPLE__) && !defined(__IPHONEOS__)
1025  SDL_EventState(SDL_FINGERMOTION, SDL_DISABLE);
1026  SDL_EventState(SDL_FINGERDOWN, SDL_DISABLE);
1027  SDL_EventState(SDL_FINGERUP, SDL_DISABLE);
1028 #endif
1029 
1030  // declare this here so that it will always be at the front of the event queue.
1031  events::event_context global_context;
1032 
1033  SDL_StartTextInput();
1034 
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:387
double t
Definition: astarsearch.cpp:63
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:1029
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:93
Standard logging facilities (interface).
#define STREAMING_LOG
Definition: log.hpp:298
#define PLAIN_LOG
Definition: log.hpp:297
@ 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:176
void set_main_thread()
Definition: events.cpp:471
std::string get_cache_dir()
Definition: filesystem.cpp:865
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
std::string get_user_data_dir()
Definition: filesystem.cpp:855
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:327
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:818
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:53
std::string get_logs_dir()
Definition: filesystem.cpp:860
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:54
bool is_userdata_initialized()
Definition: filesystem.cpp:610
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:722
bool load_font_config()
Definition: font_config.cpp:58
std::string path
Definition: filesystem.cpp:92
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:100
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:34
void switch_theme(const std::string &current_theme)
Set and activate the given gui2 theme.
Definition: gui.cpp:135
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)
bool using_own_console()
Returns true if a console was allocated by the Wesnoth process.
severity
Definition: log.hpp:83
std::string list_log_domains(const std::string &filter)
Definition: log.cpp:380
bool broke_strict()
Definition: log.cpp:400
void set_log_to_file()
Do the initial redirection to a log file if the logs directory is writable.
Definition: log.cpp:234
void set_log_sanitize(bool sanitize)
toggle log sanitization
Definition: log.cpp:404
utils::optional< bool > log_dir_writable()
Returns the result set by check_log_dir_writable().
Definition: log.cpp:280
void do_console_redirect()
Allocates a console if needed and redirects output to CONOUT.
void precise_timestamps(bool pt)
Definition: log.cpp:305
bool set_log_domain_severity(const std::string &name, severity severity)
Definition: log.cpp:347
void set_strict_severity(severity severity)
Definition: log.cpp:390
void empty_playlist()
Definition: sound.cpp:613
void play_music_config(const config &music_node, bool allow_interrupt_current_track, int i)
Definition: sound.cpp:716
void stop_music()
Definition: sound.cpp:558
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.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:629
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:130
static void safe_exit(int res)
Definition: wesnoth.cpp:124
static int do_gameloop(commandline_options &cmdline_opts)
Setups the game environment and enters the titlescreen or game loops.
Definition: wesnoth.cpp:739
static int handle_validate_command(const std::string &file, abstract_validator &validator, const std::vector< std::string > &defines)
Definition: wesnoth.cpp:306
int main(int argc, char **argv)
Definition: wesnoth.cpp:983
static int process_command_args(commandline_options &cmdline_opts)
Process commandline-arguments.
Definition: wesnoth.cpp:334
static void handle_preprocess_command(const commandline_options &cmdline_opts)
Definition: wesnoth.cpp:188
static void check_fpu()
Definition: wesnoth.cpp:710
#define LOG_PREPROC
Definition: wesnoth.cpp:119
static void init_locale()
I would prefer to setup locale first so that early error messages can get localized,...
Definition: wesnoth.cpp:610
static void handle_lua_script_args(game_launcher *game, commandline_options &)
Handles the lua script command line arguments if present.
Definition: wesnoth.cpp:647
#define error_exit(res)
Definition: wesnoth.cpp:976
static void warn_early_init_failure()
Print an alert and instructions to stderr about early initialization errors.
Definition: wesnoth.cpp:634
#define LOG_GENERAL
Definition: wesnoth.cpp:116
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