diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ae9e3e4..5fac1e924 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,7 @@ set(LIBFASTFETCH_SRC src/modules/wifi.c src/modules/wm.c src/modules/wmtheme.c + src/modules/jsonconfig/jsonconfig.c src/util/FFlist.c src/util/FFstrbuf.c src/util/FFvaluestore.c diff --git a/src/common/config.c b/src/common/config.c index 2b9f9045c..f7d124fce 100644 --- a/src/common/config.c +++ b/src/common/config.c @@ -3,116 +3,6 @@ #ifdef FF_HAVE_JSONC -#include "common/io/io.h" -#include "modules/modules.h" - -#include - -static inline bool parseModuleJsonObject(FFinstance* instance, const char* type, JSONCData* data, json_object* module) -{ - return - ffParseTitleJsonObject(instance, type, data, module) || - ffParseBatteryJsonObject(instance, type, data, module) || - ffParseCommandJsonObject(instance, type, data, module) || - ffParseOSJsonObject(instance, type, data, module) || - ffParseSeparatorJsonObject(instance, type, data, module) || - false; -} - -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(!parseModuleJsonObject(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) @@ -133,11 +23,4 @@ bool ffJsonConfigParseModuleArgs(JSONCData* data, const char* key, json_object* 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 index 23e597af4..81dd9c011 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -25,5 +25,3 @@ typedef struct 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 bfff141e9..a8fe3357e 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1494,6 +1494,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char ffPrintSound(instance); else if(strcasecmp(line, "gamepad") == 0) ffPrintGamepad(instance); + else if(strcasecmp(line, "jsonconfig") == 0) + ffPrintJsonConfig(instance); else ffPrintErrorString(instance, line, 0, NULL, NULL, ""); } @@ -1535,41 +1537,34 @@ int main(int argc, const char** argv) fflush(stdout); #endif - if (ffStrbufIgnCaseEqualS(&data.structure, "Config")) + //Parse the structure and call the modules + uint32_t startIndex = 0; + while (startIndex < data.structure.length) { - ffJsonConfigParse(&instance); - } - else - { - //Parse the structure and call the modules - uint32_t startIndex = 0; - while (startIndex < data.structure.length) + 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)) { - 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; + 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; } ffFinish(&instance); diff --git a/src/modules/jsonconfig/jsonconfig.c b/src/modules/jsonconfig/jsonconfig.c new file mode 100644 index 000000000..893972315 --- /dev/null +++ b/src/modules/jsonconfig/jsonconfig.c @@ -0,0 +1,131 @@ +#include "modules/jsonconfig/jsonconfig.h" +#include "common/config.h" +#include "common/printing.h" + +#ifdef FF_HAVE_JSONC + +#include "common/io/io.h" +#include "modules/modules.h" + +#include + +static inline bool parseModuleJsonObject(FFinstance* instance, const char* type, JSONCData* data, json_object* module) +{ + return + ffParseTitleJsonObject(instance, type, data, module) || + ffParseBatteryJsonObject(instance, type, data, module) || + ffParseCommandJsonObject(instance, type, data, module) || + ffParseOSJsonObject(instance, type, data, module) || + ffParseSeparatorJsonObject(instance, type, data, module) || + false; +} + +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(!parseModuleJsonObject(instance, type, data, module)) + return "Unknown module type"; + } + + return NULL; +} + +static const char* printJsonConfig(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; +} + +#else + +static const char* printJsonConfig(FF_MAYBE_UNUSED FFinstance* instance) +{ + return "Fastfetch was compiled without json-c support"; +} + +#endif + +void ffPrintJsonConfig(FFinstance* instance) +{ + const char* error = printJsonConfig(instance); + if (error) + ffPrintErrorString(instance, "JsonConfig", 0, NULL, NULL, "%s", error); +} diff --git a/src/modules/jsonconfig/jsonconfig.h b/src/modules/jsonconfig/jsonconfig.h new file mode 100644 index 000000000..a29f7bda5 --- /dev/null +++ b/src/modules/jsonconfig/jsonconfig.h @@ -0,0 +1,5 @@ +#pragma once + +#include "fastfetch.h" + +void ffPrintJsonConfig(FFinstance* instance); diff --git a/src/modules/modules.h b/src/modules/modules.h index f407e92d2..e2a2b672a 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -7,3 +7,4 @@ #include "modules/command/command.h" #include "modules/separator/separator.h" #include "modules/title/title.h" +#include "modules/jsonconfig/jsonconfig.h"