diff --git a/CMakeLists.txt b/CMakeLists.txt index f157d0b0f..830ec5f46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,7 +261,6 @@ endif() if(LINUX OR ANDROID OR BSD) list(APPEND LIBFASTFETCH_SRC src/detection/cpuUsage/cpuUsage_linux.c - src/detection/battery/battery_linux.c src/detection/disk/disk_linux.c ) endif() @@ -280,6 +279,7 @@ if(LINUX OR BSD) src/detection/displayserver/linux/wmde.c src/detection/terminalfont/terminalfont_linux.c src/detection/media/media_linux.c + src/detection/wmtheme/wmtheme_linux.c ) endif() @@ -299,6 +299,7 @@ if(APPLE) src/detection/terminalfont/terminalfont_apple.c src/detection/media/media_apple.m src/detection/disk/disk_apple.m + src/detection/wmtheme/wmtheme_apple.c ) endif() @@ -318,6 +319,7 @@ if(ANDROID) src/detection/displayserver/displayserver_android.c src/detection/terminalfont/terminalfont_android.c src/detection/media/media_android.c + src/detection/wmtheme/wmtheme_android.c ) endif() diff --git a/src/detection/terminalfont/terminalfont_apple.c b/src/detection/terminalfont/terminalfont_apple.c index 5c4f896b0..190ec0672 100644 --- a/src/detection/terminalfont/terminalfont_apple.c +++ b/src/detection/terminalfont/terminalfont_apple.c @@ -71,7 +71,7 @@ static const char* iterm2ParsePList(const FFinstance* instance, const FFstrbuf* exit: ffplist_free(root_node); dlclose(libplist); - return NULL; + return error; } static void detectIterm2(const FFinstance* instance, FFTerminalFontResult* terminalFont) diff --git a/src/detection/wmtheme/wmtheme.h b/src/detection/wmtheme/wmtheme.h new file mode 100644 index 000000000..e1475006f --- /dev/null +++ b/src/detection/wmtheme/wmtheme.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef FASTFETCH_INCLUDED_detection_wmtheme +#define FASTFETCH_INCLUDED_detection_wmtheme + +bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError); + +#endif diff --git a/src/detection/wmtheme/wmtheme_android.c b/src/detection/wmtheme/wmtheme_android.c new file mode 100644 index 000000000..7d9da9a5d --- /dev/null +++ b/src/detection/wmtheme/wmtheme_android.c @@ -0,0 +1,10 @@ +#include "fastfetch.h" +#include "detection/displayserver/displayserver.h" +#include "wmtheme.h" + +bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError) +{ + FF_UNUSED(instance); + ffStrbufAppendS(themeOrError, "WM theme detection is not supported on Android"); + return false; +} diff --git a/src/detection/wmtheme/wmtheme_apple.c b/src/detection/wmtheme/wmtheme_apple.c new file mode 100644 index 000000000..d1515c54e --- /dev/null +++ b/src/detection/wmtheme/wmtheme_apple.c @@ -0,0 +1,106 @@ +#include "fastfetch.h" +#include "detection/displayserver/displayserver.h" +#include "wmtheme.h" + +#ifdef FF_HAVE_LIBPLIST +#include "common/library.h" +#include "common/io.h" +#include + +static const char* quartzCompositorParsePlist(FFinstance* instance, const FFstrbuf* content, FFstrbuf* theme) +{ + FF_LIBRARY_LOAD(libplist, &instance->config.libplist, "dlopen libplist failed", "libplist-2.0"FF_LIBRARY_EXTENSION, 2); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_is_binary); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_from_bin); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_from_xml); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_dict_get_item); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_get_string_ptr); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_get_uint_val); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_free); + + plist_t root_node = NULL; + if (ffplist_is_binary(content->chars, content->length)) + ffplist_from_bin(content->chars, content->length, &root_node); + else + ffplist_from_xml(content->chars, content->length, &root_node); + + if(root_node == NULL) + return "parsing Quartz Compositor preference file failed"; + + plist_t pWmThemeColor = ffplist_dict_get_item(root_node, "AppleAccentColor"); + uint64_t wmThemeColor = 100; + if (pWmThemeColor != NULL) + ffplist_get_uint_val(pWmThemeColor, &wmThemeColor); + switch (wmThemeColor) + { + case (uint64_t)-1: ffStrbufAppendS(theme, "Graphite"); break; + case 0: ffStrbufAppendS(theme, "Red"); break; + case 1: ffStrbufAppendS(theme, "Orange"); break; + case 2: ffStrbufAppendS(theme, "Yellow"); break; + case 3: ffStrbufAppendS(theme, "Green"); break; + case 4: ffStrbufAppendS(theme, "Blue"); break; + case 5: ffStrbufAppendS(theme, "Purple"); break; + case 6: ffStrbufAppendS(theme, "Pink"); break; + default: ffStrbufAppendS(theme, "Multicolor"); break; + } + + plist_t pWmTheme = ffplist_dict_get_item(root_node, "AppleInterfaceStyle"); + ffStrbufAppendF(theme, " (%s)", pWmTheme != NULL ? ffplist_get_string_ptr(pWmTheme, NULL) : "Light"); + + ffplist_free(root_node); + return NULL; +} + +static bool detectQuartzCompositor(FFinstance* instance, FFstrbuf* themeOrError) +{ + FFstrbuf fileName; + ffStrbufInitS(&fileName, instance->state.passwd->pw_dir); + ffStrbufAppendS(&fileName, "/Library/Preferences/.GlobalPreferences.plist"); + + FFstrbuf content; + ffStrbufInit(&content); + ffAppendFileBuffer(fileName.chars, &content); + ffStrbufDestroy(&fileName); + if(content.length == 0) + { + ffStrbufDestroy(&content); + ffStrbufSetS(themeOrError, "reading Quartz Compositor preference file failed"); + return false; + } + + const char* error = quartzCompositorParsePlist(instance, &content, themeOrError); + ffStrbufDestroy(&content); + if(error) + { + ffStrbufSetS(themeOrError, error); + return false; + } + + return true; +} +#else +static bool detectQuartzCompositor(FFinstance* instance, FFstrbuf* theme) +{ + FF_UNUSED(instance); + ffStrbufSetS("Fastfetch was compiled without libplist support"); + return false; +} +#endif + +bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError) +{ + const FFDisplayServerResult* wm = ffConnectDisplayServer(instance); + + if(wm->wmPrettyName.length == 0) + { + ffStrbufAppendS(themeOrError, "WM Theme needs sucessfull WM detection"); + return false; + } + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Quartz Compositor") == 0) + return detectQuartzCompositor(instance, themeOrError); + + ffStrbufAppendS(themeOrError, "Unknown WM: "); + ffStrbufAppend(themeOrError, &wm->dePrettyName); + return false; +} diff --git a/src/detection/wmtheme/wmtheme_linux.c b/src/detection/wmtheme/wmtheme_linux.c new file mode 100644 index 000000000..0650d2f4a --- /dev/null +++ b/src/detection/wmtheme/wmtheme_linux.c @@ -0,0 +1,229 @@ +#include "fastfetch.h" +#include "common/properties.h" +#include "common/parsing.h" +#include "common/settings.h" +#include "detection/gtk.h" +#include "detection/displayserver/displayserver.h" +#include "wmtheme.h" + +static bool detectWMThemeFromConfigFile(FFinstance* instance, const char* configFile, const char* themeRegex, const char* defaultValue, FFstrbuf* themeOrError) +{ + if(!ffParsePropFileConfig(instance, configFile, themeRegex, themeOrError)) + { + ffStrbufInitF(themeOrError, "Config file %s doesn't exist", configFile); + return false; + } + + if(themeOrError->length == 0) + { + if(defaultValue == NULL) + { + ffStrbufAppendF(themeOrError, "Couldn't find WM theme in %s", configFile); + return false; + } + + ffStrbufAppendS(themeOrError, defaultValue); + return true; + } + + // Remove Plasma-generated prefixes + uint32_t idx = 0; + + idx = ffStrbufFirstIndexS(themeOrError, "qml_"); + if(idx != themeOrError->length) + ffStrbufSubstrAfter(themeOrError, idx + 3); + + idx = ffStrbufFirstIndexS(themeOrError, "svg__"); + if(idx != themeOrError->length) + ffStrbufSubstrAfter(themeOrError, idx + 4); + + return true; +} + +static bool detectWMThemeFromSettings(FFinstance* instance, const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFstrbuf* themeOrError) +{ + const char* theme = ffSettingsGet(instance, dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue; + + if(!ffStrSet(theme)) + { + ffStrbufAppendS(themeOrError, "Couldn't find WM theme in DConf or GSettings"); + return false; + } + + ffStrbufAppendS(themeOrError, theme); + return true; +} + +static bool detectGTKThemeAsWMTheme(FFinstance* instance, FFstrbuf* themeOrError) +{ + const FFGTKResult* gtk = ffDetectGTK4(instance); + if(gtk->theme.length > 0) + goto ok; + + gtk = ffDetectGTK3(instance); + if(gtk->theme.length > 0) + goto ok; + + gtk = ffDetectGTK2(instance); + if(gtk->theme.length > 0) + goto ok; + + ffStrbufAppendS(themeOrError, "Couldn't detect GTK4/3/2 theme"); + return false; + +ok: + ffStrbufAppend(themeOrError, >k->theme); + return true; +} + +static bool detectMutter(FFinstance* instance, FFstrbuf* themeOrError) +{ + const char* theme = ffSettingsGet(instance, "/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; + if(ffStrSet(theme)) + { + ffStrbufAppendS(themeOrError, theme); + return true; + } + + return detectGTKThemeAsWMTheme(instance, themeOrError); +} + +static bool detectMuffin(FFinstance* instance, FFstrbuf* themeOrError) +{ + const char* name = ffSettingsGet(instance, "/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; + const char* theme = ffSettingsGet(instance, "/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue; + + if(name == NULL && theme == NULL) + { + ffStrbufAppendS(themeOrError, "Couldn't find muffin theme in GSettings / DConf"); + return false; + } + + if(name == NULL) + { + ffStrbufAppendS(themeOrError, theme); + return true; + } + if(theme == NULL) + { + ffStrbufAppendS(themeOrError, theme); + return true; + } + ffStrbufAppendF(themeOrError, "%s (%s)", name, theme); + return true; +} + +static bool detectXFWM4(FFinstance* instance, FFstrbuf* themeOrError) +{ + const char* theme = ffSettingsGetXFConf(instance, "xfwm4", "/general/theme", FF_VARIANT_TYPE_STRING).strValue; + + if(theme == NULL) + { + ffStrbufAppendS(themeOrError, "Couldn't find xfwm4::/general/theme in XFConf"); + return false; + } + + ffStrbufAppendS(themeOrError, theme); + return true; +} + +static bool detectOpenbox(FFinstance* instance, const FFstrbuf* dePrettyName, FFstrbuf* themeOrError) +{ + FFstrbuf absolutePath; + ffStrbufInitA(&absolutePath, 64); + ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir); + ffStrbufAppendC(&absolutePath, '/'); + + if(ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0) + ffStrbufAppendS(&absolutePath, ".config/openbox/lxqt-rc.xml"); + else if(ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0) + ffStrbufAppendS(&absolutePath, ".config/openbox/lxde-rc.xml"); + else + ffStrbufAppendS(&absolutePath, ".config/openbox/rc.xml"); + + char* line = NULL; + size_t len = 0; + + FILE* file = fopen(absolutePath.chars, "r"); + if(file == NULL) + { + ffStrbufAppendF(themeOrError, "Couldn't open \"%s\"", absolutePath.chars); + ffStrbufDestroy(&absolutePath); + + return false; + } + + while(getline(&line, &len, file) != -1) + { + if(strstr(line, "") != 0) + break; + } + + while(getline(&line, &len, file) != -1) + { + if(strstr(line, "") != 0) + { + ffStrbufAppendS(themeOrError, line); + ffStrbufRemoveStrings(themeOrError, 2, "", ""); + ffStrbufTrimRight(themeOrError, '\n'); + ffStrbufTrim(themeOrError, ' '); + break; + } + + if(strstr(line, "") != 0) // sanity check + break; + } + + if(line != NULL) + free(line); + + fclose(file); + + if(themeOrError->length == 0) + { + ffStrbufAppendF(themeOrError, "Couldn't find theme name in \"%s\"", absolutePath.chars); + ffStrbufDestroy(&absolutePath); + return false; + } + + ffStrbufDestroy(&absolutePath); + return true; +} + +bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError) +{ + const FFDisplayServerResult* wm = ffConnectDisplayServer(instance); + + if(wm->wmPrettyName.length == 0) + { + ffStrbufAppendS(themeOrError, "WM Theme needs sucessfull WM detection"); + return false; + } + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "KWin") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "KDE") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Plasma") == 0) + return detectWMThemeFromConfigFile(instance, "kwinrc", "theme =", "Breeze", themeOrError); + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Xfwm4") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Xfwm") == 0) + return detectXFWM4(instance, themeOrError); + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Mutter") == 0) + { + if(ffStrbufIgnCaseCompS(&wm->dePrettyName, "Gnome") == 0) + return detectMutter(instance, themeOrError); + else + return detectGTKThemeAsWMTheme(instance, themeOrError); + } + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Muffin") == 0) + return detectMuffin(instance, themeOrError); + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Marco") == 0) + return detectWMThemeFromSettings(instance, "/org/mate/Marco/general/theme", "org.mate.Marco.general", NULL, "theme", themeOrError); + + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Openbox") == 0) + return detectOpenbox(instance, &wm->dePrettyName, themeOrError); + + ffStrbufAppendS(themeOrError, "Unknown WM: "); + ffStrbufAppend(themeOrError, &wm->dePrettyName); + return false; +} diff --git a/src/modules/wmtheme.c b/src/modules/wmtheme.c index ea78a68c3..4112d8321 100644 --- a/src/modules/wmtheme.c +++ b/src/modules/wmtheme.c @@ -1,350 +1,31 @@ #include "fastfetch.h" -#include "common/properties.h" #include "common/printing.h" -#include "common/parsing.h" -#include "common/settings.h" -#include "detection/gtk.h" -#include "detection/displayserver/displayserver.h" - -#include -#include +#include "detection/wmtheme/wmtheme.h" #define FF_WMTHEME_MODULE_NAME "WM Theme" #define FF_WMTHEME_NUM_FORMAT_ARGS 1 -static void printWMTheme(FFinstance* instance, const char* theme) -{ - if(instance->config.wmTheme.outputFormat.length == 0) - { - ffPrintLogoAndKey(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme.key); - puts(theme); - } - else - { - ffPrintFormat(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, FF_WMTHEME_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRING, theme} - }); - } -} - -static void printWMThemeFromConfigFile(FFinstance* instance, const char* configFile, const char* themeRegex, const char* defaultValue) -{ - FFstrbuf theme; - ffStrbufInit(&theme); - - if(!ffParsePropFileConfig(instance, configFile, themeRegex, &theme)) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Config file %s doesn't exist", configFile); - ffStrbufDestroy(&theme); - return; - } - - if(theme.length == 0) - { - ffStrbufDestroy(&theme); - - if(defaultValue == NULL) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't find WM theme in %s", configFile); - return; - } - - printWMTheme(instance, defaultValue); - return; - } - - // Remove Plasma-generated prefixes - uint32_t idx = 0; - - idx = ffStrbufFirstIndexS(&theme, "qml_"); - if(idx != theme.length) - ffStrbufSubstrAfter(&theme, idx + 3); - - idx = ffStrbufFirstIndexS(&theme, "svg__"); - if(idx != theme.length) - ffStrbufSubstrAfter(&theme, idx + 4); - - printWMTheme(instance, theme.chars); - ffStrbufDestroy(&theme); -} - -static void printWMThemeFromSettings(FFinstance* instance, const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey) -{ - const char* theme = ffSettingsGet(instance, dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue; - - if(!ffStrSet(theme)) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't find WM theme in DConf or GSettings"); - return; - } - - printWMTheme(instance, theme); -} - -static void printGTKThemeAsWMTheme(FFinstance* instance) -{ - const FFGTKResult* gtk = ffDetectGTK4(instance); - - if(gtk->theme.length > 0) - { - printWMTheme(instance, gtk->theme.chars); - return; - } - - gtk = ffDetectGTK3(instance); - - if(gtk->theme.length > 0) - { - printWMTheme(instance, gtk->theme.chars); - return; - } - - gtk = ffDetectGTK2(instance); - - if(gtk->theme.length > 0) - { - printWMTheme(instance, gtk->theme.chars); - return; - } - - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't detect GTK4/3/2 theme"); -} - -static void printMutter(FFinstance* instance) -{ - const char* theme = ffSettingsGet(instance, "/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; - if(ffStrSet(theme)) - { - printWMTheme(instance, theme); - return; - } - - printGTKThemeAsWMTheme(instance); -} - -static void printMuffin(FFinstance* instance) -{ - const char* name = ffSettingsGet(instance, "/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; - const char* theme = ffSettingsGet(instance, "/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue; - - if(name == NULL && theme == NULL) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't find muffin theme in GSettings / DConf"); - return; - } - - if(name == NULL) - printWMTheme(instance, theme); - else if(theme == NULL) - printWMTheme(instance, name); - else - { - FFstrbuf buffer; - ffStrbufInit(&buffer); - ffStrbufAppendS(&buffer, name); - ffStrbufAppendS(&buffer, " ("); - ffStrbufAppendS(&buffer, theme); - ffStrbufAppendC(&buffer, ')'); - - printWMTheme(instance, buffer.chars); - - ffStrbufDestroy(&buffer); - } -} - -static void printXFWM4(FFinstance* instance) -{ - const char* theme = ffSettingsGetXFConf(instance, "xfwm4", "/general/theme", FF_VARIANT_TYPE_STRING).strValue; - - if(theme == NULL) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't find xfwm4::/general/theme in XFConf"); - return; - } - - printWMTheme(instance, theme); -} - -static void printOpenbox(FFinstance* instance, const FFstrbuf* dePrettyName) -{ - FFstrbuf absolutePath; - ffStrbufInitA(&absolutePath, 64); - ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir); - ffStrbufAppendC(&absolutePath, '/'); - - if(ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0) - ffStrbufAppendS(&absolutePath, ".config/openbox/lxqt-rc.xml"); - else if(ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0) - ffStrbufAppendS(&absolutePath, ".config/openbox/lxde-rc.xml"); - else - ffStrbufAppendS(&absolutePath, ".config/openbox/rc.xml"); - - char* line = NULL; - size_t len = 0; - - FILE* file = fopen(absolutePath.chars, "r"); - if(file == NULL) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't open \"%s\"", absolutePath.chars); - ffStrbufDestroy(&absolutePath); - - return; - } - - FFstrbuf theme; - ffStrbufInitA(&theme, 256); - - while(getline(&line, &len, file) != -1) - { - if(strstr(line, "") != 0) - break; - } - - while(getline(&line, &len, file) != -1) - { - if(strstr(line, "") != 0) - { - ffStrbufAppendS(&theme, line); - ffStrbufRemoveStrings(&theme, 2, "", ""); - ffStrbufTrimRight(&theme, '\n'); - ffStrbufTrim(&theme, ' '); - break; - } - - if(strstr(line, "") != 0) // sanity check - break; - } - - if(line != NULL) - free(line); - - fclose(file); - - if(theme.length == 0) - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Couldn't find theme name in \"%s\"", absolutePath.chars); - else - printWMTheme(instance, theme.chars); - - ffStrbufDestroy(&theme); - ffStrbufDestroy(&absolutePath); -} - -#ifdef FF_HAVE_LIBPLIST -#include "common/library.h" -#include "common/io.h" -#include - -static const char* quartzCompositorParsePlist(FFinstance* instance, const FFstrbuf* content, FFstrbuf* theme) { - FF_LIBRARY_LOAD(libplist, &instance->config.libplist, "dlopen libplist failed", "libplist-2.0"FF_LIBRARY_EXTENSION, 2); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_is_binary); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_from_bin); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_from_xml); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_dict_get_item); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_get_string_ptr); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_get_uint_val); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libplist, plist_free); - - plist_t root_node = NULL; - if (ffplist_is_binary(content->chars, content->length)) - ffplist_from_bin(content->chars, content->length, &root_node); - else - ffplist_from_xml(content->chars, content->length, &root_node); - - if(root_node == NULL) - return "parsing Quartz Compositor preference file failed"; - - plist_t pWmThemeColor = ffplist_dict_get_item(root_node, "AppleAccentColor"); - uint64_t wmThemeColor = 100; - if (pWmThemeColor != NULL) - ffplist_get_uint_val(pWmThemeColor, &wmThemeColor); - switch (wmThemeColor) - { - case (uint64_t)-1: ffStrbufAppendS(theme, "Graphite"); break; - case 0: ffStrbufAppendS(theme, "Red"); break; - case 1: ffStrbufAppendS(theme, "Orange"); break; - case 2: ffStrbufAppendS(theme, "Yellow"); break; - case 3: ffStrbufAppendS(theme, "Green"); break; - case 4: ffStrbufAppendS(theme, "Blue"); break; - case 5: ffStrbufAppendS(theme, "Purple"); break; - case 6: ffStrbufAppendS(theme, "Pink"); break; - default: ffStrbufAppendS(theme, "Multicolor"); break; - } - - plist_t pWmTheme = ffplist_dict_get_item(root_node, "AppleInterfaceStyle"); - ffStrbufAppendF(theme, " (%s)", pWmTheme != NULL ? ffplist_get_string_ptr(pWmTheme, NULL) : "Light"); - - ffplist_free(root_node); - return NULL; -} - -static void printQuartzCompositor(FFinstance* instance) { - FFstrbuf fileName; - ffStrbufInitS(&fileName, instance->state.passwd->pw_dir); - ffStrbufAppendS(&fileName, "/Library/Preferences/.GlobalPreferences.plist"); - - FFstrbuf content; - ffStrbufInit(&content); - ffAppendFileBuffer(fileName.chars, &content); - ffStrbufDestroy(&fileName); - if(content.length == 0) - { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "reading Quartz Compositor preference file failed"); - ffStrbufDestroy(&content); - return; - } - - FFstrbuf theme; - ffStrbufInit(&theme); - const char* error = quartzCompositorParsePlist(instance, &content, &theme); - ffStrbufDestroy(&content); - - if(error != NULL) - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "%s", error); - else - printWMTheme(instance, theme.chars); -} -#else -static void printQuartzCompositor(FFinstance* instance) -{ - FF_UNUSED(instance); - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Fastfetch was compiled without libplist support"); -} -#endif - void ffPrintWMTheme(FFinstance* instance) { - #ifdef __ANDROID__ - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "WM theme detection is not supported on Android"); - return; - #endif - - const FFDisplayServerResult* result = ffConnectDisplayServer(instance); - - if(result->wmPrettyName.length == 0) + FFstrbuf themeOrError; + ffStrbufInit(&themeOrError); + if(ffDetectWmTheme(instance, &themeOrError)) { - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "WM Theme needs sucessfull WM detection"); - return; - } - - if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "KWin") == 0 || ffStrbufIgnCaseCompS(&result->wmPrettyName, "KDE") == 0 || ffStrbufIgnCaseCompS(&result->wmPrettyName, "Plasma") == 0) - printWMThemeFromConfigFile(instance, "kwinrc", "theme =", "Breeze"); - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Xfwm4") == 0 || ffStrbufIgnCaseCompS(&result->wmPrettyName, "Xfwm") == 0) - printXFWM4(instance); - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Mutter") == 0) - { - if(ffStrbufIgnCaseCompS(&result->dePrettyName, "Gnome") == 0) - printMutter(instance); + if(instance->config.wmTheme.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme.key); + puts(themeOrError.chars); + } else - printGTKThemeAsWMTheme(instance); + { + ffPrintFormat(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, FF_WMTHEME_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &themeOrError} + }); + } } - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Muffin") == 0) - printMuffin(instance); - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Marco") == 0) - printWMThemeFromSettings(instance, "/org/mate/Marco/general/theme", "org.mate.Marco.general", NULL, "theme"); - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Openbox") == 0) - printOpenbox(instance, &result->dePrettyName); - else if(ffStrbufIgnCaseCompS(&result->wmPrettyName, "Quartz Compositor") == 0) - printQuartzCompositor(instance); else - ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "Unknown WM: %s", result->wmPrettyName.chars); + { + ffPrintError(instance, FF_WMTHEME_MODULE_NAME, 0, &instance->config.wmTheme, "%*s", themeOrError.length, themeOrError.chars); + } + ffStrbufDestroy(&themeOrError); } diff --git a/src/util/FFlist.c b/src/util/FFlist.c index eccf96e32..d01353ffb 100644 --- a/src/util/FFlist.c +++ b/src/util/FFlist.c @@ -2,11 +2,6 @@ #include -void ffListInit(FFlist* list, uint32_t elementSize) -{ - ffListInitA(list, elementSize, FF_LIST_DEFAULT_ALLOC); -} - void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) { list->elementSize = elementSize; @@ -15,11 +10,6 @@ void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) list->data = capacity == 0 ? NULL : malloc((size_t)list->capacity * list->elementSize); } -void* ffListGet(const FFlist* list, uint32_t index) -{ - return list->data + (index * list->elementSize); -} - void* ffListAdd(FFlist* list) { if(list->length == list->capacity) diff --git a/src/util/FFlist.h b/src/util/FFlist.h index 8f477dd54..0ec1f2899 100644 --- a/src/util/FFlist.h +++ b/src/util/FFlist.h @@ -7,6 +7,7 @@ #include #include +#include #define FF_LIST_DEFAULT_ALLOC 16 @@ -18,15 +19,23 @@ typedef struct FFlist uint32_t capacity; } FFlist; -void ffListInit(FFlist* list, uint32_t elementSize); void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity); -FF_C_NODISCARD void* ffListGet(const FFlist* list, uint32_t index); - void* ffListAdd(FFlist* list); FF_C_NODISCARD uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*)); void ffListDestroy(FFlist* list); +static inline void ffListInit(FFlist* list, uint32_t elementSize) +{ + ffListInitA(list, elementSize, 0); +} + +static inline void* ffListGet(const FFlist* list, uint32_t index) +{ + assert(list->capacity > 0); + return list->data + (index * list->elementSize); +} + #endif diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index e6f705f52..1b152ae44 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -1,16 +1,10 @@ #include "FFstrbuf.h" -#include #include #include static char* CHAR_NULL_PTR = ""; -void ffStrbufInit(FFstrbuf* strbuf) -{ - ffStrbufInitA(strbuf, FASTFETCH_STRBUF_DEFAULT_ALLOC); -} - void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate) { strbuf->allocated = allocate; @@ -28,8 +22,21 @@ void ffStrbufInitCopy(FFstrbuf* strbuf, const FFstrbuf* src) ffStrbufAppend(strbuf, src); } +void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...) +{ + assert(format != NULL); + + ffStrbufInit(strbuf); + + va_list arguments; + va_start(arguments, format); + ffStrbufAppendVF(strbuf, format, arguments); + va_end(arguments); +} + uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) { + assert(strbuf != NULL); if(strbuf->allocated == 0) return 0; @@ -61,6 +68,8 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) void ffStrbufClear(FFstrbuf* strbuf) { + assert(strbuf != NULL); + if(strbuf->allocated == 0) strbuf->chars = CHAR_NULL_PTR; else @@ -69,18 +78,6 @@ void ffStrbufClear(FFstrbuf* strbuf) strbuf->length = 0; } -void ffStrbufRecalculateLength(FFstrbuf* strbuf) -{ - for(strbuf->length = 0; strbuf->chars[strbuf->length] != '\0'; ++strbuf->length); -} - -void ffStrbufAppend(FFstrbuf* strbuf, const FFstrbuf* value) -{ - if(value == NULL) - return; - ffStrbufAppendNS(strbuf, value->length, value->chars); -} - void ffStrbufAppendC(FFstrbuf* strbuf, char c) { ffStrbufEnsureFree(strbuf, 1); @@ -90,7 +87,7 @@ void ffStrbufAppendC(FFstrbuf* strbuf, char c) void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) { - if(value == NULL) + if(value == NULL || length == 0) return; ffStrbufEnsureFree(strbuf, length); @@ -101,7 +98,7 @@ void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude) { - if(value == NULL) + if(value == NULL || length == 0) return; ffStrbufEnsureFree(strbuf, length); @@ -120,10 +117,14 @@ void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transfor if(value == NULL) return; + //Ensure capacity > 0 or the modification below will fail + uint32_t length = (uint32_t) strlen(value); + if(length == 0) + return; + + ffStrbufEnsureFree(strbuf, length); for(uint32_t i = 0; value[i] != '\0'; i++) { - if(i % 16 == 0) - ffStrbufEnsureFree(strbuf, 16); strbuf->chars[strbuf->length++] = (char) transformFunc(value[i]); } strbuf->chars[strbuf->length] = '\0'; @@ -131,8 +132,7 @@ void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transfor void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) { - if(format == NULL) - return; + assert(format != NULL); va_list copy; va_copy(copy, arguments); @@ -155,10 +155,11 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) strbuf->chars[strbuf->length] = '\0'; } -void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) +void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...) { - if(format == NULL) - return; + assert(format != NULL); + + ffStrbufClear(strbuf); va_list arguments; va_start(arguments, format); @@ -166,13 +167,21 @@ void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) va_end(arguments); } -void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) +void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) { - ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value); + assert(format != NULL); + + va_list arguments; + va_start(arguments, format); + ffStrbufAppendVF(strbuf, format, arguments); + va_end(arguments); } void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value) { + if(value == NULL || length == 0) + return; + ffStrbufEnsureFree(strbuf, length); memmove(strbuf->chars + length, strbuf->chars, strbuf->length + 1); // + 1 for the null byte memcpy(strbuf->chars, value, length); @@ -191,35 +200,9 @@ void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value) ffStrbufAppendNS(strbuf, value->length, value->chars); } -int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp) -{ - if(strbuf->length != comp->length) - return (int) strbuf->length - (int) comp->length; - - return ffStrbufCompS(strbuf, comp->chars); -} - -int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) -{ - return strcmp(strbuf->chars, comp); -} - -int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) -{ - if(strbuf->length != comp->length) - return (int) strbuf->length - (int) comp->length; - - return ffStrbufIgnCaseCompS(strbuf, comp->chars); -} - -int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) -{ - return strcasecmp(strbuf->chars, comp); -} - void ffStrbufTrimLeft(FFstrbuf* strbuf, char c) { - if(strbuf->allocated == 0) + if(strbuf->length == 0) //`allocated == 0` implies `length == 0` return; uint32_t index = 0; @@ -236,7 +219,7 @@ void ffStrbufTrimLeft(FFstrbuf* strbuf, char c) void ffStrbufTrimRight(FFstrbuf* strbuf, char c) { - if(strbuf->allocated == 0) + if(strbuf->length == 0) return; while(ffStrbufEndsWithC(strbuf, c)) @@ -297,58 +280,23 @@ void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, ...) uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) { - for(uint32_t i = start; i < strbuf->length; i++) - { - if(strbuf->chars[i] == c) - return i; - } - return strbuf->length; + assert(start <= strbuf->length); + + const char* ptr = (const char*)memchr(strbuf->chars + start, c, strbuf->length - start); + return ptr ? (uint32_t)(ptr - strbuf->chars) : strbuf->length; } uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) { - for(uint32_t i = start; i < strbuf->length; i++) - { - bool found = true; + assert(start <= strbuf->length); - for(uint32_t k = 0; str[k] != '\0'; k++) - { - if(i + k == strbuf->length) - return strbuf->length; - - if(strbuf->chars[i + k] != str[k]) - { - found = false; - break; - } - } - - if(found) - return i; - } - - return strbuf->length; -} - -uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) -{ - return ffStrbufNextIndexC(strbuf, 0, c); -} - -uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) -{ - return ffStrbufNextIndexS(strbuf, 0, searched->chars); -} - -uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) -{ - return ffStrbufNextIndexS(strbuf, 0, str); + const char* ptr = strstr(strbuf->chars + start, str); + return ptr ? (uint32_t)(ptr - strbuf->chars) : strbuf->length; } uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) { - if(start >= strbuf->length) - return strbuf->length; + assert(start <= strbuf->length); //We need to loop one higher than the actual index, because uint32_t is guranteed to be >= 0, so this statement would always be true for(uint32_t i = start + 1; i > 0; i--) @@ -359,11 +307,6 @@ uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) return strbuf->length; } -uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) -{ - return ffStrbufPreviousIndexC(strbuf, strbuf->length - 1, c); -} - void ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index) { if(strbuf->length <= index) @@ -420,24 +363,6 @@ void ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c) ffStrbufSubstrAfter(strbuf, index); } -bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) -{ - for(uint32_t i = 0; start[i] != '\0'; i++) - { - if(i >= strbuf->length) - return false; - - if(strbuf->chars[i] != start[i]) - return false; - } - return true; -} - -bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) -{ - return ffStrbufStartsWithS(strbuf, start->chars); -} - bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) { for(uint32_t i = 0; start[i] != '\0'; i++) @@ -451,6 +376,13 @@ bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) return true; } +bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) +{ + if (start->length > strbuf->length) + return false; + return ffStrbufStartsWithIgnCaseS(strbuf, start->chars); +} + bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) { return strbuf->length == 0 ? false : @@ -464,13 +396,7 @@ bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) if(endLength > strbuf->length) return false; - for(uint32_t i = endLength; i > 0; i--) - { - if(strbuf->chars[strbuf->length - endLength + i - 1] != end[i - 1]) - return false; - } - - return true; + return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0; } uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c) @@ -481,6 +407,7 @@ uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c) if(strbuf->chars[i] == c) result++; } + return result; } @@ -531,20 +458,16 @@ void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) double ffStrbufToDouble(const FFstrbuf* strbuf) { - double value; - if(sscanf(strbuf->chars, "%lf", &value) != 1) - return 0.0 / 0.0; //NaN - - return value; + char* str_end; + double result = strtod(strbuf->chars, &str_end); + return str_end == strbuf->chars ? 0.0/0.0 : result; } uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaultValue) { - uint16_t value; - if(sscanf(strbuf->chars, "%"SCNu16, &value) != 1) - return defaultValue; - - return value; + char* str_end; + unsigned long result = strtoul(strbuf->chars, &str_end, 10); + return str_end == strbuf->chars || result > UINT16_MAX ? defaultValue : (uint16_t)result; } void ffStrbufDestroy(FFstrbuf* strbuf) diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index be1849623..84db2f060 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include #define FASTFETCH_STRBUF_DEFAULT_ALLOC 32 @@ -22,9 +24,9 @@ typedef struct FFstrbuf #define FF_STRBUF_CREATE(name) FFstrbuf name; ffStrbufInit(&name); -void ffStrbufInit(FFstrbuf* strbuf); void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate); void ffStrbufInitCopy(FFstrbuf* strbuf, const FFstrbuf* src); +void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...); void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free); @@ -32,29 +34,18 @@ FF_C_NODISCARD uint32_t ffStrbufGetFree(const FFstrbuf* strbuf); void ffStrbufClear(FFstrbuf* strbuf); -void ffStrbufRecalculateLength(FFstrbuf* strbuf); - -void ffStrbufAppend(FFstrbuf* strbuf, const FFstrbuf* value); void ffStrbufAppendC(FFstrbuf* strbuf, char c); - void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value); - void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude); void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int)); FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...); void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments); -void ffStrbufPrependS(FFstrbuf* strbuf, const char* value); void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value); - -FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp); -FF_C_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp); - -FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp); -FF_C_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp); +void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...); void ffStrbufTrimLeft(FFstrbuf* strbuf, char c); void ffStrbufTrimRight(FFstrbuf* strbuf, char c); @@ -69,14 +60,8 @@ void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, ...); FF_C_NODISCARD uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c); FF_C_NODISCARD uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str); -FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c); -FF_C_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched); -FF_C_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str); - FF_C_NODISCARD uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c); -FF_C_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c); - void ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index); void ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c); void ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c); @@ -85,8 +70,6 @@ void ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c); void ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str); void ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c); -bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start); - bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start); bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start); @@ -107,6 +90,11 @@ FF_C_NODISCARD uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaul void ffStrbufDestroy(FFstrbuf* strbuf); +static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf) +{ + strbuf->length = (uint32_t) strlen(strbuf->chars); +} + static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value) { if(value == NULL) @@ -128,4 +116,87 @@ static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) ffStrbufAppendS(strbuf, str); } +static inline void ffStrbufAppend(FFstrbuf* strbuf, const FFstrbuf* value) +{ + assert(value != strbuf); + if(value == NULL) + return; + ffStrbufAppendNS(strbuf, value->length, value->chars); +} + +static inline void ffStrbufInit(FFstrbuf* strbuf) +{ + ffStrbufInitA(strbuf, 0); +} + +static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) +{ + if(value == NULL) + return; + ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value); +} + +static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp) +{ + uint32_t length = strbuf->length > comp->length ? comp->length : strbuf->length; + return memcmp(strbuf->chars, comp->chars, length + 1); +} + +static inline FF_C_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) +{ + return strcmp(strbuf->chars, comp); +} + +static inline FF_C_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) +{ + return strcasecmp(strbuf->chars, comp); +} + +static inline FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) +{ + return ffStrbufIgnCaseCompS(strbuf, comp->chars); +} + +static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) +{ + return ffStrbufNextIndexC(strbuf, 0, c); +} + +static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) +{ + return ffStrbufNextIndexS(strbuf, 0, searched->chars); +} + +static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) +{ + return ffStrbufNextIndexS(strbuf, 0, str); +} + +static inline FF_C_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) +{ + return ffStrbufPreviousIndexC(strbuf, strbuf->length - 1, c); +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) +{ + return strbuf->chars[0] == c; +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) +{ + if (length > strbuf->length) + return false; + + return memcmp(strbuf->chars, start, length) == 0; +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) +{ + return ffStrbufStartsWithSN(strbuf, start, (uint32_t) strlen(start)); +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) +{ + return ffStrbufStartsWithSN(strbuf, start->chars, start->length); +} #endif diff --git a/tests/list.c b/tests/list.c index ebae7c8d7..38be491e5 100644 --- a/tests/list.c +++ b/tests/list.c @@ -4,12 +4,11 @@ #include #include -static void testFailed(const FFlist* list, const char* message, ...) +__attribute__((__noreturn__)) +static void testFailed(const FFlist* list, const char* expression, int lineNo) { - va_list args; - va_start(args, message); fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stderr); - vfprintf(stderr, message, args); + fprintf(stderr, "[%d] %s, list:", lineNo, expression); for (uint32_t i = 0; i < list->length; ++i) { fprintf(stderr, "%u ", *(uint32_t*)ffListGet(list, i)); @@ -17,10 +16,16 @@ static void testFailed(const FFlist* list, const char* message, ...) fputc('\n', stderr); fputs(FASTFETCH_TEXT_MODIFIER_RESET, stderr); fputc('\n', stderr); - va_end(args); exit(1); } +static bool numEqualsAdapter(const void* first, const void* second) +{ + return *(uint32_t*)first == *(uint32_t*)second; +} + +#define VERIFY(expression) if(!(expression)) testFailed(&list, #expression, __LINE__) + int main(int argc, char** argv) { FF_UNUSED(argc, argv) @@ -29,60 +34,45 @@ int main(int argc, char** argv) //initA - ffListInitA(&list, sizeof(uint32_t), 0); + ffListInit(&list, sizeof(uint32_t)); - if(ffListGet(&list, 0) != NULL) - testFailed(&list, "ffListGet(&list, 0) != NULL"); - - if(list.elementSize != sizeof(int)) - testFailed(&list, "list.elementSize != sizeof(int)"); - - if(list.capacity != 0) - testFailed(&list, "list.capacity != 0"); - - if(list.length != 0) - testFailed(&list, "list.length != 0"); + VERIFY(list.elementSize == sizeof(uint32_t)); + VERIFY(list.capacity == 0); + VERIFY(list.length == 0); //add for (uint32_t i = 1; i <= FF_LIST_DEFAULT_ALLOC + 1; ++i) { *(uint32_t*)ffListAdd(&list) = i; - if(list.elementSize != sizeof(uint32_t)) - testFailed(&list, "list.elementSize != sizeof(uint32_t)"); - - if(list.length != i) - testFailed(&list, "list.length != i"); + VERIFY(list.elementSize == sizeof(uint32_t)); + VERIFY(list.length == i); if(i <= FF_LIST_DEFAULT_ALLOC) { - if(list.capacity != FF_LIST_DEFAULT_ALLOC) - testFailed(&list, "list.length != FF_LIST_DEFAULT_ALLOC"); + VERIFY(list.capacity == FF_LIST_DEFAULT_ALLOC); } else { - if(list.capacity != FF_LIST_DEFAULT_ALLOC * 2) - testFailed(&list, "list.length != FF_LIST_DEFAULT_ALLOC * 2"); + VERIFY(list.capacity == FF_LIST_DEFAULT_ALLOC * 2); } - if(*(uint32_t*)ffListGet(&list, 0) != 1) - testFailed(&list, "*(int*)ffListGet(&list, 0) != 1"); - - if(*(uint32_t*)ffListGet(&list, i - 1) != i) - testFailed(&list, "*(int*)ffListGet(&list, i - 1) != i"); + VERIFY(*(uint32_t*)ffListGet(&list, 0) == 1); + VERIFY(*(uint32_t*)ffListGet(&list, i - 1) == i); } + // ffListFirstIndexComp + uint32_t n = 10; + VERIFY(ffListFirstIndexComp(&list, &n, numEqualsAdapter) == 9); + n = 999; + VERIFY(ffListFirstIndexComp(&list, &n, numEqualsAdapter) == list.length); + //Destroy ffListDestroy(&list); - if(list.elementSize != sizeof(uint32_t)) - testFailed(&list, "list.elementSize != sizeof(uint32_t)"); - - if(list.capacity != 0) - testFailed(&list, "list.capacity != 0"); - - if(list.length != 0) - testFailed(&list, "list.length != 0"); + VERIFY(list.elementSize == sizeof(uint32_t)); + VERIFY(list.capacity == 0); + VERIFY(list.length == 0); //Success puts("\033[32mAll tests passed!"FASTFETCH_TEXT_MODIFIER_RESET); diff --git a/tests/strbuf.c b/tests/strbuf.c index a82180d60..da26e50e7 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -1,20 +1,23 @@ #include "fastfetch.h" #include -#include #include -static void testFailed(const FFstrbuf* strbuf, const char* message, ...) +__attribute__((__noreturn__)) +static void testFailed(const FFstrbuf* strbuf, const char* expression, int lineNo) { - va_list args; - va_start(args, message); fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stderr); - vfprintf(stderr, message, args); - fputs(", strbuf: ", stderr); + fprintf(stderr, "[%d] %s, strbuf:", lineNo, expression); ffStrbufWriteTo(strbuf, stderr); fputs(FASTFETCH_TEXT_MODIFIER_RESET, stderr); fputc('\n', stderr); - va_end(args); + exit(1); +} + +#define VERIFY(expression) if(!(expression)) testFailed(&strbuf, #expression, __LINE__) + +int shouldNotBeCalled(int c) { + FF_UNUSED(c); exit(1); } @@ -32,102 +35,134 @@ int main(int argc, char** argv) ffStrbufInitA(&strbuf, 0); - if(strbuf.chars[0] != 0) //make sure chars[0] is accessable - testFailed(&strbuf, "strbuf.chars[0] != 0"); + VERIFY(strbuf.chars[0] == 0); + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); - if(strbuf.allocated != 0) - testFailed(&strbuf, "strbuf.allocated != 0"); + VERIFY(!ffStrbufStartsWithC(&strbuf, '0')); + VERIFY(!ffStrbufEndsWithC(&strbuf, '0')); + VERIFY(!ffStrbufStartsWithS(&strbuf, "0")); + VERIFY(!ffStrbufEndsWithS(&strbuf, "0")); + VERIFY(ffStrbufCountC(&strbuf, '0') == 0); - if(strbuf.length != 0) - testFailed(&strbuf, "strbuf.length != 0"); + //Ensure following functions work with non-allocated string + ffStrbufAppendS(&strbuf, ""); + ffStrbufAppendF(&strbuf, "%s", ""); + ffStrbufAppendTransformS(&strbuf, "", shouldNotBeCalled); + ffStrbufPrependS(&strbuf, ""); + ffStrbufTrim(&strbuf, ' '); + + VERIFY(strbuf.chars[0] == 0); + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); //appendS ffStrbufAppendS(&strbuf, "12345"); + ffStrbufAppendS(&strbuf, NULL); - if(strbuf.length != 5) - testFailed(&strbuf, "strbuf.length != 5"); - - if(strbuf.allocated < 6) - testFailed(&strbuf, "strbuf.allocated < 6"); - - if(ffStrbufCompS(&strbuf, "12345") != 0) - testFailed(&strbuf, "strbuf.data != \"12345\""); + VERIFY(strbuf.length == 5); + VERIFY(strbuf.allocated >= 6); + VERIFY(ffStrbufCompS(&strbuf, "12345") == 0); //appendNS ffStrbufAppendNS(&strbuf, 4, "67890"); + ffStrbufAppendNS(&strbuf, 0, NULL); - if(strbuf.length != 9) - testFailed(&strbuf, "strbuf.length != 9"); - - if(strbuf.allocated < 10) - testFailed(&strbuf, "strbuf.allocated < 10"); - - if(ffStrbufCompS(&strbuf, "123456789") != 0) - testFailed(&strbuf, "strbuf.data != \"123456789\""); + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 10); + VERIFY(ffStrbufCompS(&strbuf, "123456789") == 0); //appendS long ffStrbufAppendS(&strbuf, "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + VERIFY(strbuf.length == 109); + VERIFY(strbuf.allocated >= 110); + VERIFY(strbuf.chars[strbuf.length] == 0); - if(strbuf.length != 109) - testFailed(&strbuf, "strbuf.length != 109"); + //substr - if(strbuf.allocated < 110) - testFailed(&strbuf, "strbuf.allocated < 110"); + ffStrbufSubstrBefore(&strbuf, 9); + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 110); + VERIFY(strbuf.chars[strbuf.length] == 0); + VERIFY(ffStrbufCompS(&strbuf, "123456789") == 0); - if(strbuf.chars[strbuf.length] != 0) - testFailed(&strbuf, "strbuf.chars[strbuf.length] != 0"); + //startsWithC - strbuf.length = 9; + VERIFY(ffStrbufStartsWithC(&strbuf, '1')); + VERIFY(!ffStrbufStartsWithC(&strbuf, '2')); //startsWithS - if(!ffStrbufStartsWithS(&strbuf, "123")) - testFailed(&strbuf, "!ffStrbufStartsWithS(&strbuf, \"123\")"); + VERIFY(ffStrbufStartsWithS(&strbuf, "123")); + VERIFY(ffStrbufStartsWithS(&strbuf, "123456789")); + VERIFY(!ffStrbufStartsWithS(&strbuf, "1234567890123")); + + //endsWithC + VERIFY(ffStrbufEndsWithC(&strbuf, '9')); + VERIFY(!ffStrbufEndsWithC(&strbuf, '1')); + + //endsWithS + + VERIFY(ffStrbufEndsWithS(&strbuf, "789")); + VERIFY(ffStrbufEndsWithS(&strbuf, "123456789")); + VERIFY(!ffStrbufEndsWithS(&strbuf, "1234567890123")); + + //toNumber + + VERIFY(ffStrbufToDouble(&strbuf) == 123456789.0); + VERIFY(ffStrbufToUInt16(&strbuf, 999) == 999); //overflow + + //countC + + VERIFY(ffStrbufCountC(&strbuf, '1') == 1); + VERIFY(ffStrbufCountC(&strbuf, '0') == 0); //removeS ffStrbufRemoveS(&strbuf, "78"); - if(strbuf.length != 7) - testFailed(&strbuf, "strbuf.length != 7"); - - if(strcmp(strbuf.chars, "1234569") != 0) - testFailed(&strbuf, "strcmp(strbuf.chars, \"123469\") != 0"); + VERIFY(strbuf.length == 7); + VERIFY(strcmp(strbuf.chars, "1234569") == 0); //removeStrings ffStrbufRemoveStrings(&strbuf, 3, "23", "45", "9"); - if(strbuf.length != 2) - testFailed(&strbuf, "strbuf.length != 2"); - - if(strcmp(strbuf.chars, "16") != 0) - testFailed(&strbuf, "strbuf.chars != \"126\""); + VERIFY(strbuf.length == 2); + VERIFY(strcmp(strbuf.chars, "16") == 0); //PrependS ffStrbufPrependS(&strbuf, "123"); + ffStrbufPrependS(&strbuf, NULL); - if(strbuf.length != 5) - testFailed(&strbuf, "strbuf.length != 5"); + VERIFY(strbuf.length == 5); + VERIFY(strcmp(strbuf.chars, "12316") == 0); - if(strcmp(strbuf.chars, "12316") != 0) - testFailed(&strbuf, "strbuf.chars != \"12316\""); + //indexC + VERIFY(ffStrbufFirstIndexC(&strbuf, '1') == 0); + VERIFY(ffStrbufNextIndexC(&strbuf, 1, '1') == 3); + VERIFY(ffStrbufNextIndexC(&strbuf, 4, '1') == 5); + VERIFY(ffStrbufLastIndexC(&strbuf, '1') == 3); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 2, '1') == 0); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 0, '1') == 0); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 0, '2') == 5); + + //indexS + VERIFY(ffStrbufFirstIndexS(&strbuf, "12316") == 0); + VERIFY(ffStrbufNextIndexS(&strbuf, 1, "1") == 3); + VERIFY(ffStrbufNextIndexS(&strbuf, 4, "1") == 5); //Destroy ffStrbufDestroy(&strbuf); - if(strbuf.allocated != 0) - testFailed(&strbuf, "strbuf.allocated != 0"); - if(strbuf.length != 0) - testFailed(&strbuf, "strbuf.length != 0"); - - if(strbuf.chars != NULL) - testFailed(&strbuf, "strbuf.chars != NULL"); + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.chars == NULL); //Success puts("\033[32mAll tests passed!"FASTFETCH_TEXT_MODIFIER_RESET);