The Battle for Wesnoth  1.17.4+dev
build_info.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2022
3  by Iris Morelle <shadowm2006@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "build_info.hpp"
19 
20 #include "desktop/version.hpp"
21 #include "game_config.hpp"
22 #include "filesystem.hpp"
23 #include "formatter.hpp"
24 #include "gettext.hpp"
27 #include "game_version.hpp"
28 #include "sound.hpp"
29 #include "video.hpp"
30 #include "addon/manager.hpp"
31 #include "sdl/point.hpp"
32 
33 #include <algorithm>
34 #include <fstream>
35 #include <iomanip>
36 
37 #include "lua/lua.h"
38 
39 #include <SDL2/SDL.h>
40 #include <SDL2/SDL_image.h>
41 #include <SDL2/SDL_mixer.h>
42 
43 #include <boost/algorithm/string.hpp>
44 #include <boost/predef.h>
45 #include <boost/version.hpp>
46 
47 #ifndef __APPLE__
48 #include <openssl/crypto.h>
49 #include <openssl/opensslv.h>
50 #endif
51 
52 #include <pango/pangocairo.h>
53 
54 #ifdef __APPLE__
55 // apple_notification.mm uses Foundation.h, which is an Objective-C header;
56 // but CoreFoundation.h is a C header which also defines these.
57 #include <CoreFoundation/CoreFoundation.h>
58 #endif
59 
60 namespace game_config
61 {
62 
63 namespace {
64 
65 struct version_table_manager
66 {
67  std::vector<std::string> compiled, linked, names;
68  std::vector<optional_feature> features;
69 
70  version_table_manager();
71 };
72 
73 const version_table_manager versions;
74 
75 #if 0
76 std::string format_version(unsigned a, unsigned b, unsigned c)
77 {
78  return formatter() << a << '.' << b << '.' << c;
79 }
80 #endif
81 
82 std::string format_version(const SDL_version& v)
83 {
84  return formatter() << static_cast<unsigned>(v.major) << '.'
85  << static_cast<unsigned>(v.minor) << '.'
86  << static_cast<unsigned>(v.patch);
87 }
88 
89 #ifndef __APPLE__
90 
91 std::string format_openssl_patch_level(uint8_t p)
92 {
93  return p <= 26
94  ? std::string(1, 'a' + static_cast<char>(p) - 1)
95  : "patch" + std::to_string(p);
96 }
97 
98 std::string format_openssl_version(long v)
99 {
100  int major, minor, fix, patch, status;
101  std::ostringstream fmt;
102 
103  //
104  // The people who maintain OpenSSL are not from this world. I suppose it's
105  // only fair that I'm the one who gets to try to make sense of their version
106  // encoding scheme. -- shadowm
107  //
108 
109  if(v < 0x0930L) {
110  // Pre-0.9.3 seems simpler times overall.
111  minor = v & 0x0F00L >> 8;
112  fix = v & 0x00F0L >> 4;
113  patch = v & 0x000FL;
114 
115  fmt << "0." << minor << '.' << fix;
116  if(patch) {
117  fmt << format_openssl_patch_level(patch);
118  }
119  } else {
120  //
121  // Note that they either assume the major version will never be greater than
122  // 9, they plan to use hexadecimal digits for versions 10.x.x through
123  // 15.x.x, or they expect long to be always > 32-bits by then. Who the hell
124  // knows, really.
125  //
126  major = (v & 0xF0000000L) >> 28;
127  minor = (v & 0x0FF00000L) >> 20;
128  fix = (v & 0x000FF000L) >> 12;
129  patch = (v & 0x00000FF0L) >> 4;
130  status = (v & 0x0000000FL);
131 
132  if(v < 0x00905100L) {
133  //
134  // From wiki.openssl.org (also mentioned in opensslv.h, in the most oblique
135  // fashion possible):
136  //
137  // "Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation:
138  // MMNNFFRBB major minor fix final beta/patch"
139  //
140  // Both the wiki and opensslv.h fail to accurately list actual version
141  // numbers that ended up used in the wild -- e.g. 0.9.3a is supposedly
142  // 0x0090301f when it really was 0x00903101.
143  //
144  const uint8_t is_final = (v & 0xF00L) >> 8;
145  status = is_final ? 0xF : 0;
146  patch = v & 0xFFL;
147  } else if(v < 0x00906000L) {
148  //
149  // Quoth opensslv.h:
150  //
151  // "For continuity reasons (because 0.9.5 is already out, and is coded
152  // 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
153  // part is slightly different, by setting the highest bit. This means
154  // that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start
155  // with 0x0090600S..."
156  //
157  patch ^= 1 << 7;
158  }
159 
160  fmt << major << '.' << minor << '.' << fix;
161 
162  if(patch) {
163  fmt << format_openssl_patch_level(patch);
164  }
165 
166  if(status == 0x0) {
167  fmt << "-dev";
168  } else if(status < 0xF) {
169  fmt << "-beta" << status;
170  }
171  }
172 
173  return fmt.str();
174 
175 }
176 
177 #endif
178 
179 version_table_manager::version_table_manager()
180  : compiled(LIB_COUNT, "")
181  , linked(LIB_COUNT, "")
182  , names(LIB_COUNT, "")
183  , features()
184 {
185  SDL_version sdl_version;
186 
187 
188  //
189  // SDL
190  //
191 
192  SDL_VERSION(&sdl_version);
193  compiled[LIB_SDL] = format_version(sdl_version);
194 
195  SDL_GetVersion(&sdl_version);
196  linked[LIB_SDL] = format_version(sdl_version);
197 
198  names[LIB_SDL] = "SDL";
199 
200  //
201  // SDL_image
202  //
203 
204  SDL_IMAGE_VERSION(&sdl_version);
205  compiled[LIB_SDL_IMAGE] = format_version(sdl_version);
206 
207  const SDL_version* sdl_rt_version = IMG_Linked_Version();
208  if(sdl_rt_version) {
209  linked[LIB_SDL_IMAGE] = format_version(*sdl_rt_version);
210  }
211 
212  names[LIB_SDL_IMAGE] = "SDL_image";
213 
214  //
215  // SDL_mixer
216  //
217 
218  SDL_MIXER_VERSION(&sdl_version);
219  compiled[LIB_SDL_MIXER] = format_version(sdl_version);
220 
221  sdl_rt_version = Mix_Linked_Version();
222  if(sdl_rt_version) {
223  linked[LIB_SDL_MIXER] = format_version(*sdl_rt_version);
224  }
225 
226  names[LIB_SDL_MIXER] = "SDL_mixer";
227 
228  //
229  // Boost
230  //
231 
232  compiled[LIB_BOOST] = BOOST_LIB_VERSION;
233  std::replace(compiled[LIB_BOOST].begin(), compiled[LIB_BOOST].end(), '_', '.');
234  names[LIB_BOOST] = "Boost";
235 
236  //
237  // Lua
238  //
239 
240  compiled[LIB_LUA] = LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "." LUA_VERSION_RELEASE;
241  names[LIB_LUA] = "Lua";
242 
243  //
244  // OpenSSL/libcrypto
245  //
246 
247 #ifndef __APPLE__
248  compiled[LIB_CRYPTO] = format_openssl_version(OPENSSL_VERSION_NUMBER);
249  linked[LIB_CRYPTO] = format_openssl_version(SSLeay());
250  names[LIB_CRYPTO] = "OpenSSL/libcrypto";
251 #endif
252 
253  //
254  // Cairo
255  //
256 
257  compiled[LIB_CAIRO] = CAIRO_VERSION_STRING;
258  linked[LIB_CAIRO] = cairo_version_string();
259  names[LIB_CAIRO] = "Cairo";
260 
261  //
262  // Pango
263  //
264 
265  compiled[LIB_PANGO] = PANGO_VERSION_STRING;
266  linked[LIB_PANGO] = pango_version_string();
267  names[LIB_PANGO] = "Pango";
268 
269  //
270  // Features table.
271  //
272 
273  features.emplace_back(N_("feature^Lua console completion"));
274 #ifdef HAVE_HISTORY
275  features.back().enabled = true;
276 #endif
277 
278 #ifdef _X11
279 
280  features.emplace_back(N_("feature^D-Bus notifications back end"));
281 #ifdef HAVE_LIBDBUS
282  features.back().enabled = true;
283 #endif
284 
285 #endif /* _X11 */
286 
287 #ifdef _WIN32
288  // Always compiled in.
289  features.emplace_back(N_("feature^Win32 notifications back end"));
290  features.back().enabled = true;
291 #endif
292 
293 #ifdef __APPLE__
294  // Always compiled in.
295  features.emplace_back(N_("feature^Cocoa notifications back end"));
296  features.back().enabled = true;
297 #endif /* __APPLE__ */
298 }
299 
300 const std::string empty_version = "";
301 
302 } // end anonymous namespace 1
303 
304 std::string build_arch()
305 {
306 #if BOOST_ARCH_X86_64
307  return "x86_64";
308 #elif BOOST_ARCH_X86_32
309  return "x86";
310 #elif BOOST_ARCH_ARM && (defined(__arm64) || defined(_M_ARM64))
311  return "arm64";
312 #elif BOOST_ARCH_ARM
313  return "arm";
314 #elif BOOST_ARCH_IA64
315  return "ia64";
316 #elif BOOST_ARCH_PPC
317  return "ppc";
318 #elif BOOST_ARCH_ALPHA
319  return "alpha";
320 #elif BOOST_ARCH_MIPS
321  return "mips";
322 #elif BOOST_ARCH_SPARC
323  return "sparc";
324 #else
325  // Congratulations, you're running Wesnoth on an exotic platform -- either that or you live in
326  // the foretold future where x86 and ARM stopped being the dominant CPU architectures for the
327  // general-purpose consumer market. If you want to add label support for your platform, check
328  // out the Boost.Predef library's documentation and alter the code above accordingly.
329  //
330  // On the other hand, if you got here looking for Wesnoth's biggest secret let me just say
331  // right here and now that Irdya is round. There, I said the thing that nobody has dared say
332  // in mainline content before.
333  return _("cpu_architecture^<unknown>");
334 #endif
335 }
336 
337 std::vector<optional_feature> optional_features_table(bool localize)
338 {
339  std::vector<optional_feature> res = versions.features;
340 
341  for(std::size_t k = 0; k < res.size(); ++k) {
342  if(localize) {
343  res[k].name = _(res[k].name.c_str());
344  } else {
345  // Strip annotation carets ("blah blah^actual text here") from translatable
346  // strings.
347  const auto caret_pos = res[k].name.find('^');
348  if(caret_pos != std::string::npos) {
349  res[k].name.erase(0, caret_pos + 1);
350  }
351  }
352  }
353  return res;
354 }
355 
356 const std::string& library_build_version(LIBRARY_ID lib)
357 {
358  if(lib >= LIB_COUNT) {
359  return empty_version;
360  }
361 
362  return versions.compiled[lib];
363 }
364 
365 const std::string& library_runtime_version(LIBRARY_ID lib)
366 {
367  if(lib >= LIB_COUNT) {
368  return empty_version;
369  }
370 
371  return versions.linked[lib];
372 }
373 
374 const std::string& library_name(LIBRARY_ID lib)
375 {
376  if(lib >= LIB_COUNT) {
377  return empty_version;
378  }
379 
380  return versions.names[lib];
381 }
382 
383 std::string dist_channel_id()
384 {
385  std::string info;
386  std::ifstream infofile(game_config::path + "/data/dist");
387  if(infofile.is_open()) {
388  std::getline(infofile, info);
389  infofile.close();
390  boost::trim(info);
391  }
392 
393  if(info.empty()) {
394  return "Default";
395  }
396 
397  return info;
398 }
399 
400 namespace {
401 
402 /**
403  * Formats items into a tidy 2-column list with a fixed-length first column.
404  */
405 class list_formatter
406 {
407 public:
408  using list_entry = std::pair<std::string, std::string>;
409  using contents_list = std::vector<list_entry>;
410 
411  list_formatter(const std::string& heading, const contents_list& contents = {}, const std::string& empty_placeholder = "")
412  : heading_(heading)
413  , placeholder_(empty_placeholder)
414  , contents_(contents)
415  {
416  }
417 
418  void insert(const std::string& label, const std::string& value)
419  {
420  contents_.emplace_back(label, value);
421  }
422 
423  void set_placeholder(const std::string& placeholder)
424  {
425  placeholder_ = placeholder;
426  }
427 
428  void stream_put(std::ostream& os) const;
429 
430 private:
431  static const char heading_delimiter;
432  static const std::string label_delimiter;
433 
434  std::string heading_;
435  std::string placeholder_;
436 
437  contents_list contents_;
438 };
439 
440 const char list_formatter::heading_delimiter = '=';
441 const std::string list_formatter::label_delimiter = ": ";
442 
443 void list_formatter::stream_put(std::ostream& os) const
444 {
445  if(!heading_.empty()) {
446  os << heading_ << '\n' << std::string(utf8::size(heading_), heading_delimiter) << "\n\n";
447  }
448 
449  if(contents_.empty() && !placeholder_.empty()) {
450  os << placeholder_ << '\n';
451  } else if(!contents_.empty()) {
452  auto label_length_comparator = [](const list_entry& a, const list_entry& b)
453  {
454  return utf8::size(a.first) < utf8::size(b.first);
455  };
456 
457  const auto longest_entry_label = std::max_element(contents_.begin(), contents_.end(), label_length_comparator);
458  const std::size_t min_length = longest_entry_label != contents_.end()
459  ? utf8::size(label_delimiter) + utf8::size(longest_entry_label->first)
460  : 0;
461 
462  // Save stream attributes for resetting them later after completing the loop
463  const std::size_t prev_width = os.width();
464  const std::ostream::fmtflags prev_flags = os.flags();
465 
466  os << std::left;
467 
468  for(const auto& entry : contents_) {
469  os << std::setw(min_length) << entry.first + label_delimiter << entry.second << '\n';
470  }
471 
472  os.width(prev_width);
473  os.flags(prev_flags);
474  }
475 
476  os << '\n';
477 }
478 
479 std::ostream& operator<<(std::ostream& os, const list_formatter& fmt)
480 {
481  fmt.stream_put(os);
482  return os;
483 }
484 
485 list_formatter library_versions_report_internal(const std::string& heading = "")
486 {
487  list_formatter fmt{heading};
488 
489  for(unsigned n = 0; n < LIB_COUNT; ++n)
490  {
491  if(versions.names[n].empty()) {
492  continue;
493  }
494 
495  std::string text = versions.compiled[n];
496  if(!versions.linked[n].empty()) {
497  text += " (runtime " + versions.linked[n] + ")";
498  }
499 
500  fmt.insert(versions.names[n], text);
501  }
502 
503  return fmt;
504 }
505 
506 list_formatter optional_features_report_internal(const std::string& heading = "")
507 {
508  list_formatter fmt{heading};
509 
510  const std::vector<optional_feature>& features = optional_features_table(false);
511 
512  for(const auto& feature : features) {
513  fmt.insert(feature.name, feature.enabled ? "yes" : "no");
514  }
515 
516  return fmt;
517 }
518 
519 template<typename T>
520 inline std::string geometry_to_string(T horizontal, T vertical)
521 {
522  return std::to_string(horizontal) + 'x' + std::to_string(vertical);
523 }
524 
525 std::string format_sdl_driver_list(std::vector<std::string> drivers, const std::string& current_driver)
526 {
527  bool found_current_driver = false;
528 
529  for(auto& drvname : drivers) {
530  if(current_driver == drvname) {
531  found_current_driver = true;
532  drvname = "[" + current_driver + "]";
533  }
534  }
535 
536  if(drivers.empty() || !found_current_driver) {
537  // This shouldn't happen but SDL is weird at times so whatevs
538  drivers.emplace_back("[" + current_driver + "]");
539  }
540 
541  return utils::join(drivers, " ");
542 }
543 
544 list_formatter video_settings_report_internal(const std::string& heading = "")
545 {
546  list_formatter fmt{heading};
547 
548  if(!CVideo::setup_completed()) {
549  fmt.set_placeholder("Graphics not initialized.");
550  return fmt;
551  }
552 
553  CVideo& video = CVideo::get_singleton();
554 
555  std::string placeholder;
556 
557  if(video.non_interactive()) {
558  placeholder = "Running in non-interactive mode.";
559  } else if(!video.has_window()) {
560  placeholder = "Running without a game window.";
561  }
562 
563  if(!placeholder.empty()) {
564  fmt.set_placeholder(placeholder);
565  return fmt;
566  }
567 
568  const auto& current_driver = CVideo::current_driver();
569  auto drivers = CVideo::enumerate_drivers();
570 
571  const auto& dpi = video.get_dpi();
572  const auto& scale = video.get_dpi_scale_factor();
573  std::string dpi_report, scale_report;
574 
575  if(dpi.first == 0.0f || dpi.second == 0.0f) {
576  scale_report = dpi_report = "<unknown>";
577  } else {
578  dpi_report = geometry_to_string(dpi.first, dpi.second);
579  scale_report = geometry_to_string(scale.first, scale.second);
580  }
581 
582  fmt.insert("SDL video drivers", format_sdl_driver_list(drivers, current_driver));
583  fmt.insert("Window size", geometry_to_string(
584  video.current_resolution().x, video.current_resolution().y));
585  fmt.insert("Game canvas size", geometry_to_string(
586  video.get_width(), video.get_height()));
587  fmt.insert("Final render target size", geometry_to_string(
588  video.output_size().x, video.output_size().y));
589  fmt.insert("Screen refresh rate", std::to_string(video.current_refresh_rate()));
590  fmt.insert("Screen dots per inch", dpi_report);
591  fmt.insert("Screen dpi scale factor", scale_report);
592 
593  return fmt;
594 }
595 
596 list_formatter sound_settings_report_internal(const std::string& heading = "")
597 {
598  list_formatter fmt{heading};
599 
600  const auto& driver_status = sound::driver_status::query();
601 
602  if(!driver_status.initialized) {
603  fmt.set_placeholder("Audio not initialized.");
604  return fmt;
605  }
606 
607  const auto& current_driver = sound::current_driver();
608  auto drivers = sound::enumerate_drivers();
609 
610  static std::map<uint16_t, std::string> audio_format_names = {
611  // 8 bits
612  { AUDIO_U8, "unsigned 8 bit" },
613  { AUDIO_S8, "signed 8 bit" },
614  // 16 bits
615  { AUDIO_U16LSB, "unsigned 16 bit little-endian" },
616  { AUDIO_U16MSB, "unsigned 16 bit big-endian" },
617  { AUDIO_S16LSB, "signed 16 bit little-endian" },
618  { AUDIO_S16MSB, "signed 16 bit big-endian" },
619  // 32 bits
620  { AUDIO_S32LSB, "signed 32 bit little-endian" },
621  { AUDIO_S32MSB, "signed 32 bit big-endian" },
622  { AUDIO_F32LSB, "signed 32 bit floating point little-endian" },
623  { AUDIO_F32MSB, "signed 32 bit floating point big-endian" },
624  };
625 
626  auto fmt_names_it = audio_format_names.find(driver_status.format);
627  // If we don't recognize the format id just print the raw number
628  const std::string fmt_name = fmt_names_it != audio_format_names.end()
629  ? fmt_names_it->second
630  : formatter() << "0x" << std::setfill('0') << std::setw(2*sizeof(driver_status.format)) << std::hex << std::uppercase << driver_status.format;
631 
632  fmt.insert("SDL audio drivers", format_sdl_driver_list(drivers, current_driver));
633  fmt.insert("Number of channels", std::to_string(driver_status.channels));
634  fmt.insert("Output rate", std::to_string(driver_status.frequency) + " Hz");
635  fmt.insert("Sample format", fmt_name);
636  fmt.insert("Sample size", std::to_string(driver_status.chunk_size) + " bytes");
637 
638  return fmt;
639 }
640 
641 } // end anonymous namespace 2
642 
644 {
645  return formatter{} << library_versions_report_internal();
646 }
647 
649 {
650  return formatter{} << optional_features_report_internal();
651 }
652 
653 std::string full_build_report()
654 {
655  list_formatter::contents_list paths{
656  {"Data dir", game_config::path},
657  {"User config dir", filesystem::get_user_config_dir()},
658  {"User data dir", filesystem::get_user_data_dir()},
659  {"Saves dir", filesystem::get_saves_dir()},
660  {"Add-ons dir", filesystem::get_addons_dir()},
661  {"Cache dir", filesystem::get_cache_dir()},
662  };
663 
664  // Obfuscate usernames in paths
665  for(auto& entry : paths) {
666  entry.second = filesystem::sanitize_path(entry.second);
667  }
668 
669  list_formatter::contents_list addons;
670 
671  for(const auto& addon_info : installed_addons_and_versions()) {
672  addons.emplace_back(addon_info.first, addon_info.second);
673  }
674 
675  std::ostringstream o;
676 
677  o << "The Battle for Wesnoth version " << game_config::revision << " " << build_arch() << '\n'
678  << "Running on " << desktop::os_version() << '\n'
679  << "Distribution channel: " << dist_channel_id() << '\n'
680  << '\n'
681  << list_formatter{"Game paths", paths}
682  << library_versions_report_internal("Libraries")
683  << optional_features_report_internal("Features")
684  << video_settings_report_internal("Current video settings")
685  << sound_settings_report_internal("Current audio settings")
686  << list_formatter("Installed add-ons", addons, "No add-ons installed.");
687 
688  return o.str();
689 }
690 
691 } // end namespace game_config
int get_height() const
Returns the height of the drawing surface in pixels.
Definition: video.cpp:508
point current_resolution()
Definition: video.cpp:865
std::string heading_
Definition: build_info.cpp:434
static const char heading_delimiter
Definition: build_info.cpp:431
std::string library_versions_report()
Produce a plain-text report of library versions suitable for stdout/stderr.
Definition: build_info.cpp:643
Interfaces for manipulating version numbers of engine, add-ons, etc.
std::string current_driver()
Definition: sound.cpp:412
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::pair< float, float > get_dpi_scale_factor() const
The current scale factor on High-DPI screens.
Definition: video.cpp:794
static const std::string label_delimiter
Definition: build_info.cpp:432
std::string optional_features_report()
Produce a plain-text report of features suitable for stdout/stderr.
Definition: build_info.cpp:648
logger & info()
Definition: log.cpp:89
#define a
std::string placeholder_
Definition: build_info.cpp:435
Definition: video.hpp:36
int get_width() const
Returns the width of the drawing surface in pixels.
Definition: video.cpp:503
contents_list contents_
Definition: build_info.cpp:437
static CVideo & get_singleton()
Definition: video.hpp:53
bool non_interactive() const
Definition: video.cpp:145
STL namespace.
const std::string & library_build_version(LIBRARY_ID lib)
Retrieve the build-time version number of the given library.
Definition: build_info.cpp:356
std::vector< optional_feature > optional_features_table(bool localize)
Retrieve the features table.
Definition: build_info.cpp:337
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string get_saves_dir()
int x
x coordinate.
Definition: point.hpp:45
#define b
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
const std::string & library_name(LIBRARY_ID lib)
Retrieve the user-visible name for the given library.
Definition: build_info.cpp:374
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
Definition: xbrz.cpp:1190
std::string label
What to show in the filter&#39;s drop-down list.
Definition: manager.cpp:217
std::vector< optional_feature > features
Definition: build_info.cpp:68
std::ostringstream wrapper.
Definition: formatter.hpp:39
std::string get_user_data_dir()
Definition: filesystem.cpp:792
static std::vector< std::string > enumerate_drivers()
Definition: video.cpp:748
std::string dist_channel_id()
Return the distribution channel identifier, or "Default" if missing.
Definition: build_info.cpp:383
std::string path
Definition: game_config.cpp:39
std::string build_arch()
Obtain the processor architecture for this build.
Definition: build_info.cpp:304
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user&#39;s name.
bool has_window()
Definition: video.hpp:90
std::ostream & operator<<(std::ostream &s, const ai::attack_result &r)
Definition: actions.cpp:1134
SDL_Point output_size() const
Returns the size of the final render target.
Definition: video.cpp:480
Platform identification and version information functions.
std::string get_cache_dir()
Definition: filesystem.cpp:797
int current_refresh_rate() const
Definition: video.hpp:234
std::vector< std::string > linked
Definition: build_info.cpp:67
const std::string revision
mock_party p
Game configuration data as global variables.
Definition: build_info.cpp:60
std::string os_version()
Returns a string with the running OS name and version information.
Definition: version.cpp:217
std::vector< std::string > names
Definition: build_info.cpp:67
const std::string & library_runtime_version(LIBRARY_ID lib)
Retrieve the runtime version number of the given library.
Definition: build_info.cpp:365
static std::string current_driver()
Definition: video.cpp:742
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:100
Declarations for File-IO.
#define N_(String)
Definition: gettext.hpp:101
std::string get_user_config_dir()
Definition: filesystem.cpp:763
std::string get_addons_dir()
void trim(std::string_view &s)
static driver_status query()
Definition: sound.cpp:431
mock_char c
std::vector< std::string > enumerate_drivers()
Definition: sound.cpp:418
static map_location::DIRECTION n
std::vector< std::string > compiled
Definition: build_info.cpp:67
int y
y coordinate.
Definition: point.hpp:48
static bool setup_completed()
Definition: video.hpp:48
std::string full_build_report()
Produce a bug report-style info dump.
Definition: build_info.cpp:653
std::pair< float, float > get_dpi() const
The current game screen dpi.
Definition: video.cpp:770
std::map< std::string, std::string > installed_addons_and_versions()
Retrieves the ids and versions of all installed add-ons.
Definition: manager.cpp:183