From 155d4e90ae1f3cd9b3094e4097c20e6545379136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 16 Sep 2022 10:21:24 +0800 Subject: [PATCH 1/5] FFlist: support static init Also fix possible memory corruption bug in ffListAdd --- src/util/FFlist.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/util/FFlist.c b/src/util/FFlist.c index 07cab9cab7..1044db5cd8 100644 --- a/src/util/FFlist.c +++ b/src/util/FFlist.c @@ -12,7 +12,7 @@ void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) list->elementSize = elementSize; list->capacity = capacity; list->length = 0; - list->data = malloc(list->capacity * list->elementSize); + list->data = capacity == 0 ? NULL : malloc((size_t)list->capacity * list->elementSize); } void* ffListGet(const FFlist* list, uint32_t index) @@ -24,12 +24,13 @@ void* ffListAdd(FFlist* list) { if(list->length == list->capacity) { - list->capacity = list->capacity * 2 * list->elementSize; - list->data = realloc(list->data, list->capacity); + list->capacity = list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2; + // realloc(NULL, newSize) is same as malloc(newSize) + list->data = realloc(list->data, (size_t)list->capacity * list->elementSize); } - void* adress = list->data + (list->length * list->elementSize); + void* address = list->data + (list->length * list->elementSize); ++list->length; - return adress; + return address; } uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*)) @@ -45,5 +46,7 @@ uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compF void ffListDestroy(FFlist* list) { + list->length = list->capacity = 0; free(list->data); + list->data = NULL; } From f362fdb01d80cf1fbadf28a48e090fe32cb30b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 16 Sep 2022 11:03:46 +0800 Subject: [PATCH 2/5] Battery: move detection code into `src/detection` Prepare for macOS implementation --- CMakeLists.txt | 3 + src/detection/battery/battery.h | 19 ++++ src/detection/battery/battery_android.c | 10 ++ src/detection/battery/battery_apple.c | 7 ++ src/detection/battery/battery_linux.c | 117 +++++++++++++++++++ src/modules/battery.c | 144 ++++-------------------- 6 files changed, 176 insertions(+), 124 deletions(-) create mode 100644 src/detection/battery/battery.h create mode 100644 src/detection/battery/battery_android.c create mode 100644 src/detection/battery/battery_apple.c create mode 100644 src/detection/battery/battery_linux.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c6a1ff8bb..81c703e5da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,6 +240,7 @@ if(APPLE) src/detection/os/os_apple.c src/detection/cpu/cpu_apple.c src/detection/gpu/gpu_apple.c + src/detection/battery/battery_apple.c src/detection/memory/memory_apple.c src/detection/displayserver/displayserver_apple.c ) @@ -249,6 +250,7 @@ elseif(ANDROID) src/detection/os/os_android.c src/detection/cpu/cpu_linux.c src/detection/gpu/gpu_android.c + src/detection/battery/battery_android.c src/detection/memory/memory_linux.c src/detection/displayserver/displayserver_android.c ) @@ -259,6 +261,7 @@ else() src/detection/cpu/cpu_linux.c src/detection/gpu/gpu_linux.c src/detection/memory/memory_linux.c + src/detection/battery/battery_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/wayland.c src/detection/displayserver/linux/xcb.c diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h new file mode 100644 index 0000000000..e7c2a859a3 --- /dev/null +++ b/src/detection/battery/battery.h @@ -0,0 +1,19 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_battery_battery +#define FF_INCLUDED_detection_battery_battery + +#include "fastfetch.h" + +typedef struct BatteryResult +{ + FFstrbuf manufacturer; + FFstrbuf modelName; + FFstrbuf technology; + FFstrbuf capacity; + FFstrbuf status; +} BatteryResult; + +const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results); + +#endif diff --git a/src/detection/battery/battery_android.c b/src/detection/battery/battery_android.c new file mode 100644 index 0000000000..2fc2b1d85c --- /dev/null +++ b/src/detection/battery/battery_android.c @@ -0,0 +1,10 @@ +#include "fastfetch.h" +#include "common/io.h" +#include "battery.h" + +#include + +const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { + FF_UNUSED(instance, results) + return "Unimplemented"; +} diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c new file mode 100644 index 0000000000..fa056c5686 --- /dev/null +++ b/src/detection/battery/battery_apple.c @@ -0,0 +1,7 @@ +#include "fastfetch.h" +#include "battery.h" + +const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { + FF_UNUSED(instance, results); + return "Unimplemented"; +} diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c new file mode 100644 index 0000000000..db6aee1629 --- /dev/null +++ b/src/detection/battery/battery_linux.c @@ -0,0 +1,117 @@ +#include "fastfetch.h" +#include "common/io.h" +#include "battery.h" + +#include + +static void parseBattery(FFstrbuf* dir, FFlist* results) +{ + uint32_t dirLength = dir->length; + + FFstrbuf testBatteryBuffer; + ffStrbufInit(&testBatteryBuffer); + + //type must exist and be "Battery" + ffStrbufAppendS(dir, "/type"); + ffReadFileBuffer(dir->chars, &testBatteryBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0) + { + ffStrbufDestroy(&testBatteryBuffer); + return; + } + + //scope may not exist or must not be "Device" + ffStrbufAppendS(dir, "/scope"); + ffReadFileBuffer(dir->chars, &testBatteryBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0) + { + ffStrbufDestroy(&testBatteryBuffer); + return; + } + + ffStrbufDestroy(&testBatteryBuffer); + BatteryResult* result = ffListAdd(results); + + //capacity must exist and be not empty + ffStrbufInit(&result->capacity); + ffStrbufAppendS(dir, "/capacity"); + ffReadFileBuffer(dir->chars, &result->capacity); + ffStrbufSubstrBefore(dir, dirLength); + + if(result->capacity.length == 0) + { + ffStrbufDestroy(&result->capacity); + --results->length; + return; + } + + //At this point, we have a battery. Try to get as much values as possible. + + ffStrbufInit(&result->manufacturer); + ffStrbufAppendS(dir, "/manufacturer"); + ffReadFileBuffer(dir->chars, &result->manufacturer); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->modelName); + ffStrbufAppendS(dir, "/model_name"); + ffReadFileBuffer(dir->chars, &result->modelName); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->technology); + ffStrbufAppendS(dir, "/technology"); + ffReadFileBuffer(dir->chars, &result->technology); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->status); + ffStrbufAppendS(dir, "/status"); + ffReadFileBuffer(dir->chars, &result->status); + ffStrbufSubstrBefore(dir, dirLength); +} + +const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { + FFstrbuf baseDir; + ffStrbufInitA(&baseDir, 64); + if(instance->config.batteryDir.length > 0) + { + ffStrbufAppend(&baseDir, &instance->config.batteryDir); + if (!ffStrbufEndsWithC(&baseDir, '/')) + { + ffStrbufAppendC(&baseDir, '/'); + } + } + else + { + ffStrbufAppendS(&baseDir, "/sys/class/power_supply/"); + } + + uint32_t baseDirLength = baseDir.length; + + DIR* dirp = opendir(baseDir.chars); + if(dirp == NULL) + { + ffStrbufDestroy(&baseDir); + return "opendir(batteryDir) == NULL"; + } + + struct dirent* entry; + while((entry = readdir(dirp)) != NULL) + { + ffStrbufAppendS(&baseDir, entry->d_name); + parseBattery(&baseDir, results); + ffStrbufSubstrBefore(&baseDir, baseDirLength); + } + + closedir(dirp); + + if(results->length == 0) { + ffStrbufDestroy(&baseDir); + return "batteryDir doesn't contain any battery folder"; + } + + ffStrbufDestroy(&baseDir); + return NULL; +} diff --git a/src/modules/battery.c b/src/modules/battery.c index d6c7f25874..8900ef2ece 100644 --- a/src/modules/battery.c +++ b/src/modules/battery.c @@ -1,89 +1,10 @@ #include "fastfetch.h" -#include "common/io.h" #include "common/printing.h" - -#include +#include "detection/battery/battery.h" #define FF_BATTERY_MODULE_NAME "Battery" #define FF_BATTERY_NUM_FORMAT_ARGS 5 -typedef struct BatteryResult -{ - FFstrbuf manufacturer; - FFstrbuf modelName; - FFstrbuf technology; - FFstrbuf capacity; - FFstrbuf status; -} BatteryResult; - -static void parseBattery(FFstrbuf* dir, FFlist* results) -{ - uint32_t dirLength = dir->length; - - FFstrbuf testBatteryBuffer; - ffStrbufInit(&testBatteryBuffer); - - //type must exist and be "Battery" - ffStrbufAppendS(dir, "/type"); - ffReadFileBuffer(dir->chars, &testBatteryBuffer); - ffStrbufSubstrBefore(dir, dirLength); - - if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0) - { - ffStrbufDestroy(&testBatteryBuffer); - return; - } - - //scope may not exist or must not be "Device" - ffStrbufAppendS(dir, "/scope"); - ffReadFileBuffer(dir->chars, &testBatteryBuffer); - ffStrbufSubstrBefore(dir, dirLength); - - if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0) - { - ffStrbufDestroy(&testBatteryBuffer); - return; - } - - ffStrbufDestroy(&testBatteryBuffer); - BatteryResult* result = ffListAdd(results); - - //capacity must exist and be not empty - ffStrbufInit(&result->capacity); - ffStrbufAppendS(dir, "/capacity"); - ffReadFileBuffer(dir->chars, &result->capacity); - ffStrbufSubstrBefore(dir, dirLength); - - if(result->capacity.length == 0) - { - ffStrbufDestroy(&result->capacity); - --results->length; - return; - } - - //At this point, we have a battery. Try to get as much values as possible. - - ffStrbufInit(&result->manufacturer); - ffStrbufAppendS(dir, "/manufacturer"); - ffReadFileBuffer(dir->chars, &result->manufacturer); - ffStrbufSubstrBefore(dir, dirLength); - - ffStrbufInit(&result->modelName); - ffStrbufAppendS(dir, "/model_name"); - ffReadFileBuffer(dir->chars, &result->modelName); - ffStrbufSubstrBefore(dir, dirLength); - - ffStrbufInit(&result->technology); - ffStrbufAppendS(dir, "/technology"); - ffReadFileBuffer(dir->chars, &result->technology); - ffStrbufSubstrBefore(dir, dirLength); - - ffStrbufInit(&result->status); - ffStrbufAppendS(dir, "/status"); - ffReadFileBuffer(dir->chars, &result->status); - ffStrbufSubstrBefore(dir, dirLength); -} - static void printBattery(FFinstance* instance, const BatteryResult* result, uint8_t index) { if(instance->config.battery.outputFormat.length == 0) @@ -127,56 +48,31 @@ static void printBattery(FFinstance* instance, const BatteryResult* result, uint void ffPrintBattery(FFinstance* instance) { - FFstrbuf baseDir; - ffStrbufInitA(&baseDir, 64); - if(instance->config.batteryDir.length > 0) - { - ffStrbufAppend(&baseDir, &instance->config.batteryDir); - ffStrbufEndsWithC(&baseDir, '/'); - } - else - { - ffStrbufAppendS(&baseDir, "/sys/class/power_supply/"); - } - - uint32_t baseDirLength = baseDir.length; - - DIR* dirp = opendir(baseDir.chars); - if(dirp == NULL) - { - ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "opendir(\"%s\") == NULL", baseDir.chars); - ffStrbufDestroy(&baseDir); - return; - } - FFlist results; - ffListInitA(&results, sizeof(BatteryResult), 4); + ffListInitA(&results, sizeof(BatteryResult), 0); + + const char* error = ffDetectBatteryImpl(instance, &results); - struct dirent* entry; - while((entry = readdir(dirp)) != NULL) + if (error) { - ffStrbufAppendS(&baseDir, entry->d_name); - parseBattery(&baseDir, &results); - ffStrbufSubstrBefore(&baseDir, baseDirLength); + ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "%s", error); } - - closedir(dirp); - - for(uint8_t i = 0; i < (uint8_t) results.length; i++) + else { - BatteryResult* result = ffListGet(&results, i); - printBattery(instance, result, i); - - ffStrbufDestroy(&result->manufacturer); - ffStrbufDestroy(&result->modelName); - ffStrbufDestroy(&result->technology); - ffStrbufDestroy(&result->capacity); - ffStrbufDestroy(&result->status); + for(uint8_t i = 0; i < (uint8_t) results.length; i++) + { + BatteryResult* result = ffListGet(&results, i); + printBattery(instance, result, i); + + ffStrbufDestroy(&result->manufacturer); + ffStrbufDestroy(&result->modelName); + ffStrbufDestroy(&result->technology); + ffStrbufDestroy(&result->capacity); + ffStrbufDestroy(&result->status); + } + if(results.length == 0) + ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "No batteries found"); } - if(results.length == 0) - ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "%s doesn't contain any battery folder", baseDir.chars); - ffListDestroy(&results); - ffStrbufDestroy(&baseDir); } From 9eeb216b7025b1f1592191265b15fd9669434091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 16 Sep 2022 14:03:14 +0800 Subject: [PATCH 3/5] util: add check macros to avoid possible mistakes --- src/common/io.h | 2 +- src/common/printing.h | 4 ++-- src/modules/opencl.c | 2 +- src/modules/opengl.c | 2 +- src/modules/terminalfont.c | 2 +- src/modules/vulkan.c | 2 +- src/util/FFcheckmacros.h | 24 ++++++++++++++++++++++++ src/util/FFlist.h | 6 ++++-- src/util/FFstrbuf.h | 34 ++++++++++++++++++---------------- src/util/FFvaluestore.h | 5 +++-- 10 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 src/util/FFcheckmacros.h diff --git a/src/common/io.h b/src/common/io.h index b4640bedbe..35a70675fc 100644 --- a/src/common/io.h +++ b/src/common/io.h @@ -19,6 +19,6 @@ bool ffFileExists(const char* fileName, mode_t mode); // Not thread safe! void ffSuppressIO(bool suppress); -void ffGetTerminalResponse(const char* request, const char* format, ...); +FF_C_SCANF(2, 3) void ffGetTerminalResponse(const char* request, const char* format, ...); #endif diff --git a/src/common/printing.h b/src/common/printing.h index 7eb6ffae67..9a734634b7 100644 --- a/src/common/printing.h +++ b/src/common/printing.h @@ -9,8 +9,8 @@ void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat); void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* format, uint32_t numArgs, const FFformatarg* arguments); void ffPrintFormat(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, uint32_t numArgs, const FFformatarg* arguments); -void ffPrintErrorString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* customErrorFormat, const char* message, ...); -void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, const char* message, ...); +FF_C_PRINTF(6, 7) void ffPrintErrorString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* customErrorFormat, const char* message, ...); +FF_C_PRINTF(5, 6) void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, const char* message, ...); void ffPrintColor(const FFstrbuf* colorValue); void ffPrintCharTimes(char c, uint32_t times); void ffPrintUserString(const char* str); diff --git a/src/modules/opencl.c b/src/modules/opencl.c index 49e8bbf1e2..6b9c0a643e 100644 --- a/src/modules/opencl.c +++ b/src/modules/opencl.c @@ -118,5 +118,5 @@ void ffPrintOpenCL(FFinstance* instance) #endif if(error != NULL) - ffPrintError(instance, FF_OPENCL_MODULE_NAME, 0, &instance->config.openCL, error); + ffPrintError(instance, FF_OPENCL_MODULE_NAME, 0, &instance->config.openCL, "%s", error); } diff --git a/src/modules/opengl.c b/src/modules/opengl.c index fdab25a2a6..9e263779e2 100644 --- a/src/modules/opengl.c +++ b/src/modules/opengl.c @@ -453,5 +453,5 @@ void ffPrintOpenGL(FFinstance* instance) #endif if(error != NULL) - ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL, error); + ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGL, "%s", error); } diff --git a/src/modules/terminalfont.c b/src/modules/terminalfont.c index 561d1163c1..b2e8dc1782 100644 --- a/src/modules/terminalfont.c +++ b/src/modules/terminalfont.c @@ -123,7 +123,7 @@ static void printKonsole(FFinstance* instance) if(profile.length == 0) { - ffPrintError(instance, FF_TERMFONT_MODULE_NAME, 0, &instance->config.terminalFont, "Couldn't find \"DefaultProfile=%[^\\n]\" in \".config/konsolerc\""); + ffPrintError(instance, FF_TERMFONT_MODULE_NAME, 0, &instance->config.terminalFont, "%s", "Couldn't find \"DefaultProfile=%[^\\n]\" in \".config/konsolerc\""); ffStrbufDestroy(&profile); return; } diff --git a/src/modules/vulkan.c b/src/modules/vulkan.c index 53285d1c74..4b3d19fea4 100644 --- a/src/modules/vulkan.c +++ b/src/modules/vulkan.c @@ -11,7 +11,7 @@ void ffPrintVulkan(FFinstance* instance) if(vulkan->error) { - ffPrintError(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkan, vulkan->error); + ffPrintError(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkan, "%s", vulkan->error); return; } diff --git a/src/util/FFcheckmacros.h b/src/util/FFcheckmacros.h new file mode 100644 index 0000000000..1ed61cf82d --- /dev/null +++ b/src/util/FFcheckmacros.h @@ -0,0 +1,24 @@ +#pragma once + +#ifndef FASTFETCH_INCLUDED_FFCHECKMACROS +#define FASTFETCH_INCLUDED_FFCHECKMACROS + +#if defined(__GNUC__) || defined(__clang__) + #define FF_C_NODISCARD __attribute__((warn_unused_result)) +#else + #define FF_C_NODISCARD +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define FF_C_PRINTF(formatStrIndex, argsStartIndex) __attribute__((__format__ (printf, formatStrIndex, argsStartIndex))) +#else + #define FF_C_PRINTF(formatStrIndex, argsStartIndex) +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define FF_C_SCANF(formatStrIndex, argsStartIndex) __attribute__((__format__ (scanf, formatStrIndex, argsStartIndex))) +#else + #define FF_C_SCANF(formatStrIndex, argsStartIndex) +#endif + +#endif diff --git a/src/util/FFlist.h b/src/util/FFlist.h index 30cef1b7a4..8f477dd545 100644 --- a/src/util/FFlist.h +++ b/src/util/FFlist.h @@ -3,6 +3,8 @@ #ifndef FF_INCLUDED_FFLIST #define FF_INCLUDED_FFLIST +#include "FFcheckmacros.h" + #include #include @@ -19,11 +21,11 @@ typedef struct FFlist void ffListInit(FFlist* list, uint32_t elementSize); void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity); -void* ffListGet(const FFlist* list, uint32_t index); +FF_C_NODISCARD void* ffListGet(const FFlist* list, uint32_t index); void* ffListAdd(FFlist* list); -uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*)); +FF_C_NODISCARD uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*)); void ffListDestroy(FFlist* list); diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 0dec7cd406..0c0b9020bf 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -3,6 +3,8 @@ #ifndef FASTFETCH_INCLUDED_FFSTRBUF #define FASTFETCH_INCLUDED_FFSTRBUF +#include "FFcheckmacros.h" + #include #include #include @@ -25,7 +27,7 @@ void ffStrbufInitCopy(FFstrbuf* strbuf, const FFstrbuf* src); void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free); -uint32_t ffStrbufGetFree(const FFstrbuf* strbuf); +FF_C_NODISCARD uint32_t ffStrbufGetFree(const FFstrbuf* strbuf); void ffStrbufClear(FFstrbuf* strbuf); @@ -37,7 +39,7 @@ void ffStrbufAppendS(FFstrbuf* strbuf, const char* value); void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude); void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int)); -void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...); +FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...); void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments); void ffStrbufPrependS(FFstrbuf* strbuf, const char* value); @@ -46,11 +48,11 @@ void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value); void ffStrbufSetS(FFstrbuf* strbuf, const char* value); -int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp); -int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp); +FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp); +FF_C_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp); -int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp); -int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp); +FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp); +FF_C_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp); void ffStrbufTrimLeft(FFstrbuf* strbuf, char c); void ffStrbufTrimRight(FFstrbuf* strbuf, char c); @@ -62,16 +64,16 @@ void ffStrbufRemoveStringsA(FFstrbuf* strbuf, uint32_t numStrings, const char* s void ffStrbufRemoveStringsV(FFstrbuf* strbuf, uint32_t numStrings, va_list arguments); void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, ...); -uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c); -uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str); +FF_C_NODISCARD uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c); +FF_C_NODISCARD uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str); -uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c); -uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched); -uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str); +FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c); +FF_C_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched); +FF_C_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str); -uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c); +FF_C_NODISCARD uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c); -uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c); +FF_C_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c); void ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index); void ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c); @@ -89,7 +91,7 @@ bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start); bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c); bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end); -uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c); +FF_C_NODISCARD uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c); bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end); @@ -98,8 +100,8 @@ void ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c); void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file); void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file); -double ffStrbufToDouble(const FFstrbuf* strbuf); -uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaultValue); +FF_C_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf); +FF_C_NODISCARD uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaultValue); void ffStrbufDestroy(FFstrbuf* strbuf); diff --git a/src/util/FFvaluestore.h b/src/util/FFvaluestore.h index 58f0b714bf..c59b584a62 100644 --- a/src/util/FFvaluestore.h +++ b/src/util/FFvaluestore.h @@ -3,12 +3,13 @@ #ifndef FASTFETCH_INCLUDED_FFVALUESTORE #define FASTFETCH_INCLUDED_FFVALUESTORE -#include "util/FFlist.h" +#include "FFlist.h" +#include "FFcheckmacros.h" typedef FFlist FFvaluestore; void ffValuestoreInit(FFvaluestore* vs, uint32_t valueSize); -void* ffValuestoreGet(FFvaluestore* vs, const char* key); +FF_C_NODISCARD void* ffValuestoreGet(FFvaluestore* vs, const char* key); void* ffValuestoreSet(FFvaluestore* vs, const char* key, bool* created); //created may be NULL void ffValuestoreDestroy(FFvaluestore* vs); From 413d126bcc75ed9bf0f6a18a6874e98146019e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 16 Sep 2022 17:41:24 +0800 Subject: [PATCH 4/5] Battery: add dirty support for macOS --- CMakeLists.txt | 1 + src/detection/battery/battery_apple.c | 67 +++++++++++++++++++++++++-- src/util/apple/cfdict_helpers.c | 45 ++++++++++++++++++ src/util/apple/cfdict_helpers.h | 14 ++++++ 4 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 src/util/apple/cfdict_helpers.c create mode 100644 src/util/apple/cfdict_helpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81c703e5da..98f83b3a88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,7 @@ if(APPLE) src/detection/battery/battery_apple.c src/detection/memory/memory_apple.c src/detection/displayserver/displayserver_apple.c + src/util/apple/cfdict_helpers.c ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index fa056c5686..53a2431e5a 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -1,7 +1,68 @@ #include "fastfetch.h" #include "battery.h" +#include "util/apple/cfdict_helpers.h" -const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { - FF_UNUSED(instance, results); - return "Unimplemented"; +#include + +const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) +{ + FF_UNUSED(instance); + + CFMutableDictionaryRef matchDict = IOServiceMatching("AppleSmartBattery"); + if (matchDict == NULL) + return "IOServiceMatching(\"AppleSmartBattery\") failed"; + + io_iterator_t iterator; + if(IOServiceGetMatchingServices(0, matchDict, &iterator) != kIOReturnSuccess) + return "IOServiceGetMatchingServices() failed"; + + io_registry_entry_t registryEntry; + while((registryEntry = IOIteratorNext(iterator)) != 0) + { + CFMutableDictionaryRef properties; + if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) + { + IOObjectRelease(registryEntry); + continue; + } + + int intValue; + bool boolValue; + + BatteryResult* battery = ffListAdd(results); + ffStrbufInit(&battery->capacity); + if(ffCfDictGetInt(properties, "CurrentCapacity", &intValue)) + ffStrbufAppendF(&battery->capacity, "%d", intValue); + + ffStrbufInit(&battery->manufacturer); + ffStrbufInit(&battery->modelName); + ffStrbufInit(&battery->technology); + if (ffCfDictGetBool(properties, "built-in", &boolValue) && boolValue) + { + ffStrbufAppendS(&battery->manufacturer, "Apple Inc."); + ffStrbufAppendS(&battery->modelName, "Builtin"); + ffStrbufAppendS(&battery->technology, "Lithium"); + } + else + { + ffStrbufAppendS(&battery->manufacturer, "Unknown"); + ffStrbufAppendS(&battery->modelName, "Unknown"); + ffStrbufAppendS(&battery->technology, "Unknown"); + } + + ffStrbufInit(&battery->status); + if (ffCfDictGetBool(properties, "FullyCharged", &boolValue) && boolValue) + ffStrbufAppendS(&battery->status, "Fully charged"); + else if (ffCfDictGetBool(properties, "IsCharging", &boolValue) && boolValue) + ffStrbufAppendS(&battery->status, "Charging"); + else + ffStrbufAppendS(&battery->status, ""); + + CFRelease(properties); + IOObjectRelease(registryEntry); + } + + IOObjectRelease(iterator); + + return NULL; } diff --git a/src/util/apple/cfdict_helpers.c b/src/util/apple/cfdict_helpers.c new file mode 100644 index 0000000000..9da7ca917f --- /dev/null +++ b/src/util/apple/cfdict_helpers.c @@ -0,0 +1,45 @@ +#include "cfdict_helpers.h" + +const void* ffCfDictGetValue(CFMutableDictionaryRef dict, const char* key) +{ + CFStringRef cfKey = CFStringCreateWithCStringNoCopy(NULL, key, kCFStringEncodingASCII, kCFAllocatorNull); + return CFDictionaryGetValue(dict, cfKey); +} + +bool ffCfDictGetString(CFMutableDictionaryRef dict, const char* key, FFstrbuf* result) +{ + CFStringRef cf = (CFStringRef)ffCfDictGetValue(dict, key); + if(cf == NULL || CFGetTypeID(cf) != CFStringGetTypeID()) + return false; + + uint32_t length = (uint32_t)CFStringGetLength(cf); + ffStrbufEnsureFree(result, length + 1); + if(CFStringGetCString(cf, result->chars, length + 1, kCFStringEncodingASCII)) + { + result->length = length; + // CFStringGetCString ensures the buffer is NUL terminated + // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring + } + return true; +} + +bool ffCfDictGetBool(CFMutableDictionaryRef dict, const char* key, bool* result) +{ + CFBooleanRef cf = (CFBooleanRef)ffCfDictGetValue(dict, key); + if(cf == NULL || CFGetTypeID(cf) != CFNumberGetTypeID()) + return false; + + *result = CFBooleanGetValue(cf); + return true; +} + +bool ffCfDictGetInt(CFMutableDictionaryRef dict, const char* key, int* result) +{ + CFNumberRef cf = (CFNumberRef)ffCfDictGetValue(dict, key); + if (cf == NULL || CFGetTypeID(cf) != CFStringGetTypeID()) + return false; + + if(!CFNumberGetValue(cf, kCFNumberSInt32Type, result)) + return false; + return true; +} diff --git a/src/util/apple/cfdict_helpers.h b/src/util/apple/cfdict_helpers.h new file mode 100644 index 0000000000..a00522e740 --- /dev/null +++ b/src/util/apple/cfdict_helpers.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef FASTFETCH_INCLUDED_cfdict_helpers +#define FASTFETCH_INCLUDED_cfdict_helpers + +#include "fastfetch.h" +#include + +const void* ffCfDictGetValue(CFMutableDictionaryRef dict, const char* str); +bool ffCfDictGetString(CFMutableDictionaryRef dict, const char* key, FFstrbuf* result); +bool ffCfDictGetBool(CFMutableDictionaryRef dict, const char* key, bool* result); +bool ffCfDictGetInt(CFMutableDictionaryRef dict, const char* key, int* result); + +#endif From 09f3bd5a79046b4e5b8bdb9d02e7b387610bdd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 16 Sep 2022 18:11:39 +0800 Subject: [PATCH 5/5] GPU: correct detection of Apple M1 GPU Don't cheat --- presets/verbose | 2 +- src/detection/gpu/gpu.h | 2 ++ src/detection/gpu/gpu_android.c | 3 ++- src/detection/gpu/gpu_apple.c | 48 ++++++++++----------------------- src/detection/gpu/gpu_linux.c | 27 ++++++++++--------- src/fastfetch.c | 5 ++-- src/modules/gpu.c | 8 ++++-- 7 files changed, 43 insertions(+), 52 deletions(-) diff --git a/presets/verbose b/presets/verbose index 7839bd1a72..9d470737ab 100644 --- a/presets/verbose +++ b/presets/verbose @@ -17,7 +17,7 @@ --terminal-font-format Raw: {}; Name: {}; Size: {}; Styles: {}; Pretty: {} --cpu-format Name: {}, Vendor: {}, CoresPhysical: {}, CoresLogical: {}, CoresOnline: {}, FrequencyMin: {}, FrequencyMax: {}, Temperature: {} --cpu-usage-format Percentage: {} ---gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {} +--gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {} --memory-format Used: {}; Total: {}; Percentage: {} --disk-format Used: {}; Total: {}; Files: {}; Percentage: {} --battery-format Manufactor: {}; Model: {}; Technology: {}; Capacity: {}; Status: {} diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index 0b750b4e5a..08b90d3be1 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -6,6 +6,7 @@ #include "fastfetch.h" #define FF_GPU_TEMP_UNSET (0/0.0) +#define FF_GPU_CORE_COUNT_UNSET -1 typedef struct FFGPUResult { @@ -13,6 +14,7 @@ typedef struct FFGPUResult FFstrbuf name; FFstrbuf driver; double temperature; + int coreCount; } FFGPUResult; const FFlist* ffDetectGPU(const FFinstance* instance); diff --git a/src/detection/gpu/gpu_android.c b/src/detection/gpu/gpu_android.c index 9b07669a2a..6e0afe389b 100644 --- a/src/detection/gpu/gpu_android.c +++ b/src/detection/gpu/gpu_android.c @@ -1,6 +1,7 @@ #include "gpu.h" -void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) { FF_UNUSED(gpus, instance); + return "Unimplemented"; } diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 6f22e47215..b8a2b34e69 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -1,33 +1,18 @@ #include "gpu.h" #include "common/library.h" #include "detection/cpu/cpu.h" +#include "util/apple/cfdict_helpers.h" -#include #include -void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) { FF_UNUSED(instance); - const FFCPUResult* cpu = ffDetectCPU(); - if(ffStrbufStartsWithIgnCaseS(&cpu->name, "Apple M")) - { - FFGPUResult* gpu = ffListAdd(gpus); - - ffStrbufInit(&gpu->vendor); - ffStrbufAppendS(&gpu->vendor, "Apple"); - - ffStrbufInit(&gpu->name); - ffStrbufAppendS(&gpu->name, cpu->name.chars + 6); //Cut "Apple " - - ffStrbufInitA(&gpu->driver, 0); - gpu->temperature = FF_GPU_TEMP_UNSET; - } - - CFMutableDictionaryRef matchDict = IOServiceMatching("IOPCIDevice"); + CFMutableDictionaryRef matchDict = IOServiceMatching(kIOAcceleratorClassName); io_iterator_t iterator; if(IOServiceGetMatchingServices(0, matchDict, &iterator) != kIOReturnSuccess) - return; + return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; while((registryEntry = IOIteratorNext(iterator)) != 0) @@ -39,25 +24,19 @@ void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) continue; } - CFStringRef key = CFStringCreateWithCStringNoCopy(NULL, "model", kCFStringEncodingASCII, kCFAllocatorNull); - CFStringRef model = CFDictionaryGetValue(properties, key); - if(model == NULL || CFGetTypeID(model) != CFDataGetTypeID()) - { - CFRelease(properties); - IOObjectRelease(registryEntry); - continue; - } - FFGPUResult* gpu = ffListAdd(gpus); - uint32_t modelLength = (uint32_t) CFStringGetLength(model); - ffStrbufInitA(&gpu->name, modelLength + 1); - CFStringGetCString(model, gpu->name.chars, modelLength + 1, kCFStringEncodingASCII); - gpu->name.length = modelLength; - gpu->name.chars[gpu->name.length] = '\0'; + ffStrbufInit(&gpu->name); + ffCfDictGetString(properties, "model", &gpu->name); + + if (!ffCfDictGetInt(properties, "gpu-core-count", &gpu->coreCount)) + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; ffStrbufInitA(&gpu->vendor, 0); - ffStrbufInitA(&gpu->driver, 0); + + ffStrbufInit(&gpu->driver); + ffCfDictGetString(properties, "CFBundleIdentifier", &gpu->driver); + gpu->temperature = FF_GPU_TEMP_UNSET; CFRelease(properties); @@ -65,4 +44,5 @@ void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) } IOObjectRelease(iterator); + return NULL; } diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index ebab29a8cf..1aa33f6d95 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -168,24 +168,26 @@ static void pciHandleDevice(FFlist* results, PCIData* pci, struct pci_dev* devic ffStrbufInit(&gpu->driver); pciDetectDriverName(gpu, pci, device); + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; + gpu->temperature = FF_GPU_TEMP_UNSET; pciDetectTemperatur(gpu, device); } -static void pciDetectGPUs(const FFinstance* instance, FFlist* gpus) +static const char* pciDetectGPUs(const FFinstance* instance, FFlist* gpus) { PCIData pci; - FF_LIBRARY_LOAD(libpci, instance->config.libPCI, , "libpci.so", 4) - FF_LIBRARY_LOAD_SYMBOL(libpci, pci_alloc, ) - FF_LIBRARY_LOAD_SYMBOL(libpci, pci_init, ) - FF_LIBRARY_LOAD_SYMBOL(libpci, pci_scan_bus, ) - FF_LIBRARY_LOAD_SYMBOL(libpci, pci_cleanup, ) + FF_LIBRARY_LOAD(libpci, instance->config.libPCI, "dlopen libpci.so failed", "libpci.so", 4) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_alloc) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_init) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_scan_bus) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_cleanup) - FF_LIBRARY_LOAD_SYMBOL_VAR(libpci, pci, pci_read_byte, ) - FF_LIBRARY_LOAD_SYMBOL_VAR(libpci, pci, pci_read_word, ) - FF_LIBRARY_LOAD_SYMBOL_VAR(libpci, pci, pci_lookup_name, ) - FF_LIBRARY_LOAD_SYMBOL_VAR(libpci, pci, pci_get_param, ) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_read_byte) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_read_word) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_lookup_name) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_get_param) pci.access = ffpci_alloc(); ffpci_init(pci.access); @@ -200,13 +202,14 @@ static void pciDetectGPUs(const FFinstance* instance, FFlist* gpus) ffpci_cleanup(pci.access); dlclose(libpci); + return NULL; } #endif -void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) { #ifdef FF_HAVE_LIBPCI - pciDetectGPUs(instance, gpus); + return pciDetectGPUs(instance, gpus); #endif } diff --git a/src/fastfetch.c b/src/fastfetch.c index 6b674f321f..17f5cab304 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -274,11 +274,12 @@ static inline void printCommandHelp(const char* command) } else if(strcasecmp(command, "gpu-format") == 0) { - constructAndPrintCommandHelpFormat("gpu", "{} {}", 4, + constructAndPrintCommandHelpFormat("gpu", "{} {}", 5, "GPU vendor", "GPU name", "GPU driver", - "GPU temperature" + "GPU temperature", + "GPU core count" ); } else if(strcasecmp(command, "memory-format") == 0) diff --git a/src/modules/gpu.c b/src/modules/gpu.c index 599843e008..93aaa69401 100644 --- a/src/modules/gpu.c +++ b/src/modules/gpu.c @@ -7,7 +7,7 @@ #include #define FF_GPU_MODULE_NAME "GPU" -#define FF_GPU_NUM_FORMAT_ARGS 4 +#define FF_GPU_NUM_FORMAT_ARGS 5 static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, FFGPUResult* gpu) { @@ -22,11 +22,15 @@ static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, ffStrbufAppend(&output, &gpu->name); + if(gpu->coreCount != FF_GPU_CORE_COUNT_UNSET) + ffStrbufAppendF(&output, " (%d)", gpu->coreCount); + ffPrintAndAppendToCache(instance, FF_GPU_MODULE_NAME, index, &instance->config.gpu, cache, &output, FF_GPU_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->driver}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->temperature} + {FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->temperature}, + {FF_FORMAT_ARG_TYPE_INT, &gpu->coreCount}, }); ffStrbufDestroy(&output);