Modules: refactor module option handling for static allocation

Moves module option structs out of global config and removes dynamic allocation, using static buffers and size assertions for safer, simpler management.

Refactors module initialization and destruction to work with isolated option structs, eliminating the need for the previous modules container and related code.

Unifies module option header usage and updates detection logic to leverage statically-sized option buffers, improving encapsulation and maintainability.

Simplifies module function signatures and reduces coupling between modules and config.

Enhances future extensibility and reliability by enforcing max size constraints and removing unnecessary indirections.
This commit is contained in:
李通洲
2025-08-04 14:25:14 +08:00
parent 559082806b
commit 75d2c668d0
289 changed files with 1449 additions and 1672 deletions
+30 -12
View File
@@ -12,7 +12,6 @@
void ffPrepareCommandOption(FFdata* data)
{
FFOptionsModules* const options = &instance.config.modules;
//If we don't have a custom structure, use the default one
if(data->structure.length == 0)
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
@@ -21,22 +20,38 @@ void ffPrepareCommandOption(FFdata* data)
ffPrepareCPUUsage();
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
ffPrepareDiskIO(&options->diskIo);
{
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
ffPrepareNetIO(&options->netIo);
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
if(instance.config.general.multithreading)
{
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
ffPreparePublicIp(&options->publicIP);
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
ffPrepareWeather(&options->weather);
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
}
}
static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
{
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
if (!modules)
@@ -48,7 +63,7 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
if (baseInfo->generateJsonConfig)
baseInfo->generateJsonConfig(baseInfo, doc, module);
baseInfo->generateJsonConfig(options, doc, module);
if (yyjson_mut_obj_size(module) > 1)
yyjson_mut_arr_add_val(modules, module);
@@ -56,19 +71,19 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
yyjson_mut_arr_add_strbuf(doc, modules, &type);
}
static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
if (baseInfo->generateJsonResult)
baseInfo->generateJsonResult(baseInfo, doc, module);
baseInfo->generateJsonResult(options, doc, module);
else
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
}
static void parseStructureCommand(
const char* line,
void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc),
void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc),
yyjson_mut_doc* jsonDoc
)
{
@@ -79,10 +94,13 @@ static void parseStructureCommand(
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(line, baseInfo->name))
{
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (__builtin_expect(jsonDoc != NULL, false))
fn(baseInfo, jsonDoc);
fn(baseInfo, optionBuf, jsonDoc);
else
baseInfo->printModule(baseInfo);
baseInfo->printModule(optionBuf);
baseInfo->destroyOptions(optionBuf);
return;
}
}
+1 -8
View File
@@ -42,14 +42,13 @@ static void defaultConfig(void)
{
ffOptionsInitLogo(&instance.config.logo);
ffOptionsInitGeneral(&instance.config.general);
ffOptionsInitModules(&instance.config.modules);
ffOptionsInitDisplay(&instance.config.display);
}
void ffInitInstance(void)
{
#ifdef WIN32
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
setlocale(LC_ALL, ".UTF8");
#else
// Never use `setlocale(LC_ALL, "")`
@@ -96,11 +95,6 @@ static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
void ffStart(void)
{
#ifdef FF_START_DETECTION_THREADS
if(instance.config.general.multithreading)
startDetectionThreads();
#endif
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
@@ -150,7 +144,6 @@ static void destroyConfig(void)
{
ffOptionsDestroyLogo(&instance.config.logo);
ffOptionsDestroyGeneral(&instance.config.general);
ffOptionsDestroyModules(&instance.config.modules);
ffOptionsDestroyDisplay(&instance.config.display);
}
+24 -14
View File
@@ -99,12 +99,12 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
return "Invalid enum value type; must be a string or integer";
}
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
if (baseInfo->generateJsonResult)
baseInfo->generateJsonResult(baseInfo, doc, module);
baseInfo->generateJsonResult(options, doc, module);
else
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
}
@@ -118,11 +118,14 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(type, baseInfo->name))
{
if (jsonVal) baseInfo->parseJsonObject(baseInfo, jsonVal);
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
if (__builtin_expect(jsonDoc != NULL, false))
genJsonResult(baseInfo, jsonDoc);
genJsonResult(baseInfo, optionBuf, jsonDoc);
else
baseInfo->printModule(baseInfo);
baseInfo->printModule(optionBuf);
baseInfo->destroyOptions(optionBuf);
return true;
}
}
@@ -131,7 +134,6 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
{
FFconfig* cfg = &instance.config;
switch (type[0])
{
case 'b': case 'B': {
@@ -142,32 +144,40 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
case 'd': case 'D': {
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
{
if (module) cfg->modules.diskIo.moduleInfo.parseJsonObject(&cfg->modules.diskIo, module);
ffPrepareDiskIO(&cfg->modules.diskIo);
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
ffPrepareDiskIO(&options);
}
break;
}
case 'n': case 'N': {
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
{
if (module) cfg->modules.netIo.moduleInfo.parseJsonObject(&cfg->modules.netIo, module);
ffPrepareNetIO(&cfg->modules.netIo);
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
ffPrepareNetIO(&options);
}
break;
}
case 'p': case 'P': {
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
{
if (module) cfg->modules.publicIP.moduleInfo.parseJsonObject(&cfg->modules.publicIP, module);
ffPreparePublicIp(&cfg->modules.publicIP);
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
ffPreparePublicIp(&options);
}
break;
}
case 'w': case 'W': {
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
{
if (module) cfg->modules.weather.moduleInfo.parseJsonObject(&cfg->modules.weather, module);
ffPrepareWeather(&cfg->modules.weather);
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
ffPrepareWeather(&options);
}
break;
}
+74 -74
View File
@@ -1,69 +1,69 @@
#include "fastfetch.h"
#include "modules/modules.h"
static FFModuleBaseInfo* A[] = {
NULL,
};
static FFModuleBaseInfo* B[] = {
(FFModuleBaseInfo*) &instance.config.modules.battery,
(FFModuleBaseInfo*) &instance.config.modules.bios,
(FFModuleBaseInfo*) &instance.config.modules.bluetooth,
(FFModuleBaseInfo*) &instance.config.modules.bluetoothRadio,
(FFModuleBaseInfo*) &instance.config.modules.board,
(FFModuleBaseInfo*) &instance.config.modules.bootmgr,
(FFModuleBaseInfo*) &instance.config.modules.break_,
(FFModuleBaseInfo*) &instance.config.modules.brightness,
(FFModuleBaseInfo*) &instance.config.modules.btrfs,
&ffBatteryModuleInfo,
&ffBiosModuleInfo,
&ffBluetoothModuleInfo,
&ffBluetoothRadioModuleInfo,
&ffBoardModuleInfo,
&ffBootmgrModuleInfo,
&ffBreakModuleInfo,
&ffBrightnessModuleInfo,
&ffBtrfsModuleInfo,
NULL,
};
static FFModuleBaseInfo* C[] = {
(FFModuleBaseInfo*) &instance.config.modules.camera,
(FFModuleBaseInfo*) &instance.config.modules.chassis,
(FFModuleBaseInfo*) &instance.config.modules.command,
(FFModuleBaseInfo*) &instance.config.modules.colors,
(FFModuleBaseInfo*) &instance.config.modules.cpu,
(FFModuleBaseInfo*) &instance.config.modules.cpuCache,
(FFModuleBaseInfo*) &instance.config.modules.cpuUsage,
(FFModuleBaseInfo*) &instance.config.modules.cursor,
(FFModuleBaseInfo*) &instance.config.modules.custom,
&ffCameraModuleInfo,
&ffChassisModuleInfo,
&ffCommandModuleInfo,
&ffColorsModuleInfo,
&ffCPUModuleInfo,
&ffCPUCacheModuleInfo,
&ffCPUUsageModuleInfo,
&ffCursorModuleInfo,
&ffCustomModuleInfo,
NULL,
};
static FFModuleBaseInfo* D[] = {
(FFModuleBaseInfo*) &instance.config.modules.dateTime,
(FFModuleBaseInfo*) &instance.config.modules.de,
(FFModuleBaseInfo*) &instance.config.modules.display,
(FFModuleBaseInfo*) &instance.config.modules.disk,
(FFModuleBaseInfo*) &instance.config.modules.diskIo,
(FFModuleBaseInfo*) &instance.config.modules.dns,
&ffDateTimeModuleInfo,
&ffDEModuleInfo,
&ffDisplayModuleInfo,
&ffDiskModuleInfo,
&ffDiskIOModuleInfo,
&ffDNSModuleInfo,
NULL,
};
static FFModuleBaseInfo* E[] = {
(FFModuleBaseInfo*) &instance.config.modules.editor,
&ffEditorModuleInfo,
NULL,
};
static FFModuleBaseInfo* F[] = {
(FFModuleBaseInfo*) &instance.config.modules.font,
&ffFontModuleInfo,
NULL,
};
static FFModuleBaseInfo* G[] = {
(FFModuleBaseInfo*) &instance.config.modules.gamepad,
(FFModuleBaseInfo*) &instance.config.modules.gpu,
&ffGamepadModuleInfo,
&ffGPUModuleInfo,
NULL,
};
static FFModuleBaseInfo* H[] = {
(FFModuleBaseInfo*) &instance.config.modules.host,
&ffHostModuleInfo,
NULL,
};
static FFModuleBaseInfo* I[] = {
(FFModuleBaseInfo*) &instance.config.modules.icons,
(FFModuleBaseInfo*) &instance.config.modules.initSystem,
&ffIconsModuleInfo,
&ffInitSystemModuleInfo,
NULL,
};
@@ -72,47 +72,47 @@ static FFModuleBaseInfo* J[] = {
};
static FFModuleBaseInfo* K[] = {
(FFModuleBaseInfo*) &instance.config.modules.kernel,
(FFModuleBaseInfo*) &instance.config.modules.keyboard,
&ffKernelModuleInfo,
&ffKeyboardModuleInfo,
NULL,
};
static FFModuleBaseInfo* L[] = {
(FFModuleBaseInfo*) &instance.config.modules.lm,
(FFModuleBaseInfo*) &instance.config.modules.loadavg,
(FFModuleBaseInfo*) &instance.config.modules.locale,
(FFModuleBaseInfo*) &instance.config.modules.localIP,
&ffLMModuleInfo,
&ffLoadavgModuleInfo,
&ffLocaleModuleInfo,
&ffLocalIPModuleInfo,
NULL,
};
static FFModuleBaseInfo* M[] = {
(FFModuleBaseInfo*) &instance.config.modules.media,
(FFModuleBaseInfo*) &instance.config.modules.memory,
(FFModuleBaseInfo*) &instance.config.modules.monitor,
(FFModuleBaseInfo*) &instance.config.modules.mouse,
&ffMediaModuleInfo,
&ffMemoryModuleInfo,
&ffMonitorModuleInfo,
&ffMouseModuleInfo,
NULL,
};
static FFModuleBaseInfo* N[] = {
(FFModuleBaseInfo*) &instance.config.modules.netIo,
&ffNetIOModuleInfo,
NULL,
};
static FFModuleBaseInfo* O[] = {
(FFModuleBaseInfo*) &instance.config.modules.openCL,
(FFModuleBaseInfo*) &instance.config.modules.openGL,
(FFModuleBaseInfo*) &instance.config.modules.os,
&ffOpenCLModuleInfo,
&ffOpenGLModuleInfo,
&ffOSModuleInfo,
NULL,
};
static FFModuleBaseInfo* P[] = {
(FFModuleBaseInfo*) &instance.config.modules.packages,
(FFModuleBaseInfo*) &instance.config.modules.physicalDisk,
(FFModuleBaseInfo*) &instance.config.modules.physicalMemory,
(FFModuleBaseInfo*) &instance.config.modules.player,
(FFModuleBaseInfo*) &instance.config.modules.powerAdapter,
(FFModuleBaseInfo*) &instance.config.modules.processes,
(FFModuleBaseInfo*) &instance.config.modules.publicIP,
&ffPackagesModuleInfo,
&ffPhysicalDiskModuleInfo,
&ffPhysicalMemoryModuleInfo,
&ffPlayerModuleInfo,
&ffPowerAdapterModuleInfo,
&ffProcessesModuleInfo,
&ffPublicIPModuleInfo,
NULL,
};
@@ -125,42 +125,42 @@ static FFModuleBaseInfo* R[] = {
};
static FFModuleBaseInfo* S[] = {
(FFModuleBaseInfo*) &instance.config.modules.separator,
(FFModuleBaseInfo*) &instance.config.modules.shell,
(FFModuleBaseInfo*) &instance.config.modules.sound,
(FFModuleBaseInfo*) &instance.config.modules.swap,
&ffSeparatorModuleInfo,
&ffShellModuleInfo,
&ffSoundModuleInfo,
&ffSwapModuleInfo,
NULL,
};
static FFModuleBaseInfo* T[] = {
(FFModuleBaseInfo*) &instance.config.modules.terminal,
(FFModuleBaseInfo*) &instance.config.modules.terminalFont,
(FFModuleBaseInfo*) &instance.config.modules.terminalSize,
(FFModuleBaseInfo*) &instance.config.modules.terminalTheme,
(FFModuleBaseInfo*) &instance.config.modules.title,
(FFModuleBaseInfo*) &instance.config.modules.theme,
(FFModuleBaseInfo*) &instance.config.modules.tpm,
&ffTerminalModuleInfo,
&ffTerminalFontModuleInfo,
&ffTerminalSizeModuleInfo,
&ffTerminalThemeModuleInfo,
&ffTitleModuleInfo,
&ffThemeModuleInfo,
&ffTPMModuleInfo,
NULL,
};
static FFModuleBaseInfo* U[] = {
(FFModuleBaseInfo*) &instance.config.modules.uptime,
(FFModuleBaseInfo*) &instance.config.modules.users,
&ffUptimeModuleInfo,
&ffUsersModuleInfo,
NULL,
};
static FFModuleBaseInfo* V[] = {
(FFModuleBaseInfo*) &instance.config.modules.version,
(FFModuleBaseInfo*) &instance.config.modules.vulkan,
&ffVersionModuleInfo,
&ffVulkanModuleInfo,
NULL,
};
static FFModuleBaseInfo* W[] = {
(FFModuleBaseInfo*) &instance.config.modules.wallpaper,
(FFModuleBaseInfo*) &instance.config.modules.weather,
(FFModuleBaseInfo*) &instance.config.modules.wm,
(FFModuleBaseInfo*) &instance.config.modules.wifi,
(FFModuleBaseInfo*) &instance.config.modules.wmTheme,
&ffWallpaperModuleInfo,
&ffWeatherModuleInfo,
&ffWMModuleInfo,
&ffWifiModuleInfo,
&ffWMThemeModuleInfo,
NULL,
};
@@ -173,7 +173,7 @@ static FFModuleBaseInfo* Y[] = {
};
static FFModuleBaseInfo* Z[] = {
(FFModuleBaseInfo*) &instance.config.modules.zpool,
&ffZpoolModuleInfo,
NULL,
};
+2
View File
@@ -95,3 +95,5 @@ static inline void ffOptionDestroyModuleArg(FFModuleArgs* args)
ffStrbufDestroy(&args->outputFormat);
ffStrbufDestroy(&args->outputColor);
}
enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation