From 790ca460d4c501ac2aab7dd969fe8689fdfe8ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 9 Mar 2023 16:01:18 +0800 Subject: [PATCH] Battery: init support of JSON config --- CMakeLists.txt | 3 +- src/common/config.c | 132 ++++++++++++++++++++++++++++++++++ src/common/config.h | 29 ++++++++ src/fastfetch.c | 58 ++++++++------- src/modules/battery/battery.c | 45 ++++++++++++ src/modules/battery/battery.h | 5 ++ 6 files changed, 246 insertions(+), 26 deletions(-) create mode 100644 src/common/config.c create mode 100644 src/common/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b6b9dee1e..bd302d562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,7 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" cmake_dependent_option(ENABLE_LIBNM "Enable libnm" ON "LINUX" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR BSD" OFF) -cmake_dependent_option(ENABLE_JSONC "Enable json-c" ON "LINUX OR WIN32" OFF) +cmake_dependent_option(ENABLE_JSONC "Enable json-c" ON "LINUX OR APPLE OR BSD OR WIN32 OR ANDROID" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF) cmake_dependent_option(ENABLE_BUFFER "Enable stdout buffer" ON "LINUX OR APPLE OR BSD OR WIN32 OR ANDROID" OFF) @@ -228,6 +228,7 @@ configure_file(src/fastfetch_config.h.in fastfetch_config.h) set(LIBFASTFETCH_SRC src/common/bar.c + src/common/config.c src/common/font.c src/common/format.c src/common/init.c diff --git a/src/common/config.c b/src/common/config.c new file mode 100644 index 000000000..75af071c8 --- /dev/null +++ b/src/common/config.c @@ -0,0 +1,132 @@ +#include "fastfetch.h" +#include "common/config.h" + +#ifdef FF_HAVE_JSONC + +#include "common/io/io.h" +#include "modules/modules.h" + +#include + +static inline void wrapJsoncFree(JSONCData* data) +{ + assert(data); + if (data->root) + data->ffjson_object_put(data->root); +} + +static const char* parseModules(FFinstance* instance, JSONCData* data, json_object* modules) +{ + array_list* list = data->ffjson_object_get_array(modules); + if (!list) return "modules must be an array of strings or objects"; + + for (size_t idx = 0; idx < list->length; ++idx) + { + json_object* module = (json_object*) list->array[idx]; + const char* type = NULL; + if (data->ffjson_object_is_type(module, json_type_string)) + { + type = data->ffjson_object_get_string(module); + module = NULL; + } + else if (data->ffjson_object_is_type(module, json_type_object)) + { + type = data->ffjson_object_get_string(data->ffjson_object_object_get(module, "type")); + if (!type) return "module object must contain a type key"; + } + else + return "modules must be an array of strings or objects"; + + if(!ffParseBatteryJsonObject(instance, type, data, module)) + return "Unknown module type"; + } + + return NULL; +} + +const char* ffJsonConfigParse(FFinstance* instance) +{ + FF_LIBRARY_LOAD(libjsonc, &instance->config.libJSONC, "dlopen libjson-c" FF_LIBRARY_EXTENSION" failed", + #ifdef _WIN32 + "libjson-c-5" FF_LIBRARY_EXTENSION, -1 + #else + "libjson-c" FF_LIBRARY_EXTENSION, 5 + #endif + ) + JSONCData __attribute__((__cleanup__(wrapJsoncFree))) data = {}; + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_tokener_parse) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_is_type) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_array) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_boolean) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_double) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_string_len) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_string) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_get_object) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_object_get) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libjsonc, data, json_object_put) + + FF_STRBUF_AUTO_DESTROY content; + ffStrbufInit(&content); + FF_LIST_FOR_EACH(FFstrbuf, filename, instance->state.platform.configDirs) + { + uint32_t oldLength = filename->length; + ffStrbufAppendS(filename, "fastfetch/config.json"); + bool success = ffAppendFileBuffer(filename->chars, &content); + ffStrbufSubstrBefore(filename, oldLength); + if (success) break; + } + + data.root = data.ffjson_tokener_parse(content.chars); + if (!data.root) + return "Failed to parse JSON config file"; + + lh_table* rootObject = data.ffjson_object_get_object(data.root); + if (!rootObject) + return "Invalid JSON config format. Root value must be an object"; + + struct lh_entry* entry; + lh_foreach(rootObject, entry) + { + const char* key = (const char *)lh_entry_k(entry); + json_object* val = (struct json_object *)lh_entry_v(entry); + + if (strcmp(key, "modules") == 0) + { + const char* error = parseModules(instance, &data, val); + if (error) return error; + } + else + return "Unknown JSON config key in root object"; + } + + return NULL; +} + +bool ffJsonConfigParseModuleArgs(JSONCData* data, const char* key, json_object* val, FFModuleArgs* moduleArgs) +{ + if(strcasecmp(key, "key") == 0) + { + ffStrbufSetNS(&moduleArgs->key, (uint32_t) data->ffjson_object_get_string_len(val), data->ffjson_object_get_string(val)); + return true; + } + else if(strcasecmp(key, "format") == 0) + { + ffStrbufSetNS(&moduleArgs->outputFormat, (uint32_t) data->ffjson_object_get_string_len(val), data->ffjson_object_get_string(val)); + return true; + } + else if(strcasecmp(key, "error") == 0) + { + ffStrbufSetNS(&moduleArgs->errorFormat, (uint32_t) data->ffjson_object_get_string_len(val), data->ffjson_object_get_string(val)); + return true; + } + return false; +} + +#else + +const char* ffParseJsonConfig(FF_MAYBE_UNUSED FFinstance* instance) +{ + return "Fastfetch was compiled without json-c support"; +} + +#endif diff --git a/src/common/config.h b/src/common/config.h new file mode 100644 index 000000000..23e597af4 --- /dev/null +++ b/src/common/config.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef FF_HAVE_JSONC + +#include + +#include "common/library.h" + +typedef struct JSONCData +{ + FF_LIBRARY_SYMBOL(json_tokener_parse) + FF_LIBRARY_SYMBOL(json_object_is_type) + FF_LIBRARY_SYMBOL(json_object_get_array) + FF_LIBRARY_SYMBOL(json_object_get_boolean) + FF_LIBRARY_SYMBOL(json_object_get_double) + FF_LIBRARY_SYMBOL(json_object_get_string_len) + FF_LIBRARY_SYMBOL(json_object_get_string) + FF_LIBRARY_SYMBOL(json_object_get_object) + FF_LIBRARY_SYMBOL(json_object_object_get) + FF_LIBRARY_SYMBOL(json_object_put) + + json_object* root; +} JSONCData; + +bool ffJsonConfigParseModuleArgs(JSONCData* data, const char* key, json_object* val, FFModuleArgs* moduleArgs); + +#endif + +const char* ffJsonConfigParse(FFinstance* instance); diff --git a/src/fastfetch.c b/src/fastfetch.c index a838592ff..ade8d4d35 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -18,6 +18,7 @@ #pragma GCC diagnostic ignored "-Wsign-conversion" #include "modules/os/os.h" +#include "common/config.h" #include "modules/modules.h" typedef struct CustomValue @@ -1537,34 +1538,41 @@ int main(int argc, const char** argv) fflush(stdout); #endif - //Parse the structure and call the modules - uint32_t startIndex = 0; - while (startIndex < data.structure.length) + if (ffStrbufIgnCaseEqualS(&data.structure, "Config")) { - uint32_t colonIndex = ffStrbufNextIndexC(&data.structure, startIndex, ':'); - data.structure.chars[colonIndex] = '\0'; - - uint64_t ms = 0; - if(__builtin_expect(instance.config.stat, false)) - ms = ffTimeGetTick(); - - parseStructureCommand(&instance, &data, data.structure.chars + startIndex); - - if(__builtin_expect(instance.config.stat, false)) + ffJsonConfigParse(&instance); + } + else + { + //Parse the structure and call the modules + uint32_t startIndex = 0; + while (startIndex < data.structure.length) { - char str[32]; - int len = snprintf(str, sizeof str, "%" PRIu64 "ms", ffTimeGetTick() - ms); - if(instance.config.pipe) - puts(str); - else - printf("\033[s\033[1A\033[9999999C\033[%dD%s\033[u", len, str); // Save; Up 1; Right 9999999; Left ; Print ; Load + uint32_t colonIndex = ffStrbufNextIndexC(&data.structure, startIndex, ':'); + data.structure.chars[colonIndex] = '\0'; + + uint64_t ms = 0; + if(__builtin_expect(instance.config.stat, false)) + ms = ffTimeGetTick(); + + parseStructureCommand(&instance, &data, data.structure.chars + startIndex); + + if(__builtin_expect(instance.config.stat, false)) + { + char str[32]; + int len = snprintf(str, sizeof str, "%" PRIu64 "ms", ffTimeGetTick() - ms); + if(instance.config.pipe) + puts(str); + else + printf("\033[s\033[1A\033[9999999C\033[%dD%s\033[u", len, str); // Save; Up 1; Right 9999999; Left ; Print ; Load + } + + #if defined(_WIN32) && defined(FF_ENABLE_BUFFER) + fflush(stdout); + #endif + + startIndex = colonIndex + 1; } - - #if defined(_WIN32) && defined(FF_ENABLE_BUFFER) - fflush(stdout); - #endif - - startIndex = colonIndex + 1; } ffFinish(&instance); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 4ba93c49d..f76f67797 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -146,3 +146,48 @@ void ffDestroyBatteryOptions(FFBatteryOptions* options) ffStrbufDestroy(&options->dir); #endif } + +#ifdef FF_HAVE_JSONC +bool ffParseBatteryJsonObject(FFinstance* instance, const char* type, JSONCData* data, json_object* module) +{ + if (strcasecmp(type, FF_BATTERY_MODULE_NAME) != 0) + return false; + + FFBatteryOptions __attribute__((__cleanup__(ffDestroyBatteryOptions))) options; + ffInitBatteryOptions(&options); + + if (module) + { + struct lh_entry* entry; + lh_foreach(data->ffjson_object_get_object(module), entry) + { + const char* key = (const char *)lh_entry_k(entry); + if (strcasecmp(key, "type") == 0) + continue; + json_object* val = (struct json_object *)lh_entry_v(entry); + + if (ffJsonConfigParseModuleArgs(data, key, val, &options.moduleArgs)) + continue; + + #ifdef __linux__ + if (strcasecmp(key, "dir") == 0) + { + ffStrbufSetS(&options.dir, data->ffjson_object_get_string(val)); + continue; + } + #endif + + if (strcasecmp(key, "temp") == 0) + { + options.temp = (bool) data->ffjson_object_get_boolean(val); + continue; + } + + ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &options.moduleArgs, "Unknown JSON key %s", key); + } + } + + ffPrintBattery(instance, &options); + return true; +} +#endif diff --git a/src/modules/battery/battery.h b/src/modules/battery/battery.h index c6eb2951f..14d31c3f0 100644 --- a/src/modules/battery/battery.h +++ b/src/modules/battery/battery.h @@ -8,3 +8,8 @@ void ffPrintBattery(FFinstance* instance, FFBatteryOptions* options); void ffInitBatteryOptions(FFBatteryOptions* options); bool ffParseBatteryCommandOptions(FFBatteryOptions* options, const char* key, const char* value); void ffDestroyBatteryOptions(FFBatteryOptions* options); + +#ifdef FF_HAVE_JSONC +#include "common/config.h" +bool ffParseBatteryJsonObject(FFinstance* instance, const char* type, JSONCData* data, json_object* module); +#endif