diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc3415073..d6eb8d76c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,8 +245,7 @@ jobs: - name: install required packages run: | - brew update - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install vulkan-loader vulkan-headers molten-vk imagemagick chafa + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b14c0329..5cb31dd9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 2.8.9 + +Bugfixes: +* Don't detect `SessionLeader` as terminal, actually (Terminal, Linux) +* Fix blurry chafa result when specifying both width and height (#757, Logo) + +Features: +* Support new MacBook Air (Host, macOS) +* Distinguish min frequency and base frequency (CPU) + +Logo: +* Fix proxmox + # 2.8.8 Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index a68bb140d..1c3100abb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.8.8 + VERSION 2.8.9 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" diff --git a/debian/changelog b/debian/changelog index dbdcc4b4a..80ba492cb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +fastfetch (2.8.8) jammy; urgency=medium + + * Update to 2.8.8 + + -- Carter Li Fri, 08 Mar 2024 09:59:41 +0800 + fastfetch (2.8.6) jammy; urgency=medium * Update to 2.8.6 diff --git a/debian/files b/debian/files index df3bbef93..094800a84 100644 --- a/debian/files +++ b/debian/files @@ -1 +1 @@ -fastfetch_2.8.6_source.buildinfo universe/utils optional +fastfetch_2.8.8_source.buildinfo universe/utils optional diff --git a/screenshots/example1.png b/screenshots/example1.png index 7839a9701..3c32199d1 100644 Binary files a/screenshots/example1.png and b/screenshots/example1.png differ diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index 9586e686e..628698e4b 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -13,10 +13,12 @@ typedef struct FFCPUResult uint16_t coresLogical; uint16_t coresOnline; - double frequencyMin; // GHz + double frequencyBase; // GHz double frequencyMax; // GHz + double frequencyMin; // GHz double temperature; } FFCPUResult; +const char* ffCPUDetectByCpuid(FFCPUResult* cpu); const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu); diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index 2f3ec2de7..de3b18707 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -60,14 +60,13 @@ static const char* detectFrequency(FFCPUResult* cpu) ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL); cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000); } - else - cpu->frequencyMax = 0.0; return NULL; } #else static const char* detectFrequency(FFCPUResult* cpu) { + cpu->frequencyBase = ffSysctlGetInt64("hw.cpufrequency", 0) / 1000.0 / 1000.0 / 1000.0; cpu->frequencyMin = ffSysctlGetInt64("hw.cpufrequency_min", 0) / 1000.0 / 1000.0 / 1000.0; cpu->frequencyMax = ffSysctlGetInt64("hw.cpufrequency_max", 0); if(cpu->frequencyMax > 0.0) diff --git a/src/detection/cpu/cpu_bsd.c b/src/detection/cpu/cpu_bsd.c index 2d6a1bd28..e1d647cd3 100644 --- a/src/detection/cpu/cpu_bsd.c +++ b/src/detection/cpu/cpu_bsd.c @@ -11,8 +11,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->coresLogical = cpu->coresPhysical; cpu->coresOnline = cpu->coresPhysical; - cpu->frequencyMin = ffSysctlGetInt("hw.clockrate", 0) / 1000.0; - cpu->frequencyMax = cpu->frequencyMin; + cpu->frequencyBase = ffSysctlGetInt("hw.clockrate", 0) / 1000.0; cpu->temperature = FF_CPU_TEMP_UNSET; if (options->temp) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 00936133a..673f0cbdb 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -94,11 +94,14 @@ static double getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, cons if (ok) return ffStrbufToDouble(buffer) / 1e6; - ffStrbufAppendS(basePath, scalingFileName); - ok = ffReadFileBuffer(basePath->chars, buffer); - ffStrbufSubstrBefore(basePath, baseLen); - if (ok) - return ffStrbufToDouble(buffer) / 1e6; + if (scalingFileName) + { + ffStrbufAppendS(basePath, scalingFileName); + ok = ffReadFileBuffer(basePath->chars, buffer); + ffStrbufSubstrBefore(basePath, baseLen); + if (ok) + return ffStrbufToDouble(buffer) / 1e6; + } return 0.0/0.0; } @@ -111,7 +114,6 @@ static bool detectFrequency(FFCPUResult* cpu) FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); uint32_t baseLen = path.length; - bool flag = false; struct dirent* entry; while((entry = readdir(dir)) != NULL) @@ -119,26 +121,34 @@ static bool detectFrequency(FFCPUResult* cpu) if (ffStrStartsWith(entry->d_name, "policy") && isdigit(entry->d_name[strlen("policy")])) { ffStrbufAppendS(&path, entry->d_name); - double fmin = getFrequency(&path, "/cpuinfo_min_freq", "/scaling_min_freq", &buffer); - if (fmin != fmin) continue; + double fbase = getFrequency(&path, "/base_frequency", NULL, &buffer); + if (fbase == fbase) + { + if (cpu->frequencyBase == cpu->frequencyBase) + cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase; + else + cpu->frequencyBase = fbase; + } double fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer); - if (fmax != fmax) continue; - - if (flag) + if (fmax == fmax) { - cpu->frequencyMin = cpu->frequencyMin < fmin ? cpu->frequencyMin : fmin; - cpu->frequencyMax = cpu->frequencyMax > fmax ? cpu->frequencyMax : fmax; + if (cpu->frequencyMax == cpu->frequencyMax) + cpu->frequencyMax = cpu->frequencyMax > fmax ? cpu->frequencyMax : fmax; + else + cpu->frequencyMax = fmax; } - else + double fmin = getFrequency(&path, "/cpuinfo_min_freq", "/scaling_min_freq", &buffer); + if (fmin == fmin) { - cpu->frequencyMin = fmin; - cpu->frequencyMax = fmax; - flag = true; + if (cpu->frequencyMin == cpu->frequencyMin) + cpu->frequencyMin = cpu->frequencyMin < fmin ? cpu->frequencyMin : fmin; + else + cpu->frequencyMin = fmin; } ffStrbufSubstrBefore(&path, baseLen); } } - return flag; + return true; } static double detectCPUTemp(void) @@ -234,8 +244,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->coresOnline = (uint16_t) get_nprocs(); cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical); - if (!detectFrequency(cpu)) - cpu->frequencyMin = cpu->frequencyMax = ffStrbufToDouble(&cpuMHz) / 1000; + if (!detectFrequency(cpu) || cpu->frequencyBase != cpu->frequencyBase) + cpu->frequencyBase = ffStrbufToDouble(&cpuMHz) / 1000; if(cpuUarch.length > 0) { diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 1bb169d74..855ae7d29 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -64,50 +64,53 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) return "No active CPU is found in SMBIOS data"; } - double speed; if (data->MaxSpeed > 0 && data->MaxSpeed < 30000) // VMware reports weird values - speed = data->MaxSpeed / 1000.0; - else - speed = data->CurrentSpeed / 1000.0; + { + double speed = data->MaxSpeed / 1000.0; + if (cpu->frequencyBase < speed) + cpu->frequencyMax = speed; + } - if (cpu->frequencyMax < speed) - cpu->frequencyMax = speed; return NULL; } -static const char* detectByOS(FFCPUResult* cpu) +static const char* detectNCores(FFCPUResult* cpu) { + DWORD length = 0; + GetLogicalProcessorInformationEx(RelationAll, NULL, &length); + if (length == 0) + return "GetLogicalProcessorInformationEx(RelationAll, NULL, &length) failed"; + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE + pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); + + if (!pProcessorInfo || !GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length)) + return "GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length) failed"; + + for( + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; + (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; + ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) + ) { - DWORD length = 0; - GetLogicalProcessorInformationEx(RelationAll, NULL, &length); - if (length == 0) - return "GetLogicalProcessorInformationEx(RelationAll, NULL, &length) failed"; - - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE - pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - - if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length)) + if(ptr->Relationship == RelationProcessorCore) + ++cpu->coresPhysical; + else if(ptr->Relationship == RelationGroup) { - for( - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; - (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; - ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) - ) + for (uint32_t index = 0; index < ptr->Group.ActiveGroupCount; ++index) { - if(ptr->Relationship == RelationProcessorCore) - ++cpu->coresPhysical; - else if(ptr->Relationship == RelationGroup) - { - cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; - cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; - } + cpu->coresOnline += ptr->Group.GroupInfo[index].ActiveProcessorCount; + cpu->coresLogical += ptr->Group.GroupInfo[index].MaximumProcessorCount; } } - else - return "GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length) failed"; } + return NULL; +} + +static const char* detectByRegistry(FFCPUResult* cpu) +{ FF_HKEY_AUTO_DESTROY hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL)) return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed"; @@ -115,24 +118,34 @@ static const char* detectByOS(FFCPUResult* cpu) { uint32_t mhz; if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL)) - cpu->frequencyMin = cpu->frequencyMax = mhz / 1000.0; + cpu->frequencyBase = mhz / 1000.0; } ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL); ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL); + if (cpu->coresLogical == 0) + { + DWORD cores; + if (RegQueryInfoKeyW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", NULL, NULL, &cores, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + cpu->coresOnline = cpu->coresPhysical = cpu->coresLogical = (uint16_t) cores; + } + return NULL; } const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { - const char* error = detectByOS(cpu); + detectNCores(cpu); + + const char* error = detectByRegistry(cpu); if (error) return error; + detectMaxSpeedBySmbios(cpu); + if(options->temp) ffDetectSmbiosTemp(&cpu->temperature, NULL); - detectMaxSpeedBySmbios(cpu); return NULL; } diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 402c2f07e..d1065d9b8 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -111,6 +111,8 @@ static const char* getProductNameWithHwModel(const FFstrbuf* hwModel) else if(ffStrbufStartsWithS(hwModel, "Mac")) { const char* version = hwModel->chars + strlen("Mac"); + if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)"; + if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)"; if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)"; if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)"; if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)"; diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 00aabad33..fc29113f4 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -231,7 +231,6 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) ffStrEquals(name, "ltrace") || ffStrEquals(name, "perf") || ffStrEquals(name, "guake-wrapped") || - ffStrEquals(name, "SessionLeader") || // #750 ffStrContainsIgnCase(name, "debug") || ffStrContainsIgnCase(name, "not-found") || ffStrEndsWith(name, ".sh") @@ -342,6 +341,7 @@ static void getTerminalFromEnv(FFTerminalResult* result) !ffStrbufEqualS(&result->processName, "systemd") && !ffStrbufEqualS(&result->processName, "init") && !ffStrbufEqualS(&result->processName, "(init)") && + !ffStrbufEqualS(&result->processName, "SessionLeader") && // #750 #endif !ffStrbufEqualS(&result->processName, "0") diff --git a/src/fastfetch.c b/src/fastfetch.c index 07220e0ba..0109c2717 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1,20 +1,15 @@ #include "fastfetch.h" #include "common/commandoption.h" -#include "common/printing.h" -#include "common/parsing.h" #include "common/io/io.h" -#include "common/time.h" #include "common/jsonconfig.h" #include "detection/version/version.h" #include "util/stringUtils.h" #include "util/mallocHelper.h" -#include "logo/logo.h" #include "fastfetch_datatext.h" #include #include #include -#include #ifdef WIN32 #include "util/windows/getline.h" @@ -824,7 +819,10 @@ static void run(FFdata* data) ffPrintCommandOption(data, instance.state.resultDoc); if (instance.state.resultDoc) + { yyjson_mut_write_fp(stdout, instance.state.resultDoc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, NULL, NULL); + putchar('\n'); + } else ffFinish(); } diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 92be4c8bb..45e61e8aa 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -3299,6 +3299,17 @@ static const FFlogo P[] = { FF_COLOR_FG_WHITE, }, }, + // Proxmox + { + .names = {"proxmox"}, + .lines = FASTFETCH_DATATEXT_LOGO_PROXMOX, + .colors = { + FF_COLOR_FG_WHITE, + FF_COLOR_FG_256 "202" + }, + .colorKeys = FF_COLOR_FG_WHITE, + .colorTitle = FF_COLOR_FG_256 "202", + }, // PuffOS { .names = {"PuffOS"}, @@ -3558,17 +3569,6 @@ static const FFlogo R[] = { .colorKeys = FF_COLOR_FG_BLUE, .colorTitle = FF_COLOR_FG_BLUE, }, - // Proxmox - { - .names = {"proxmox"}, - .lines = FASTFETCH_DATATEXT_LOGO_PROXMOX, - .colors = { - FF_COLOR_FG_WHITE, - FF_COLOR_FG_256 "202" - }, - .colorKeys = FF_COLOR_FG_WHITE, - .colorTitle = FF_COLOR_FG_256 "202", - }, // LAST {}, }; diff --git a/src/logo/image/image.c b/src/logo/image/image.c index 460ea3db0..12c7711f6 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -768,10 +768,8 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError) requestData.characterPixelWidth = 1; requestData.characterPixelHeight = 1; - if( - (type != FF_LOGO_TYPE_IMAGE_CHAFA || instance.config.logo.width == 0 || instance.config.logo.height == 0) && - !getCharacterPixelDimensions(&requestData) - ) { + if(!getCharacterPixelDimensions(&requestData)) + { if(printError) fputs("Logo: getCharacterPixelDimensions() failed", stderr); return false; diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 281310313..5da296f30 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -13,7 +13,7 @@ void ffPrintCPU(FFCPUOptions* options) FFCPUResult cpu; cpu.temperature = FF_CPU_TEMP_UNSET; cpu.coresPhysical = cpu.coresLogical = cpu.coresOnline = 0; - cpu.frequencyMax = cpu.frequencyMin = 0; + cpu.frequencyMin = cpu.frequencyMax = cpu.frequencyBase = 0.0/0.0; ffStrbufInit(&cpu.name); ffStrbufInit(&cpu.vendor); @@ -48,8 +48,11 @@ void ffPrintCPU(FFCPUOptions* options) if(cpu.coresOnline > 1) ffStrbufAppendF(&str, " (%u)", cpu.coresOnline); - if(cpu.frequencyMax > 0.0) - ffStrbufAppendF(&str, " @ %.*f GHz", options->freqNdigits, cpu.frequencyMax); + double freq = cpu.frequencyMax; + if(freq != freq) + freq = cpu.frequencyBase; + if(freq == freq) + ffStrbufAppendF(&str, " @ %.*f GHz", options->freqNdigits, freq); if(cpu.temperature == cpu.temperature) //FF_CPU_TEMP_UNSET { @@ -69,7 +72,7 @@ void ffPrintCPU(FFCPUOptions* options) {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresPhysical}, {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresLogical}, {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresOnline}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu.frequencyMin}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu.frequencyBase}, {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu.frequencyMax}, {FF_FORMAT_ARG_TYPE_STRBUF, &tempStr} })); @@ -143,7 +146,7 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ FFCPUResult cpu; cpu.temperature = FF_CPU_TEMP_UNSET; cpu.coresPhysical = cpu.coresLogical = cpu.coresOnline = 0; - cpu.frequencyMax = cpu.frequencyMin = 0; + cpu.frequencyMin = cpu.frequencyMax = cpu.frequencyBase = 0.0/0.0; ffStrbufInit(&cpu.name); ffStrbufInit(&cpu.vendor); @@ -169,8 +172,9 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_obj_add_uint(doc, cores, "online", cpu.coresOnline); yyjson_mut_val* frequency = yyjson_mut_obj_add_obj(doc, obj, "frequency"); - yyjson_mut_obj_add_real(doc, frequency, "min", cpu.frequencyMin); + yyjson_mut_obj_add_real(doc, frequency, "base", cpu.frequencyBase); yyjson_mut_obj_add_real(doc, frequency, "max", cpu.frequencyMax); + yyjson_mut_obj_add_real(doc, frequency, "min", cpu.frequencyMin); yyjson_mut_obj_add_real(doc, obj, "temperature", cpu.temperature); } @@ -187,7 +191,7 @@ void ffPrintCPUHelpFormat(void) "Physical core count", "Logical core count", "Online core count", - "Min frequency", + "Base frequency", "Max frequency", "Temperature (formatted)" })); diff --git a/src/util/windows/registry.c b/src/util/windows/registry.c index 998bfaf3c..a324527cd 100644 --- a/src/util/windows/registry.c +++ b/src/util/windows/registry.c @@ -154,3 +154,17 @@ bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error ffStrbufSetWS(result, resultW); return true; } + +bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error) +{ + DWORD buffer; + if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &buffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + { + if (error) + ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed"); + return false; + } + + *result = buffer; + return true; +} diff --git a/src/util/windows/registry.h b/src/util/windows/registry.h index 42dd08aaf..959fea5e3 100644 --- a/src/util/windows/registry.h +++ b/src/util/windows/registry.h @@ -21,5 +21,6 @@ bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint3 bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error); bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error); bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error); +bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error); #endif