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