16 #define GETTEXT_DOMAIN "wesnoth-lib"
29 #include "addon/manager.hpp"
39 #include <SDL3_image/SDL_image.h>
40 #include <SDL3_mixer/SDL_mixer.h>
42 #include <boost/algorithm/string.hpp>
43 #include <boost/predef.h>
44 #include <boost/version.hpp>
46 #if defined(__APPLE__)
47 #include <TargetConditionals.h>
51 #include <openssl/crypto.h>
52 #include <openssl/opensslv.h>
55 #if !(defined(__APPLE__) && TARGET_OS_IPHONE)
56 #include <curl/curl.h>
59 #include <pango/pangocairo.h>
64 #include <CoreFoundation/CoreFoundation.h>
72 struct version_table_manager
77 version_table_manager();
80 const version_table_manager versions;
82 std::string format_version(
unsigned a,
unsigned b,
unsigned c)
89 std::string format_openssl_patch_level(uint8_t
p)
92 ? std::string(1,
'a' +
static_cast<char>(
p) - 1)
96 std::string format_openssl_version(
long v)
98 int major, minor, fix, patch, status;
99 std::ostringstream fmt;
109 minor = v & 0x0F00L >> 8;
110 fix = v & 0x00F0L >> 4;
113 fmt <<
"0." << minor <<
'.' << fix;
115 fmt << format_openssl_patch_level(patch);
124 major = (v & 0xF0000000L) >> 28;
125 minor = (v & 0x0FF00000L) >> 20;
126 fix = (v & 0x000FF000L) >> 12;
127 patch = (v & 0x00000FF0L) >> 4;
128 status = (v & 0x0000000FL);
130 if(v < 0x00905100L) {
142 const uint8_t is_final = (v & 0xF00L) >> 8;
143 status = is_final ? 0xF : 0;
145 }
else if(v < 0x00906000L) {
158 fmt << major <<
'.' << minor <<
'.' << fix;
161 fmt << format_openssl_patch_level(patch);
166 }
else if(status < 0xF) {
167 fmt <<
"-beta" << status;
176 version_table_manager::version_table_manager()
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));
196 compiled[
LIB_SDL_IMAGE] = format_version(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_MICRO_VERSION);
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));
207 compiled[
LIB_SDL_MIXER] = format_version(SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_MICRO_VERSION);
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));
226 compiled[
LIB_LUA] = LUA_VERSION_MAJOR
"." LUA_VERSION_MINOR
"." LUA_VERSION_RELEASE;
243 #if defined(__APPLE__) && TARGET_OS_IPHONE
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) {
281 features.emplace_back(
N_(
"feature^Lua console completion"));
288 features.emplace_back(
N_(
"feature^D-Bus notifications back end"));
297 features.emplace_back(
N_(
"feature^Win32 notifications back end"));
303 features.emplace_back(
N_(
"feature^Cocoa notifications back end"));
308 const std::string empty_version =
"";
314 #if BOOST_ARCH_X86_64
316 #elif BOOST_ARCH_X86_32
318 #elif BOOST_ARCH_ARM && (defined(__arm64) || defined(_M_ARM64))
322 #elif BOOST_ARCH_IA64
326 #elif BOOST_ARCH_ALPHA
328 #elif BOOST_ARCH_MIPS
330 #elif BOOST_ARCH_SPARC
333 #warning Unrecognized platform or Boost.Predef broken/unavailable
342 return _(
"cpu_architecture^<unknown>");
348 std::vector<optional_feature> res = versions.features;
350 for(std::size_t k = 0; k < res.size(); ++k) {
352 res[k].name =
_(res[k].name.c_str());
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);
368 return empty_version;
371 return versions.compiled[lib];
377 return empty_version;
380 return versions.linked[lib];
386 return empty_version;
389 return versions.names[lib];
396 if(infofile.is_open()) {
397 std::getline(infofile,
info);
417 using list_entry = std::pair<std::string, std::string>;
418 using contents_list = std::vector<list_entry>;
420 list_formatter(
const std::string& heading,
const contents_list& contents = {},
const std::string& empty_placeholder =
"")
427 void insert(
const std::string&
label,
const std::string& value)
432 void set_placeholder(
const std::string& placeholder)
437 void stream_put(std::ostream& os)
const;
452 void list_formatter::stream_put(std::ostream& os)
const
461 auto label_length_comparator = [](
const list_entry& a,
const list_entry&
b)
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()
472 const std::size_t prev_width = os.width();
473 const std::ostream::fmtflags prev_flags = os.flags();
478 os << std::setw(min_length) << entry.first +
label_delimiter << entry.second <<
'\n';
481 os.width(prev_width);
482 os.flags(prev_flags);
488 std::ostream&
operator<<(std::ostream& os,
const list_formatter& fmt)
494 list_formatter library_versions_report_internal(
const std::string& heading =
"")
496 list_formatter fmt{heading};
500 if(versions.names[
n].empty()) {
504 std::string text = versions.compiled[
n];
505 if(!versions.linked[
n].empty()) {
506 text +=
" (runtime " + versions.linked[
n] +
")";
509 fmt.insert(versions.names[
n], text);
515 list_formatter optional_features_report_internal(
const std::string& heading =
"")
517 list_formatter fmt{heading};
521 for(
const auto& feature :
features) {
522 fmt.insert(feature.name, feature.enabled ?
"yes" :
"no");
528 inline std::string geometry_to_string(
point p)
533 template<
typename coordinateType>
534 inline std::string geometry_to_string(coordinateType horizontal, coordinateType vertical)
537 return formatter() << std::fixed << std::setprecision(2) << horizontal <<
'x' << vertical;
540 std::string format_sdl_driver_list(std::vector<std::string> drivers,
const std::string&
current_driver)
542 bool found_current_driver =
false;
544 for(
auto& drvname : drivers) {
546 found_current_driver =
true;
551 if(drivers.empty() || !found_current_driver) {
559 list_formatter video_settings_report_internal(
const std::string& heading =
"")
561 list_formatter fmt{heading};
563 std::string placeholder;
566 placeholder =
"Running in non-interactive mode.";
570 placeholder =
"Video not initialized yet.";
573 if(!placeholder.empty()) {
574 fmt.set_placeholder(placeholder);
581 fmt.insert(
"SDL video drivers", format_sdl_driver_list(drivers,
current_driver));
593 fmt.insert(
info.first,
info.second);
599 list_formatter sound_settings_report_internal(
const std::string& heading =
"")
601 list_formatter fmt{heading};
605 if(!driver_status.initialized) {
606 fmt.set_placeholder(
"Audio not initialized.");
613 static std::map<uint16_t, std::string> audio_format_names = {
615 { SDL_AUDIO_U8,
"unsigned 8 bit" },
616 { SDL_AUDIO_S8,
"signed 8 bit" },
618 { SDL_AUDIO_S16LE,
"signed 16 bit little-endian" },
619 { SDL_AUDIO_S16BE,
"signed 16 bit big-endian" },
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" },
627 auto fmt_names_it = audio_format_names.find(driver_status.format);
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;
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");
646 return formatter{} << library_versions_report_internal();
651 return formatter{} << optional_features_report_internal();
656 list_formatter::contents_list paths{
666 for(
auto& entry : paths) {
670 list_formatter::contents_list addons;
676 std::ostringstream o;
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.");
std::ostream & operator<<(std::ostream &s, const ai::attack_result &r)
std::map< std::string, std::string > installed_addons_and_versions()
Retrieves the ids and versions of all installed add-ons.
static const char heading_delimiter
std::vector< optional_feature > features
std::vector< std::string > compiled
std::vector< std::string > linked
std::vector< std::string > names
static const std::string label_delimiter
Platform identification and version information functions.
Declarations for File-IO.
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
std::string label
What to show in the filter's drop-down list.
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.
std::string get_cache_dir()
std::string get_user_data_dir()
std::string get_saves_dir()
std::string get_logs_dir()
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.
const std::string & library_name(LIBRARY_ID lib)
Retrieve the user-visible name for the given library.
std::string full_build_report()
Produce a bug report-style info dump.
std::string library_versions_report()
Produce a plain-text report of library versions suitable for stdout/stderr.
std::vector< optional_feature > optional_features_table(bool localize)
Retrieve the features table.
const std::string & library_runtime_version(LIBRARY_ID lib)
Retrieve the runtime version number of the given library.
const std::string & library_build_version(LIBRARY_ID lib)
Retrieve the build-time version number of the given library.
std::string build_arch()
Obtain the processor architecture for this build.
std::string optional_features_report()
Produce a plain-text report of features suitable for stdout/stderr.
const std::string revision
std::string dist_channel_id()
Return the distribution channel identifier, or "Default" if missing.
std::vector< std::string > enumerate_drivers()
std::string current_driver()
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
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.
bool headless()
The game is running headless.
std::vector< std::pair< std::string, std::string > > renderer_report()
Provides diagnostic information about the current renderer for the build_info API.
point output_size()
Returns the size of the final render target.
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
bool has_window()
Whether the game has set up a window to render into.
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
point current_resolution()
The current window size in desktop coordinates.
int native_refresh_rate()
The native refresh rate of display, not taking any user preferences into account.
int current_refresh_rate()
The refresh rate of the screen.
std::string current_driver()
The current video driver in use, or else "<not initialized>".
std::string to_string(const Range &range, const Func &op)
static driver_status query()
static map_location::direction n