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