From 260c883d07a94e0091514b7c6d8af0dacefcb43d Mon Sep 17 00:00:00 2001 From: AcatXIo <512@keemail.me> Date: Tue, 7 May 2024 02:54:36 +0200 Subject: [PATCH 01/59] Presets: Update hardware.jsonc (#899) Update hardware.jsonc preset, fix logo being forced to arch, add more hardware information. --- presets/hardware.jsonc | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/presets/hardware.jsonc b/presets/hardware.jsonc index d976285fc..c6c22a758 100644 --- a/presets/hardware.jsonc +++ b/presets/hardware.jsonc @@ -1,25 +1,37 @@ { "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", - "logo": { - "type": "builtin", - "source": "arch" - }, "modules": [ - "host", - "display", + { + "type": "host", + "format": "{?2}{2}{?}{?5} ({5}){?}" + }, + "chassis", + { + "type": "board", + "format": "{?1}{1}{?}{?2} ({2}){?}" + }, "cpu", - "gpu", { "type": "memory", "format": "{?2}{2}{?}" }, - { - "type": "disk", - "format": "{?2}{2}{?}" - }, + "physicaldisk", + "gpu", + "display", + "monitor", + { + "type": "wifi", + "format": "{?1}{1}{?}{?6} - {6}{?}" + }, + { + "type": "sound", + "format": "{?2}{2}{?}" + }, + "camera", { "type": "battery", - "format": "{?1}{1} {?}{?2}{2} {?}{?3}({3}){?}" - } + "format": "{?1}{1}{?}{?2} {2}{?}{?3} ({3}){?}" + }, + "poweradapter" ] } From 299bc7468fb73c234fcbfca8981073dc76044007 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 8 May 2024 09:53:07 +0800 Subject: [PATCH 02/59] Terminal (Linux): fix exePath detection --- src/detection/terminalshell/terminalshell_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index b2ad822dd..dbdc08900 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -46,7 +46,7 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1); if (length > 0) // doesn't contain trailing NUL { - exePath->chars[length + 1] = '\0'; + exePath->chars[length] = '\0'; exePath->length = (uint32_t) length; } From 8f457f047ca1f5d48a879fb0a41b1cff52495cc4 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 8 May 2024 09:54:22 +0800 Subject: [PATCH 03/59] TerminalFont (Linux): searching for font config in st binary --- .../terminalfont/terminalfont_linux.c | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index 247959fc3..bcb640f3d 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -3,6 +3,7 @@ #include "common/properties.h" #include "common/parsing.h" #include "common/io/io.h" +#include "common/processing.h" #include "detection/terminalshell/terminalshell.h" #include "detection/displayserver/displayserver.h" #include "util/mallocHelper.h" @@ -265,9 +266,9 @@ static void detectXterm(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); } -static void detectSt(FFTerminalFontResult* terminalFont, uint32_t pid) +static void detectSt(FFTerminalFontResult* terminalFont, const FFTerminalResult* terminal) { - FF_STRBUF_AUTO_DESTROY size = ffStrbufCreateF("/proc/%u/cmdline", pid); + FF_STRBUF_AUTO_DESTROY size = ffStrbufCreateF("/proc/%u/cmdline", terminal->pid); FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate(); if (!ffAppendFileBuffer(size.chars, &font)) { @@ -276,20 +277,53 @@ static void detectSt(FFTerminalFontResult* terminalFont, uint32_t pid) } const char* p = memmem(font.chars, font.length, "\0-f", sizeof("\0-f")); // find parameter of `-f` - if (!p) + if (p) { - ffStrbufAppendF(&terminalFont->error, "st was not executed with `-f` parameter"); - return; + // st was executed with `-f` parameter + ffStrbufSubstrAfter(&font, (uint32_t) (p + (sizeof("\0-f") - 1) - font.chars)); + ffStrbufRecalculateLength(&font); + } + else + { + ffStrbufClear(&font); + if (ffProcessAppendStdOut(&font, (char* const[]) { + "strings", + terminal->exePath.chars, + NULL, + }) != NULL || font.length == 0) + { + ffStrbufAppendS(&terminalFont->error, "Failed to run `strings st`"); + return; + } + + // Search font config string in st binary + uint32_t middleIndex = ffStrbufFirstIndexS(&font, "size="); + if (middleIndex == font.length) + { + ffStrbufAppendS(&terminalFont->error, "No font config found in st binary"); + return; + } + + uint32_t startIndex = ffStrbufPreviousIndexC(&font, middleIndex, '\n'); + if (startIndex == font.length) startIndex = 0; + uint32_t endIndex = ffStrbufNextIndexC(&font, middleIndex, '\n'); + + ffStrbufSubstrBefore(&font, endIndex); + ffStrbufSubstrAfter(&font, startIndex); } - ffStrbufSubstrAfter(&font, (uint32_t) (p + (sizeof("\0-f") - 1) - font.chars)); - ffStrbufRecalculateLength(&font); + // JetBrainsMono Nerd Font Mono:pixelsize=12:antialias=true:autohint=true - // `monospace:size=15` || `monospace` || `:size=15` - uint32_t index = ffStrbufFirstIndexS(&font, ":size="); + uint32_t index = ffStrbufFirstIndexC(&font, ':'); if (index != font.length) { - ffStrbufSetS(&size, font.chars + index + strlen(":size=")); + uint32_t sIndex = ffStrbufNextIndexS(&font, index + 1, "size="); + if (sIndex != font.length) + { + sIndex += strlen("size="); + uint32_t sIndexEnd = ffStrbufNextIndexC(&font, sIndex, ':'); + ffStrbufSetNS(&size, sIndexEnd - sIndex, font.chars + sIndex); + } ffStrbufSubstrBefore(&font, index); } else @@ -365,7 +399,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo else if(ffStrbufIgnCaseEqualS(&terminal->processName, "xterm")) detectXterm(terminalFont); else if(ffStrbufIgnCaseEqualS(&terminal->processName, "st")) - detectSt(terminalFont, terminal->pid); + detectSt(terminalFont, terminal); else if(ffStrbufIgnCaseEqualS(&terminal->processName, "warp")) detectWarp(terminalFont); else if(ffStrbufIgnCaseEqualS(&terminal->processName, "weston-terminal")) From 19b8849bfc39db6705d4e1a10c0a6957258114c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 11:05:00 +0800 Subject: [PATCH 04/59] Fastfetch: remove the long deprecated flag `--set` & ``-set-keyless` --- completions/bash | 2 -- src/common/commandoption.c | 23 ++-------------------- src/common/commandoption.h | 8 -------- src/common/option.h | 1 + src/data/help.json | 16 --------------- src/fastfetch.c | 40 +------------------------------------- 6 files changed, 4 insertions(+), 86 deletions(-) diff --git a/completions/bash b/completions/bash index 783ddefe0..f22266f38 100644 --- a/completions/bash +++ b/completions/bash @@ -227,8 +227,6 @@ __fastfetch_completion() "--separator" "-s" "--structure" - "--set" - "--set-keyless" "--player-name" "--percent-type" "--publicip-url" diff --git a/src/common/commandoption.c b/src/common/commandoption.c index d1824d0fc..3d9c93742 100644 --- a/src/common/commandoption.c +++ b/src/common/commandoption.c @@ -79,29 +79,10 @@ static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc) static void parseStructureCommand( const char* line, - FFlist* customValues, void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc), yyjson_mut_doc* jsonDoc ) { - // handle `--set` and `--set-keyless` - FF_LIST_FOR_EACH(FFCustomValue, customValue, *customValues) - { - if (ffStrbufEqualS(&customValue->key, line)) - { - __attribute__((__cleanup__(ffDestroyCustomOptions))) FFCustomOptions options; - ffInitCustomOptions(&options); - if (customValue->printKey) - ffStrbufAppend(&options.moduleArgs.key, &customValue->key); - ffStrbufAppend(&options.moduleArgs.outputFormat, &customValue->value); - if (__builtin_expect(jsonDoc != NULL, false)) - fn((FFModuleBaseInfo*) &options, jsonDoc); - else - ffPrintCustom(&options); - return; - } - } - if(ffCharIsEnglishAlphabet(line[0])) { for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules) @@ -134,7 +115,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc) if(instance.config.display.stat) ms = ffTimeGetTick(); - parseStructureCommand(data->structure.chars + startIndex, &data->customValues, genJsonResult, jsonDoc); + parseStructureCommand(data->structure.chars + startIndex, genJsonResult, jsonDoc); if(instance.config.display.stat) { @@ -177,7 +158,7 @@ void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc) uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':'); data->structure.chars[colonIndex] = '\0'; - parseStructureCommand(data->structure.chars + startIndex, &data->customValues, genJsonConfig, jsonDoc); + parseStructureCommand(data->structure.chars + startIndex, genJsonConfig, jsonDoc); startIndex = colonIndex + 1; } diff --git a/src/common/commandoption.h b/src/common/commandoption.h index 1736a4f12..f8cf12044 100644 --- a/src/common/commandoption.h +++ b/src/common/commandoption.h @@ -2,18 +2,10 @@ #include "fastfetch.h" -typedef struct FFCustomValue -{ - bool printKey; - FFstrbuf key; - FFstrbuf value; -} FFCustomValue; - // Things only needed by fastfetch typedef struct FFdata { FFstrbuf structure; - FFlist customValues; // List of FFCustomValue bool configLoaded; } FFdata; diff --git a/src/common/option.h b/src/common/option.h index a76c9e623..e7dba9b22 100644 --- a/src/common/option.h +++ b/src/common/option.h @@ -50,6 +50,7 @@ typedef struct FFModuleArgs FFstrbuf key; FFstrbuf keyColor; FFstrbuf outputFormat; + FFstrbuf outputColor; uint32_t keyWidth; } FFModuleArgs; diff --git a/src/data/help.json b/src/data/help.json index 2e2538e4f..aba92b334 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -481,22 +481,6 @@ "default": ": " } }, - { - "long": "set", - "desc": "Hard set the value of a key", - "remark": "Deprecated. Use \"Custom\" module instead", - "arg": { - "type": "key=value" - } - }, - { - "long": "set-keyless", - "desc": "Hard set the value of a key, but don't print the key or the separator", - "remark": "Deprecated. Use \"Custom\" module instead", - "arg": { - "type": "key=value" - } - }, { "long": "show-errors", "desc": "Print occurring errors", diff --git a/src/fastfetch.c b/src/fastfetch.c index a57b0a3f4..4283fd56a 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -695,38 +695,7 @@ static void parseCommand(FFdata* data, char* key, char* value) static void parseOption(FFdata* data, const char* key, const char* value) { - if(ffStrEqualsIgnCase(key, "--set") || ffStrEqualsIgnCase(key, "--set-keyless")) - { - FF_STRBUF_AUTO_DESTROY customValueStr = ffStrbufCreate(); - ffOptionParseString(key, value, &customValueStr); - uint32_t index = ffStrbufFirstIndexC(&customValueStr, '='); - if(index == 0 || index == customValueStr.length) - { - fprintf(stderr, "Error: usage: %s =\n", key); - exit(477); - } - - FF_STRBUF_AUTO_DESTROY customKey = ffStrbufCreateNS(index, customValueStr.chars); - - FFCustomValue* customValue = NULL; - FF_LIST_FOR_EACH(FFCustomValue, x, data->customValues) - { - if(ffStrbufEqual(&x->key, &customKey)) - { - ffStrbufDestroy(&x->key); - ffStrbufDestroy(&x->value); - customValue = x; - break; - } - } - if(!customValue) customValue = (FFCustomValue*) ffListAdd(&data->customValues); - ffStrbufInitMove(&customValue->key, &customKey); - ffStrbufSubstrAfter(&customValueStr, index); - ffStrbufInitMove(&customValue->value, &customValueStr); - customValue->printKey = key[5] == '\0'; - } - - else if(ffStrEqualsIgnCase(key, "-s") || ffStrEqualsIgnCase(key, "--structure")) + if(ffStrEqualsIgnCase(key, "-s") || ffStrEqualsIgnCase(key, "--structure")) ffOptionParseString(key, value, &data->structure); else if( @@ -868,7 +837,6 @@ int main(int argc, char** argv) //Data stores things only needed for the configuration of fastfetch FFdata data = { .structure = ffStrbufCreate(), - .customValues = ffListCreate(sizeof(FFCustomValue)), .configLoaded = false, }; @@ -883,10 +851,4 @@ int main(int argc, char** argv) writeConfigFile(&data, &instance.state.genConfigPath); ffStrbufDestroy(&data.structure); - FF_LIST_FOR_EACH(FFCustomValue, customValue, data.customValues) - { - ffStrbufDestroy(&customValue->key); - ffStrbufDestroy(&customValue->value); - } - ffListDestroy(&data.customValues); } From b80c30ace3a1433f1efcc9dd08b8459401539c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 11:06:38 +0800 Subject: [PATCH 05/59] Doc: default `--hide-cursor` to false --- src/data/help.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/help.json b/src/data/help.json index aba92b334..19b30d01c 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -505,7 +505,7 @@ "arg": { "type": "bool", "optional": true, - "default": true + "default": false } }, { From 64cb1bfdfd687df1f6a36aa77d0d2ce60ea812cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 14:33:00 +0800 Subject: [PATCH 06/59] Doc: remove duplicated entry --- completions/bash | 1 - 1 file changed, 1 deletion(-) diff --git a/completions/bash b/completions/bash index f22266f38..d3d6964c7 100644 --- a/completions/bash +++ b/completions/bash @@ -191,7 +191,6 @@ __fastfetch_completion() "--escape-bedrock" "--pipe" "--title-fqdn" - "--escape-bedrock" "--disk-folders" "--disk-show-external" "--disk-show-hidden" From 28805365135f59120fc969ceba034f9fd60935fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 15:01:57 +0800 Subject: [PATCH 07/59] Fastfetch: support `--module-ouput-color` (WIP) --- doc/json_schema.json | 83 +++++++++++++++++++++++++++++++++++++++++ src/common/jsonconfig.c | 5 +++ src/common/option.c | 12 ++++++ src/common/printing.c | 7 +++- src/options/display.c | 10 +++++ src/options/display.h | 1 + 6 files changed, 117 insertions(+), 1 deletion(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 65d80d8aa..8017c24f2 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -27,6 +27,10 @@ "description": "Output format of the module", "type": "string" }, + "outputColor": { + "description": "Output color of the module", + "$ref": "#/$defs/colors" + }, "percent": { "description": "Threshold of percentage colors", "type": "object", @@ -380,6 +384,10 @@ "title": { "description": "Set the color of the title", "$ref": "#/$defs/colors" + }, + "output": { + "description": "Set the color of the module output", + "$ref": "#/$defs/colors" } } } @@ -893,6 +901,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -927,6 +938,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -958,6 +972,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1002,6 +1019,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1035,6 +1055,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1142,6 +1165,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1166,6 +1192,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1215,6 +1244,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1275,6 +1307,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1307,6 +1342,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1335,6 +1373,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1361,6 +1402,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1406,6 +1450,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1468,6 +1515,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1494,6 +1544,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1531,6 +1584,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1564,6 +1620,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1618,6 +1677,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1648,6 +1710,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1683,6 +1748,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1735,6 +1803,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1761,6 +1832,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1808,6 +1882,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1846,6 +1923,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, @@ -1874,6 +1954,9 @@ "keyColor": { "$ref": "#/$defs/keyColor" }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, "keyWidth": { "$ref": "#/$defs/keyWidth" }, diff --git a/src/common/jsonconfig.c b/src/common/jsonconfig.c index de34b2b10..735b93032 100644 --- a/src/common/jsonconfig.c +++ b/src/common/jsonconfig.c @@ -22,6 +22,11 @@ bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* ffStrbufSetNS(&moduleArgs->outputFormat, (uint32_t) yyjson_get_len(val), yyjson_get_str(val)); return true; } + else if(ffStrEqualsIgnCase(key, "outputColor")) + { + ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor); + return true; + } else if(ffStrEqualsIgnCase(key, "keyColor")) { ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor); diff --git a/src/common/option.c b/src/common/option.c index 81efd69d1..9ebc2f33e 100644 --- a/src/common/option.c +++ b/src/common/option.c @@ -39,6 +39,16 @@ bool ffOptionParseModuleArgs(const char* argumentKey, const char* subKey, const ffOptionParseString(argumentKey, value, &result->outputFormat); return true; } + else if(ffStrEqualsIgnCase(subKey, "output-color")) + { + if(value == NULL) + { + fprintf(stderr, "Error: usage: %s \n", argumentKey); + exit(477); + } + ffOptionParseColor(value, &result->outputColor); + return true; + } else if(ffStrEqualsIgnCase(subKey, "key-color")) { if(value == NULL) @@ -180,6 +190,7 @@ void ffOptionInitModuleArg(FFModuleArgs* args) ffStrbufInit(&args->key); ffStrbufInit(&args->keyColor); ffStrbufInit(&args->outputFormat); + ffStrbufInit(&args->outputColor); args->keyWidth = 0; } @@ -188,4 +199,5 @@ void ffOptionDestroyModuleArg(FFModuleArgs* args) ffStrbufDestroy(&args->key); ffStrbufDestroy(&args->keyColor); ffStrbufDestroy(&args->outputFormat); + ffStrbufDestroy(&args->outputColor); } diff --git a/src/common/printing.c b/src/common/printing.c index 2eaf41a16..846d49122 100644 --- a/src/common/printing.c +++ b/src/common/printing.c @@ -49,8 +49,13 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu ffStrbufWriteTo(&instance.config.display.keyValueSeparator, stdout); if(!instance.config.display.pipe) + { fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout); - + if (moduleArgs->outputColor.length) + ffPrintColor(&moduleArgs->outputColor); + else if (instance.config.display.colorOutput.length) + ffPrintColor(&instance.config.display.colorOutput); + } if (!instance.config.display.pipe && !(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_WIDTH)) { diff --git a/src/options/display.c b/src/options/display.c index 2ef919fc0..292ced618 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -48,6 +48,9 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va const char* colorTitle = yyjson_get_str(yyjson_obj_get(val, "title")); if (colorTitle) ffOptionParseColor(colorTitle, &options->colorTitle); + const char* colorOutput = yyjson_get_str(yyjson_obj_get(val, "output")); + if (colorOutput) + ffOptionParseColor(colorOutput, &options->colorOutput); } else return "display.color must be either a string or an object"; @@ -244,6 +247,11 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key optionCheckString(key, value, &options->colorTitle); ffOptionParseColor(value, &options->colorTitle); } + else if(ffStrEqualsIgnCase(subkey, "output")) + { + optionCheckString(key, value, &options->colorOutput); + ffOptionParseColor(value, &options->colorOutput); + } else return false; } @@ -346,6 +354,7 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) { ffStrbufInit(&options->colorKeys); ffStrbufInit(&options->colorTitle); + ffStrbufInit(&options->colorOutput); options->brightColor = true; ffStrbufInitStatic(&options->keyValueSeparator, ": "); @@ -389,6 +398,7 @@ void ffOptionsDestroyDisplay(FFOptionsDisplay* options) { ffStrbufDestroy(&options->colorKeys); ffStrbufDestroy(&options->colorTitle); + ffStrbufDestroy(&options->colorOutput); ffStrbufDestroy(&options->keyValueSeparator); ffStrbufDestroy(&options->barCharElapsed); ffStrbufDestroy(&options->barCharTotal); diff --git a/src/options/display.h b/src/options/display.h index eb3a7c68c..b29df43eb 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -21,6 +21,7 @@ typedef struct FFOptionsDisplay //If one of those is empty, ffLogoPrint will set them FFstrbuf colorKeys; FFstrbuf colorTitle; + FFstrbuf colorOutput; bool brightColor; From 459f159b1b597e1cd35d73ecc09c5f4a950be627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 15:25:59 +0800 Subject: [PATCH 08/59] Fastfetch: revert to module color after printing custom colors --- src/common/percent.c | 18 +++++++++++++++--- src/common/percent.h | 5 +++-- src/common/temps.c | 8 +++++++- src/common/temps.h | 3 ++- src/modules/battery/battery.c | 10 +++++----- src/modules/bluetooth/bluetooth.c | 4 ++-- src/modules/brightness/brightness.c | 6 +++--- src/modules/cpu/cpu.c | 4 ++-- src/modules/cpuusage/cpuusage.c | 12 ++++++------ src/modules/disk/disk.c | 8 ++++---- src/modules/gamepad/gamepad.c | 4 ++-- src/modules/gpu/gpu.c | 6 +++--- src/modules/memory/memory.c | 6 +++--- src/modules/physicaldisk/physicaldisk.c | 4 ++-- src/modules/sound/sound.c | 6 +++--- src/modules/swap/swap.c | 10 +++++----- 16 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/common/percent.c b/src/common/percent.c index a80f3ed10..14ab93f55 100644 --- a/src/common/percent.c +++ b/src/common/percent.c @@ -6,7 +6,15 @@ #include "util/textModifier.h" #include "util/stringUtils.h" -void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFColorRangeConfig config) +static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module) +{ + if (module->outputColor.length) + ffStrbufAppendF(buffer, "\e[%sm", module->outputColor.chars); + else if (instance.config.display.colorOutput.length) + ffStrbufAppendF(buffer, "\e[%sm", instance.config.display.colorOutput.chars); +} + +void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFColorRangeConfig config, const FFModuleArgs* module) { uint8_t green = config.green, yellow = config.yellow; assert(green <= 100 && yellow <= 100); @@ -66,16 +74,19 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFColorRangeConfig con if(options->barBorder) { if(!options->pipe) - ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m ]"); + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m ]");\ else ffStrbufAppendS(buffer, " ]"); } if(!options->pipe) + { ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + appendOutputColor(buffer, module); + } } -void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFColorRangeConfig config, bool parentheses) +void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFColorRangeConfig config, bool parentheses, const FFModuleArgs* module) { uint8_t green = config.green, yellow = config.yellow; assert(green <= 100 && yellow <= 100); @@ -120,6 +131,7 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFColorRangeConfig con if (colored && !options->pipe) { ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + appendOutputColor(buffer, module); } if (parentheses) diff --git a/src/common/percent.h b/src/common/percent.h index 6d7c6b2e8..8ae87708c 100644 --- a/src/common/percent.h +++ b/src/common/percent.h @@ -2,6 +2,7 @@ #include "util/FFstrbuf.h" #include "common/parsing.h" +#include "common/option.h" enum { @@ -21,8 +22,8 @@ enum // [yellow, green): print yellow // [0, yellow): print red -void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFColorRangeConfig config); -void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFColorRangeConfig config, bool parentheses); +void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFColorRangeConfig config, const FFModuleArgs* module); +void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFColorRangeConfig config, bool parentheses, const FFModuleArgs* module); typedef struct yyjson_val yyjson_val; typedef struct yyjson_mut_doc yyjson_mut_doc; diff --git a/src/common/temps.c b/src/common/temps.c index d72f46f0e..09eb955d7 100644 --- a/src/common/temps.c +++ b/src/common/temps.c @@ -3,7 +3,7 @@ #include "util/textModifier.h" #include "util/stringUtils.h" -void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config) +void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module) { if (celsius != celsius) // ignores NaN return; @@ -51,7 +51,13 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi } if (!options->pipe) + { ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + if (module->outputColor.length) + ffStrbufAppendF(buffer, "\e[%sm", module->outputColor.chars); + else if (instance.config.display.colorOutput.length) + ffStrbufAppendF(buffer, "\e[%sm", instance.config.display.colorOutput.chars); + } } bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config) diff --git a/src/common/temps.h b/src/common/temps.h index bbbc74766..2236713d2 100644 --- a/src/common/temps.h +++ b/src/common/temps.h @@ -1,8 +1,9 @@ #pragma once #include "common/parsing.h" +#include "common/option.h" -void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config); +void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module); bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config); bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config); void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index ee82e42d5..918fc7819 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -25,7 +25,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, result->capacity, options->percent); + ffPercentAppendBar(&str, result->capacity, options->percent, &options->moduleArgs); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -33,7 +33,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, result->capacity, options->percent, str.length > 0); + ffPercentAppendNum(&str, result->capacity, options->percent, str.length > 0, &options->moduleArgs); } } @@ -50,7 +50,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendS(&str, " - "); - ffTempsAppendNum(result->temperature, &str, options->tempConfig); + ffTempsAppendNum(result->temperature, &str, options->tempConfig, &options->moduleArgs); } ffStrbufPutTo(&str, stdout); @@ -58,9 +58,9 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin else { FF_STRBUF_AUTO_DESTROY capacityStr = ffStrbufCreate(); - ffPercentAppendNum(&capacityStr, result->capacity, options->percent, false); + ffPercentAppendNum(&capacityStr, result->capacity, options->percent, false, &options->moduleArgs); FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate(); - ffTempsAppendNum(result->temperature, &tempStr, options->tempConfig); + ffTempsAppendNum(result->temperature, &tempStr, options->tempConfig, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_BATTERY_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_BATTERY_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index c638252e7..6beef48b7 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -19,7 +19,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0, &options->moduleArgs); } if (!device->connected) @@ -30,7 +30,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->battery, options->percent, false); + ffPercentAppendNum(&percentageStr, device->battery, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_BLUETOOTH_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, diff --git a/src/modules/brightness/brightness.c b/src/modules/brightness/brightness.c index f5defe068..8e2aff84d 100644 --- a/src/modules/brightness/brightness.c +++ b/src/modules/brightness/brightness.c @@ -52,7 +52,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percent, options->percent); + ffPercentAppendBar(&str, percent, options->percent, &options->moduleArgs); } if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -60,7 +60,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, percent, options->percent, str.length > 0); + ffPercentAppendNum(&str, percent, options->percent, str.length > 0, &options->moduleArgs); } ffStrbufPutTo(&str, stdout); @@ -68,7 +68,7 @@ void ffPrintBrightness(FFBrightnessOptions* options) else { FF_STRBUF_AUTO_DESTROY valueStr = ffStrbufCreate(); - ffPercentAppendNum(&valueStr, percent, options->percent, false); + ffPercentAppendNum(&valueStr, percent, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_BRIGHTNESS_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &valueStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &item->name}, diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 5da296f30..43ec9fe9a 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -57,7 +57,7 @@ void ffPrintCPU(FFCPUOptions* options) if(cpu.temperature == cpu.temperature) //FF_CPU_TEMP_UNSET { ffStrbufAppendS(&str, " - "); - ffTempsAppendNum(cpu.temperature, &str, options->tempConfig); + ffTempsAppendNum(cpu.temperature, &str, options->tempConfig, &options->moduleArgs); } ffStrbufPutTo(&str, stdout); @@ -65,7 +65,7 @@ void ffPrintCPU(FFCPUOptions* options) else { FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate(); - ffTempsAppendNum(cpu.temperature, &tempStr, options->tempConfig); + ffTempsAppendNum(cpu.temperature, &tempStr, options->tempConfig, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_CPU_NUM_FORMAT_ARGS, ((FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &cpu.name}, {FF_FORMAT_ARG_TYPE_STRBUF, &cpu.vendor}, diff --git a/src/modules/cpuusage/cpuusage.c b/src/modules/cpuusage/cpuusage.c index 0909763f7..aa3bfccac 100644 --- a/src/modules/cpuusage/cpuusage.c +++ b/src/modules/cpuusage/cpuusage.c @@ -52,12 +52,12 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) if (!options->separate) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) - ffPercentAppendBar(&str, avgValue, options->percent); + ffPercentAppendBar(&str, avgValue, options->percent, &options->moduleArgs); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, avgValue, options->percent, str.length > 0); + ffPercentAppendNum(&str, avgValue, options->percent, str.length > 0, &options->moduleArgs); } } else @@ -66,7 +66,7 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, *percent, options->percent, false); + ffPercentAppendNum(&str, *percent, options->percent, false, &options->moduleArgs); } } ffStrbufPutTo(&str, stdout); @@ -74,11 +74,11 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options) else { FF_STRBUF_AUTO_DESTROY avgStr = ffStrbufCreate(); - ffPercentAppendNum(&avgStr, avgValue, options->percent, false); + ffPercentAppendNum(&avgStr, avgValue, options->percent, false, &options->moduleArgs); FF_STRBUF_AUTO_DESTROY minStr = ffStrbufCreate(); - ffPercentAppendNum(&minStr, minValue, options->percent, false); + ffPercentAppendNum(&minStr, minValue, options->percent, false, &options->moduleArgs); FF_STRBUF_AUTO_DESTROY maxStr = ffStrbufCreate(); - ffPercentAppendNum(&maxStr, maxValue, options->percent, false); + ffPercentAppendNum(&maxStr, maxValue, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_CPUUSAGE_NUM_FORMAT_ARGS, ((FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &avgStr}, {FF_FORMAT_ARG_TYPE_STRBUF, &maxStr}, diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index e44290479..8942754be 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -60,7 +60,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, bytesPercentage, options->percent); + ffPercentAppendBar(&str, bytesPercentage, options->percent, &options->moduleArgs); ffStrbufAppendC(&str, ' '); } @@ -69,7 +69,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { - ffPercentAppendNum(&str, bytesPercentage, options->percent, str.length > 0); + ffPercentAppendNum(&str, bytesPercentage, options->percent, str.length > 0, &options->moduleArgs); ffStrbufAppendC(&str, ' '); } } @@ -105,10 +105,10 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk) else { FF_STRBUF_AUTO_DESTROY bytesPercentageStr = ffStrbufCreate(); - ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, options->percent, false); + ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, options->percent, false, &options->moduleArgs); FF_STRBUF_AUTO_DESTROY filesPercentageStr = ffStrbufCreate(); double filesPercentage = disk->filesTotal > 0 ? ((double) disk->filesUsed / (double) disk->filesTotal) * 100.0 : 0; - ffPercentAppendNum(&filesPercentageStr, filesPercentage, options->percent, false); + ffPercentAppendNum(&filesPercentageStr, filesPercentage, options->percent, false, &options->moduleArgs); bool isExternal = !!(disk->type & FF_DISK_VOLUME_TYPE_EXTERNAL_BIT); bool isHidden = !!(disk->type & FF_DISK_VOLUME_TYPE_HIDDEN_BIT); diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index d14beb279..bc5417d58 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -19,14 +19,14 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if (buffer.length) ffStrbufAppendC(&buffer, ' '); - ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0); + ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0, &options->moduleArgs); } ffStrbufPutTo(&buffer, stdout); } else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->battery, options->percent, false); + ffPercentAppendNum(&percentageStr, device->battery, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_GAMEPAD_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index aa63b16dd..47d9fa91e 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -45,7 +45,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu if(gpu->temperature == gpu->temperature) //FF_GPU_TEMP_UNSET { ffStrbufAppendS(&output, " - "); - ffTempsAppendNum(gpu->temperature, &output, options->tempConfig); + ffTempsAppendNum(gpu->temperature, &output, options->tempConfig, &options->moduleArgs); } if(gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET && gpu->dedicated.total != 0) @@ -61,7 +61,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu if(gpu->dedicated.used != FF_GPU_VMEM_SIZE_UNSET) { ffStrbufAppendS(&output, ", "); - ffPercentAppendNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, options->percent, false); + ffPercentAppendNum(&output, (double) gpu->dedicated.used / (double) gpu->dedicated.total * 100.0, options->percent, false, &options->moduleArgs); } ffStrbufAppendC(&output, ')'); } @@ -74,7 +74,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu else { FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate(); - ffTempsAppendNum(gpu->temperature, &tempStr, options->tempConfig); + ffTempsAppendNum(gpu->temperature, &tempStr, options->tempConfig, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_GPU_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_GPU_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->name}, diff --git a/src/modules/memory/memory.c b/src/modules/memory/memory.c index 52ec97939..9f143d0aa 100644 --- a/src/modules/memory/memory.c +++ b/src/modules/memory/memory.c @@ -40,7 +40,7 @@ void ffPrintMemory(FFMemoryOptions* options) if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percentage, options->percent); + ffPercentAppendBar(&str, percentage, options->percent, &options->moduleArgs); ffStrbufAppendC(&str, ' '); } @@ -48,7 +48,7 @@ void ffPrintMemory(FFMemoryOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffPercentAppendNum(&str, percentage, options->percent, str.length > 0); + ffPercentAppendNum(&str, percentage, options->percent, str.length > 0, &options->moduleArgs); ffStrbufTrimRight(&str, ' '); ffStrbufPutTo(&str, stdout); @@ -57,7 +57,7 @@ void ffPrintMemory(FFMemoryOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, percentage, options->percent, false); + ffPercentAppendNum(&percentageStr, percentage, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_MEMORY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_MEMORY_NUM_FORMAT_ARGS, ((FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, diff --git a/src/modules/physicaldisk/physicaldisk.c b/src/modules/physicaldisk/physicaldisk.c index 0b9eff49e..73380bcdf 100644 --- a/src/modules/physicaldisk/physicaldisk.c +++ b/src/modules/physicaldisk/physicaldisk.c @@ -97,14 +97,14 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options) if(buffer.length > 0) ffStrbufAppendS(&buffer, " - "); - ffTempsAppendNum(dev->temperature, &buffer, options->tempConfig); + ffTempsAppendNum(dev->temperature, &buffer, options->tempConfig, &options->moduleArgs); } ffStrbufPutTo(&buffer, stdout); } else { FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate(); - ffTempsAppendNum(dev->temperature, &tempStr, options->tempConfig); + ffTempsAppendNum(dev->temperature, &tempStr, options->tempConfig, &options->moduleArgs); if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE) readOnlyType = "Read-write"; FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_PHYSICALDISK_NUM_FORMAT_ARGS, ((FFformatarg[]){ diff --git a/src/modules/sound/sound.c b/src/modules/sound/sound.c index 0cea6b4e0..9b9437be9 100644 --- a/src/modules/sound/sound.c +++ b/src/modules/sound/sound.c @@ -24,7 +24,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffPercentAppendBar(&str, device->volume, options->percent); + ffPercentAppendBar(&str, device->volume, options->percent, &options->moduleArgs); } if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) @@ -32,7 +32,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui if (str.length) ffStrbufAppendC(&str, ' '); - ffPercentAppendNum(&str, device->volume, options->percent, str.length > 0); + ffPercentAppendNum(&str, device->volume, options->percent, str.length > 0, &options->moduleArgs); } } @@ -47,7 +47,7 @@ static void printDevice(FFSoundOptions* options, const FFSoundDevice* device, ui else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, device->volume, options->percent, false); + ffPercentAppendNum(&percentageStr, device->volume, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_SOUND_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_SOUND_NUM_FORMAT_ARGS, ((FFformatarg[]) { {FF_FORMAT_ARG_TYPE_BOOL, &device->main}, diff --git a/src/modules/swap/swap.c b/src/modules/swap/swap.c index 36b4c8df6..4b68c4709 100644 --- a/src/modules/swap/swap.c +++ b/src/modules/swap/swap.c @@ -37,19 +37,19 @@ void ffPrintSwap(FFSwapOptions* options) { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, 0, options->percent); + ffPercentAppendBar(&str, 0, options->percent, &options->moduleArgs); ffStrbufAppendC(&str, ' '); } if(!(instance.config.display.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) ffStrbufAppendS(&str, "Disabled"); else - ffPercentAppendNum(&str, 0, options->percent, str.length > 0); + ffPercentAppendNum(&str, 0, options->percent, str.length > 0, &options->moduleArgs); } else { if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT) { - ffPercentAppendBar(&str, percentage, options->percent); + ffPercentAppendBar(&str, percentage, options->percent, &options->moduleArgs); ffStrbufAppendC(&str, ' '); } @@ -57,7 +57,7 @@ void ffPrintSwap(FFSwapOptions* options) ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffPercentAppendNum(&str, percentage, options->percent, str.length > 0); + ffPercentAppendNum(&str, percentage, options->percent, str.length > 0, &options->moduleArgs); } ffStrbufTrimRight(&str, ' '); @@ -66,7 +66,7 @@ void ffPrintSwap(FFSwapOptions* options) else { FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate(); - ffPercentAppendNum(&percentageStr, percentage, options->percent, false); + ffPercentAppendNum(&percentageStr, percentage, options->percent, false, &options->moduleArgs); FF_PRINT_FORMAT_CHECKED(FF_SWAP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_SWAP_NUM_FORMAT_ARGS, ((FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty}, {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty}, From 9cb08d115a9341666b32eef49164e556a120f0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 16:11:16 +0800 Subject: [PATCH 09/59] Separator: add `--separator-output-color` --- doc/json_schema.json | 3 +++ src/data/help.json | 8 ++++++++ src/modules/separator/option.h | 1 + src/modules/separator/separator.c | 14 ++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/doc/json_schema.json b/doc/json_schema.json index 8017c24f2..82ab9c5f0 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1772,6 +1772,9 @@ "description": "Set the string to be printed", "type": "string", "default": "-" + }, + "outputColor": { + "$ref": "#/$defs/outputColor" } } }, diff --git a/src/data/help.json b/src/data/help.json index 19b30d01c..f80316c6e 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -921,6 +921,14 @@ "default": "-" } }, + { + "long": "separator-output-color", + "desc": "Set the color of the separator module", + "arg": { + "type": "color", + "default": "default" + } + }, { "long": "disk-folders", "desc": "A colon (semicolon on Windows) separated list of folder paths to be detected", diff --git a/src/modules/separator/option.h b/src/modules/separator/option.h index c858e6193..6f4d49953 100644 --- a/src/modules/separator/option.h +++ b/src/modules/separator/option.h @@ -9,4 +9,5 @@ typedef struct FFSeparatorOptions FFModuleBaseInfo moduleInfo; FFstrbuf string; + FFstrbuf outputColor; } FFSeparatorOptions; diff --git a/src/modules/separator/separator.c b/src/modules/separator/separator.c index 7f8ac41d3..cf2be92bf 100644 --- a/src/modules/separator/separator.c +++ b/src/modules/separator/separator.c @@ -43,6 +43,8 @@ void ffPrintSeparator(FFSeparatorOptions* options) + (fqdn ? platform->hostName.length : ffStrbufFirstIndexC(&platform->hostName, '.')); // host name ffLogoPrintLine(); + if(options->outputColor.length) + ffPrintColor(&options->outputColor); if(__builtin_expect(options->string.length == 1, 1)) { ffPrintCharTimes(options->string.chars[0], titleLength); @@ -97,6 +99,12 @@ bool ffParseSeparatorCommandOptions(FFSeparatorOptions* options, const char* key return true; } + if (ffStrEqualsIgnCase(subKey, "output-color")) + { + ffOptionParseColor(value, &options->outputColor); + return true; + } + return false; } @@ -116,6 +124,12 @@ void ffParseSeparatorJsonObject(FFSeparatorOptions* options, yyjson_val* module) continue; } + if (ffStrEndsWithIgnCase(key, "outputColor")) + { + ffOptionParseColor(yyjson_get_str(val), &options->outputColor); + continue; + } + ffPrintError(FF_SEPARATOR_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", key); } } From 4204cfc500308483c5fccabb077854b0ad2255f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 16:17:05 +0800 Subject: [PATCH 10/59] Doc: update help message for `--module-output-color` --- src/data/help.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/data/help.json b/src/data/help.json index f80316c6e..ed7b3adba 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -436,7 +436,7 @@ { "long": "color-keys", "desc": "Set the color of the keys", - "remark": "See `-h color` for the list of available colors", + "remark": "Doesn't affect module Title, Separator and Colors. See `-h color` for the list of available colors", "arg": { "type": "color" } @@ -449,6 +449,14 @@ "type": "color" } }, + { + "long": "color-output", + "desc": "Set the color of module output", + "remark": "See `-h color` for the list of available colors", + "arg": { + "type": "color" + } + }, { "long": "color", "desc": "Set the color of both the keys and title", @@ -1506,6 +1514,14 @@ }, "pseudo": true }, + { + "long": "-output-color", + "desc": "Override the global \"--color-output\" option for each specific module", + "arg": { + "type": "color" + }, + "pseudo": true + }, { "long": "-key-width", "desc": "Override the global \"--key-width\" option for each specific module", From 738daa1c7770f1935d898e6c37c901003b0fae7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 16:41:33 +0800 Subject: [PATCH 11/59] Loadavg: new module --- CMakeLists.txt | 8 +- doc/json_schema.json | 27 +++++ src/common/modules.c | 1 + src/detection/loadavg/loadavg.h | 5 + src/detection/loadavg/loadavg_linux.c | 8 ++ src/detection/loadavg/loadavg_nosupport.c | 6 ++ src/modules/loadavg/loadavg.c | 114 ++++++++++++++++++++++ src/modules/loadavg/loadavg.h | 9 ++ src/modules/loadavg/option.h | 11 +++ src/modules/modules.h | 1 + src/modules/options.h | 1 + src/options/modules.c | 2 + src/options/modules.h | 1 + 13 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/detection/loadavg/loadavg.h create mode 100644 src/detection/loadavg/loadavg_linux.c create mode 100644 src/detection/loadavg/loadavg_nosupport.c create mode 100644 src/modules/loadavg/loadavg.c create mode 100644 src/modules/loadavg/loadavg.h create mode 100644 src/modules/loadavg/option.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 89649978b..031b20422 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,7 @@ set(LIBFASTFETCH_SRC src/modules/gamepad/gamepad.c src/modules/kernel/kernel.c src/modules/lm/lm.c + src/modules/loadavg/loadavg.c src/modules/locale/locale.c src/modules/localip/localip.c src/modules/memory/memory.c @@ -417,6 +418,7 @@ if(LINUX) src/detection/icons/icons_linux.c src/detection/libc/libc_linux.c src/detection/lm/lm_linux.c + src/detection/loadavg/loadavg_linux.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_linux.c @@ -472,6 +474,7 @@ elseif(ANDROID) src/detection/icons/icons_nosupport.c src/detection/libc/libc_android.c src/detection/lm/lm_nosupport.c + src/detection/loadavg/loadavg_linux.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_nosupport.c @@ -538,6 +541,7 @@ elseif(BSD) src/detection/lm/lm_linux.c src/detection/icons/icons_linux.c src/detection/libc/libc_bsd.c + src/detection/loadavg/loadavg_linux.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_bsd.c @@ -592,8 +596,9 @@ elseif(APPLE) src/detection/gpu/gpu_apple.c src/detection/gpu/gpu_apple.m src/detection/host/host_apple.c - src/detection/lm/lm_nosupport.c src/detection/icons/icons_nosupport.c + src/detection/lm/lm_nosupport.c + src/detection/loadavg/loadavg_linux.c src/detection/libc/libc_apple.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c @@ -651,6 +656,7 @@ elseif(WIN32) src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp src/detection/lm/lm_nosupport.c + src/detection/loadavg/loadavg_nosupport.c src/detection/locale/locale_windows.c src/detection/localip/localip_windows.c src/detection/gamepad/gamepad_windows.c diff --git a/doc/json_schema.json b/doc/json_schema.json index 82ab9c5f0..ef71c7bda 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -702,6 +702,7 @@ "icons", "kernel", "lm", + "loadavg", "locale", "localip", "media", @@ -1555,6 +1556,32 @@ } } }, + { + "title": "Loadavg", + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "const": "loadavg", + "description": "Print system load averages" + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + } + }, { "title": "NetIO", "type": "object", diff --git a/src/common/modules.c b/src/common/modules.c index 718a8114a..1c4d43e4f 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -71,6 +71,7 @@ static FFModuleBaseInfo* K[] = { static FFModuleBaseInfo* L[] = { (void*) &instance.config.modules.lm, + (void*) &instance.config.modules.loadavg, (void*) &instance.config.modules.locale, (void*) &instance.config.modules.localIP, NULL, diff --git a/src/detection/loadavg/loadavg.h b/src/detection/loadavg/loadavg.h new file mode 100644 index 000000000..4cfa696ed --- /dev/null +++ b/src/detection/loadavg/loadavg.h @@ -0,0 +1,5 @@ +#pragma once + +#include "fastfetch.h" + +const char* ffDetectLoadavg(double result[3]); diff --git a/src/detection/loadavg/loadavg_linux.c b/src/detection/loadavg/loadavg_linux.c new file mode 100644 index 000000000..69a38e7db --- /dev/null +++ b/src/detection/loadavg/loadavg_linux.c @@ -0,0 +1,8 @@ +#include "detection/loadavg/loadavg.h" + +#include + +const char* ffDetectLoadavg(double result[3]) +{ + return getloadavg(result, 3) < 0 ? "getloadavg() failed" : NULL; +} diff --git a/src/detection/loadavg/loadavg_nosupport.c b/src/detection/loadavg/loadavg_nosupport.c new file mode 100644 index 000000000..2d51217a5 --- /dev/null +++ b/src/detection/loadavg/loadavg_nosupport.c @@ -0,0 +1,6 @@ +#include "detection/loadavg/loadavg.h" + +const char* ffDetectLoadavg(FF_MAYBE_UNUSED double result[3]) +{ + return "Not supported on this platform"; +} diff --git a/src/modules/loadavg/loadavg.c b/src/modules/loadavg/loadavg.c new file mode 100644 index 000000000..4cba6f93d --- /dev/null +++ b/src/modules/loadavg/loadavg.c @@ -0,0 +1,114 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "detection/loadavg/loadavg.h" +#include "modules/loadavg/loadavg.h" +#include "util/stringUtils.h" + +#define FF_LOADAVG_NUM_FORMAT_ARGS 3 + +void ffPrintLoadavg(FFLoadavgOptions* options) +{ + double result[3] = { 0.0 / 0.0, 0.0 / 0.0, 0.0 / 0.0 }; + + const char* error = ffDetectLoadavg(result); + if(error) + { + ffPrintError(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + return; + } + + if(options->moduleArgs.outputFormat.length == 0) + { + ffPrintLogoAndKey(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + printf("%.2f, %.2f, %.2f\n", result[0], result[1], result[2]); + } + else + { + FF_PRINT_FORMAT_CHECKED(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_LOADAVG_NUM_FORMAT_ARGS, ((FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_DOUBLE, &result[0]}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &result[1]}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &result[2]}, + })); + } +} + +bool ffParseLoadavgCommandOptions(FFLoadavgOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_LOADAVG_MODULE_NAME); + if (!subKey) return false; + if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) + return true; + + return false; +} + +void ffParseLoadavgJsonObject(FFLoadavgOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + ffPrintError(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); + } +} + +void ffGenerateLoadavgJsonConfig(FFLoadavgOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyLoadavgOptions))) FFLoadavgOptions defaultOptions; + ffInitLoadavgOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); +} + +void ffGenerateLoadavgJsonResult(FF_MAYBE_UNUSED FFLoadavgOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + double result[3] = { 0.0 / 0.0, 0.0 / 0.0, 0.0 / 0.0 }; + + const char* error = ffDetectLoadavg(result); + if(error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + return; + } + + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); + for (size_t i = 0; i < 3; i++) + yyjson_mut_arr_add_real(doc, arr, result[i]); +} + +void ffPrintLoadavgHelpFormat(void) +{ + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_LOADAVG_MODULE_NAME, "{1}, {2}, {3}", FF_LOADAVG_NUM_FORMAT_ARGS, ((const char* []) { + "Load average over 1min", + "Load average over 5min", + "Load average over 15min", + })); +} + +void ffInitLoadavgOptions(FFLoadavgOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_LOADAVG_MODULE_NAME, + "Print system load averages", + ffParseLoadavgCommandOptions, + ffParseLoadavgJsonObject, + ffPrintLoadavg, + ffGenerateLoadavgJsonResult, + ffPrintLoadavgHelpFormat, + ffGenerateLoadavgJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs); +} + +void ffDestroyLoadavgOptions(FFLoadavgOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); +} diff --git a/src/modules/loadavg/loadavg.h b/src/modules/loadavg/loadavg.h new file mode 100644 index 000000000..1d546f57b --- /dev/null +++ b/src/modules/loadavg/loadavg.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_LOADAVG_MODULE_NAME "Loadavg" + +void ffPrintLoadavg(FFLoadavgOptions* options); +void ffInitLoadavgOptions(FFLoadavgOptions* options); +void ffDestroyLoadavgOptions(FFLoadavgOptions* options); diff --git a/src/modules/loadavg/option.h b/src/modules/loadavg/option.h new file mode 100644 index 000000000..d61f04d7c --- /dev/null +++ b/src/modules/loadavg/option.h @@ -0,0 +1,11 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" + +typedef struct FFLoadavgOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; +} FFLoadavgOptions; diff --git a/src/modules/modules.h b/src/modules/modules.h index 84c7f9dec..cfff529c9 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -28,6 +28,7 @@ #include "modules/icons/icons.h" #include "modules/kernel/kernel.h" #include "modules/lm/lm.h" +#include "modules/loadavg/loadavg.h" #include "modules/locale/locale.h" #include "modules/localip/localip.h" #include "modules/media/media.h" diff --git a/src/modules/options.h b/src/modules/options.h index 1e998396a..af4ec7e99 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -27,6 +27,7 @@ #include "modules/gpu/option.h" #include "modules/icons/option.h" #include "modules/kernel/option.h" +#include "modules/loadavg/option.h" #include "modules/locale/option.h" #include "modules/lm/option.h" #include "modules/localip/option.h" diff --git a/src/options/modules.c b/src/options/modules.c index 0de31e727..a64ca5ef9 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -29,6 +29,7 @@ void ffOptionsInitModules(FFOptionsModules* options) ffInitIconsOptions(&options->icons); ffInitKernelOptions(&options->kernel); ffInitLMOptions(&options->lm); + ffInitLoadavgOptions(&options->loadavg); ffInitLocalIpOptions(&options->localIP); ffInitLocaleOptions(&options->locale); ffInitMediaOptions(&options->media); @@ -93,6 +94,7 @@ void ffOptionsDestroyModules(FFOptionsModules* options) ffDestroyIconsOptions(&options->icons); ffDestroyKernelOptions(&options->kernel); ffDestroyLMOptions(&options->lm); + ffDestroyLoadavgOptions(&options->loadavg); ffDestroyLocalIpOptions(&options->localIP); ffDestroyLocaleOptions(&options->locale); ffDestroyMediaOptions(&options->media); diff --git a/src/options/modules.h b/src/options/modules.h index 7c19db986..d04f65071 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -30,6 +30,7 @@ typedef struct FFOptionsModules FFIconsOptions icons; FFKernelOptions kernel; FFLMOptions lm; + FFLoadavgOptions loadavg; FFLocalIpOptions localIP; FFLocaleOptions locale; FFMediaOptions media; From df3fa6f8a8a89a6d6318404ce9b4c1e697d9b944 Mon Sep 17 00:00:00 2001 From: Quinten Van Damme <58103738+quintenvandamme@users.noreply.github.com> Date: Wed, 8 May 2024 13:30:25 +0200 Subject: [PATCH 12/59] Logo: Fix dahliaOS detection (#906) --- src/logo/builtin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 263e714dc..90e9deca6 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -1115,9 +1115,9 @@ static const FFlogo C[] = { }; static const FFlogo D[] = { - // Dahlia + // DahliaOS { - .names = {"dahlia"}, + .names = {"dahliaOS"}, .lines = FASTFETCH_DATATEXT_LOGO_DAHLIA, .colors = { FF_COLOR_FG_RED, From 852c6abf2e5b106d6f5138d1833b964c1ecbb99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 8 May 2024 21:54:13 +0800 Subject: [PATCH 13/59] Loadavg (Android): fix compiling --- CMakeLists.txt | 4 ++-- src/detection/loadavg/loadavg_bsd.c | 8 ++++++++ src/detection/loadavg/loadavg_linux.c | 27 +++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/detection/loadavg/loadavg_bsd.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 031b20422..8334482f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,7 +541,7 @@ elseif(BSD) src/detection/lm/lm_linux.c src/detection/icons/icons_linux.c src/detection/libc/libc_bsd.c - src/detection/loadavg/loadavg_linux.c + src/detection/loadavg/loadavg_bsd.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_bsd.c @@ -598,7 +598,7 @@ elseif(APPLE) src/detection/host/host_apple.c src/detection/icons/icons_nosupport.c src/detection/lm/lm_nosupport.c - src/detection/loadavg/loadavg_linux.c + src/detection/loadavg/loadavg_bsd.c src/detection/libc/libc_apple.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c diff --git a/src/detection/loadavg/loadavg_bsd.c b/src/detection/loadavg/loadavg_bsd.c new file mode 100644 index 000000000..69a38e7db --- /dev/null +++ b/src/detection/loadavg/loadavg_bsd.c @@ -0,0 +1,8 @@ +#include "detection/loadavg/loadavg.h" + +#include + +const char* ffDetectLoadavg(double result[3]) +{ + return getloadavg(result, 3) < 0 ? "getloadavg() failed" : NULL; +} diff --git a/src/detection/loadavg/loadavg_linux.c b/src/detection/loadavg/loadavg_linux.c index 69a38e7db..47085a744 100644 --- a/src/detection/loadavg/loadavg_linux.c +++ b/src/detection/loadavg/loadavg_linux.c @@ -1,8 +1,31 @@ #include "detection/loadavg/loadavg.h" +#include "common/io/io.h" -#include +#include const char* ffDetectLoadavg(double result[3]) { - return getloadavg(result, 3) < 0 ? "getloadavg() failed" : NULL; + #ifndef __ANDROID__ // cat: /proc/loadavg: Permission denied + + // Don't use syscall for container compatibility. #620 + char buf[64]; + ssize_t nRead = ffReadFileData("/proc/uptime", sizeof(buf) - 1, buf); + if (nRead > 0) + { + buf[nRead] = '\0'; + + if (sscanf(buf, "%lf %lf %lf", &result[0], &result[1], &result[2]) == 3) + return NULL; + } + + #endif + + // getloadavg requires higher ANDROID_API version + struct sysinfo si; + if (sysinfo(&si) < 0) + return "sysinfo() failed"; + + for (int i = 0; i < 3; i++) + result[i] = (double) si.loads[i] / (1 << SI_LOAD_SHIFT); + return NULL; } From 31c433b353eb449618129e532627d822d52ce3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 08:46:52 +0800 Subject: [PATCH 14/59] Display: rename `--temperature-*` to `--temp-*` as stated in help messages Fix #908 --- src/common/temps.c | 2 +- src/options/display.c | 14 +++++++------- src/options/display.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common/temps.c b/src/common/temps.c index 09eb955d7..e413d4c5c 100644 --- a/src/common/temps.c +++ b/src/common/temps.c @@ -37,7 +37,7 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi } } - switch (options->temperatureUnit) + switch (options->tempUnit) { case FF_TEMPERATURE_UNIT_CELSIUS: ffStrbufAppendF(buffer, "%.*f°C", options->tempNdigits, celsius); diff --git a/src/options/display.c b/src/options/display.c index 292ced618..35815f7c0 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -116,7 +116,7 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va {}, }); if (error) return error; - options->temperatureUnit = (FFTemperatureUnit) value; + options->tempUnit = (FFTemperatureUnit) value; } yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); @@ -285,12 +285,12 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key {} }); } - else if(ffStrStartsWithIgnCase(key, "--temperature-")) + else if(ffStrStartsWithIgnCase(key, "--temp-")) { - const char* subkey = key + strlen("--temperature-"); + const char* subkey = key + strlen("--temp-"); if(ffStrEqualsIgnCase(subkey, "unit")) { - options->temperatureUnit = (FFTemperatureUnit) ffOptionParseEnum(key, value, (FFKeyValuePair[]) { + options->tempUnit = (FFTemperatureUnit) ffOptionParseEnum(key, value, (FFKeyValuePair[]) { { "CELSIUS", FF_TEMPERATURE_UNIT_CELSIUS }, { "C", FF_TEMPERATURE_UNIT_CELSIUS }, { "FAHRENHEIT", FF_TEMPERATURE_UNIT_FAHRENHEIT }, @@ -375,7 +375,7 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) options->noBuffer = false; options->keyWidth = 0; - options->temperatureUnit = FF_TEMPERATURE_UNIT_CELSIUS; + options->tempUnit = FF_TEMPERATURE_UNIT_CELSIUS; options->tempNdigits = 1; ffStrbufInitStatic(&options->tempColorGreen, FF_COLOR_FG_GREEN); ffStrbufInitStatic(&options->tempColorYellow, FF_COLOR_FG_LIGHT_YELLOW); @@ -488,9 +488,9 @@ void ffOptionsGenerateDisplayJsonConfig(FFOptionsDisplay* options, yyjson_mut_do { yyjson_mut_val* temperature = yyjson_mut_obj(doc); - if (options->temperatureUnit != defaultOptions.temperatureUnit) + if (options->tempUnit != defaultOptions.tempUnit) { - switch (options->temperatureUnit) + switch (options->tempUnit) { case FF_TEMPERATURE_UNIT_CELSIUS: yyjson_mut_obj_add_str(doc, obj, "unit", "C"); diff --git a/src/options/display.h b/src/options/display.h index b29df43eb..e2307b2d4 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -35,7 +35,7 @@ typedef struct FFOptionsDisplay FFBinaryPrefixType binaryPrefixType; uint8_t sizeNdigits; uint8_t sizeMaxPrefix; - FFTemperatureUnit temperatureUnit; + FFTemperatureUnit tempUnit; uint8_t tempNdigits; FFstrbuf tempColorGreen; FFstrbuf tempColorYellow; From f79498e4b5dd5b50e3bf8b4aada169b4d70be793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 08:49:25 +0800 Subject: [PATCH 15/59] PublicIP / Weather: clarify error messages Fix #907 --- src/detection/publicip/publicip.c | 2 +- src/detection/weather/weather.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detection/publicip/publicip.c b/src/detection/publicip/publicip.c index d144f7219..a66d9f3d1 100644 --- a/src/detection/publicip/publicip.c +++ b/src/detection/publicip/publicip.c @@ -9,7 +9,7 @@ void ffPreparePublicIp(FFPublicIpOptions* options) { if (status != FF_UNITIALIZED) { - fputs("Error: this module can only be used once due to internal limitations\n", stderr); + fputs("Error: PublicIp module can only be used once due to internal limitations\n", stderr); exit(1); } diff --git a/src/detection/weather/weather.c b/src/detection/weather/weather.c index de3281348..fccdd2d12 100644 --- a/src/detection/weather/weather.c +++ b/src/detection/weather/weather.c @@ -8,7 +8,7 @@ void ffPrepareWeather(FFWeatherOptions* options) { if (status != FF_UNITIALIZED) { - fputs("Error: this module can only be used once due to internal limitations\n", stderr); + fputs("Error: Weather module can only be used once due to internal limitations\n", stderr); exit(1); } From b62ad16aa6c2224cde7ca7bd4e3e7f22b67a272d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 09:20:18 +0800 Subject: [PATCH 16/59] Loadavg (BSD): use sysctl --- src/detection/loadavg/loadavg_bsd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/detection/loadavg/loadavg_bsd.c b/src/detection/loadavg/loadavg_bsd.c index 69a38e7db..95c0c49cb 100644 --- a/src/detection/loadavg/loadavg_bsd.c +++ b/src/detection/loadavg/loadavg_bsd.c @@ -1,8 +1,14 @@ #include "detection/loadavg/loadavg.h" -#include +#include const char* ffDetectLoadavg(double result[3]) { - return getloadavg(result, 3) < 0 ? "getloadavg() failed" : NULL; + struct loadavg load; + size_t size = sizeof(load); + if (sysctl((int []) { CTL_VM, VM_LOADAVG }, 2, &load, &size, NULL, 0) < 0) + return "sysctl({CTL_VM, VM_LOADAVG}) failed"; + for (int i = 0; i < 3; i++) + result[i] = (double) load.ldavg[i] / (double) load.fscale; + return NULL; } From 0f5e746fe2122932c13364042d373e3f8c7195bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 09:40:53 +0800 Subject: [PATCH 17/59] Loadavg: add option `--loadavg-ndigits` --- doc/json_schema.json | 7 +++++++ src/data/help.json | 8 ++++++++ src/modules/loadavg/loadavg.c | 19 ++++++++++++++++++- src/modules/loadavg/option.h | 2 ++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index ef71c7bda..8c3b3122d 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1565,6 +1565,13 @@ "const": "loadavg", "description": "Print system load averages" }, + "ndigits": { + "type": "integer", + "description": "Set the number of digits to keep after the decimal point", + "minimum": 0, + "maximum": 9, + "default": 2 + }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/data/help.json b/src/data/help.json index ed7b3adba..93e4132e1 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1228,6 +1228,14 @@ "default": false } }, + { + "long": "loadavg-ndigits", + "desc": "Set the number of digits to keep after the decimal point when printing load average", + "arg": { + "type": "num", + "default": 2 + } + }, { "long": "localip-show-ipv4", "desc": "Show IPv4 addresses in local ip module", diff --git a/src/modules/loadavg/loadavg.c b/src/modules/loadavg/loadavg.c index 4cba6f93d..0caf0f445 100644 --- a/src/modules/loadavg/loadavg.c +++ b/src/modules/loadavg/loadavg.c @@ -20,7 +20,7 @@ void ffPrintLoadavg(FFLoadavgOptions* options) if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - printf("%.2f, %.2f, %.2f\n", result[0], result[1], result[2]); + printf("%.*f, %.*f, %.*f\n", options->ndigits, result[0], options->ndigits, result[1], options->ndigits, result[2]); } else { @@ -39,6 +39,12 @@ bool ffParseLoadavgCommandOptions(FFLoadavgOptions* options, const char* key, co if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + if (ffStrEqualsIgnCase(subKey, "ndigits")) + { + options->ndigits = (uint8_t) ffOptionParseUInt32(key, value); + return true; + } + return false; } @@ -55,6 +61,12 @@ void ffParseLoadavgJsonObject(FFLoadavgOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (ffStrEqualsIgnCase(key, "ndigits")) + { + options->ndigits = (uint8_t) yyjson_get_uint(val); + continue; + } + ffPrintError(FF_LOADAVG_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); } } @@ -65,6 +77,9 @@ void ffGenerateLoadavgJsonConfig(FFLoadavgOptions* options, yyjson_mut_doc* doc, ffInitLoadavgOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + if (defaultOptions.ndigits != options->ndigits) + yyjson_mut_obj_add_uint(doc, module, "ndigits", options->ndigits); } void ffGenerateLoadavgJsonResult(FF_MAYBE_UNUSED FFLoadavgOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -106,6 +121,8 @@ void ffInitLoadavgOptions(FFLoadavgOptions* options) ffGenerateLoadavgJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); + + options->ndigits = 2; } void ffDestroyLoadavgOptions(FFLoadavgOptions* options) diff --git a/src/modules/loadavg/option.h b/src/modules/loadavg/option.h index d61f04d7c..bc8df7077 100644 --- a/src/modules/loadavg/option.h +++ b/src/modules/loadavg/option.h @@ -8,4 +8,6 @@ typedef struct FFLoadavgOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + uint8_t ndigits; } FFLoadavgOptions; From 34a6eb13c63b6621137d8371bc4d17dd5d98da08 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 9 May 2024 09:51:41 +0800 Subject: [PATCH 18/59] Loadavg (BSD): add missing headers --- src/detection/loadavg/loadavg_bsd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/detection/loadavg/loadavg_bsd.c b/src/detection/loadavg/loadavg_bsd.c index 95c0c49cb..71c4304c1 100644 --- a/src/detection/loadavg/loadavg_bsd.c +++ b/src/detection/loadavg/loadavg_bsd.c @@ -2,6 +2,12 @@ #include +#ifdef __FreeBSD__ + #include + #include + #include +#endif + const char* ffDetectLoadavg(double result[3]) { struct loadavg load; From 7eb145fb7fb231b193fb74423c3d1610135673d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 09:56:34 +0800 Subject: [PATCH 19/59] Presets: add loadavg to `all.jsonc` and `ci.jsonc` --- presets/all.jsonc | 1 + presets/ci.jsonc | 1 + 2 files changed, 2 insertions(+) diff --git a/presets/all.jsonc b/presets/all.jsonc index ddbf89289..628bfed3d 100644 --- a/presets/all.jsonc +++ b/presets/all.jsonc @@ -10,6 +10,7 @@ "chassis", "kernel", "uptime", + "loadavg", "processes", "packages", "shell", diff --git a/presets/ci.jsonc b/presets/ci.jsonc index 799a31c13..d9236a26a 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -16,6 +16,7 @@ "chassis", "kernel", "uptime", + "loadavg", "processes", "packages", "shell", From acc77ebddd9f6f2aa42066958892bdab75ae2bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 10:13:04 +0800 Subject: [PATCH 20/59] PublicIP: add option `--publicip-ipv6` --- doc/json_schema.json | 5 +++++ src/common/networking.h | 1 + src/common/networking_linux.c | 2 +- src/common/networking_windows.c | 2 +- src/data/help.json | 8 ++++++++ src/detection/publicip/publicip.c | 25 +++++++++++++++---------- src/modules/publicip/option.h | 1 + src/modules/publicip/publicip.c | 19 +++++++++++++++++++ 8 files changed, 51 insertions(+), 12 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 8c3b3122d..c5cadfec5 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1776,6 +1776,11 @@ "minimum": 0, "default": "disabled (0)" }, + "ipv6": { + "description": "Whether to use IPv6 for public IP detection server", + "type": "boolean", + "default": false + }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/common/networking.h b/src/common/networking.h index cc8285cc5..8122e4eb0 100644 --- a/src/common/networking.h +++ b/src/common/networking.h @@ -22,6 +22,7 @@ typedef struct FFNetworkingState { #endif uint32_t timeout; + bool ipv6; } FFNetworkingState; const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers); diff --git a/src/common/networking_linux.c b/src/common/networking_linux.c index 7a8054918..8bdd16bbd 100644 --- a/src/common/networking_linux.c +++ b/src/common/networking_linux.c @@ -14,7 +14,7 @@ static const char* connectAndSend(FFNetworkingState* state) struct addrinfo* addr; if(getaddrinfo(state->host.chars, "80", &(struct addrinfo) { - .ai_family = AF_INET, + .ai_family = state->ipv6 ? AF_INET6 : AF_INET, .ai_socktype = SOCK_STREAM, }, &addr) != 0) { diff --git a/src/common/networking_windows.c b/src/common/networking_windows.c index 27a884216..e6c8a4616 100644 --- a/src/common/networking_windows.c +++ b/src/common/networking_windows.c @@ -51,7 +51,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho struct addrinfo* addr; if(getaddrinfo(host, "80", &(struct addrinfo) { - .ai_family = AF_INET, + .ai_family = state.ipv6 ? AF_INET6 : AF_INET, .ai_socktype = SOCK_STREAM, }, &addr) != 0) return "getaddrinfo() failed"; diff --git a/src/data/help.json b/src/data/help.json index 93e4132e1..7801aafbf 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1348,6 +1348,14 @@ "type": "str" } }, + { + "long": "publicip-ipv6", + "desc": "Whether to use IPv6 for public IP detection server", + "arg": { + "type": "bool", + "default": false + } + }, { "long": "weather-location", "desc": "Set the location to be used", diff --git a/src/detection/publicip/publicip.c b/src/detection/publicip/publicip.c index a66d9f3d1..aa5f22419 100644 --- a/src/detection/publicip/publicip.c +++ b/src/detection/publicip/publicip.c @@ -2,21 +2,24 @@ #include "common/networking.h" #define FF_UNITIALIZED ((const char*)(uintptr_t) -1) -static FFNetworkingState state; -static const char* status = FF_UNITIALIZED; +static FFNetworkingState states[2]; +static const char* statuses[2] = { FF_UNITIALIZED, FF_UNITIALIZED }; void ffPreparePublicIp(FFPublicIpOptions* options) { - if (status != FF_UNITIALIZED) + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status != FF_UNITIALIZED) { fputs("Error: PublicIp module can only be used once due to internal limitations\n", stderr); exit(1); } - state.timeout = options->timeout; + state->timeout = options->timeout; + state->ipv6 = options->ipv6; if (options->url.length == 0) - status = ffNetworkingSendHttpRequest(&state, "ipinfo.io", "/json", NULL); + *status = ffNetworkingSendHttpRequest(state, options->ipv6 ? "v6.ipinfo.io" : "ipinfo.io", "/json", NULL); else { FF_STRBUF_AUTO_DESTROY host = ffStrbufCreateCopy(&options->url); @@ -40,7 +43,7 @@ void ffPreparePublicIp(FFPublicIpOptions* options) host.chars[pathStartIndex] = '\0'; } - status = ffNetworkingSendHttpRequest(&state, host.chars, path.length == 0 ? "/" : path.chars, NULL); + *status = ffNetworkingSendHttpRequest(state, host.chars, path.length == 0 ? "/" : path.chars, NULL); } } @@ -53,14 +56,16 @@ static inline void wrapYyjsonFree(yyjson_doc** doc) const char* ffDetectPublicIp(FFPublicIpOptions* options, FFPublicIpResult* result) { - if (status == FF_UNITIALIZED) + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status == FF_UNITIALIZED) ffPreparePublicIp(options); - if (status != NULL) - return status; + if (*status != NULL) + return *status; FF_STRBUF_AUTO_DESTROY response = ffStrbufCreateA(4096); - const char* error = ffNetworkingRecvHttpResponse(&state, &response); + const char* error = ffNetworkingRecvHttpResponse(state, &response); if (error == NULL) ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n"); else diff --git a/src/modules/publicip/option.h b/src/modules/publicip/option.h index f05b95c23..427bab31a 100644 --- a/src/modules/publicip/option.h +++ b/src/modules/publicip/option.h @@ -11,4 +11,5 @@ typedef struct FFPublicIpOptions FFstrbuf url; uint32_t timeout; + bool ipv6; } FFPublicIpOptions; diff --git a/src/modules/publicip/publicip.c b/src/modules/publicip/publicip.c index eb5a41b0a..7de504790 100644 --- a/src/modules/publicip/publicip.c +++ b/src/modules/publicip/publicip.c @@ -59,6 +59,12 @@ bool ffParsePublicIpCommandOptions(FFPublicIpOptions* options, const char* key, return true; } + if (ffStrEqualsIgnCase(subKey, "ipv6")) + { + options->ipv6 = ffOptionParseBoolean(value); + return true; + } + return false; } @@ -87,6 +93,12 @@ void ffParsePublicIpJsonObject(FFPublicIpOptions* options, yyjson_val* module) continue; } + if (ffStrEqualsIgnCase(key, "ipv6")) + { + options->ipv6 = yyjson_get_bool(val); + continue; + } + ffPrintError(FF_PUBLICIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); } } @@ -100,6 +112,12 @@ void ffGeneratePublicIpJsonConfig(FFPublicIpOptions* options, yyjson_mut_doc* do if (!ffStrbufEqual(&options->url, &defaultOptions.url)) yyjson_mut_obj_add_strbuf(doc, module, "url", &options->url); + + if (defaultOptions.timeout != options->timeout) + yyjson_mut_obj_add_uint(doc, module, "timeout", options->timeout); + + if (defaultOptions.ipv6 != options->ipv6) + yyjson_mut_obj_add_bool(doc, module, "ipv6", options->ipv6); } void ffGeneratePublicIpJsonResult(FFPublicIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -148,6 +166,7 @@ void ffInitPublicIpOptions(FFPublicIpOptions* options) ffStrbufInit(&options->url); options->timeout = 0; + options->ipv6 = false; } void ffDestroyPublicIpOptions(FFPublicIpOptions* options) From f16843d60f9a982fd906c9fc5c7787ba8c897446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 16:27:24 +0800 Subject: [PATCH 21/59] Doc: update changelog --- CHANGELOG.md | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2dee4177..b8bd1e648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,34 +1,45 @@ +# 2.12.0 + +Changes: +* The long deprecated options `--set` and `--set-keyless` are removed. + +Features: +* Support st terminal font detection for font configuration compiled in st binary (TerminalFont, Linux) +* Support option `--color-output` to change output color of all modules except `Title`, `Separator` and `Colors` + * `display.color.output` in JSONC config file +* Support option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` +* Add new module `Loadavg` to print load averages (Loadavg) +* Add option `--publicip-ipv6` to print IPv6 address (PublicIP) + +Bugfixes: +* Rename option `--temperature-unit` to `--temp-unit` as stated in help messages + # 2.11.5 Bugfix: - * Fix logo printing for OpenMandriva (#896) * Remove `--os-file` in help messages # 2.11.4 Changes: - * Fastfetch will print a colorless ascii logo in `--pipe` mode for better `lolcat` compatibility. `fastfetch | lolcat` should work and no `--pipe false` needed. * Previously the logo would be disabled in `--pipe` mode. -* `--os-file` was removed and CMake option `-DCUSTOM_OS_RELEASE_PATH=/path/to/os-release` was added. This option should not used in most cases. + * Use `--pipe -l none` to get the old beheavior +* `--os-file` was removed and CMake option `-DCUSTOM_OS_RELEASE_PATH=/path/to/os-release` was introduced for configuring at compile time by package managers if needed. This option should not used in most cases. Bugfixes: - * Fix possible out-of-bound memory access (#868) -* Fix Apple Terminal detection (macOS, Terminal) -* Fix doubled output in custom formation (#852) +* Fix Apple Terminal detection (#878, macOS, Terminal) * Fix deprecation warning for macOS 14.0 hopefully (#860, macOS, Camera) -* Fix memory leaks when passing informative options +* Fix memory leaks when passing informative options (#888) * Fix JSON config `size.ndigits` doesn't work Features: - * Enable `--pipe` mode if environment variable `$NO_COLOR` is set * Support Armbian and Proxmox distro detection (OS, Linux) Logo: - * Add Armbian # 2.11.3 From 01d2fa12284042b1a11a2eedc20615536b6b12dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 16:32:10 +0800 Subject: [PATCH 22/59] Doc: update changelog (ci skip) --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8bd1e648..71bb65ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ Features: Bugfixes: * Rename option `--temperature-unit` to `--temp-unit` as stated in help messages +Logos: +* Fix DahliaOS detection + # 2.11.5 Bugfix: From 2accfbc8941651b0dae9f87910da33515aa36675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 May 2024 16:35:51 +0800 Subject: [PATCH 23/59] Networking (Windows): fix compiling --- src/common/networking_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/networking_windows.c b/src/common/networking_windows.c index e6c8a4616..83b3fd864 100644 --- a/src/common/networking_windows.c +++ b/src/common/networking_windows.c @@ -51,7 +51,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho struct addrinfo* addr; if(getaddrinfo(host, "80", &(struct addrinfo) { - .ai_family = state.ipv6 ? AF_INET6 : AF_INET, + .ai_family = state->ipv6 ? AF_INET6 : AF_INET, .ai_socktype = SOCK_STREAM, }, &addr) != 0) return "getaddrinfo() failed"; From ec0af17fb579a0b7c7b1eff80cb55f855e94b81d Mon Sep 17 00:00:00 2001 From: Souma <101255979+5ouma@users.noreply.github.com> Date: Thu, 9 May 2024 20:39:17 +0900 Subject: [PATCH 24/59] Terminal (macOS): fix compatibility with `(*term)` (#909) Ignore (term). This is because Fig( (figterm)) migrated to CodeWhisperer( (cwterm)) and CodeWhisperer renamed to Q( (qterm)). Future changes will all be ignored by this change. Related: #676 --- src/detection/terminalshell/terminalshell_linux.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index dbdc08900..006f40a37 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -307,10 +307,19 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) #ifdef __APPLE__ // https://github.com/fastfetch-cli/fastfetch/discussions/501 - if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)")) + const char* pLeft = strstr(name, " ("); + if (pLeft) { - if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid, NULL) != NULL, false)) - return 0; + pLeft += 2; + const char* pRight = strstr(pLeft, "term)"); + if (pRight && pRight[5] == '\0') + { + for (; pLeft < pRight; ++pLeft) + if (*pLeft < 'a' || *pLeft > 'z') + break; + if (pLeft == pRight && getProcessNameAndPpid(ppid, name, &ppid, NULL) != NULL) + return 0; + } } #endif From 7d8c085254fb47e58dac0b1e538df193947eb4ba Mon Sep 17 00:00:00 2001 From: djinnalexio Date: Thu, 9 May 2024 20:11:00 +0100 Subject: [PATCH 25/59] =?UTF-8?q?=F0=9F=94=A7=20JsonConfig:=20add=20dim=20?= =?UTF-8?q?colors=20to=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/json_schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index c5cadfec5..eb376a18b 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -6,7 +6,8 @@ "enum": [ "reset_", "bright_", "dim_", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default", - "bright_black", "bright_red", "bright_green", "bright_yellow", "bright_blue", "bright_magenta", "bright_cyan", "bright_white" + "bright_black", "bright_red", "bright_green", "bright_yellow", "bright_blue", "bright_magenta", "bright_cyan", "bright_white", + "dim_black", "dim_red", "dim_green", "dim_yellow", "dim_blue", "dim_magenta", "dim_cyan", "dim_white" ] }, "key": { From ce6b5954216428aa5b25c2bbc734c71e6874356b Mon Sep 17 00:00:00 2001 From: djinnalexio Date: Thu, 9 May 2024 20:20:50 +0100 Subject: [PATCH 26/59] =?UTF-8?q?=F0=9F=94=A7=20JsonConfig:=20add=20missin?= =?UTF-8?q?g=20`brightness`=20properties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/json_schema.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/json_schema.json b/doc/json_schema.json index eb376a18b..67933df43 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1003,6 +1003,21 @@ "minimum": 0, "maximum": 400, "default": 10 + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "outputColor": { + "$ref": "#/$defs/outputColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" } } }, From 3d4077c2d02cc4f3171bc3189a6b0340823dcf90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 10 May 2024 13:37:46 +0800 Subject: [PATCH 27/59] Config: support more color prefixes --- doc/json_schema.json | 8 +++----- src/common/option.c | 6 ++++++ src/data/help_color.txt | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 67933df43..7b0efd4c8 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -4,10 +4,8 @@ "colors": { "type": "string", "enum": [ - "reset_", "bright_", "dim_", - "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default", - "bright_black", "bright_red", "bright_green", "bright_yellow", "bright_blue", "bright_magenta", "bright_cyan", "bright_white", - "dim_black", "dim_red", "dim_green", "dim_yellow", "dim_blue", "dim_magenta", "dim_cyan", "dim_white" + "reset_", "bright_", "dim_", "italic_", "underline_", "blink_", "inverse_", "hidden_", "strike_", "light_", + "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default" ] }, "key": { @@ -29,7 +27,7 @@ "type": "string" }, "outputColor": { - "description": "Output color of the module", + "description": "Output color of the module. Left empty to use `display.color.output`", "$ref": "#/$defs/colors" }, "percent": { diff --git a/src/common/option.c b/src/common/option.c index 9ebc2f33e..a9fa3878f 100644 --- a/src/common/option.c +++ b/src/common/option.c @@ -158,6 +158,12 @@ void ffOptionParseColor(const char* value, FFstrbuf* buffer) FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET) else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD) else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM) + else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC) + else FF_APPEND_COLOR_CODE_COND(underline_, FF_COLOR_MODE_UNDERLINE) + else FF_APPEND_COLOR_CODE_COND(blink_, FF_COLOR_MODE_BLINK) + else FF_APPEND_COLOR_CODE_COND(inverse_, FF_COLOR_MODE_INVERSE) + else FF_APPEND_COLOR_CODE_COND(hidden_, FF_COLOR_MODE_HIDDEN) + else FF_APPEND_COLOR_CODE_COND(strike_, FF_COLOR_MODE_STRIKETHROUGH) else FF_APPEND_COLOR_CODE_COND(black, FF_COLOR_FG_BLACK) else FF_APPEND_COLOR_CODE_COND(red, FF_COLOR_FG_RED) else FF_APPEND_COLOR_CODE_COND(green, FF_COLOR_FG_GREEN) diff --git a/src/data/help_color.txt b/src/data/help_color.txt index a05ef5d7c..1804498e9 100644 --- a/src/data/help_color.txt +++ b/src/data/help_color.txt @@ -5,6 +5,6 @@ Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_co Examples: --color 35: sets the color to magenta. `--color magenta` is also supported --color 38;5;38: sets the color to 38th color of ANSI 256 colors - --color 4;92: sets the color to bright Green with underline + --color 4;92: sets the color to bright Green with underline. `--color underline_green` is also supported --color 5;104: blinking text on a blue background If no color is set, the main color of the logo will be used. From d6a99c631e6c1690ce3c5f60c96e89cd8281dc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 10 May 2024 14:30:00 +0800 Subject: [PATCH 28/59] Image: support specifying `--logo-width` only for `--kitty-direct` and `--iterm` Fix: #836 Ref: https://github.com/kovidgoyal/kitty/issues/7424 --- src/logo/image/image.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/logo/image/image.c b/src/logo/image/image.c index a64a3d5e5..3daf8cfde 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -84,9 +84,10 @@ static bool printImageIterm(bool printError) ffStrbufAppendNC(&buf, options->paddingTop, '\n'); ffStrbufAppendNC(&buf, options->paddingLeft, ' '); } - ffStrbufAppendF(&buf, "\e]1337;File=inline=1:%s\a", - base64.chars - ); + if (options->width) + ffStrbufAppendF(&buf, "\e]1337;File=inline=1;width=%u:%s\a", (unsigned) options->width, base64.chars); + else + ffStrbufAppendF(&buf, "\e]1337;File=inline=1:%s\a", base64.chars); ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), &buf); if (!options->separate) @@ -164,7 +165,11 @@ static bool printImageKittyDirect(bool printError) ffPrintCharTimes('\n', options->paddingTop); ffPrintCharTimes(' ', options->paddingLeft); } - printf("\e_Ga=T,f=100,t=f;%s\e\\", base64.chars); + + if (options->width) + printf("\e_Ga=T,f=100,t=f,c=%u;%s\e\\", (unsigned) options->width, base64.chars); + else + printf("\e_Ga=T,f=100,t=f;%s\e\\", base64.chars); fflush(stdout); if (!options->separate) { From 08a940bfd42e3a4701f9d1e7f6c385cc1b876a0d Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Sat, 11 May 2024 09:03:13 +0200 Subject: [PATCH 29/59] Logo: Add the openSUSE Slowroll distribution (#913) --- src/logo/ascii/opensuse_slowroll.txt | 20 ++++++++++++++++++++ src/logo/builtin.c | 10 ++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/logo/ascii/opensuse_slowroll.txt diff --git a/src/logo/ascii/opensuse_slowroll.txt b/src/logo/ascii/opensuse_slowroll.txt new file mode 100644 index 000000000..e63697fb7 --- /dev/null +++ b/src/logo/ascii/opensuse_slowroll.txt @@ -0,0 +1,20 @@ + _,......,_ + _aaQQQQQQWQQQQQQQaa. + ajQQQ??^' '^??QQQw. + ,aQQP^ ?4QQa + wQQP ^4QQa + ,QQP' ,aaaaa. ^$Q6, + ,QQP ajQQQWWWWQQQw. 4QQ + QQP aQQP? ?$QQ. 4Q6 +jQQ jQQ' ?WQr 'QQb +QQf ]QQ' ]QQ QQ6 +QQf ]QQ ]QQ) QQQ +QQ6 'QQ6 ]QQ QQf +]QQ. ^4QQaa .QQP ,QQ' + $QQ. ^?QQQQf _yQP ,QQP + ^WQQ6. aQQ? _QQP + ^4QQQ6a. ajQQP' aQQP + ?QQQQQWQaaaaaaajQWQP? aQQP' + ?QQQQP????????^' saWQP? + ^?QQQgaaa._ __aaaQQQP?' + '^?QWQQQQQQQQ@??^' \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 90e9deca6..853b7c453 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -3004,6 +3004,16 @@ static const FFlogo O[] = { .colorKeys = FF_COLOR_FG_GREEN, .colorTitle = FF_COLOR_FG_GREEN, }, + // openSUSESlowroll + { + .names = {"opensuse_slowroll", "opensuse-slowroll", "opensuse-tumbleweed-slowroll"}, + .lines = FASTFETCH_DATATEXT_LOGO_OPENSUSE_SLOWROLL, + .colors = { + FF_COLOR_FG_WHITE, + }, + .colorKeys = FF_COLOR_FG_GREEN, + .colorTitle = FF_COLOR_FG_GREEN, + }, // OpenMandriva { .names = {"openmandriva", "open-mandriva", "open_mandriva", "openmandriva lx"}, From fef3100fd7c9fea0385164cbe494374a2987f268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 10 May 2024 22:46:10 +0800 Subject: [PATCH 30/59] Smbios: add struct layout check --- src/detection/battery/battery_windows.c | 7 ++++--- src/detection/bios/bios_windows.c | 7 +++++-- src/detection/board/board_windows.c | 9 ++++++--- src/detection/chassis/chassis_windows.c | 5 ++++- src/detection/cpu/cpu_windows.c | 5 ++++- src/detection/host/host_windows.c | 7 +++++-- src/util/smbiosHelper.h | 2 +- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 357000ec3..72373bceb 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -154,8 +154,6 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results return NULL; } - - typedef struct FFSmbiosPortableBattery { FFSmbiosHeader Header; @@ -178,7 +176,10 @@ typedef struct FFSmbiosPortableBattery uint8_t SbdsDeviceChemistry; // string uint8_t DesignCapacityMultiplier; // varies uint16_t OEMSpecific; // varies -} FFSmbiosPortableBattery; +} __attribute__((__packed__)) FFSmbiosPortableBattery; + +static_assert(offsetof(FFSmbiosPortableBattery, OEMSpecific) == 0x16, + "FFSmbiosPortableBattery: Wrong struct alignment"); const char* detectBySmbios(FFBatteryResult* battery) { diff --git a/src/detection/bios/bios_windows.c b/src/detection/bios/bios_windows.c index 23ff25275..1ea9ee97d 100644 --- a/src/detection/bios/bios_windows.c +++ b/src/detection/bios/bios_windows.c @@ -35,7 +35,7 @@ typedef struct FFSmbiosBios uint16_t BiosStartingAddressSegment; // varies uint8_t BiosReleaseDate; // string uint8_t BiosRomSize; // string - uint32_t BiosCharacteristics; // bit field + uint64_t BiosCharacteristics; // bit field // 2.4+ uint8_t BiosCharacteristicsExtensionBytes[2]; // bit field @@ -46,7 +46,10 @@ typedef struct FFSmbiosBios // 3.1+ uint16_t ExtendedBiosRomSize; // bit field -} FFSmbiosBios; +} __attribute__((__packed__)) FFSmbiosBios; + +static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18, + "FFSmbiosBios: Wrong struct alignment"); const char* ffDetectBios(FFBiosResult* bios) { diff --git a/src/detection/board/board_windows.c b/src/detection/board/board_windows.c index d16d4a905..78a8ff7d4 100644 --- a/src/detection/board/board_windows.c +++ b/src/detection/board/board_windows.c @@ -14,9 +14,12 @@ typedef struct FFSmbiosBaseboard uint8_t LocationInChassis; // string uint16_t ChassisHandle; // varies uint8_t BoardType; // enum - uint8_t NumberOfContainedObjectHandle; // varies - uint16_t ContainedObjectHandle[]; // varies -} FFSmbiosBaseboard; + uint8_t NumberOfContainedObjectHandles; // varies + uint16_t ContainedObjectHandles[]; // varies +} __attribute__((__packed__)) FFSmbiosBaseboard; + +static_assert(offsetof(FFSmbiosBaseboard, ContainedObjectHandles) == 0x0F, + "FFSmbiosBaseboard: Wrong struct alignment"); const char* ffDetectBoard(FFBoardResult* board) { diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 754b85a3d..2075ef20d 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -25,7 +25,10 @@ typedef struct FFSmbiosSystemEnclosure uint8_t ContainedElementCount; // varies uint8_t ContainedRecordLength; // varies uint8_t ContainedElements[]; // varies -} FFSmbiosSystemEnclosure; +} __attribute__((__packed__)) FFSmbiosSystemEnclosure; + +static_assert(offsetof(FFSmbiosSystemEnclosure, ContainedElements) == 0x15, + "FFSmbiosSystemEnclosure: Wrong struct alignment"); const char* ffDetectChassis(FFChassisResult* result) { diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 81bae35a1..aad79ce1d 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -48,7 +48,10 @@ typedef struct FFSmbiosProcessorInfo // 3.6+ uint16_t ThreadEnabled; // varies -} FFSmbiosProcessorInfo; +} __attribute__((__packed__)) FFSmbiosProcessorInfo; + +static_assert(offsetof(FFSmbiosProcessorInfo, ThreadEnabled) == 0x30, + "FFSmbiosProcessorInfo: Wrong struct alignment"); #if defined(__x86_64__) || defined(__i386__) diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index 8efe70a2f..0470c1210 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -18,13 +18,16 @@ typedef struct FFSmbiosSystemInfo uint8_t ClockSeqHiAndReserved; uint8_t ClockSeqLow; uint8_t Node[6]; - } UUID; // varies + } __attribute__((__packed__)) UUID; // varies uint8_t WakeUpType; // enum // 2.4+ uint8_t SKUNumber; // string uint8_t Family; // string -} FFSmbiosSystemInfo; +} __attribute__((__packed__)) FFSmbiosSystemInfo; + +static_assert(offsetof(FFSmbiosSystemInfo, Family) == 0x1A, + "FFSmbiosSystemInfo: Wrong struct alignment"); const char* ffDetectHost(FFHostResult* host) { diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index 6a80b3ab5..81e820be0 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -78,7 +78,7 @@ typedef struct FFSmbiosHeader FFSmbiosType Type; uint8_t Length; uint16_t Handle; -} FFSmbiosHeader; +} __attribute__((__packed__)) FFSmbiosHeader; static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes"); typedef struct FFRawSmbiosData From 68efcdd0ddeb43b471d05a2fcd4eb70b8ba85bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 10 May 2024 23:47:15 +0800 Subject: [PATCH 31/59] PhysicalMemory: add new module --- CMakeLists.txt | 6 + src/common/modules.c | 1 + src/detection/physicalmemory/physicalmemory.h | 17 ++ .../physicalmemory/physicalmemory_nosupport.c | 6 + .../physicalmemory/physicalmemory_windows.c | 193 ++++++++++++++++++ src/modules/modules.h | 1 + src/modules/options.h | 1 + src/modules/physicalmemory/option.h | 12 ++ src/modules/physicalmemory/physicalmemory.c | 180 ++++++++++++++++ src/modules/physicalmemory/physicalmemory.h | 9 + src/options/modules.c | 2 + src/options/modules.h | 1 + 12 files changed, 429 insertions(+) create mode 100644 src/detection/physicalmemory/physicalmemory.h create mode 100644 src/detection/physicalmemory/physicalmemory_nosupport.c create mode 100644 src/detection/physicalmemory/physicalmemory_windows.c create mode 100644 src/modules/physicalmemory/option.h create mode 100644 src/modules/physicalmemory/physicalmemory.c create mode 100644 src/modules/physicalmemory/physicalmemory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8334482f6..3091d5bde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -345,6 +345,7 @@ set(LIBFASTFETCH_SRC src/modules/os/os.c src/modules/packages/packages.c src/modules/physicaldisk/physicaldisk.c + src/modules/physicalmemory/physicalmemory.c src/modules/processes/processes.c src/modules/player/player.c src/modules/poweradapter/poweradapter.c @@ -400,6 +401,7 @@ if(LINUX) src/detection/bluetooth/bluetooth_linux.c src/detection/disk/disk_linux.c src/detection/physicaldisk/physicaldisk_linux.c + src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -466,6 +468,7 @@ elseif(ANDROID) src/detection/cpuusage/cpuusage_linux.c src/detection/disk/disk_linux.c src/detection/physicaldisk/physicaldisk_linux.c + src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_linux.c src/detection/displayserver/displayserver_android.c src/detection/font/font_nosupport.c @@ -523,6 +526,7 @@ elseif(BSD) src/detection/cursor/cursor_linux.c src/detection/disk/disk_bsd.c src/detection/physicaldisk/physicaldisk_bsd.c + src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_bsd.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -590,6 +594,7 @@ elseif(APPLE) src/detection/cursor/cursor_apple.m src/detection/disk/disk_bsd.c src/detection/physicaldisk/physicaldisk_apple.c + src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_apple.c src/detection/displayserver/displayserver_apple.c src/detection/font/font_apple.m @@ -662,6 +667,7 @@ elseif(WIN32) src/detection/gamepad/gamepad_windows.c src/detection/media/media_nosupport.c src/detection/memory/memory_windows.c + src/detection/physicalmemory/physicalmemory_windows.c src/detection/monitor/monitor_windows.c src/detection/netio/netio_windows.c src/detection/opengl/opengl_windows.c diff --git a/src/common/modules.c b/src/common/modules.c index 1c4d43e4f..ea9958eb3 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -99,6 +99,7 @@ static FFModuleBaseInfo* O[] = { static FFModuleBaseInfo* P[] = { (void*) &instance.config.modules.packages, (void*) &instance.config.modules.physicalDisk, + (void*) &instance.config.modules.physicalMemory, (void*) &instance.config.modules.player, (void*) &instance.config.modules.powerAdapter, (void*) &instance.config.modules.processes, diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h new file mode 100644 index 000000000..08e783a22 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "fastfetch.h" + +typedef struct FFPhysicalMemoryResult +{ + uint64_t size; // B + uint32_t maxSpeed; // MT/s + uint32_t runningSpeed; // MT/s + FFstrbuf type; + FFstrbuf formFactor; + FFstrbuf deviceLocator; + FFstrbuf vendor; + FFstrbuf serial; +} FFPhysicalMemoryResult; + +const char* ffDetectPhysicalMemory(FFlist* result); // list of FFPhysicalMemoryResult diff --git a/src/detection/physicalmemory/physicalmemory_nosupport.c b/src/detection/physicalmemory/physicalmemory_nosupport.c new file mode 100644 index 000000000..a035753d7 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_nosupport.c @@ -0,0 +1,6 @@ +#include "physicalmemory.h" + +const char* ffDetectPhysicalMemory(FF_MAYBE_UNUSED FFlist* result) +{ + return "Not supported on this platform"; +} diff --git a/src/detection/physicalmemory/physicalmemory_windows.c b/src/detection/physicalmemory/physicalmemory_windows.c new file mode 100644 index 000000000..0426d72c7 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_windows.c @@ -0,0 +1,193 @@ +#include "physicalmemory.h" +#include "util/smbiosHelper.h" + +// 7.18 +typedef struct FFSmbiosMemoryDevice +{ + FFSmbiosHeader Header; + + // 2.1+ + uint16_t PhysicalMemoryArrayHandle; // varies + uint16_t MemoryErrorInformationHandle; //varies + uint16_t TotalWidth; // varies + uint16_t DataWidth; // varies + uint16_t Size; // varies + uint8_t FormFactor; // enum + uint8_t DeviceSet; // varies + uint8_t DeviceLocator; // string + uint8_t BankLocator; // string + uint8_t MemoryType; // enum + uint16_t TypeDetail; // bit field + + // 2.3+ + uint16_t Speed; // varies + uint8_t Manufacturer; // string + uint8_t SerialNumber; // string + uint8_t AssetTag; // string + uint8_t PartNumber; // string + + // 2.6+ + uint8_t Attributes; // varies + + // 2.7+ + uint32_t ExtendedSize; // varies + uint16_t ConfiguredMemorySpeed; // varies + + // 2.8+ + uint16_t MinimumVoltage; // varies + uint16_t MaximumVoltage; // varies + uint16_t ConfiguredVoltage; // varies + + // 3.2+ + uint8_t MemoryTechnology; // varies + uint16_t MemoryOperatingMode; // bit field + uint8_t FirmwareVersion; // string + uint16_t ModuleManufacturerID; // varies + uint16_t ModuleProductID; // varies + uint16_t MemorySubsystemControllerManufacturerID; // vaies + uint16_t MemorySubsystemControllerProductID; // varies + uint64_t NonVolatileSize; // varies + uint64_t VolatileSize; // varies + uint64_t CacheSize; // varies + uint64_t LogicalSize; // varies + + // 3.3+ + uint32_t ExtendedSpeed; // varies + uint32_t ExtendedConfiguredSpeed; // varies + + // 3.7+ + uint16_t Pmic0ManufacturerID; // varies + uint16_t Pmic0RevisionNumber; // varies + uint16_t RcdManufacturerID; // varies + uint16_t RcdRevisionNumber; // varies +} __attribute__((__packed__)) FFSmbiosMemoryDevice; + +static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62, + "FFSmbiosMemoryDevice: Wrong struct alignment"); + +const char* ffDetectPhysicalMemory(FFlist* result) +{ + const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_MEMORY_DEVICE]; + if (!data) + return "System enclosure is not found in SMBIOS data"; + + for (; data->Header.Type == FF_SMBIOS_TYPE_MEMORY_DEVICE; + data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) + { + if (data->Size == 0) continue; + + const char* strings = (const char*) data + data->Header.Length; + + FFPhysicalMemoryResult* device = ffListAdd(result); + ffStrbufInit(&device->type); + ffStrbufInit(&device->formFactor); + ffStrbufInit(&device->deviceLocator); + ffStrbufInit(&device->vendor); + ffStrbufInit(&device->serial); + device->size = 0; + device->maxSpeed = 0; + device->runningSpeed = 0; + + if (data->Size != 0xFFFF) + { + if (data->Size == 0x7FFF) + device->size = (data->ExtendedSize & ~(1 << 31)) * 1024 * 1024; + else if (data->Size & (1 << 15)) + { + // in kB + device->size = (data->Size & ~(1u << 15)) * 1024ULL; + } + else + { + // in MB + device->size = data->Size * 1024ULL * 1024ULL; + } + } + + ffStrbufSetStatic(&device->deviceLocator, ffSmbiosLocateString(strings, data->DeviceLocator)); + ffCleanUpSmbiosValue(&device->deviceLocator); + + switch (data->FormFactor) + { + case 0x01: ffStrbufSetStatic(&device->formFactor, "Other"); break; + case 0x02: ffStrbufSetStatic(&device->formFactor, "Unknown"); break; + case 0x03: ffStrbufSetStatic(&device->formFactor, "SIMM"); break; + case 0x04: ffStrbufSetStatic(&device->formFactor, "SIP"); break; + case 0x05: ffStrbufSetStatic(&device->formFactor, "Chip"); break; + case 0x06: ffStrbufSetStatic(&device->formFactor, "DIP"); break; + case 0x07: ffStrbufSetStatic(&device->formFactor, "ZIP"); break; + case 0x08: ffStrbufSetStatic(&device->formFactor, "Proprietary Card"); break; + case 0x09: ffStrbufSetStatic(&device->formFactor, "DIMM"); break; + case 0x0A: ffStrbufSetStatic(&device->formFactor, "TSOP"); break; + case 0x0B: ffStrbufSetStatic(&device->formFactor, "Row of chips"); break; + case 0x0C: ffStrbufSetStatic(&device->formFactor, "RIMM"); break; + case 0x0D: ffStrbufSetStatic(&device->formFactor, "SODIMM"); break; + case 0x0E: ffStrbufSetStatic(&device->formFactor, "SRIMM"); break; + case 0x0F: ffStrbufSetStatic(&device->formFactor, "FBDIMM"); break; + case 0x10: ffStrbufSetStatic(&device->formFactor, "Die"); break; + default: ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor); break; + } + + switch (data->MemoryType) + { + case 0x01: ffStrbufSetStatic(&device->type, "Other"); break; + case 0x02: ffStrbufSetStatic(&device->type, "Unknown"); break; + case 0x03: ffStrbufSetStatic(&device->type, "DRAM"); break; + case 0x04: ffStrbufSetStatic(&device->type, "EDRAM"); break; + case 0x05: ffStrbufSetStatic(&device->type, "VRAM"); break; + case 0x06: ffStrbufSetStatic(&device->type, "SRAM"); break; + case 0x07: ffStrbufSetStatic(&device->type, "RAM"); break; + case 0x08: ffStrbufSetStatic(&device->type, "ROM"); break; + case 0x09: ffStrbufSetStatic(&device->type, "FLASH"); break; + case 0x0A: ffStrbufSetStatic(&device->type, "EEPROM"); break; + case 0x0B: ffStrbufSetStatic(&device->type, "FEPROM"); break; + case 0x0C: ffStrbufSetStatic(&device->type, "EPROM"); break; + case 0x0D: ffStrbufSetStatic(&device->type, "CDRAM"); break; + case 0x0E: ffStrbufSetStatic(&device->type, "3DRAM"); break; + case 0x0F: ffStrbufSetStatic(&device->type, "SDRAM"); break; + case 0x10: ffStrbufSetStatic(&device->type, "SGRAM"); break; + case 0x11: ffStrbufSetStatic(&device->type, "RDRAM"); break; + case 0x12: ffStrbufSetStatic(&device->type, "DDR"); break; + case 0x13: ffStrbufSetStatic(&device->type, "DDR2"); break; + case 0x14: ffStrbufSetStatic(&device->type, "DDR2 FB-DIMM"); break; + case 0x15: + case 0x16: + case 0x17: ffStrbufSetStatic(&device->type, "Reserved"); break; + case 0x18: ffStrbufSetStatic(&device->type, "DDR3"); break; + case 0x19: ffStrbufSetStatic(&device->type, "FBD2"); break; + case 0x1A: ffStrbufSetStatic(&device->type, "DDR4"); break; + case 0x1B: ffStrbufSetStatic(&device->type, "LPDDR"); break; + case 0x1C: ffStrbufSetStatic(&device->type, "LPDDR2"); break; + case 0x1D: ffStrbufSetStatic(&device->type, "LPDDR3"); break; + case 0x1E: ffStrbufSetStatic(&device->type, "LPDDR4"); break; + case 0x1F: ffStrbufSetStatic(&device->type, "Logical non-volatile device"); break; + case 0x20: ffStrbufSetStatic(&device->type, "HBM"); break; + case 0x21: ffStrbufSetStatic(&device->type, "HBM2"); break; + case 0x22: ffStrbufSetStatic(&device->type, "DDR5"); break; + case 0x23: ffStrbufSetStatic(&device->type, "LPDDR5"); break; + case 0x24: ffStrbufSetStatic(&device->type, "HBM3"); break; + default: ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType); break; + } + + if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+ + { + if (data->Speed) + device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed; + + ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&device->vendor); + + ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&device->serial); + } + + if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ + { + if (data->ConfiguredMemorySpeed) + device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF + ? data->ExtendedConfiguredSpeed : data->ConfiguredMemorySpeed; + } + } + + return NULL; +} diff --git a/src/modules/modules.h b/src/modules/modules.h index cfff529c9..7bb11f8b2 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -40,6 +40,7 @@ #include "modules/os/os.h" #include "modules/packages/packages.h" #include "modules/physicaldisk/physicaldisk.h" +#include "modules/physicalmemory/physicalmemory.h" #include "modules/player/player.h" #include "modules/poweradapter/poweradapter.h" #include "modules/processes/processes.h" diff --git a/src/modules/options.h b/src/modules/options.h index af4ec7e99..cfcf931d0 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -40,6 +40,7 @@ #include "modules/os/option.h" #include "modules/packages/option.h" #include "modules/physicaldisk/option.h" +#include "modules/physicalmemory/option.h" #include "modules/player/option.h" #include "modules/poweradapter/option.h" #include "modules/processes/option.h" diff --git a/src/modules/physicalmemory/option.h b/src/modules/physicalmemory/option.h new file mode 100644 index 000000000..96ebccc57 --- /dev/null +++ b/src/modules/physicalmemory/option.h @@ -0,0 +1,12 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" +#include "common/percent.h" + +typedef struct FFPhysicalMemoryOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; +} FFPhysicalMemoryOptions; diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c new file mode 100644 index 000000000..faabab6ff --- /dev/null +++ b/src/modules/physicalmemory/physicalmemory.c @@ -0,0 +1,180 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "common/parsing.h" +#include "common/percent.h" +#include "detection/physicalmemory/physicalmemory.h" +#include "modules/physicalmemory/physicalmemory.h" +#include "util/stringUtils.h" + +#define FF_PHYSICALMEMORY_NUM_FORMAT_ARGS 9 +#define FF_PHYSICALMEMORY_DISPLAY_NAME "Physical Memory" + +void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) +{ + FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFPhysicalMemoryResult)); + const char* error = ffDetectPhysicalMemory(&result); + + if(error) + { + ffPrintError(FF_PHYSICALMEMORY_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + return; + } + + FF_STRBUF_AUTO_DESTROY prettySize = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate(); + + uint32_t i = 0; + FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) + { + ++i; + ffStrbufClear(&prettySize); + ffParseSize(device->size, &prettySize); + + if(options->moduleArgs.key.length == 0) + { + ffStrbufSetF(&key, "%s (%s %s-%u)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars, device->maxSpeed); + } + else + { + FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, 5, ((FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_UINT, &i}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, + {FF_FORMAT_ARG_TYPE_UINT, &device->maxSpeed}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->deviceLocator}, + })); + } + + if (options->moduleArgs.outputFormat.length == 0) + { + ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + printf("%s, running at %u MT/s\n", prettySize.chars, device->runningSpeed); + } + else + { + FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_PHYSICALMEMORY_NUM_FORMAT_ARGS, ((FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_UINT64, &device->size}, + {FF_FORMAT_ARG_TYPE_STRBUF, &prettySize}, + {FF_FORMAT_ARG_TYPE_UINT, &device->maxSpeed}, + {FF_FORMAT_ARG_TYPE_UINT, &device->runningSpeed}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->formFactor}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &device->deviceLocator}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->serial}, + })); + } + } + + FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) + { + ffStrbufDestroy(&device->type); + ffStrbufDestroy(&device->formFactor); + ffStrbufDestroy(&device->vendor); + ffStrbufDestroy(&device->serial); + } +} + +bool ffParsePhysicalMemoryCommandOptions(FFPhysicalMemoryOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_PHYSICALMEMORY_MODULE_NAME); + if (!subKey) return false; + if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) + return true; + + return false; +} + +void ffParsePhysicalMemoryJsonObject(FFPhysicalMemoryOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + ffPrintError(FF_PHYSICALMEMORY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); + } +} + +void ffGeneratePhysicalMemoryJsonConfig(FFPhysicalMemoryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyPhysicalMemoryOptions))) FFPhysicalMemoryOptions defaultOptions; + ffInitPhysicalMemoryOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); +} + +void ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFPhysicalMemoryResult)); + const char* error = ffDetectPhysicalMemory(&result); + + if(error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + return; + } + + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); + FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) + { + yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); + yyjson_mut_obj_add_uint(doc, obj, "size", device->size); + yyjson_mut_obj_add_uint(doc, obj, "maxSpeed", device->maxSpeed); + yyjson_mut_obj_add_uint(doc, obj, "runningSpeed", device->runningSpeed); + yyjson_mut_obj_add_strbuf(doc, obj, "type", &device->type); + yyjson_mut_obj_add_strbuf(doc, obj, "formFactor", &device->formFactor); + yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &device->vendor); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial); + } + + FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) + { + ffStrbufDestroy(&device->type); + ffStrbufDestroy(&device->formFactor); + ffStrbufDestroy(&device->vendor); + ffStrbufDestroy(&device->serial); + } +} + +void ffPrintPhysicalMemoryHelpFormat(void) +{ + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_PHYSICALMEMORY_MODULE_NAME, "{7} {5}-{3}: {2}, running at {4} MT/s", FF_PHYSICALMEMORY_NUM_FORMAT_ARGS, ((const char* []) { + "Size (in bytes)", + "Size formatted", + "Max speed (in MT/s)", + "Running speed (in MT/s)", + "Type (DDR4, DDR5, etc.)", + "Form factor (SODIMM, DIMM, etc.)", + "Device locator (SIMM1, SIMM2, etc.)", + "Vendor", + "Serial number", + })); +} + +void ffInitPhysicalMemoryOptions(FFPhysicalMemoryOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_PHYSICALMEMORY_MODULE_NAME, + "Print system physical memory devices", + ffParsePhysicalMemoryCommandOptions, + ffParsePhysicalMemoryJsonObject, + ffPrintPhysicalMemory, + ffGeneratePhysicalMemoryJsonResult, + ffPrintPhysicalMemoryHelpFormat, + ffGeneratePhysicalMemoryJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs); +} + +void ffDestroyPhysicalMemoryOptions(FFPhysicalMemoryOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); +} diff --git a/src/modules/physicalmemory/physicalmemory.h b/src/modules/physicalmemory/physicalmemory.h new file mode 100644 index 000000000..c9e0048d1 --- /dev/null +++ b/src/modules/physicalmemory/physicalmemory.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_PHYSICALMEMORY_MODULE_NAME "PhysicalMemory" + +void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options); +void ffInitPhysicalMemoryOptions(FFPhysicalMemoryOptions* options); +void ffDestroyPhysicalMemoryOptions(FFPhysicalMemoryOptions* options); diff --git a/src/options/modules.c b/src/options/modules.c index a64ca5ef9..d3a501c32 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -41,6 +41,7 @@ void ffOptionsInitModules(FFOptionsModules* options) ffInitOpenGLOptions(&options->openGL); ffInitPackagesOptions(&options->packages); ffInitPhysicalDiskOptions(&options->physicalDisk); + ffInitPhysicalMemoryOptions(&options->physicalMemory); ffInitPlayerOptions(&options->player); ffInitPowerAdapterOptions(&options->powerAdapter); ffInitProcessesOptions(&options->processes); @@ -105,6 +106,7 @@ void ffOptionsDestroyModules(FFOptionsModules* options) ffDestroyOpenCLOptions(&options->openCL); ffDestroyOpenGLOptions(&options->openGL); ffDestroyPhysicalDiskOptions(&options->physicalDisk); + ffDestroyPhysicalMemoryOptions(&options->physicalMemory); ffDestroyPackagesOptions(&options->packages); ffDestroyPlayerOptions(&options->player); ffDestroyPowerAdapterOptions(&options->powerAdapter); diff --git a/src/options/modules.h b/src/options/modules.h index d04f65071..dcd6e5bdc 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -42,6 +42,7 @@ typedef struct FFOptionsModules FFOpenGLOptions openGL; FFPackagesOptions packages; FFPhysicalDiskOptions physicalDisk; + FFPhysicalMemoryOptions physicalMemory; FFPlayerOptions player; FFPowerAdapterOptions powerAdapter; FFProcessesOptions processes; From 07747aa8196fe5c0f3c29f949a0984117b26260c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 11 May 2024 14:46:52 +0800 Subject: [PATCH 32/59] PhysicalMemory (macOS): add support --- CMakeLists.txt | 2 +- .../physicalmemory/physicalmemory_apple.m | 109 ++++++++++++++++++ src/modules/physicalmemory/physicalmemory.c | 10 +- 3 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/detection/physicalmemory/physicalmemory_apple.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 3091d5bde..417a42c68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -594,7 +594,7 @@ elseif(APPLE) src/detection/cursor/cursor_apple.m src/detection/disk/disk_bsd.c src/detection/physicaldisk/physicaldisk_apple.c - src/detection/physicalmemory/physicalmemory_nosupport.c + src/detection/physicalmemory/physicalmemory_apple.m src/detection/diskio/diskio_apple.c src/detection/displayserver/displayserver_apple.c src/detection/font/font_apple.m diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m new file mode 100644 index 000000000..8101184e6 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -0,0 +1,109 @@ +#include "physicalmemory.h" +#include "common/processing.h" +#include "util/stringUtils.h" + +#import + +static void appendDevice( + FFlist* result, + NSString* type, + NSString* vendor, + NSString* size, + + // Intel only + NSString* deviceLocator, + NSString* serial, + NSString* speed) +{ + FFPhysicalMemoryResult* device = ffListAdd(result); + ffStrbufInitS(&device->type, type.UTF8String); + ffStrbufInit(&device->formFactor); + ffStrbufInitS(&device->deviceLocator, deviceLocator.UTF8String); + ffStrbufInitS(&device->vendor, vendor.UTF8String); + ffStrbufInitS(&device->serial, serial.UTF8String); + device->size = 0; + device->maxSpeed = 0; + device->runningSpeed = 0; + + if (size) + { + char* unit = NULL; + device->size = strtoul(size.UTF8String, &unit, 10); + if (*unit == ' ') ++unit; + + switch (*unit) + { + case 'G': device->size *= 1024ULL * 1024 * 1024; break; + case 'M': device->size *= 1024ULL * 1024; break; + case 'K': device->size *= 1024ULL; break; + case 'T': device->size *= 1024ULL * 1024 * 1024 * 1024; break; + } + } + + if (speed) + { + char* unit = NULL; + device->maxSpeed = (uint32_t) strtoul(speed.UTF8String, &unit, 10); + if (*unit == ' ') ++unit; + + switch (*unit) + { + case 'T': device->maxSpeed *= 1000 * 1000; break; + case 'G': device->maxSpeed *= 1000; break; + case 'K': device->maxSpeed /= 1000; break; + } + device->runningSpeed = device->maxSpeed; + } +} + +const char* ffDetectPhysicalMemory(FFlist* result) +{ + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + if (ffProcessAppendStdOut(&buffer, (char* const[]) { + "system_profiler", + "SPMemoryDataType", + "-xml", + "-detailLevel", + "full", + NULL + }) != NULL) + return "Starting `system_profiler SPMemoryDataType -xml -detailLevel full` failed"; + + NSArray* arr = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytes:buffer.chars length:buffer.length] + options:NSPropertyListImmutable + format:nil + error:nil]; + if (!arr || !arr.count) + return "system_profiler SPMemoryDataType returned an empty array"; + + for (NSDictionary* data in arr[0][@"_items"]) + { + if (data[@"_items"]) + { + // for Intel + for (NSDictionary* item in data[@"_items"]) + { + appendDevice(result, + item[@"dimm_type"], + item[@"dimm_manufacturer"], + item[@"dimm_size"], + item[@"_name"], + item[@"dimm_serial_number"], + item[@"dimm_speed"]); + } + } + else + { + // for Apple Silicon + appendDevice(result, + data[@"dimm_type"], + data[@"dimm_manufacturer"], + data[@"SPMemoryDataType"], + nil, + nil, + nil); + } + } + + return NULL; +} diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c index faabab6ff..8b071d77b 100644 --- a/src/modules/physicalmemory/physicalmemory.c +++ b/src/modules/physicalmemory/physicalmemory.c @@ -32,7 +32,10 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) if(options->moduleArgs.key.length == 0) { - ffStrbufSetF(&key, "%s (%s %s-%u)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars, device->maxSpeed); + if (device->maxSpeed) + ffStrbufSetF(&key, "%s (%s %s-%u)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars, device->maxSpeed); + else + ffStrbufSetF(&key, "%s (%s %s)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars); } else { @@ -48,7 +51,10 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) if (options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - printf("%s, running at %u MT/s\n", prettySize.chars, device->runningSpeed); + if (device->runningSpeed > 0 && device->runningSpeed != device->maxSpeed) + printf("%s, running at %u MT/s\n", prettySize.chars, device->runningSpeed); + else + puts(prettySize.chars); } else { From ab0bd79bb81d63a3510b23021c11378249b8e576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 11 May 2024 14:57:37 +0800 Subject: [PATCH 33/59] PhysicalMemory: add module to `ci.jsonc` and `all.jsonc` --- presets/all.jsonc | 1 + presets/ci.jsonc | 1 + 2 files changed, 2 insertions(+) diff --git a/presets/all.jsonc b/presets/all.jsonc index 628bfed3d..cf7f2af93 100644 --- a/presets/all.jsonc +++ b/presets/all.jsonc @@ -34,6 +34,7 @@ "cpuusage", "gpu", "memory", + "physicalmemory", "swap", "disk", "battery", diff --git a/presets/ci.jsonc b/presets/ci.jsonc index d9236a26a..a7696b3f0 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -40,6 +40,7 @@ "cpuusage", "gpu", "memory", + "physicalmemory", "swap", "disk", "battery", From 41f09715709a8f1771018bb39334cfdbc3f01e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 11 May 2024 15:09:48 +0800 Subject: [PATCH 34/59] PhysicalMemory: ignore trash values --- src/detection/physicalmemory/physicalmemory_apple.m | 3 +++ src/util/smbiosHelper.c | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m index 8101184e6..950f1b256 100644 --- a/src/detection/physicalmemory/physicalmemory_apple.m +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -1,5 +1,6 @@ #include "physicalmemory.h" #include "common/processing.h" +#include "util/smbiosHelper.h" #include "util/stringUtils.h" #import @@ -20,7 +21,9 @@ static void appendDevice( ffStrbufInit(&device->formFactor); ffStrbufInitS(&device->deviceLocator, deviceLocator.UTF8String); ffStrbufInitS(&device->vendor, vendor.UTF8String); + ffCleanUpSmbiosValue(&device->vendor); ffStrbufInitS(&device->serial, serial.UTF8String); + ffCleanUpSmbiosValue(&device->serial); device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index b9418cab9..29265d03a 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -11,10 +11,8 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) !ffStrbufStartsWithIgnCaseS(value, "To be set") && !ffStrbufStartsWithIgnCaseS(value, "OEM") && !ffStrbufStartsWithIgnCaseS(value, "O.E.M.") && + !ffStrbufStartsWithIgnCaseS(value, "System Product") && !ffStrbufIgnCaseEqualS(value, "None") && - !ffStrbufIgnCaseEqualS(value, "System Product") && - !ffStrbufIgnCaseEqualS(value, "System Product Name") && - !ffStrbufIgnCaseEqualS(value, "System Product Version") && !ffStrbufIgnCaseEqualS(value, "System Name") && !ffStrbufIgnCaseEqualS(value, "System Version") && !ffStrbufIgnCaseEqualS(value, "Default string") && @@ -28,7 +26,8 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) !ffStrbufIgnCaseEqualS(value, "No Enclosure") && !ffStrbufIgnCaseEqualS(value, "Chassis Version") && !ffStrbufIgnCaseEqualS(value, "All Series") && - !ffStrbufIgnCaseEqualS(value, "N/A") + !ffStrbufIgnCaseEqualS(value, "N/A") && + !ffStrbufIgnCaseEqualS(value, "0x0000") ; } From d28907ee9d57082e230cfec4300d8d87b4abf9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 11 May 2024 08:14:56 +0000 Subject: [PATCH 35/59] PhysicalMemory (Linux): add support Note: this module requires root permission to work in Linux --- CMakeLists.txt | 4 +- ...emory_windows.c => physicalmemory_linux.c} | 8 +- src/util/smbiosHelper.c | 74 +++++++++++++++---- src/util/smbiosHelper.h | 16 +--- 4 files changed, 71 insertions(+), 31 deletions(-) rename src/detection/physicalmemory/{physicalmemory_windows.c => physicalmemory_linux.c} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 417a42c68..214938392 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,7 +401,7 @@ if(LINUX) src/detection/bluetooth/bluetooth_linux.c src/detection/disk/disk_linux.c src/detection/physicaldisk/physicaldisk_linux.c - src/detection/physicalmemory/physicalmemory_nosupport.c + src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -667,7 +667,7 @@ elseif(WIN32) src/detection/gamepad/gamepad_windows.c src/detection/media/media_nosupport.c src/detection/memory/memory_windows.c - src/detection/physicalmemory/physicalmemory_windows.c + src/detection/physicalmemory/physicalmemory_linux.c src/detection/monitor/monitor_windows.c src/detection/netio/netio_windows.c src/detection/opengl/opengl_windows.c diff --git a/src/detection/physicalmemory/physicalmemory_windows.c b/src/detection/physicalmemory/physicalmemory_linux.c similarity index 97% rename from src/detection/physicalmemory/physicalmemory_windows.c rename to src/detection/physicalmemory/physicalmemory_linux.c index 0426d72c7..8b45aa805 100644 --- a/src/detection/physicalmemory/physicalmemory_windows.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -67,9 +67,13 @@ static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62, const char* ffDetectPhysicalMemory(FFlist* result) { - const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_MEMORY_DEVICE]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE]; if (!data) - return "System enclosure is not found in SMBIOS data"; + return "Memory device is not found in SMBIOS data"; for (; data->Header.Type == FF_SMBIOS_TYPE_MEMORY_DEVICE; data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 29265d03a..4808a1ac8 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -1,6 +1,7 @@ #include "smbiosHelper.h" #include "common/io/io.h" #include "util/unused.h" +#include "util/mallocHelper.h" bool ffIsSmbiosValueSet(FFstrbuf* value) { @@ -31,7 +32,25 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) ; } +const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) +{ + const char* p = ((const char*) header) + header->Length; + if (*p) + { + do + p += strlen(p) + 1; + while (*p); + } + else // The terminator is always double 0 even if there is no string + p ++; + + return (const FFSmbiosHeader*) (p + 1); +} + #ifdef __linux__ +#include +#include + bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) { if (ffReadFileBuffer(devicesPath, buffer)) @@ -51,25 +70,50 @@ bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* ffStrbufClear(buffer); return false; } + +const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() +{ + static FFstrbuf buffer; + static FFSmbiosHeaderTable table; + + if (buffer.chars == NULL) + { + ffStrbufInit(&buffer); + if (!ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", &buffer)) + return NULL; + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars; + (const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length; + header = ffSmbiosNextEntry(header) + ) + { + if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE) + { + if (!table[header->Type]) + table[header->Type] = header; + } + else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) + break; + } + } + + return &table; +} #elif defined(_WIN32) #include #pragma GCC diagnostic ignored "-Wmultichar" -const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) +typedef struct FFRawSmbiosData { - const char* p = ((const char*) header) + header->Length; - if (*p) - { - do - p += strlen(p) + 1; - while (*p); - } - else // The terminator is always double 0 even if there is no string - p ++; - - return (const FFSmbiosHeader*) (p + 1); -} + uint8_t Used20CallingMethod; + uint8_t SMBIOSMajorVersion; + uint8_t SMBIOSMinorVersion; + uint8_t DmiRevision; + uint32_t Length; + uint8_t SMBIOSTableData[]; +} FFRawSmbiosData; const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { @@ -80,7 +124,9 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { const DWORD signature = 'RSMB'; uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0); - assert(bufSize > sizeof(FFRawSmbiosData)); + if (bufSize <= sizeof(FFRawSmbiosData)) + return NULL; + buffer = (FFRawSmbiosData*) malloc(bufSize); assert(buffer); FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index 81e820be0..7d7a4b18d 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -12,9 +12,6 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value) ffStrbufClear(value); } -#ifdef __linux__ -bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); -#elif defined(_WIN32) // https://github.com/KunYi/DumpSMBIOS // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf @@ -81,16 +78,6 @@ typedef struct FFSmbiosHeader } __attribute__((__packed__)) FFSmbiosHeader; static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes"); -typedef struct FFRawSmbiosData -{ - uint8_t Used20CallingMethod; - uint8_t SMBIOSMajorVersion; - uint8_t SMBIOSMinorVersion; - uint8_t DmiRevision; - uint32_t Length; - uint8_t SMBIOSTableData[]; -} FFRawSmbiosData; - static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */) { if (index == 0 || *start == '\0') @@ -104,6 +91,9 @@ typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE]; const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header); const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable(); + +#ifdef __linux__ +bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); #endif #endif From 6439921f854b16188530a8f45ab70fd45e2c863f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 11 May 2024 18:07:56 +0800 Subject: [PATCH 36/59] Smbios (Windows): check if getting SMBIOS data succeeds --- src/detection/battery/battery_windows.c | 6 +++++- src/detection/bios/bios_windows.c | 6 +++++- src/detection/board/board_windows.c | 6 +++++- src/detection/chassis/chassis_windows.c | 6 +++++- src/detection/cpu/cpu_windows.c | 6 +++++- src/detection/host/host_windows.c | 6 +++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 72373bceb..5a0a78a3c 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -183,7 +183,11 @@ static_assert(offsetof(FFSmbiosPortableBattery, OEMSpecific) == 0x16, const char* detectBySmbios(FFBatteryResult* battery) { - const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PORTABLE_BATTERY]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*smbiosTable)[FF_SMBIOS_TYPE_PORTABLE_BATTERY]; if (!data) return "Portable battery section is not found in SMBIOS data"; diff --git a/src/detection/bios/bios_windows.c b/src/detection/bios/bios_windows.c index 1ea9ee97d..d8a305493 100644 --- a/src/detection/bios/bios_windows.c +++ b/src/detection/bios/bios_windows.c @@ -53,7 +53,11 @@ static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18, const char* ffDetectBios(FFBiosResult* bios) { - const FFSmbiosBios* data = (const FFSmbiosBios*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BIOS]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosBios* data = (const FFSmbiosBios*) (*smbiosTable)[FF_SMBIOS_TYPE_BIOS]; if (!data) return "BIOS section is not found in SMBIOS data"; diff --git a/src/detection/board/board_windows.c b/src/detection/board/board_windows.c index 78a8ff7d4..bec6192e7 100644 --- a/src/detection/board/board_windows.c +++ b/src/detection/board/board_windows.c @@ -23,7 +23,11 @@ static_assert(offsetof(FFSmbiosBaseboard, ContainedObjectHandles) == 0x0F, const char* ffDetectBoard(FFBoardResult* board) { - const FFSmbiosBaseboard* data = (const FFSmbiosBaseboard*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BASEBOARD_INFO]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosBaseboard* data = (const FFSmbiosBaseboard*) (*smbiosTable)[FF_SMBIOS_TYPE_BASEBOARD_INFO]; if (!data) return "Baseboard information section is not found in SMBIOS data"; diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 2075ef20d..a9f4aeedb 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -32,7 +32,11 @@ static_assert(offsetof(FFSmbiosSystemEnclosure, ContainedElements) == 0x15, const char* ffDetectChassis(FFChassisResult* result) { - const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) (*smbiosTable)[FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE]; if (!data) return "System enclosure is not found in SMBIOS data"; diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index aad79ce1d..0f3bb55d5 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -80,7 +80,11 @@ inline static const char* detectSpeedByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu) static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) { - const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PROCESSOR_INFO]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_PROCESSOR_INFO]; if (!data) return "Processor information is not found in SMBIOS data"; diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index 0470c1210..c505d9071 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -31,7 +31,11 @@ static_assert(offsetof(FFSmbiosSystemInfo, Family) == 0x1A, const char* ffDetectHost(FFHostResult* host) { - const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_INFO]; + const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); + if (!smbiosTable) + return "Failed to get SMBIOS data"; + + const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_SYSTEM_INFO]; if (!data) return "System information is not found in SMBIOS data"; From d0d6323b1fec251f01f118deb5523d0651a37954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 17:54:54 +0800 Subject: [PATCH 37/59] PhysicalMemory (FreeBSD): add support --- CMakeLists.txt | 4 +- src/util/smbiosHelper.c | 91 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 214938392..1c75c6270 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -526,7 +526,7 @@ elseif(BSD) src/detection/cursor/cursor_linux.c src/detection/disk/disk_bsd.c src/detection/physicaldisk/physicaldisk_bsd.c - src/detection/physicalmemory/physicalmemory_nosupport.c + src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_bsd.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -779,7 +779,7 @@ if(BSD AND EXISTS "/usr/local/bin/objdump") endif() endif() -target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE __STDC_WANT_LIB_EXT1__=1) +target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE __STDC_WANT_LIB_EXT1__=1 _FILE_OFFSET_BITS=64) if(WIN32) target_compile_definitions(libfastfetch PUBLIC WIN32_LEAN_AND_MEAN=1) elseif(APPLE) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 4808a1ac8..0847617f0 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -47,9 +47,17 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) return (const FFSmbiosHeader*) (p + 1); } -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) #include #include +#include + +#ifdef __linux__ + #include "common/properties.h" +#else + #include "common/settings.h" + #define loff_t off_t // FreeBSD doesn't have loff_t +#endif bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) { @@ -71,20 +79,87 @@ bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* return false; } +typedef struct FFSmbios30EntryPoint +{ + uint8_t AnchorString[5]; + uint8_t EntryPointStructureChecksum; + uint8_t EntryPointLength; + uint8_t SmbiosMajorVersion; + uint8_t SmbiosMinorVersion; + uint8_t SmbiosDocrev; + uint8_t EntryPointRevision; + uint8_t Reversed; + uint32_t StructureTableMaximumSize; + uint64_t StructureTableAddress; +} __attribute__((__packed__)) FFSmbios30EntryPoint; + +static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10, + "FFSmbiosProcessorInfo: Wrong struct alignment"); + const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { - static FFstrbuf buffer; + static void* buffer; static FFSmbiosHeaderTable table; - if (buffer.chars == NULL) + if (!buffer) { - ffStrbufInit(&buffer); - if (!ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", &buffer)) - return NULL; + uint64_t bufLen = 0; + + #ifdef __linux__ + { + FF_AUTO_CLOSE_FD int fd = open("/sys/firmware/dmi/tables/DMI", O_RDONLY); + if (fd > 0) + { + struct stat st; + if (fstat(fd, &st) == 0) + { + buffer = mmap(NULL, (size_t) st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (buffer == MAP_FAILED) + buffer = NULL; + else + bufLen = (uint64_t) st.st_size; + } + } + } + if (!buffer) + #endif + { + FF_STRBUF_AUTO_DESTROY strEntry = ffStrbufCreate(); + // Only support SMBIOS 3.x for simplication + #ifdef __FreeBSD__ + if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntry)) + return NULL; + #else + if (!ffParsePropFile("/sys/firmware/efi/systab", "SMBIOS3=", &strEntry)) + return NULL; + #endif + + loff_t pEntry = (loff_t) strtol(strEntry.chars, NULL, 0); + if (pEntry == 0) return NULL; + + FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY); + if (fd < 0) return NULL; + + FFSmbios30EntryPoint entryPoint; + if (pread(fd, &entryPoint, sizeof(entryPoint), pEntry) != sizeof(entryPoint)) + return NULL; + + if (memcmp(entryPoint.AnchorString, "_SM3_", sizeof(entryPoint.AnchorString)) != 0 || + entryPoint.EntryPointLength != sizeof(entryPoint)) + return NULL; + + buffer = mmap(NULL, entryPoint.StructureTableMaximumSize, PROT_READ, MAP_SHARED, fd, (loff_t) entryPoint.StructureTableAddress); + if (buffer == MAP_FAILED) + { + buffer = NULL; + return NULL; + } + bufLen = entryPoint.StructureTableMaximumSize; + } for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars; - (const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length; + const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer; + (const uint8_t*) header < (const uint8_t*) buffer + bufLen; header = ffSmbiosNextEntry(header) ) { From 82d848727cccd986b3f9cc92acd69e36979b392f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 18:24:44 +0800 Subject: [PATCH 38/59] Logo (Builtin): fix alternate logo doesn't work with type builtin Fix #914 --- src/logo/logo.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/logo/logo.c b/src/logo/logo.c index c78926339..f8956ec74 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -436,7 +436,7 @@ static bool logoTryKnownType(void) } if(options->type == FF_LOGO_TYPE_BUILTIN) - return logoPrintBuiltinIfExists(&options->source, FF_LOGO_SIZE_NORMAL); + return logoPrintBuiltinIfExists(&options->source, FF_LOGO_SIZE_UNKNOWN); if(options->type == FF_LOGO_TYPE_SMALL) return logoPrintBuiltinIfExists(&options->source, FF_LOGO_SIZE_SMALL); @@ -461,12 +461,6 @@ static bool logoTryKnownType(void) return logoPrintImageIfExists(options->type, instance.config.display.showErrors); } -static void logoPrintKnownType(void) -{ - if(!logoTryKnownType()) - logoPrintDetected(FF_LOGO_SIZE_UNKNOWN); -} - void ffLogoPrint(void) { //When generate JSON result, we don't have a logo or padding. @@ -497,7 +491,17 @@ void ffLogoPrint(void) //If the source and source type is set to something else than auto, always print with the set type. if(options->source.length > 0 && options->type != FF_LOGO_TYPE_AUTO) { - logoPrintKnownType(); + if(!logoTryKnownType()) + { + if (instance.config.display.showErrors) + { + // Image logo should have been handled + if(options->type == FF_LOGO_TYPE_BUILTIN || options->type == FF_LOGO_TYPE_SMALL) + fprintf(stderr, "Logo: Failed to load %s logo: %s \n", options->type == FF_LOGO_TYPE_BUILTIN ? "builtin" : "builtin small", options->source.chars); + } + + logoPrintDetected(FF_LOGO_SIZE_UNKNOWN); + } return; } From df6ab6427e94997b788eae494ce081b868fe9fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 19:13:21 +0800 Subject: [PATCH 39/59] PhysicalMemory: improve default output format; detect part number --- src/detection/physicalmemory/physicalmemory.h | 1 + .../physicalmemory/physicalmemory_apple.m | 5 +++ .../physicalmemory/physicalmemory_linux.c | 4 ++ src/modules/physicalmemory/physicalmemory.c | 45 +++++++++---------- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h index 08e783a22..138099931 100644 --- a/src/detection/physicalmemory/physicalmemory.h +++ b/src/detection/physicalmemory/physicalmemory.h @@ -10,6 +10,7 @@ typedef struct FFPhysicalMemoryResult FFstrbuf type; FFstrbuf formFactor; FFstrbuf deviceLocator; + FFstrbuf partNumber; FFstrbuf vendor; FFstrbuf serial; } FFPhysicalMemoryResult; diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m index 950f1b256..3c5eab589 100644 --- a/src/detection/physicalmemory/physicalmemory_apple.m +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -14,6 +14,7 @@ static void appendDevice( // Intel only NSString* deviceLocator, NSString* serial, + NSString* partNumber, NSString* speed) { FFPhysicalMemoryResult* device = ffListAdd(result); @@ -24,6 +25,8 @@ static void appendDevice( ffCleanUpSmbiosValue(&device->vendor); ffStrbufInitS(&device->serial, serial.UTF8String); ffCleanUpSmbiosValue(&device->serial); + ffStrbufInitS(&device->partNumber, partNumber.UTF8String); + ffCleanUpSmbiosValue(&device->partNumber); device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; @@ -92,6 +95,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) item[@"dimm_size"], item[@"_name"], item[@"dimm_serial_number"], + item[@"dimm_part_number"], item[@"dimm_speed"]); } } @@ -104,6 +108,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) data[@"SPMemoryDataType"], nil, nil, + nil, nil); } } diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c index 8b45aa805..ea35813ca 100644 --- a/src/detection/physicalmemory/physicalmemory_linux.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -88,6 +88,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) ffStrbufInit(&device->deviceLocator); ffStrbufInit(&device->vendor); ffStrbufInit(&device->serial); + ffStrbufInit(&device->partNumber); device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; @@ -183,6 +184,9 @@ const char* ffDetectPhysicalMemory(FFlist* result) ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber)); ffCleanUpSmbiosValue(&device->serial); + + ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber)); + ffCleanUpSmbiosValue(&device->partNumber); } if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c index 8b071d77b..58ba210c8 100644 --- a/src/modules/physicalmemory/physicalmemory.c +++ b/src/modules/physicalmemory/physicalmemory.c @@ -6,7 +6,7 @@ #include "modules/physicalmemory/physicalmemory.h" #include "util/stringUtils.h" -#define FF_PHYSICALMEMORY_NUM_FORMAT_ARGS 9 +#define FF_PHYSICALMEMORY_NUM_FORMAT_ARGS 10 #define FF_PHYSICALMEMORY_DISPLAY_NAME "Physical Memory" void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) @@ -30,31 +30,25 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) ffStrbufClear(&prettySize); ffParseSize(device->size, &prettySize); - if(options->moduleArgs.key.length == 0) - { - if (device->maxSpeed) - ffStrbufSetF(&key, "%s (%s %s-%u)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars, device->maxSpeed); - else - ffStrbufSetF(&key, "%s (%s %s)", FF_PHYSICALMEMORY_DISPLAY_NAME, device->vendor.chars, device->type.chars); - } - else - { - FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, 5, ((FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_UINT, &i}, - {FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor}, - {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, - {FF_FORMAT_ARG_TYPE_UINT, &device->maxSpeed}, - {FF_FORMAT_ARG_TYPE_STRBUF, &device->deviceLocator}, - })); - } - if (options->moduleArgs.outputFormat.length == 0) { - ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + ffPrintLogoAndKey( + FF_PHYSICALMEMORY_DISPLAY_NAME, + result.length == 1 ? 0 : (uint8_t) i, + &options->moduleArgs, + FF_PRINT_TYPE_DEFAULT); + + fputs(prettySize.chars, stdout); + fputs(" - ", stdout); + + ffStrbufWriteTo(&device->type, stdout); + if (device->maxSpeed > 0) + printf("-%u", device->maxSpeed); if (device->runningSpeed > 0 && device->runningSpeed != device->maxSpeed) - printf("%s, running at %u MT/s\n", prettySize.chars, device->runningSpeed); - else - puts(prettySize.chars); + printf(" at %u MT/s\n", device->runningSpeed); + if (device->vendor.length > 0) + printf(" (%s)", device->vendor.chars); + putchar('\n'); } else { @@ -68,6 +62,7 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) {FF_FORMAT_ARG_TYPE_DOUBLE, &device->deviceLocator}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->serial}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->partNumber}, })); } } @@ -78,6 +73,7 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) ffStrbufDestroy(&device->formFactor); ffStrbufDestroy(&device->vendor); ffStrbufDestroy(&device->serial); + ffStrbufDestroy(&device->partNumber); } } @@ -138,6 +134,7 @@ void ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* yyjson_mut_obj_add_strbuf(doc, obj, "formFactor", &device->formFactor); yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &device->vendor); yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial); + yyjson_mut_obj_add_strbuf(doc, obj, "partNumber", &device->partNumber); } FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) @@ -146,6 +143,7 @@ void ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* ffStrbufDestroy(&device->formFactor); ffStrbufDestroy(&device->vendor); ffStrbufDestroy(&device->serial); + ffStrbufDestroy(&device->partNumber); } } @@ -161,6 +159,7 @@ void ffPrintPhysicalMemoryHelpFormat(void) "Device locator (SIMM1, SIMM2, etc.)", "Vendor", "Serial number", + "Part number", })); } From df2862996b07e5fdcce9bccc227b79c15f9e01d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 19:55:04 +0800 Subject: [PATCH 40/59] PhysicalMemory: detect ecc & bank locator --- src/detection/physicalmemory/physicalmemory.h | 3 ++- .../physicalmemory/physicalmemory_apple.m | 14 +++++++++----- .../physicalmemory/physicalmemory_linux.c | 9 ++++++--- src/modules/physicalmemory/physicalmemory.c | 15 +++++++++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h index 138099931..4d7465eba 100644 --- a/src/detection/physicalmemory/physicalmemory.h +++ b/src/detection/physicalmemory/physicalmemory.h @@ -9,10 +9,11 @@ typedef struct FFPhysicalMemoryResult uint32_t runningSpeed; // MT/s FFstrbuf type; FFstrbuf formFactor; - FFstrbuf deviceLocator; + FFstrbuf locator; FFstrbuf partNumber; FFstrbuf vendor; FFstrbuf serial; + bool ecc; } FFPhysicalMemoryResult; const char* ffDetectPhysicalMemory(FFlist* result); // list of FFPhysicalMemoryResult diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m index 3c5eab589..a965ee906 100644 --- a/src/detection/physicalmemory/physicalmemory_apple.m +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -12,15 +12,16 @@ static void appendDevice( NSString* size, // Intel only - NSString* deviceLocator, + NSString* locator, NSString* serial, NSString* partNumber, - NSString* speed) + NSString* speed, + bool ecc) { FFPhysicalMemoryResult* device = ffListAdd(result); ffStrbufInitS(&device->type, type.UTF8String); ffStrbufInit(&device->formFactor); - ffStrbufInitS(&device->deviceLocator, deviceLocator.UTF8String); + ffStrbufInitS(&device->locator, locator.UTF8String); ffStrbufInitS(&device->vendor, vendor.UTF8String); ffCleanUpSmbiosValue(&device->vendor); ffStrbufInitS(&device->serial, serial.UTF8String); @@ -30,6 +31,7 @@ static void appendDevice( device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; + device->ecc = ecc; if (size) { @@ -96,7 +98,8 @@ const char* ffDetectPhysicalMemory(FFlist* result) item[@"_name"], item[@"dimm_serial_number"], item[@"dimm_part_number"], - item[@"dimm_speed"]); + item[@"dimm_speed"], + !![data[@"global_ecc_state"] isEqualToString:@"ecc_enabled"]); } } else @@ -109,7 +112,8 @@ const char* ffDetectPhysicalMemory(FFlist* result) nil, nil, nil, - nil); + nil, + false); } } diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c index ea35813ca..824464311 100644 --- a/src/detection/physicalmemory/physicalmemory_linux.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -85,13 +85,17 @@ const char* ffDetectPhysicalMemory(FFlist* result) FFPhysicalMemoryResult* device = ffListAdd(result); ffStrbufInit(&device->type); ffStrbufInit(&device->formFactor); - ffStrbufInit(&device->deviceLocator); + ffStrbufInit(&device->locator); ffStrbufInit(&device->vendor); ffStrbufInit(&device->serial); ffStrbufInit(&device->partNumber); device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; + device->ecc = false; + + if (data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF) + device->ecc = data->TotalWidth > data->DataWidth; if (data->Size != 0xFFFF) { @@ -109,8 +113,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) } } - ffStrbufSetStatic(&device->deviceLocator, ffSmbiosLocateString(strings, data->DeviceLocator)); - ffCleanUpSmbiosValue(&device->deviceLocator); + ffStrbufSetF(&device->locator, "%s/%s", ffSmbiosLocateString(strings, data->BankLocator), ffSmbiosLocateString(strings, data->DeviceLocator)); switch (data->FormFactor) { diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c index 58ba210c8..16525ac62 100644 --- a/src/modules/physicalmemory/physicalmemory.c +++ b/src/modules/physicalmemory/physicalmemory.c @@ -6,7 +6,7 @@ #include "modules/physicalmemory/physicalmemory.h" #include "util/stringUtils.h" -#define FF_PHYSICALMEMORY_NUM_FORMAT_ARGS 10 +#define FF_PHYSICALMEMORY_NUM_FORMAT_ARGS 11 #define FF_PHYSICALMEMORY_DISPLAY_NAME "Physical Memory" void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) @@ -40,7 +40,6 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) fputs(prettySize.chars, stdout); fputs(" - ", stdout); - ffStrbufWriteTo(&device->type, stdout); if (device->maxSpeed > 0) printf("-%u", device->maxSpeed); @@ -48,6 +47,8 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) printf(" at %u MT/s\n", device->runningSpeed); if (device->vendor.length > 0) printf(" (%s)", device->vendor.chars); + if (device->ecc) + fputs(" - ECC", stdout); putchar('\n'); } else @@ -59,10 +60,11 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) {FF_FORMAT_ARG_TYPE_UINT, &device->runningSpeed}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->formFactor}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &device->deviceLocator}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &device->locator}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->serial}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->partNumber}, + {FF_FORMAT_ARG_TYPE_BOOL, &device->ecc}, })); } } @@ -70,6 +72,7 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) { ffStrbufDestroy(&device->type); + ffStrbufDestroy(&device->locator); ffStrbufDestroy(&device->formFactor); ffStrbufDestroy(&device->vendor); ffStrbufDestroy(&device->serial); @@ -131,15 +134,18 @@ void ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* yyjson_mut_obj_add_uint(doc, obj, "maxSpeed", device->maxSpeed); yyjson_mut_obj_add_uint(doc, obj, "runningSpeed", device->runningSpeed); yyjson_mut_obj_add_strbuf(doc, obj, "type", &device->type); + yyjson_mut_obj_add_strbuf(doc, obj, "locator", &device->locator); yyjson_mut_obj_add_strbuf(doc, obj, "formFactor", &device->formFactor); yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &device->vendor); yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial); yyjson_mut_obj_add_strbuf(doc, obj, "partNumber", &device->partNumber); + yyjson_mut_obj_add_bool(doc, obj, "ecc", device->ecc); } FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) { ffStrbufDestroy(&device->type); + ffStrbufDestroy(&device->locator); ffStrbufDestroy(&device->formFactor); ffStrbufDestroy(&device->vendor); ffStrbufDestroy(&device->serial); @@ -156,10 +162,11 @@ void ffPrintPhysicalMemoryHelpFormat(void) "Running speed (in MT/s)", "Type (DDR4, DDR5, etc.)", "Form factor (SODIMM, DIMM, etc.)", - "Device locator (SIMM1, SIMM2, etc.)", + "Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)", "Vendor", "Serial number", "Part number", + "ECC enabled", })); } From 217bb6657e75ae0cb580fb8a19724c7c22bf13fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 20:17:57 +0800 Subject: [PATCH 41/59] PhysicalMemory: fix output format --- src/modules/physicalmemory/physicalmemory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c index 16525ac62..8b92517a7 100644 --- a/src/modules/physicalmemory/physicalmemory.c +++ b/src/modules/physicalmemory/physicalmemory.c @@ -44,7 +44,7 @@ void ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) if (device->maxSpeed > 0) printf("-%u", device->maxSpeed); if (device->runningSpeed > 0 && device->runningSpeed != device->maxSpeed) - printf(" at %u MT/s\n", device->runningSpeed); + printf(" @ %u MT/s", device->runningSpeed); if (device->vendor.length > 0) printf(" (%s)", device->vendor.chars); if (device->ecc) From b36b74448f69893bfa060e1bd1f9827e6a9c55ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 12 May 2024 20:24:56 +0800 Subject: [PATCH 42/59] Doc: update changelog --- CHANGELOG.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71bb65ebe..e7895b2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,18 +4,24 @@ Changes: * The long deprecated options `--set` and `--set-keyless` are removed. Features: -* Support st terminal font detection for font configuration compiled in st binary (TerminalFont, Linux) -* Support option `--color-output` to change output color of all modules except `Title`, `Separator` and `Colors` +* Support `st` terminal font detection for font configuration compiled in `st` binary (TerminalFont, Linux) +* Support option `--color-output` to change output color of all modules except `Title`, `Separator` * `display.color.output` in JSONC config file * Support option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` -* Add new module `Loadavg` to print load averages (Loadavg) * Add option `--publicip-ipv6` to print IPv6 address (PublicIP) +* Add new module `Loadavg` to print load averages (Loadavg) +* Add new module `PhysicalMemory` to print information of physical memory devices (PhysicalMemory) + * Requires root permission to work on Linux and FreeBSD +* Support specifying `--logo-width` only for `--kitty-direct` and `--iterm` (Logo) Bugfixes: * Rename option `--temperature-unit` to `--temp-unit` as stated in help messages +* Fix compatibility with `(*term)` (#909, Terminal, macOS) +* Fix alternate logo doesn't work with type builtin (Logo) +* Fix DahliaOS detection (Logo) Logos: -* Fix DahliaOS detection +* Add openSUSE Slowroll # 2.11.5 From 68942c1d3fa602581ae23017fc2948e159e0ffbf Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 13 May 2024 09:42:15 +0800 Subject: [PATCH 43/59] PhysicalMemory (FreeBSD): fix EFAULT errors --- src/util/smbiosHelper.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 0847617f0..35cb179f0 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -142,12 +142,21 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() FFSmbios30EntryPoint entryPoint; if (pread(fd, &entryPoint, sizeof(entryPoint), pEntry) != sizeof(entryPoint)) - return NULL; + { + // `pread /dev/mem` returns EFAULT in FreeBSD + // https://stackoverflow.com/questions/69372330/how-to-read-dev-mem-using-read + void* p = mmap(NULL, sizeof(entryPoint), PROT_READ, MAP_SHARED, fd, pEntry); + if (p == MAP_FAILED) return NULL; + memcpy(&entryPoint, p, sizeof(entryPoint)); + munmap(p, sizeof(entryPoint)); + } if (memcmp(entryPoint.AnchorString, "_SM3_", sizeof(entryPoint.AnchorString)) != 0 || entryPoint.EntryPointLength != sizeof(entryPoint)) return NULL; + // entryPoint.StructureTableAddress must be page aligned. + // Unaligned physical memory access results in all kinds of crashes. buffer = mmap(NULL, entryPoint.StructureTableMaximumSize, PROT_READ, MAP_SHARED, fd, (loff_t) entryPoint.StructureTableAddress); if (buffer == MAP_FAILED) { From b80eb47ecde758b6733231e7312e83b53c795de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 06:38:00 +0000 Subject: [PATCH 44/59] PhysicalMemory: better Linux compatibility --- src/util/smbiosHelper.c | 53 ++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 35cb179f0..13b119ec4 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -98,34 +98,17 @@ static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10, const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { - static void* buffer; + static FFstrbuf buffer; static FFSmbiosHeaderTable table; - if (!buffer) + if (buffer.chars == NULL) { - uint64_t bufLen = 0; - #ifdef __linux__ - { - FF_AUTO_CLOSE_FD int fd = open("/sys/firmware/dmi/tables/DMI", O_RDONLY); - if (fd > 0) - { - struct stat st; - if (fstat(fd, &st) == 0) - { - buffer = mmap(NULL, (size_t) st.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (buffer == MAP_FAILED) - buffer = NULL; - else - bufLen = (uint64_t) st.st_size; - } - } - } - if (!buffer) + if (!ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", &buffer)) #endif { FF_STRBUF_AUTO_DESTROY strEntry = ffStrbufCreate(); - // Only support SMBIOS 3.x for simplication + // Only support SMBIOS 3.x for simplification #ifdef __FreeBSD__ if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntry)) return NULL; @@ -155,20 +138,30 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() entryPoint.EntryPointLength != sizeof(entryPoint)) return NULL; - // entryPoint.StructureTableAddress must be page aligned. - // Unaligned physical memory access results in all kinds of crashes. - buffer = mmap(NULL, entryPoint.StructureTableMaximumSize, PROT_READ, MAP_SHARED, fd, (loff_t) entryPoint.StructureTableAddress); - if (buffer == MAP_FAILED) + ffStrbufEnsureFixedLengthFree(&buffer, entryPoint.StructureTableMaximumSize); + if (pread(fd, buffer.chars, entryPoint.StructureTableMaximumSize, pEntry) == (loff_t) entryPoint.StructureTableMaximumSize) { - buffer = NULL; - return NULL; + buffer.length = (uint32_t) entryPoint.StructureTableMaximumSize; + buffer.chars[buffer.length] = '\0'; + } + else + { + // entryPoint.StructureTableAddress must be page aligned. + // Unaligned physical memory access results in all kinds of crashes. + void* p = mmap(NULL, entryPoint.StructureTableMaximumSize, PROT_READ, MAP_SHARED, fd, (loff_t) entryPoint.StructureTableAddress); + if (p == MAP_FAILED) + { + ffStrbufDestroy(&buffer); // free buffer and reset state + return NULL; + } + ffStrbufSetNS(&buffer, entryPoint.StructureTableMaximumSize, (char*) p); + munmap(p, entryPoint.StructureTableMaximumSize); } - bufLen = entryPoint.StructureTableMaximumSize; } for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer; - (const uint8_t*) header < (const uint8_t*) buffer + bufLen; + const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars; + (const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length; header = ffSmbiosNextEntry(header) ) { From c985bdbbfd5a7ea25117569d8d0228b233a0a4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 15:50:10 +0800 Subject: [PATCH 45/59] Logo: add macOS3 --- CHANGELOG.md | 1 + src/logo/ascii/macos3.txt | 16 ++++++++++++++++ src/logo/builtin.c | 15 +++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/logo/ascii/macos3.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e7895b2e5..1e68b4b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Bugfixes: Logos: * Add openSUSE Slowroll +* Add macOS3 # 2.11.5 diff --git a/src/logo/ascii/macos3.txt b/src/logo/ascii/macos3.txt new file mode 100644 index 000000000..d3900c02a --- /dev/null +++ b/src/logo/ascii/macos3.txt @@ -0,0 +1,16 @@ +${c1} -:+:. +${c1} :++++. +${c1} /+++/. +${c1} .:-::- .+/:-\`\`.::- +${c1} .:/++++++/::::/++++++/::` +${c2} .:///////////////////////::` +${c2} /////////////////////////` +${c3}+++++++++++++++++++++++++` +${c3}++++++++++++++++++++++++ +${c4}ssssssssssssssssssssssss. +${c4}:ssssssssssssssssssssssss- +${c5} osssssssssssssssssssssssss` +${c5} `syyyyyyyyyyyyyyyyyyyyyyyyys` +${c6} `ossssssssssssssssssssssss +${c6} :ooooooooooooooooooo+. +${c6} `:++oo+/:- -:/+o+/- diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 853b7c453..103ee952f 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -2461,6 +2461,21 @@ static const FFlogo M[] = { .colorKeys = FF_COLOR_FG_YELLOW, .colorTitle = FF_COLOR_FG_GREEN, }, + // MacOS3 + { + .names = {"macos3", "mac3"}, + .type = FF_LOGO_LINE_TYPE_ALTER_BIT, + .lines = FASTFETCH_DATATEXT_LOGO_MACOS3, + .colors = { + FF_COLOR_FG_GREEN, + FF_COLOR_FG_YELLOW, + FF_COLOR_FG_RED, + FF_COLOR_FG_MAGENTA, + FF_COLOR_FG_BLUE, + }, + .colorKeys = FF_COLOR_FG_YELLOW, + .colorTitle = FF_COLOR_FG_GREEN, + }, // MainsailOS { .names = {"MainsailOS"}, From c8e3c6882ae25a6f0789f0efc30930bea29011fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 16:41:00 +0800 Subject: [PATCH 46/59] Kernel: print kernel name in default format --- CHANGELOG.md | 1 + src/modules/kernel/kernel.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e68b4b2d..b19f38ec7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Changes: * The long deprecated options `--set` and `--set-keyless` are removed. +* `Kernel` module now prints kernel name by default Features: * Support `st` terminal font detection for font configuration compiled in `st` binary (TerminalFont, Linux) diff --git a/src/modules/kernel/kernel.c b/src/modules/kernel/kernel.c index 2839af7a0..43cdf766f 100644 --- a/src/modules/kernel/kernel.c +++ b/src/modules/kernel/kernel.c @@ -11,7 +11,7 @@ void ffPrintKernel(FFKernelOptions* options) if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_KERNEL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufWriteTo(&platform->systemRelease, stdout); + printf("%s %s", platform->systemName.chars, platform->systemRelease.chars); if(platform->systemDisplayVersion.length > 0) printf(" (%s)\n", platform->systemDisplayVersion.chars); @@ -77,7 +77,7 @@ void ffGenerateKernelJsonResult(FF_MAYBE_UNUSED FFKernelOptions* options, yyjson void ffPrintKernelHelpFormat(void) { - FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_KERNEL_MODULE_NAME, "{2}", FF_KERNEL_NUM_FORMAT_ARGS, ((const char* []) { + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_KERNEL_MODULE_NAME, "{1} {2}", FF_KERNEL_NUM_FORMAT_ARGS, ((const char* []) { "Sysname", "Release", "Version", From 131e01f35b7dc2395d39eef3afa2287cea9733cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 16:43:24 +0800 Subject: [PATCH 47/59] Presets: add archey Ref: https://github.com/HorlogeSkynet/archey4 --- presets/archey.jsonc | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 presets/archey.jsonc diff --git a/presets/archey.jsonc b/presets/archey.jsonc new file mode 100644 index 000000000..e2cd8a3c9 --- /dev/null +++ b/presets/archey.jsonc @@ -0,0 +1,80 @@ +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "modules": [ + { + "type": "title", + "key": "User", + "format": "{1}" + }, + { + "type": "title", + "key": "Hostname", + "format": "{2}" + }, + { + "type": "host", + "key": "Model" + }, + { + "type": "os", + "format": "{3} {9} {12}" + }, + "kernel", + "uptime", + { + "type": "loadavg", + "key": "Load Average" + }, + "processes", + { + "type": "wm", + "key": "Window Manager" + }, + { + "type": "de", + "key": "Desktop Environment" + }, + { + "type": "shell", + "format": "{7}" + }, + { + "type": "terminal", + "format": "{5} {6} \u001b[31m█\u001b[91m█ \u001b[32m█\u001b[92m█ \u001b[33m█\u001b[93m█ \u001b[34m█\u001b[94m█ \u001b[35m█\u001b[95m█ \u001b[36m█\u001b[96m█" + }, + { + "type": "packages", + "format": "{1}" + }, + { + "type": "cpu", + "key": "Temperature", + "temp": true, + "format": "{8}" + }, + { + "type": "cpu", + "key": "CPU", + "format": "{4} x {1}" + }, + { + "type": "gpu", + "format": "{2}" + }, + { + "type": "memory", + "key": "RAM" + }, + { + "type": "disk", + "key": "Disk", + "folders": "/" + }, + { + "type": "localip", + "key": "LAN IP", + "showIpv6": true, + "showPrefixLen": false + } + ] +} From caef317adea331e96326aef2ac2582edf5d82470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 19:33:31 +0800 Subject: [PATCH 48/59] GPU: a tiny optimization --- src/detection/gpu/gpu.c | 48 +++++++++++++---------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index 3f65e1791..4f70d3452 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -14,42 +14,24 @@ const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft"; const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat"; const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle"; -static inline bool arrayContains(const unsigned arr[], unsigned vendorId, unsigned length) -{ - for (unsigned i = 0; i < length; ++i) - { - if (arr[i] == vendorId) - return true; - } - return false; -} - const char* ffGetGPUVendorString(unsigned vendorId) { // https://devicehunt.com/all-pci-vendors - if(vendorId == 0x106b) - return FF_GPU_VENDOR_NAME_APPLE; - if(arrayContains((const unsigned[]) {0x1002, 0x1022}, vendorId, 2)) - return FF_GPU_VENDOR_NAME_AMD; - else if(arrayContains((const unsigned[]) {0x03e7, 0x8086, 0x8087}, vendorId, 3)) - return FF_GPU_VENDOR_NAME_INTEL; - else if(arrayContains((const unsigned[]) {0x0955, 0x10de, 0x12d2}, vendorId, 3)) - return FF_GPU_VENDOR_NAME_NVIDIA; - else if(arrayContains((const unsigned[]) {0x5143}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_QUALCOMM; - else if(arrayContains((const unsigned[]) {0x14c3}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_MTK; - else if(arrayContains((const unsigned[]) {0x15ad}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_VMWARE; - else if(arrayContains((const unsigned[]) {0x1af4}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_REDHAT; - else if(arrayContains((const unsigned[]) {0x1ab8}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_PARALLEL; - else if(arrayContains((const unsigned[]) {0x1414}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_MICROSOFT; - else if(arrayContains((const unsigned[]) {0x108e}, vendorId, 1)) - return FF_GPU_VENDOR_NAME_ORACLE; - return NULL; + switch (vendorId) + { + case 0x106b: return FF_GPU_VENDOR_NAME_APPLE; + case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD; + case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL; + case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA; + case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM; + case 0x14c3: return FF_GPU_VENDOR_NAME_MTK; + case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE; + case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT; + case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL; + case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT; + case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE; + default: return NULL; + } } const char* detectByOpenGL(FFlist* gpus) From 56403bab5c893808f844e7797664afde90a447ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 20:29:46 +0800 Subject: [PATCH 49/59] PhysicalMemory: try converting vendor ID to name --- CMakeLists.txt | 1 + src/detection/physicalmemory/physicalmemory.c | 42 +++++++++++++++++++ src/detection/physicalmemory/physicalmemory.h | 2 + .../physicalmemory/physicalmemory_apple.m | 2 +- .../physicalmemory/physicalmemory_linux.c | 2 +- 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/detection/physicalmemory/physicalmemory.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c75c6270..b68db9bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,6 +297,7 @@ set(LIBFASTFETCH_SRC src/detection/opencl/opencl.c src/detection/os/os.c src/detection/packages/packages.c + src/detection/physicalmemory/physicalmemory.c src/detection/publicip/publicip.c src/detection/terminaltheme/terminaltheme.c src/detection/terminalfont/terminalfont.c diff --git a/src/detection/physicalmemory/physicalmemory.c b/src/detection/physicalmemory/physicalmemory.c new file mode 100644 index 000000000..f8137c7be --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory.c @@ -0,0 +1,42 @@ +#include "physicalmemory.h" + +static inline const char* getVendorString(unsigned vendorId) +{ + switch (vendorId) + { + case 0x017A: return "Apacer"; + case 0x0198: return "HyperX"; + case 0x029E: return "Corsair"; + case 0x04CB: return "A-DATA"; + case 0x04CD: return "G-Skill"; + case 0x059B: case 0x859B: case 0x1315: return "Crucial"; + case 0x00CE: case 0x80CE: case 0xCE00: return "Samsung"; + case 0x014F: return "Transcend"; + case 0x2C00: case 0x802C: return "Micron"; + case 0xAD00: case 0x80AD: return "Hynix"; + case 0x5105: case 0x8551: return "Qimonda"; + case 0x02FE: return "Elpida"; + default: return NULL; + } +} + +void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device) +{ + char vendorIdStr[5]; + if (ffStrbufStartsWithS(&device->vendor, "0x")) + { + if (device->vendor.length < 6) return; + memcpy(vendorIdStr, device->vendor.chars + 2, 4); + } + else + { + if (device->vendor.length < 4) return; + memcpy(vendorIdStr, device->vendor.chars, 4); + } + vendorIdStr[4] = '\0'; + char* pEnd = NULL; + uint32_t vendorId = (uint32_t) strtoul(vendorIdStr, &pEnd, 16); + if (*pEnd != '\0') return; + const char* vendorStr = getVendorString(vendorId); + if (vendorStr) ffStrbufSetStatic(&device->vendor, vendorStr); +} diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h index 4d7465eba..2580295ca 100644 --- a/src/detection/physicalmemory/physicalmemory.h +++ b/src/detection/physicalmemory/physicalmemory.h @@ -17,3 +17,5 @@ typedef struct FFPhysicalMemoryResult } FFPhysicalMemoryResult; const char* ffDetectPhysicalMemory(FFlist* result); // list of FFPhysicalMemoryResult + +void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device); diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m index a965ee906..243b35aca 100644 --- a/src/detection/physicalmemory/physicalmemory_apple.m +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -23,7 +23,7 @@ static void appendDevice( ffStrbufInit(&device->formFactor); ffStrbufInitS(&device->locator, locator.UTF8String); ffStrbufInitS(&device->vendor, vendor.UTF8String); - ffCleanUpSmbiosValue(&device->vendor); + FFPhysicalMemoryUpdateVendorString(device); ffStrbufInitS(&device->serial, serial.UTF8String); ffCleanUpSmbiosValue(&device->serial); ffStrbufInitS(&device->partNumber, partNumber.UTF8String); diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c index 824464311..a773d3d93 100644 --- a/src/detection/physicalmemory/physicalmemory_linux.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -183,7 +183,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed; ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); - ffCleanUpSmbiosValue(&device->vendor); + FFPhysicalMemoryUpdateVendorString(device); ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber)); ffCleanUpSmbiosValue(&device->serial); From c661e550534783057512645dcf4e448248f88e44 Mon Sep 17 00:00:00 2001 From: Null-Ping <141347595+Null-Ping@users.noreply.github.com> Date: Mon, 13 May 2024 16:20:27 +0200 Subject: [PATCH 50/59] PhysicalMemory: Fix ram vendor names from ids. (#917) Change 0x0198 from HyperX to Kingston to match https://www.jedec.org/standards-documents/docs/jep-106ab. (The standard does not contain an entry for HyperX at all). Remove the ambiguous 0x1315 - according to the standard, it belongs to Tioga Technologies and not Crucial. Rename Hynix to SK Hynix to match the standard. --- src/detection/physicalmemory/physicalmemory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detection/physicalmemory/physicalmemory.c b/src/detection/physicalmemory/physicalmemory.c index f8137c7be..cda43c3a5 100644 --- a/src/detection/physicalmemory/physicalmemory.c +++ b/src/detection/physicalmemory/physicalmemory.c @@ -5,15 +5,15 @@ static inline const char* getVendorString(unsigned vendorId) switch (vendorId) { case 0x017A: return "Apacer"; - case 0x0198: return "HyperX"; + case 0x0198: return "Kingston"; case 0x029E: return "Corsair"; case 0x04CB: return "A-DATA"; case 0x04CD: return "G-Skill"; - case 0x059B: case 0x859B: case 0x1315: return "Crucial"; + case 0x059B: case 0x859B: return "Crucial"; case 0x00CE: case 0x80CE: case 0xCE00: return "Samsung"; case 0x014F: return "Transcend"; case 0x2C00: case 0x802C: return "Micron"; - case 0xAD00: case 0x80AD: return "Hynix"; + case 0xAD00: case 0x80AD: return "SK Hynix"; case 0x5105: case 0x8551: return "Qimonda"; case 0x02FE: return "Elpida"; default: return NULL; From 3b8c2d6ee6f92c55b0c7d9aa0cf1c4a45cad1fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 22:27:35 +0800 Subject: [PATCH 51/59] Logo (Builtin): add Quirinux --- CHANGELOG.md | 1 + src/logo/ascii/quirinux.txt | 17 +++++++++++++++++ src/logo/builtin.c | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100644 src/logo/ascii/quirinux.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index b19f38ec7..d027ea8c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Bugfixes: Logos: * Add openSUSE Slowroll * Add macOS3 +* Add Quirinux # 2.11.5 diff --git a/src/logo/ascii/quirinux.txt b/src/logo/ascii/quirinux.txt new file mode 100644 index 000000000..2046bd947 --- /dev/null +++ b/src/logo/ascii/quirinux.txt @@ -0,0 +1,17 @@ +$2 @=++++++++++=@ +$2 =++++++++++++++++++= +$2 *++++++++++++++++++++++* +$2 =++++++++++++++++++++++++++= +$2 *++++++++$1-..........-$2++++++++* +$2 =++++++++$1..............$2++++++++= +$2@++++++++$1:.....$2:++$1:.....:$2++++++++@ +$2=++++++++$1:.....$2++++$1.....:$2++++++++= +$2=++++++++$1:.....$2++++$1.....:$2++++++++= +$2#++++++++$1:.....$2++++$1.....:$2++++++++# +$2 +++++++++$1......$2--$1......$2+++++++++ +$2 @++++++++$1:............:$2++++++++@ +$2 @+++++++++++$1-....-$2+++++++++++@ +$2 *++++++++++$1::::$2++++++++++* +$2 *++++++++++++++++++++* +$2 @*++++++++++++++*@ +$2 @#====#@ diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 103ee952f..be92989e6 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -3467,6 +3467,15 @@ static const FFlogo Q[] = { FF_COLOR_FG_WHITE, }, }, + // Quirinux + { + .names = {"Quirinux"}, + .lines = FASTFETCH_DATATEXT_LOGO_QUIRINUX, + .colors = { + FF_COLOR_FG_WHITE, + FF_COLOR_FG_MAGENTA, + }, + }, // LAST {}, }; From be1791e386033d0ef036cb83b9e9957b86f8e0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 13 May 2024 22:59:39 +0800 Subject: [PATCH 52/59] LocalIP: add option `--localip-show-all-ips` --- CHANGELOG.md | 6 ++- doc/json_schema.json | 5 +++ src/data/help.json | 9 ++++ src/detection/localip/localip_linux.c | 24 ++++++---- src/detection/localip/localip_windows.c | 14 +++++- src/modules/localip/localip.c | 60 +++++++++++++++++-------- src/modules/localip/option.h | 5 ++- 7 files changed, 92 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d027ea8c3..ddf6b647e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,16 @@ Changes: Features: * Support `st` terminal font detection for font configuration compiled in `st` binary (TerminalFont, Linux) -* Support option `--color-output` to change output color of all modules except `Title`, `Separator` +* Add option `--color-output` to change output color of all modules except `Title`, `Separator` * `display.color.output` in JSONC config file -* Support option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` +* Add option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` * Add option `--publicip-ipv6` to print IPv6 address (PublicIP) * Add new module `Loadavg` to print load averages (Loadavg) * Add new module `PhysicalMemory` to print information of physical memory devices (PhysicalMemory) * Requires root permission to work on Linux and FreeBSD * Support specifying `--logo-width` only for `--kitty-direct` and `--iterm` (Logo) +* Add option `--localip-show-all-ips` to show all IPs assigned to the same interface (LocalIP) + * By default first IP will be shown only Bugfixes: * Rename option `--temperature-unit` to `--temp-unit` as stated in help messages diff --git a/doc/json_schema.json b/doc/json_schema.json index 7b0efd4c8..ac3bfad9c 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1510,6 +1510,11 @@ "type": "boolean", "default": true }, + "showAllIps": { + "description": "Show all IPs bound to the same interface.\nBy default only the first IP is shown", + "type": "boolean", + "default": false + }, "compact": { "description": "Show all IPs in one line", "type": "boolean", diff --git a/src/data/help.json b/src/data/help.json index 7801aafbf..7e3631e35 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1298,6 +1298,15 @@ "default": true } }, + { + "long": "localip-show-all-ips", + "desc": "Show all IPs bound to the same interface. By default only the first IP is shown", + "arg": { + "type": "bool", + "optional": true, + "default": false + } + }, { "long": "localip-compact", "desc": "Show all IPs in one line", diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c index 905dec568..9c23b987f 100644 --- a/src/detection/localip/localip_linux.c +++ b/src/detection/localip/localip_linux.c @@ -17,7 +17,7 @@ #include #endif -static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool defaultRoute) +static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool defaultRoute, bool firstOnly) { FFLocalIpResult* ip = NULL; @@ -40,11 +40,19 @@ static void addNewIp(FFlist* list, const char* name, const char* addr, int type, switch (type) { case AF_INET: - if (ip->ipv4.length) ffStrbufAppendC(&ip->ipv4, ','); + if (ip->ipv4.length) + { + if (firstOnly) return; + ffStrbufAppendC(&ip->ipv4, ','); + } ffStrbufAppendS(&ip->ipv4, addr); break; case AF_INET6: - if (ip->ipv6.length) ffStrbufAppendC(&ip->ipv6, ','); + if (ip->ipv6.length) + { + if (firstOnly) return; + ffStrbufAppendC(&ip->ipv6, ','); + } ffStrbufAppendS(&ip->ipv6, addr); break; case -1: @@ -67,7 +75,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) continue; bool isDefaultRoute = ffStrEquals(defaultRouteIfName, ifa->ifa_name); - if (options->defaultRouteOnly && !isDefaultRoute) + if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute) continue; if ((ifa->ifa_flags & IFF_LOOPBACK) && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT)) @@ -96,7 +104,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } } - addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); } else if (ifa->ifa_addr->sa_family == AF_INET6) { @@ -121,7 +129,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } } - addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); } #if defined(__FreeBSD__) || defined(__APPLE__) else if (ifa->ifa_addr->sa_family == AF_LINK) @@ -133,7 +141,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = (uint8_t*) LLADDR((struct sockaddr_dl *)ifa->ifa_addr); snprintf(addressBuffer, sizeof(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, false); } #else else if (ifa->ifa_addr->sa_family == AF_PACKET) @@ -145,7 +153,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = ((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr; snprintf(addressBuffer, sizeof(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, false); } #endif } diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 96463c331..0650ae54a 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -78,7 +78,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next) { bool isDefaultRoute = adapter->IfIndex == defaultRouteIfIndex; - if (options->defaultRouteOnly && !isDefaultRoute) + if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute) continue; bool isLoop = adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK; @@ -102,10 +102,14 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) newIp = false; } + uint32_t typesToAdd = options->showType & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT); + for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next) { if (ifa->Address.lpSockaddr->sa_family == AF_INET) { + if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue; + SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr; char addressBuffer[INET_ADDRSTRLEN + 4]; inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN); @@ -118,9 +122,14 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) addNewIp(results, name, addressBuffer, AF_INET, newIp, isDefaultRoute); newIp = false; + + typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV4_BIT; + if (typesToAdd == 0) break; } else if (ifa->Address.lpSockaddr->sa_family == AF_INET6) { + if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue; + SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr; char addressBuffer[INET6_ADDRSTRLEN + 4]; inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN); @@ -133,6 +142,9 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) addNewIp(results, name, addressBuffer, AF_INET6, newIp, isDefaultRoute); newIp = false; + + typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV6_BIT; + if (typesToAdd == 0) break; } } } diff --git a/src/modules/localip/localip.c b/src/modules/localip/localip.c index 6f02338ad..9cb042eb2 100644 --- a/src/modules/localip/localip.c +++ b/src/modules/localip/localip.c @@ -192,15 +192,27 @@ bool ffParseLocalIpCommandOptions(FFLocalIpOptions* options, const char* key, co return true; } - if (ffStrEqualsIgnCase(subKey, "name-prefix")) + if (ffStrEqualsIgnCase(subKey, "default-route-only")) { - ffOptionParseString(key, value, &options->namePrefix); + if (ffOptionParseBoolean(value)) + options->showType |= FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; return true; } - if (ffStrEqualsIgnCase(subKey, "default-route-only")) + if (ffStrEqualsIgnCase(subKey, "show-all-ips")) { - options->defaultRouteOnly = ffOptionParseBoolean(value); + if (ffOptionParseBoolean(value)) + options->showType |= FF_LOCALIP_TYPE_ALL_IPS_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_ALL_IPS_BIT; + return true; + } + + if (ffStrEqualsIgnCase(subKey, "name-prefix")) + { + ffOptionParseString(key, value, &options->namePrefix); return true; } @@ -274,15 +286,27 @@ void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module) continue; } - if (ffStrEqualsIgnCase(key, "namePrefix")) + if (ffStrEqualsIgnCase(key, "defaultRouteOnly")) { - ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); + if (yyjson_get_bool(val)) + options->showType |= FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; continue; } - if (ffStrEqualsIgnCase(key, "defaultRouteOnly")) + if (ffStrEqualsIgnCase(key, "showAllIps")) { - options->defaultRouteOnly = yyjson_get_bool(val); + if (yyjson_get_bool(val)) + options->showType |= FF_LOCALIP_TYPE_ALL_IPS_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_ALL_IPS_BIT; + continue; + } + + if (ffStrEqualsIgnCase(key, "namePrefix")) + { + ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); continue; } @@ -316,13 +340,16 @@ void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc, if (options->showType & FF_LOCALIP_TYPE_COMPACT_BIT) yyjson_mut_obj_add_bool(doc, module, "compact", true); + + if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) + yyjson_mut_obj_add_bool(doc, module, "defaultRouteOnly", true); + + if (options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) + yyjson_mut_obj_add_bool(doc, module, "showAllIps", true); } if (!ffStrbufEqual(&options->namePrefix, &defaultOptions.namePrefix)) yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix); - - if (options->defaultRouteOnly != defaultOptions.defaultRouteOnly) - yyjson_mut_obj_add_bool(doc, module, "defaultRouteOnly", options->defaultRouteOnly); } void ffGenerateLocalIpJsonResult(FF_MAYBE_UNUSED FFLocalIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -383,15 +410,12 @@ void ffInitLocalIpOptions(FFLocalIpOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); - options->showType = FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_PREFIX_LEN_BIT; - ffStrbufInit(&options->namePrefix); - options->defaultRouteOnly = - #ifdef __ANDROID__ - false - #else - true + options->showType = FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_PREFIX_LEN_BIT + #ifndef __ANDROID__ + | FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT #endif ; + ffStrbufInit(&options->namePrefix); } void ffDestroyLocalIpOptions(FFLocalIpOptions* options) diff --git a/src/modules/localip/option.h b/src/modules/localip/option.h index 56092e98d..55b9192cd 100644 --- a/src/modules/localip/option.h +++ b/src/modules/localip/option.h @@ -13,7 +13,9 @@ typedef enum FFLocalIpType FF_LOCALIP_TYPE_MAC_BIT = 1 << 3, FF_LOCALIP_TYPE_PREFIX_LEN_BIT = 1 << 4, - FF_LOCALIP_TYPE_COMPACT_BIT = 1 << 10, + FF_LOCALIP_TYPE_COMPACT_BIT = 1 << 10, + FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT = 1 << 11, + FF_LOCALIP_TYPE_ALL_IPS_BIT = 1 << 12, } FFLocalIpType; typedef struct FFLocalIpOptions @@ -23,5 +25,4 @@ typedef struct FFLocalIpOptions FFLocalIpType showType; FFstrbuf namePrefix; - bool defaultRouteOnly; } FFLocalIpOptions; From 1d9e612262bd1bf956797bdfdabee4f1b600a950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 09:11:27 +0800 Subject: [PATCH 53/59] Presets: update [ci skip] --- presets/archey.jsonc | 6 +++++- presets/ci.jsonc | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/presets/archey.jsonc b/presets/archey.jsonc index e2cd8a3c9..ae5401d08 100644 --- a/presets/archey.jsonc +++ b/presets/archey.jsonc @@ -40,7 +40,7 @@ }, { "type": "terminal", - "format": "{5} {6} \u001b[31m█\u001b[91m█ \u001b[32m█\u001b[92m█ \u001b[33m█\u001b[93m█ \u001b[34m█\u001b[94m█ \u001b[35m█\u001b[95m█ \u001b[36m█\u001b[96m█" + "format": "{5} {6} \u001b[37m█\u001b[97m█ \u001b[36m█\u001b[96m█ \u001b[35m█\u001b[95m█ \u001b[34m█\u001b[94m█ \u001b[33m█\u001b[93m█ \u001b[32m█\u001b[92m█ \u001b[31m█\u001b[91m█ \u001b[30m█\u001b[90m█" }, { "type": "packages", @@ -75,6 +75,10 @@ "key": "LAN IP", "showIpv6": true, "showPrefixLen": false + }, + { + "type": "publicip", + "key": "WAN IP" } ] } diff --git a/presets/ci.jsonc b/presets/ci.jsonc index a7696b3f0..e78ac6ce3 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -6,6 +6,7 @@ "showErrors": true, "noBuffer": true }, + "logo": null, "modules": [ "title", "separator", From dc94ac8d0c5d39604dab7b3331c24183c1971704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 10:25:29 +0800 Subject: [PATCH 54/59] Doc: update json_schema --- doc/json_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index ac3bfad9c..dc43ff932 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -23,7 +23,7 @@ "default": 0 }, "format": { - "description": "Output format of the module", + "description": "Output format of the module. See `-h <module>-format` for detail", "type": "string" }, "outputColor": { From 30b85fc169158df7a52618fd7b0b756759a12f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 10:47:20 +0800 Subject: [PATCH 55/59] JsonConfig: report row and column on JSON parsing errors --- src/fastfetch.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/fastfetch.c b/src/fastfetch.c index 4283fd56a..c2f02765a 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -319,18 +319,60 @@ static void listModules(bool pretty) static void parseOption(FFdata* data, const char* key, const char* value); +// Temporary copy before new release of yyjson +static bool ffyyjson_locate_pos(const char *str, size_t len, size_t pos, + size_t *line, size_t *col, size_t *chr) { + size_t line_sum = 0, line_pos = 0, chr_sum = 0; + const uint8_t *cur = (const uint8_t *)str; + const uint8_t *end = cur + pos; + + if (!str || pos > len) { + if (line) *line = 0; + if (col) *col = 0; + if (chr) *chr = 0; + return false; + } + + while (cur < end) { + uint8_t c = *cur; + chr_sum += 1; + if (__builtin_expect(c < 0x80, true)) { /* 0xxxxxxx (0x00-0x7F) ASCII */ + if (c == '\n') { + line_sum += 1; + line_pos = chr_sum; + } + cur += 1; + } + else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */ + else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */ + else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */ + else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */ + else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */ + } + + if (line) *line = line_sum + 1; + if (col) *col = chr_sum - line_pos + 1; + if (chr) *chr = chr_sum; + return true; +} + + static bool parseJsoncFile(const char* path) { assert(!instance.state.configDoc); { yyjson_read_err error; - instance.state.configDoc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN, NULL, &error); + instance.state.configDoc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS, NULL, &error); if (!instance.state.configDoc) { if (error.code != YYJSON_READ_ERROR_FILE_OPEN) { - fprintf(stderr, "Error: failed to parse JSON config file `%s` at pos %zu: %s\n", path, error.pos, error.msg); + size_t row = 0, col = error.pos; + FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate(); + if (ffAppendFileBuffer(path, &content)) + ffyyjson_locate_pos(content.chars, content.length, error.pos, &row, &col, NULL); + fprintf(stderr, "Error: failed to parse JSON config file `%s` at (%zu, %zu): %s\n", path, row, col, error.msg); exit(477); } return false; From 4290efb49d5c3d86be48d06932e0ddf56822d89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 10:48:21 +0800 Subject: [PATCH 56/59] Release: v2.12.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b68db9bda..735998c1a 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.11.5 + VERSION 2.12.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" From ba76b18367db8df80643645fae87497d837c48ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 14:08:54 +0800 Subject: [PATCH 57/59] Fastfetch: remove support of flag based config --- CHANGELOG.md | 5 +- src/fastfetch.c | 144 ++++-------------------------------------------- 2 files changed, 16 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddf6b647e..540de190d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # 2.12.0 Changes: -* The long deprecated options `--set` and `--set-keyless` are removed. +* The native support of (long deprecated) flag based config files are removed. + * They can still be used by `xargs fastfetch < /path/to/config.conf` + * `--gen-config` can be used to migrate them to json based config files +* The (long deprecated) options `--set` and `--set-keyless` are removed. * `Kernel` module now prints kernel name by default Features: diff --git a/src/fastfetch.c b/src/fastfetch.c index c2f02765a..722c61462 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -317,8 +317,6 @@ static void listModules(bool pretty) } } -static void parseOption(FFdata* data, const char* key, const char* value); - // Temporary copy before new release of yyjson static bool ffyyjson_locate_pos(const char *str, size_t len, size_t pos, size_t *line, size_t *col, size_t *chr) { @@ -402,104 +400,6 @@ static bool parseJsoncFile(const char* path) return true; } -static bool parseConfigFile(FFdata* data, const char* path) -{ - FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r"); - if(file == NULL) - return false; - - char* line = NULL; - size_t len = 0; - ssize_t read; - FF_STRBUF_AUTO_DESTROY unescaped = ffStrbufCreate(); - - while ((read = getline(&line, &len, file)) != -1) - { - char* lineStart = line; - char* lineEnd = line + read - 1; - - //Trim line left - while(isspace(*lineStart)) - ++lineStart; - - //Continue if line is empty or a comment - if(*lineStart == '\0' || *lineStart == '#') - continue; - - //Trim line right - while(lineEnd > lineStart && isspace(*lineEnd)) - --lineEnd; - *(lineEnd + 1) = '\0'; - - char* valueStart = strchr(lineStart, ' '); - - //If the line has no white space, it is only a key - if(valueStart == NULL) - { - parseOption(data, lineStart, NULL); - continue; - } - - //separate the key from the value - *valueStart = '\0'; - ++valueStart; - - //Trim space of value left - while(isspace(*valueStart)) - ++valueStart; - - //If we want whitespace in values, we need to quote it. This is done to keep consistency with shell. - if((*valueStart == '"' || *valueStart == '\'') && *valueStart == *lineEnd && lineEnd > valueStart) - { - ++valueStart; - *lineEnd = '\0'; - --lineEnd; - } - - if (strchr(valueStart, '\\')) - { - // Unescape all `\x`s - const char* value = valueStart; - while(*value != '\0') - { - if(*value != '\\') - { - ffStrbufAppendC(&unescaped, *value); - ++value; - continue; - } - - ++value; - - switch(*value) - { - case 'n': ffStrbufAppendC(&unescaped, '\n'); break; - case 't': ffStrbufAppendC(&unescaped, '\t'); break; - case 'e': ffStrbufAppendC(&unescaped, '\e'); break; - case '\\': ffStrbufAppendC(&unescaped, '\\'); break; - default: - ffStrbufAppendC(&unescaped, '\\'); - ffStrbufAppendC(&unescaped, *value); - break; - } - - ++value; - } - parseOption(data, lineStart, unescaped.chars); - ffStrbufClear(&unescaped); - } - else - { - parseOption(data, lineStart, valueStart); - } - } - - if(line != NULL) - free(line); - - return true; -} - static void generateConfigFile(bool force, const char* filePath) { if (!filePath) @@ -509,11 +409,6 @@ static void generateConfigFile(bool force, const char* filePath) } else { - if (ffStrEqualsIgnCase(filePath, "conf") || ffStrEqualsIgnCase(filePath, "jsonc")) - { - fputs("Error: specifying file type is no longer supported\n", stderr); - exit(477); - } ffStrbufSetS(&instance.state.genConfigPath, filePath); } @@ -549,19 +444,15 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val if (ffStrEqualsIgnCase(value, "none")) return; - bool isJsonConfig = fileNameLen > strlen(".jsonc") && strcasecmp(value + fileNameLen - strlen(".jsonc"), ".jsonc") == 0; + if (ffStrEndsWithIgnCase(value, ".conf")) + { + fprintf(stderr, "Error: flag based config files are no longer not supported: %s\n", value); + exit(414); + } //Try to load as an absolute path - if(isJsonConfig ? parseJsoncFile(value) : parseConfigFile(data, value)) - return; - - { - bool success = isJsonConfig ? parseJsoncFile(value) : parseConfigFile(data, value); - - if(success) - return; - } + if (parseJsoncFile(value)) return; //Try to load as a relative path @@ -573,15 +464,14 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val ffStrbufAppendS(&absolutePath, "fastfetch/presets/"); ffStrbufAppendS(&absolutePath, value); - bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars); + bool success = parseJsoncFile(absolutePath.chars); if (!success) { ffStrbufAppendS(&absolutePath, ".jsonc"); success = parseJsoncFile(absolutePath.chars); } - if(success) - return; + if (success) return; } { @@ -591,15 +481,14 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val ffStrbufAppendS(&absolutePath, "/presets/"); ffStrbufAppendS(&absolutePath, value); - bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars); + bool success = parseJsoncFile(absolutePath.chars); if (!success) { ffStrbufAppendS(&absolutePath, ".jsonc"); success = parseJsoncFile(absolutePath.chars); } - if(success) - return; + if (success) return; } //File not found @@ -755,7 +644,7 @@ static void parseOption(FFdata* data, const char* key, const char* value) } } -static void parseConfigFiles(FFdata* data) +static void parseConfigFiles(void) { if (__builtin_expect(instance.state.genConfigPath.length == 0, true)) { @@ -769,15 +658,6 @@ static void parseConfigFiles(FFdata* data) if (success) return; } } - FF_LIST_FOR_EACH(FFstrbuf, dir, instance.state.platform.configDirs) - { - uint32_t dirLength = dir->length; - - ffStrbufAppendS(dir, "fastfetch/config.conf"); - bool success = parseConfigFile(data, dir->chars); - ffStrbufSubstrBefore(dir, dirLength); - if (success) return; - } } static void parseArguments(FFdata* data, int argc, char** argv, void (*parser)(FFdata* data, char* key, char* value)) @@ -884,7 +764,7 @@ int main(int argc, char** argv) parseArguments(&data, argc, argv, parseCommand); if(!data.configLoaded && !getenv("NO_CONFIG")) - parseConfigFiles(&data); + parseConfigFiles(); parseArguments(&data, argc, argv, (void*) parseOption); if (__builtin_expect(instance.state.genConfigPath.length == 0, true)) From a6212c5b018461745c5868b0874186a7acf3f9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 14:11:12 +0800 Subject: [PATCH 58/59] PhysicalMemory: add Ramaxel vendor id support --- src/detection/physicalmemory/physicalmemory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/detection/physicalmemory/physicalmemory.c b/src/detection/physicalmemory/physicalmemory.c index cda43c3a5..6591c3245 100644 --- a/src/detection/physicalmemory/physicalmemory.c +++ b/src/detection/physicalmemory/physicalmemory.c @@ -16,6 +16,7 @@ static inline const char* getVendorString(unsigned vendorId) case 0xAD00: case 0x80AD: return "SK Hynix"; case 0x5105: case 0x8551: return "Qimonda"; case 0x02FE: return "Elpida"; + case 0x0467: return "Ramaxel"; default: return NULL; } } From 533f54fb73b9c88ee357b56127179b60fdc9b7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 14 May 2024 15:20:22 +0800 Subject: [PATCH 59/59] Doc: update changelog [ci skip] --- CHANGELOG.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 540de190d..1869906db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ # 2.12.0 Changes: -* The native support of (long deprecated) flag based config files are removed. - * They can still be used by `xargs fastfetch < /path/to/config.conf` +* The long deprecated flag based config files are removed. + * They can still be used with `xargs fastfetch < /path/to/config.conf` * `--gen-config` can be used to migrate them to json based config files -* The (long deprecated) options `--set` and `--set-keyless` are removed. +* The long deprecated options `--set` and `--set-keyless` are removed. * `Kernel` module now prints kernel name by default Features: @@ -18,15 +18,15 @@ Features: * Requires root permission to work on Linux and FreeBSD * Support specifying `--logo-width` only for `--kitty-direct` and `--iterm` (Logo) * Add option `--localip-show-all-ips` to show all IPs assigned to the same interface (LocalIP) - * By default first IP will be shown only + * Default to `false` +* Improve compatibility with `(*term)` (#909, Terminal, macOS) Bugfixes: -* Rename option `--temperature-unit` to `--temp-unit` as stated in help messages -* Fix compatibility with `(*term)` (#909, Terminal, macOS) -* Fix alternate logo doesn't work with type builtin (Logo) -* Fix DahliaOS detection (Logo) +* Rename option `--temperature-unit` to `--temp-unit` as documented in help messages +* Fix alternate logo doesn't work with `{ "type": "builtin" }` (#914, Logo) Logos: +* Fix DahliaOS detection * Add openSUSE Slowroll * Add macOS3 * Add Quirinux