From f5d6d59c94afd3258021507b9585f8e77cbf3a83 Mon Sep 17 00:00:00 2001 From: neitsa Date: Tue, 21 May 2019 19:01:59 +0200 Subject: [PATCH 01/12] Add precise versions for Windows systems. --- src/debug.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/debug.h | 3 ++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index 600e5541ae6e7..13ebc850f6351 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -814,6 +814,89 @@ std::string game_info::operating_system() #endif } +/** Get a precise version number for Windows systems. + * @note Since Windows 10 all version-related APIs lie about the underlying system if the application is not Manifested (see VerifyVersionInfoA + * or GetVersionEx documentation for further explanation). In this function we use the registry or the native RtlGetVersion which both + * report correct versions and are compatible down to XP. + * @returns If successful, a string containing the Windows system version number, otherwise an empty string. + */ +std::string windows_version() +{ + std::string output; + + HKEY handle_key; + bool success = RegOpenKeyExA( HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", + 0, + KEY_QUERY_VALUE, &handle_key ) == ERROR_SUCCESS; + if( success ) { + DWORD value_type; + constexpr DWORD c_buffer_size = 512; + std::vector byte_buffer( c_buffer_size ); + DWORD buffer_size = c_buffer_size; + DWORD major_version = 0; + success = RegQueryValueExA( handle_key, "CurrentMajorVersionNumber", nullptr, &value_type, + &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; + if( success ) { + major_version = *reinterpret_cast( &byte_buffer[0] ); + output.append( std::to_string( major_version ) ); + } + if( success ) { + buffer_size = c_buffer_size; + success = RegQueryValueExA( handle_key, "CurrentMinorVersionNumber", nullptr, &value_type, + &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; + if( success ) { + const DWORD minor_version = *reinterpret_cast( &byte_buffer[0] ); + output.append( "." ); + output.append( std::to_string( minor_version ) ); + } + } + if( success && major_version == 10 ) { + buffer_size = c_buffer_size; + success = RegQueryValueExA( handle_key, "ReleaseId", nullptr, &value_type, &byte_buffer[0], + &buffer_size ) == ERROR_SUCCESS && value_type == REG_SZ; + if( success ) { + output.append( " " ); + output.append( std::string( byte_buffer.begin(), byte_buffer.end() ) ); + } + } + + RegCloseKey( handle_key ); + } + + if( !success ) { + output = ""; + typedef LONG( WINAPI * RtlGetVersion )( PRTL_OSVERSIONINFOW ); + const HMODULE handle_ntdll = GetModuleHandleA( "ntdll" ); + if( handle_ntdll != nullptr ) { + const auto rtl_get_version_func = reinterpret_cast( GetProcAddress( handle_ntdll, + "RtlGetVersion" ) ); + if( rtl_get_version_func != nullptr ) { + RTL_OSVERSIONINFOW os_version_info = { 0 }; + os_version_info.dwOSVersionInfoSize = sizeof RTL_OSVERSIONINFOW; + if( rtl_get_version_func( &os_version_info ) == 0 ) { // NT_STATUS_SUCCESS = 0 + output.append( std::to_string( os_version_info.dwMajorVersion ) ); + output.append( "." ); + output.append( std::to_string( os_version_info.dwMinorVersion ) ); + output.append( " " ); + output.append( std::to_string( os_version_info.dwBuildNumber ) ); + } + } + } + } + + return output; +} + + +std::string game_info::operating_system_version() +{ +#if defined(_WIN32) + return windows_version(); +#else + return ""; +#endif +} + std::string game_info::bitness() { if( sizeof( void * ) == 8 ) { @@ -867,7 +950,7 @@ std::string game_info::game_report() { std::stringstream report; report << - "- OS: " << operating_system() << " [" << bitness() << "]\n" << + "- OS: " << operating_system() << " " << operating_system_version() << " [" << bitness() << "]\n" << "- Game Version: " << game_version() << "\n" << "- Graphics Version: " << graphics_version() << "\n" << "- Mods loaded: [\n " << mods_loaded() << "\n]\n"; diff --git a/src/debug.h b/src/debug.h index 2df1a85b77c90..2da05a4520fd6 100644 --- a/src/debug.h +++ b/src/debug.h @@ -87,6 +87,9 @@ namespace game_info /** Return the name of the current operating system. */ std::string operating_system(); +/** Return a detailed version of the operating system; e.g. "Ubuntu 18.04" or "(Windows) 10 1809". + */ +std::string operating_system_version(); /** Return the "bitness" of the game (not necessarily of the operating system); either: 64-bit, 32-bit or Unknown. */ std::string bitness(); From 12e173dbf427a798b58b240fef1f2d51624592b9 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 10:55:05 +0200 Subject: [PATCH 02/12] Add Android system version retrieval. --- src/debug.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 13ebc850f6351..bf76a440a5656 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -59,6 +59,11 @@ # endif #endif // TILES +#if defined(__ANDROID__) +// used by android_version() function for __system_property_get(). +#include +#endif + // Static defines {{{1 // --------------------------------------------------------------------- @@ -824,6 +829,7 @@ std::string windows_version() { std::string output; +#if defined (_WIN32) HKEY handle_key; bool success = RegOpenKeyExA( HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, @@ -883,14 +889,80 @@ std::string windows_version() } } } +#endif + return output; +} + +/** Get a precise version number for Android systems. + * @note see: + * - https://stackoverflow.com/a/19777977/507028 + * - https://github.com/pytorch/cpuinfo/blob/master/test/build.prop/galaxy-s7-us.log + * @returns If successful, a string containing the Android system version, otherwise an empty string. + */ +std::string android_version() +{ + std::string output; + +#if defined (__ANDROID__) + // buffer used for the __system_property_get() function. + // note: according to android sources, it can't be greater than 92 chars (see 'PROP_VALUE_MAX' define in system_properties.h) + std::vector buffer( 255 ); + + std::map system_properties = { + // The manufacturer of the product/hardware; e.g. "Samsung", this is different than the carrier. + { "ro.product.manufacturer", "Manufacturer"}, + /* The model fingerprint; built as follow: + * $(BRAND)/$(PRODUCT)/$(DEVICE)/$(BOARD):$(VERSION.RELEASE)/$(ID)/$(VERSION.INCREMENTAL):$(TYPE)/$(TAGS) + * example: samsung/heroqlteuc/heroqlteatt:6.0.1/MMB29M/G930AUCS4APK1:user/release-keys */ + {"ro.build.fingerprint", "Fingerprint"}, + }; + + bool success = true; + for( const auto &entry : system_properties ) { + int len = __system_property_get( entry.first, &buffer[0] ); + if( len == 0 ) { + // failed to get the property + success = false; + break; + } + output.append( string_format( "%s: %s; ", entry.second, std::string( buffer.begin(), + buffer.end() ) ) ); + } + if( !success ) { + output = ""; + system_properties.clear(); + system_properties = { + // The manufacturer of the product/hardware; e.g. "Samsung", this is different than the carrier. + { "ro.product.manufacturer", "Manufacturer"}, + // The end-user-visible name for the end product; .e.g. "SAMSUNG-SM-G930A" for a Samsung S7. + {"ro.product.model", "Model"}, + // The Android system version; e.g. "6.0.1" + {"ro.build.version.release", "Release"}, + // The internal value used by the underlying source control to represent this build; e.g "G930AUCS4APK1" for a Samsung S7 on 6.0.1. + {"ro.build.version.incremental", "Incremental"}, + }; + + for( const auto &entry : system_properties ) { + int len = __system_property_get( entry.first, &buffer[0] ); + if( len == 0 ) { + // failed to get the property + continue; + } + output.append( string_format( "%s: %s; ", entry.second, std::string( buffer.begin(), + buffer.end() ) ) ); + } + } +#endif return output; } std::string game_info::operating_system_version() { -#if defined(_WIN32) +#if defined(__ANDROID__) + return android_version(); +#elif defined(_WIN32) return windows_version(); #else return ""; @@ -950,7 +1022,8 @@ std::string game_info::game_report() { std::stringstream report; report << - "- OS: " << operating_system() << " " << operating_system_version() << " [" << bitness() << "]\n" << + "- OS: " << operating_system() << " [" << bitness() << "]\n" << + " - OS Version: " << operating_system_version() << "\"n" << "- Game Version: " << game_version() << "\n" << "- Graphics Version: " << graphics_version() << "\n" << "- Mods loaded: [\n " << mods_loaded() << "\n]\n"; From 4428a269f2699b5bc1c16b3b3fa6e5aef6eae8dd Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 10:59:37 +0200 Subject: [PATCH 03/12] Simplify formatting for Windows version. --- src/debug.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index bf76a440a5656..c1be4e4cc2fa7 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -880,11 +880,8 @@ std::string windows_version() RTL_OSVERSIONINFOW os_version_info = { 0 }; os_version_info.dwOSVersionInfoSize = sizeof RTL_OSVERSIONINFOW; if( rtl_get_version_func( &os_version_info ) == 0 ) { // NT_STATUS_SUCCESS = 0 - output.append( std::to_string( os_version_info.dwMajorVersion ) ); - output.append( "." ); - output.append( std::to_string( os_version_info.dwMinorVersion ) ); - output.append( " " ); - output.append( std::to_string( os_version_info.dwBuildNumber ) ); + output.append( string_format( "%i.%i %i", os_version_info.dwMajorVersion, + os_version_info.dwMinorVersion, os_version_info.dwBuildNumber ) ); } } } From 6f8b9c15e86deeb856d1bb45f9c503444563dc71 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 11:59:58 +0200 Subject: [PATCH 04/12] Add Linux system version. --- src/debug.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/debug.cpp b/src/debug.cpp index c1be4e4cc2fa7..53549898a6e66 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,8 @@ #include #include #include +#include +#include #include "cursesdef.h" #include "filesystem.h" @@ -954,11 +957,46 @@ std::string android_version() return output; } +/** Get a precise version number for Linux systems. + * @note The code shells-out to call `lsb_release -a`. + * @returns If successful, a string containing the Linux system version ('' if the system is a Linux system but doesn't follow LSB), otherwise an empty string. + */ +std::string linux_version() +{ + std::string output; +#if defined(__linux__) + std::vectorbuffer( 512 ); + std::unique_ptr pipe( popen( "lsb_release -a", "r" ), pclose ); + if( pipe ) { + while( fgets( buffer.data(), buffer.size(), pipe.get() ) != nullptr ) { + output += buffer.data(); + } + } + if( output.empty() ) { + output = ""; + } else { + // replace '\n' and '\t' in output. + std::vector> to_replace = { + {"\n", "; "}, + {"\t", " "}, + }; + for( const auto &e : to_replace ) { + std::string::size_type pos; + while( ( pos = output.find( e.first ) ) != std::string::npos ) { + output.replace( pos, e.first.length(), e.second ); + } + } + } +#endif + return output; +} std::string game_info::operating_system_version() { #if defined(__ANDROID__) return android_version(); +#elif defined(__linux__) + return linux_version(); #elif defined(_WIN32) return windows_version(); #else From 91f6ba2301594de5e6c0d388da71292c882caacb Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 12:13:48 +0200 Subject: [PATCH 05/12] make operating_system_version() return '' if the version can't be determined. - Invert condition on Linux version function; --- src/debug.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 53549898a6e66..bdba61682be4a 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -959,7 +959,7 @@ std::string android_version() /** Get a precise version number for Linux systems. * @note The code shells-out to call `lsb_release -a`. - * @returns If successful, a string containing the Linux system version ('' if the system is a Linux system but doesn't follow LSB), otherwise an empty string. + * @returns If successful, a string containing the Linux system version, otherwise an empty string. */ std::string linux_version() { @@ -972,9 +972,7 @@ std::string linux_version() output += buffer.data(); } } - if( output.empty() ) { - output = ""; - } else { + if( !output.empty() ) { // replace '\n' and '\t' in output. std::vector> to_replace = { {"\n", "; "}, @@ -1000,7 +998,7 @@ std::string game_info::operating_system_version() #elif defined(_WIN32) return windows_version(); #else - return ""; + return ""; #endif } From 8d59dec5cc430a99d754a0f4a9d1cb642ecdf411 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 12:24:02 +0200 Subject: [PATCH 06/12] Simplify Android version retrieval. --- src/debug.cpp | 51 ++++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index bdba61682be4a..eaf68e426bc16 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -908,50 +908,27 @@ std::string android_version() // note: according to android sources, it can't be greater than 92 chars (see 'PROP_VALUE_MAX' define in system_properties.h) std::vector buffer( 255 ); - std::map system_properties = { + system_properties = { // The manufacturer of the product/hardware; e.g. "Samsung", this is different than the carrier. - { "ro.product.manufacturer", "Manufacturer"}, - /* The model fingerprint; built as follow: - * $(BRAND)/$(PRODUCT)/$(DEVICE)/$(BOARD):$(VERSION.RELEASE)/$(ID)/$(VERSION.INCREMENTAL):$(TYPE)/$(TAGS) - * example: samsung/heroqlteuc/heroqlteatt:6.0.1/MMB29M/G930AUCS4APK1:user/release-keys */ - {"ro.build.fingerprint", "Fingerprint"}, + { "ro.product.manufacturer", "Manufacturer" }, + // The end-user-visible name for the end product; .e.g. "SAMSUNG-SM-G930A" for a Samsung S7. + { "ro.product.model", "Model" }, + // The Android system version; e.g. "6.0.1" + { "ro.build.version.release", "Release" }, + // The internal value used by the underlying source control to represent this build; e.g "G930AUCS4APK1" for a Samsung S7 on 6.0.1. + { "ro.build.version.incremental", "Incremental" }, }; - bool success = true; for( const auto &entry : system_properties ) { int len = __system_property_get( entry.first, &buffer[0] ); - if( len == 0 ) { + std::string value; + if( len <= 0 ) { // failed to get the property - success = false; - break; - } - output.append( string_format( "%s: %s; ", entry.second, std::string( buffer.begin(), - buffer.end() ) ) ); - } - - if( !success ) { - output = ""; - system_properties.clear(); - system_properties = { - // The manufacturer of the product/hardware; e.g. "Samsung", this is different than the carrier. - { "ro.product.manufacturer", "Manufacturer"}, - // The end-user-visible name for the end product; .e.g. "SAMSUNG-SM-G930A" for a Samsung S7. - {"ro.product.model", "Model"}, - // The Android system version; e.g. "6.0.1" - {"ro.build.version.release", "Release"}, - // The internal value used by the underlying source control to represent this build; e.g "G930AUCS4APK1" for a Samsung S7 on 6.0.1. - {"ro.build.version.incremental", "Incremental"}, - }; - - for( const auto &entry : system_properties ) { - int len = __system_property_get( entry.first, &buffer[0] ); - if( len == 0 ) { - // failed to get the property - continue; - } - output.append( string_format( "%s: %s; ", entry.second, std::string( buffer.begin(), - buffer.end() ) ) ); + value = ""; + } else { + value = std::string( buffer.begin(), buffer.end() ); } + output.append( string_format( "%s: %s; ", entry.second, value ) ); } #endif return output; From f9bc0778e6529be6765ab85bece558661984c8fd Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 14:37:54 +0200 Subject: [PATCH 07/12] Extract shell execution function. - will be reused by Linux, Mac and BSD. --- src/debug.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index eaf68e426bc16..95104b9d2edf8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -934,6 +934,30 @@ std::string android_version() return output; } +#if defined (__linux__) || defined(unix) || defined(__unix__) || defined(__unix) || ( defined(__APPLE__) && defined(__MACH__) ) || defined(BSD) // linux; unix; MacOs; BSD +/** Execute a command with the shell by using `popen()`. + * @param command The full command to execute. + * @note The output buffer is limited to 512 characters. + * @returns The result of the command (only stdout) or an empty string if there was a problem. + */ +std::string shell_exec( const std::string &command ) +{ + std::vector buffer( 512 ); + std::string output; + try { + std::unique_ptr pipe( popen( command.c_str(), "r" ), pclose ); + if( pipe ) { + while( fgets( buffer.data(), buffer.size(), pipe.get() ) != nullptr ) { + output += buffer.data(); + } + } + } catch( ... ) { + output = ""; + } + return output; +} +#endif + /** Get a precise version number for Linux systems. * @note The code shells-out to call `lsb_release -a`. * @returns If successful, a string containing the Linux system version, otherwise an empty string. @@ -942,13 +966,7 @@ std::string linux_version() { std::string output; #if defined(__linux__) - std::vectorbuffer( 512 ); - std::unique_ptr pipe( popen( "lsb_release -a", "r" ), pclose ); - if( pipe ) { - while( fgets( buffer.data(), buffer.size(), pipe.get() ) != nullptr ) { - output += buffer.data(); - } - } + output = shell_exec( "lsb_release -a" ); if( !output.empty() ) { // replace '\n' and '\t' in output. std::vector> to_replace = { From b20c71ab66766712f6a612c5badd2bbbf8d2cf57 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 14:56:23 +0200 Subject: [PATCH 08/12] Add MacOS system version. --- src/debug.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/debug.cpp b/src/debug.cpp index 95104b9d2edf8..057123d0b5644 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -984,12 +984,43 @@ std::string linux_version() return output; } +/** Get a precise version number for MacOs systems. + * @note The code shells-out to call `sw_vers` with various options. + * @returns If successful, a string containing the Linux system version, otherwise an empty string. + */ +std::string mac_os_version() +{ + std::string output; +#if defined(__APPLE__) && defined(__MACH__) + std::vector> commands = { + { "sw_vers -productName", "Name" }, + { "sw_vers -productVersion", "Version" }, + { "sw_vers -buildVersion", "Build" }, + }; + + for( const auto &entry : commands ) { + std::string command_result = shell_exec( entry.first ); + if( command_result.empty() ) { + command_result = ""; + } else { + // remove trailing '\n' + str.erase( std::remove( command_result.begin(), command_result.end(), '\n' ), + command_result.end() ); + } + output.append( string_format( "%s: %s; ", entry.second, command_result ) ); + } +#endif + return output; +} + std::string game_info::operating_system_version() { #if defined(__ANDROID__) return android_version(); #elif defined(__linux__) return linux_version(); +#elif defined(__APPLE__) && defined(__MACH__) + return mac_os_version(); #elif defined(_WIN32) return windows_version(); #else From 889358e2647cc476944c8c0b00f780f424d0626f Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 15:02:34 +0200 Subject: [PATCH 09/12] Sort methods alphabetically. --- src/debug.cpp | 141 +++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 057123d0b5644..92f5422f90d71 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -822,77 +822,6 @@ std::string game_info::operating_system() #endif } -/** Get a precise version number for Windows systems. - * @note Since Windows 10 all version-related APIs lie about the underlying system if the application is not Manifested (see VerifyVersionInfoA - * or GetVersionEx documentation for further explanation). In this function we use the registry or the native RtlGetVersion which both - * report correct versions and are compatible down to XP. - * @returns If successful, a string containing the Windows system version number, otherwise an empty string. - */ -std::string windows_version() -{ - std::string output; - -#if defined (_WIN32) - HKEY handle_key; - bool success = RegOpenKeyExA( HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", - 0, - KEY_QUERY_VALUE, &handle_key ) == ERROR_SUCCESS; - if( success ) { - DWORD value_type; - constexpr DWORD c_buffer_size = 512; - std::vector byte_buffer( c_buffer_size ); - DWORD buffer_size = c_buffer_size; - DWORD major_version = 0; - success = RegQueryValueExA( handle_key, "CurrentMajorVersionNumber", nullptr, &value_type, - &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; - if( success ) { - major_version = *reinterpret_cast( &byte_buffer[0] ); - output.append( std::to_string( major_version ) ); - } - if( success ) { - buffer_size = c_buffer_size; - success = RegQueryValueExA( handle_key, "CurrentMinorVersionNumber", nullptr, &value_type, - &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; - if( success ) { - const DWORD minor_version = *reinterpret_cast( &byte_buffer[0] ); - output.append( "." ); - output.append( std::to_string( minor_version ) ); - } - } - if( success && major_version == 10 ) { - buffer_size = c_buffer_size; - success = RegQueryValueExA( handle_key, "ReleaseId", nullptr, &value_type, &byte_buffer[0], - &buffer_size ) == ERROR_SUCCESS && value_type == REG_SZ; - if( success ) { - output.append( " " ); - output.append( std::string( byte_buffer.begin(), byte_buffer.end() ) ); - } - } - - RegCloseKey( handle_key ); - } - - if( !success ) { - output = ""; - typedef LONG( WINAPI * RtlGetVersion )( PRTL_OSVERSIONINFOW ); - const HMODULE handle_ntdll = GetModuleHandleA( "ntdll" ); - if( handle_ntdll != nullptr ) { - const auto rtl_get_version_func = reinterpret_cast( GetProcAddress( handle_ntdll, - "RtlGetVersion" ) ); - if( rtl_get_version_func != nullptr ) { - RTL_OSVERSIONINFOW os_version_info = { 0 }; - os_version_info.dwOSVersionInfoSize = sizeof RTL_OSVERSIONINFOW; - if( rtl_get_version_func( &os_version_info ) == 0 ) { // NT_STATUS_SUCCESS = 0 - output.append( string_format( "%i.%i %i", os_version_info.dwMajorVersion, - os_version_info.dwMinorVersion, os_version_info.dwBuildNumber ) ); - } - } - } - } -#endif - return output; -} - /** Get a precise version number for Android systems. * @note see: * - https://stackoverflow.com/a/19777977/507028 @@ -1013,6 +942,76 @@ std::string mac_os_version() return output; } +/** Get a precise version number for Windows systems. + * @note Since Windows 10 all version-related APIs lie about the underlying system if the application is not Manifested (see VerifyVersionInfoA + * or GetVersionEx documentation for further explanation). In this function we use the registry or the native RtlGetVersion which both + * report correct versions and are compatible down to XP. + * @returns If successful, a string containing the Windows system version number, otherwise an empty string. + */ +std::string windows_version() +{ + std::string output; +#if defined (_WIN32) + HKEY handle_key; + bool success = RegOpenKeyExA( HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", + 0, + KEY_QUERY_VALUE, &handle_key ) == ERROR_SUCCESS; + if( success ) { + DWORD value_type; + constexpr DWORD c_buffer_size = 512; + std::vector byte_buffer( c_buffer_size ); + DWORD buffer_size = c_buffer_size; + DWORD major_version = 0; + success = RegQueryValueExA( handle_key, "CurrentMajorVersionNumber", nullptr, &value_type, + &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; + if( success ) { + major_version = *reinterpret_cast( &byte_buffer[0] ); + output.append( std::to_string( major_version ) ); + } + if( success ) { + buffer_size = c_buffer_size; + success = RegQueryValueExA( handle_key, "CurrentMinorVersionNumber", nullptr, &value_type, + &byte_buffer[0], &buffer_size ) == ERROR_SUCCESS && value_type == REG_DWORD; + if( success ) { + const DWORD minor_version = *reinterpret_cast( &byte_buffer[0] ); + output.append( "." ); + output.append( std::to_string( minor_version ) ); + } + } + if( success && major_version == 10 ) { + buffer_size = c_buffer_size; + success = RegQueryValueExA( handle_key, "ReleaseId", nullptr, &value_type, &byte_buffer[0], + &buffer_size ) == ERROR_SUCCESS && value_type == REG_SZ; + if( success ) { + output.append( " " ); + output.append( std::string( byte_buffer.begin(), byte_buffer.end() ) ); + } + } + + RegCloseKey( handle_key ); + } + + if( !success ) { + output = ""; + typedef LONG( WINAPI * RtlGetVersion )( PRTL_OSVERSIONINFOW ); + const HMODULE handle_ntdll = GetModuleHandleA( "ntdll" ); + if( handle_ntdll != nullptr ) { + const auto rtl_get_version_func = reinterpret_cast( GetProcAddress( handle_ntdll, + "RtlGetVersion" ) ); + if( rtl_get_version_func != nullptr ) { + RTL_OSVERSIONINFOW os_version_info = { 0 }; + os_version_info.dwOSVersionInfoSize = sizeof RTL_OSVERSIONINFOW; + if( rtl_get_version_func( &os_version_info ) == 0 ) { // NT_STATUS_SUCCESS = 0 + output.append( string_format( "%i.%i %i", os_version_info.dwMajorVersion, + os_version_info.dwMinorVersion, os_version_info.dwBuildNumber ) ); + } + } + } + } +#endif + return output; +} + std::string game_info::operating_system_version() { #if defined(__ANDROID__) From 7ee5b16884ee5acffae96c150ca870564704c8c6 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 15:18:37 +0200 Subject: [PATCH 10/12] Add BSD version retrieval. --- src/debug.cpp | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 92f5422f90d71..f6a2f0d2396af 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -796,7 +796,7 @@ std::string game_info::operating_system() return "Windows"; #elif defined(__linux__) return "Linux"; -#elif defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) && defined(__MACH__) // unix; BSD; MacOs +#elif defined(unix) || defined(__unix__) || defined(__unix) || ( defined(__APPLE__) && defined(__MACH__) ) // unix; BSD; MacOs #if defined(__APPLE__) && defined(__MACH__) // The following include is **only** needed for the TARGET_xxx defines below and is only included if both of the above defines are true. // The whole function only relying on compiler defines, it is probably more meaningful to include it here and not mingle with the @@ -812,7 +812,7 @@ std::string game_info::operating_system() /* OSX */ return "MacOs"; #endif // TARGET_IPHONE_SIMULATOR -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(BSD) // defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) return "BSD"; #else return "Unix"; @@ -887,6 +887,24 @@ std::string shell_exec( const std::string &command ) } #endif +/** Get a precise version number for BSD systems. + * @note The code shells-out to call `uname -a`. + * @returns If successful, a string containing the Linux system version, otherwise an empty string. + */ +std::string bsd_version() +{ + std::string output; +#if defined(BSD) + output = shell_exec( "uname -a" ); + if( !output.empty() ) { + // remove trailing '\n', if any. + output.erase( std::remove( output.begin(), output.end(), '\n' ), + output.end() ); + } +#endif + return output; +} + /** Get a precise version number for Linux systems. * @note The code shells-out to call `lsb_release -a`. * @returns If successful, a string containing the Linux system version, otherwise an empty string. @@ -915,12 +933,12 @@ std::string linux_version() /** Get a precise version number for MacOs systems. * @note The code shells-out to call `sw_vers` with various options. - * @returns If successful, a string containing the Linux system version, otherwise an empty string. + * @returns If successful, a string containing the MacOS system version, otherwise an empty string. */ std::string mac_os_version() { std::string output; -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) && !defined(BSD) std::vector> commands = { { "sw_vers -productName", "Name" }, { "sw_vers -productVersion", "Version" }, @@ -932,7 +950,7 @@ std::string mac_os_version() if( command_result.empty() ) { command_result = ""; } else { - // remove trailing '\n' + // remove trailing '\n', if any. str.erase( std::remove( command_result.begin(), command_result.end(), '\n' ), command_result.end() ); } @@ -1016,9 +1034,11 @@ std::string game_info::operating_system_version() { #if defined(__ANDROID__) return android_version(); +#elif defined(BSD) + return bsd_version(); #elif defined(__linux__) return linux_version(); -#elif defined(__APPLE__) && defined(__MACH__) +#elif defined(__APPLE__) && defined(__MACH__) && !defined(BSD) return mac_os_version(); #elif defined(_WIN32) return windows_version(); @@ -1078,10 +1098,14 @@ std::string game_info::mods_loaded() std::string game_info::game_report() { + std::string os_version = operating_system_version(); + if( os_version.empty() ) { + os_version = ""; + } std::stringstream report; report << "- OS: " << operating_system() << " [" << bitness() << "]\n" << - " - OS Version: " << operating_system_version() << "\"n" << + " - OS Version: " << os_version << "\"n" << "- Game Version: " << game_version() << "\n" << "- Graphics Version: " << graphics_version() << "\n" << "- Mods loaded: [\n " << mods_loaded() << "\n]\n"; From 0739adbe9db6e598d22c73e71109be7d57249201 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 16:40:21 +0200 Subject: [PATCH 11/12] Fix structure init. Fix error in macos function. --- src/debug.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index f6a2f0d2396af..973d5385eab6b 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -951,8 +951,8 @@ std::string mac_os_version() command_result = ""; } else { // remove trailing '\n', if any. - str.erase( std::remove( command_result.begin(), command_result.end(), '\n' ), - command_result.end() ); + command_result.erase( std::remove( command_result.begin(), command_result.end(), '\n' ), + command_result.end() ); } output.append( string_format( "%s: %s; ", entry.second, command_result ) ); } @@ -1017,8 +1017,8 @@ std::string windows_version() const auto rtl_get_version_func = reinterpret_cast( GetProcAddress( handle_ntdll, "RtlGetVersion" ) ); if( rtl_get_version_func != nullptr ) { - RTL_OSVERSIONINFOW os_version_info = { 0 }; - os_version_info.dwOSVersionInfoSize = sizeof RTL_OSVERSIONINFOW; + RTL_OSVERSIONINFOW os_version_info = RTL_OSVERSIONINFOW(); + os_version_info.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOW ); if( rtl_get_version_func( &os_version_info ) == 0 ) { // NT_STATUS_SUCCESS = 0 output.append( string_format( "%i.%i %i", os_version_info.dwMajorVersion, os_version_info.dwMinorVersion, os_version_info.dwBuildNumber ) ); From f03f817a06831a6168f7091d5bbf01a4ab6c6792 Mon Sep 17 00:00:00 2001 From: neitsa Date: Wed, 22 May 2019 19:00:57 +0200 Subject: [PATCH 12/12] Fix typo in output... --- src/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index 973d5385eab6b..3f8fc729bc754 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -1105,7 +1105,7 @@ std::string game_info::game_report() std::stringstream report; report << "- OS: " << operating_system() << " [" << bitness() << "]\n" << - " - OS Version: " << os_version << "\"n" << + " - OS Version: " << os_version << "\n" << "- Game Version: " << game_version() << "\n" << "- Graphics Version: " << graphics_version() << "\n" << "- Mods loaded: [\n " << mods_loaded() << "\n]\n";